Spring NoSuchBeanDefinitionException ao mudar para JPMS (Java Platform Module System)
Estou tentando migrar um grande projeto para JPMS (Java Platform Module System).
Ele contém alguns componentes do Spring que estão me causando problemas. Criei um repositório de teste para demonstrar o problema. Quando removo o arquivo module-info.java, ele funciona muito bem, conforme mostrado pelo teste em TestControllerTest.java . No entanto, se eu adicionar o module-info.java, ele para de funcionar com a seguinte exceção:
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'RESTConfiguration': Unsatisfied dependency expressed through field 'fooAuthenticationProvider'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.spacemetric.spring.jpmstest.auth.FooAuthenticationProvider' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at [email protected]/org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:643)
at [email protected]/org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:130)
at …
O rastreamento de pilha parece indicar que o ApplicationContextnão consegue encontrar a @Autowiredimplementação. Abri todo o módulo para uma reflexão profunda. Meu palpite altamente inculto é que isso pode estar relacionado ao caminho de classe versus caminho de módulo, mas não sei o que fazer a respeito.
O arquivo module-info.java é o seguinte:
open module com.spacemetric.spring.jpmstest {
requires spring.core;
requires spring.context;
requires spring.beans;
requires spring.security.config;
requires spring.security.web;
requires spring.webmvc;
requires spring.security.core;
requires javax.servlet.api;
requires spring.web;
}
A seguir está a linha de comando usada pelo Eclipse para executar o teste (conforme solicitado):
C: \ Arquivos de programas \ Java \ java-11-openjdk-11.0.7.10-1.windows.redhat.x86_64 \ bin \ javaw.exe -ea --add-opens com.spacemetric.spring.jpmstest / com.spacemetric. spring.jpmstest = ALL-UNNAMED --add-modules = ALL-MODULE-PATH -Dfile.encoding = UTF-8 -p "C: \ dev \ source \ spring-jpms-test \ target \ classes; C: \ Usuários \ Oscar Haglund.m2 \ repository \ org \ springframework \ spring-core \ 5.2.6.RELEASE \ spring-core-5.2.6.RELEASE.jar; C: \ Users \ Oscar Haglund.m2 \ repository \ org \ springframework \ security \ spring-security-web \ 5.3.2.RELEASE \ spring-security-web-5.3.2.RELEASE.jar; C: \ Users \ Oscar Haglund.m2 \ repository \ org \ springframework \ security \ spring-security- core \ 5.3.2.RELEASE \ spring-security-core-5.3.2.RELEASE.jar; C: \ Users \ Oscar Haglund.m2 \ repository \ org \ springframework \ spring-beans \ 5.2.6.RELEASE \ spring- beans-5.2.6.RELEASE.jar; C: \ Usuários \ Oscar Haglund.m2 \ repository \ org \ springframework \ spring-context \ 5.2.6.RELEASE \ spring-context-5.2.6.RELEASE.jar; C: \ Users \ Oscar Haglund.m2 \ repository \ org \ springframework \ spring-web \ 5.2.6.RELEASE \ spring-web-5. 2.6.RELEASE.jar; C: \ Users \ Oscar Haglund.m2 \ repository \ org \ springframework \ security \ spring-security-config \ 5.3.2.RELEASE \ spring-security-config-5.3.2.RELEASE.jar; C: \ Users \ Oscar Haglund.m2 \ repository \ org \ springframework \ spring-webmvc \ 5.2.6.RELEASE \ spring-webmvc-5.2.6.RELEASE.jar; C: \ Users \ Oscar Haglund.m2 \ repository \ javax \ servlet \ javax.servlet-api \ 3.1.0 \ javax.servlet-api-3.1.0.jar "-classpath" C: \ Users \ Oscar Haglund.m2 \ repository \ org \ springframework \ spring-jcl \ 5.2 .6.RELEASE \ spring-jcl-5.2.6.RELEASE.jar; C: \ Users \ Oscar Haglund.m2 \ repository \ org \ springframework \ spring-aop \ 5.2.6.RELEASE \ spring-aop-5.2.6 .RELEASE.jar; C: \ Users \ Oscar Haglund.m2 \ repository \ org \ springframework \ spring-expression \ 5.2.6.RELEASE \ spring-expression-5.2.6.RELEASE.jar; C: \ Users \ Oscar Haglund .m2 \ repository \ org \ junit \ jupiter \ junit-jupiter-engine \ 5.7.0 \ junit-jupiter-engine-5.7.0.jar; C: \ Users \ Oscar Haglund.m2 \ repository \ org \ apiguardian \ apiguardian -api \ 1.1.0 \ apiguardian-api-1.1.0.jar; C: \ Users \ Oscar Haglund.m2 \ repository \ org \ junit \ platform \ junit-platform-engine \ 1.7.0 \ junit-platform-engine-1.7.0.jar; C: \ Users \ Oscar Haglund.m2 \ repository \ org \ opentest4j \ opentest4j \ 1.2.0 \ opentest4j-1.2 .0.jar; C: \ Users \ Oscar Haglund.m2 \ repository \ org \ junit \ platform \ junit-platform-commons \ 1.7.0 \ junit-platform-commons-1.7.0.jar; C: \ Users \ Oscar Haglund.m2 \ repository \ org \ junit \ jupiter \ junit-jupiter-api \ 5.7.0 \ junit-jupiter-api-5.7.0.jar; C: \ Users \ Oscar Haglund.m2 \ repository \ org \ springframework \ spring-test \ 5.2.6.RELEASE \ spring-test-5.2.6.RELEASE.jar; C: \ Users \ Oscar Haglund.m2 \ repository \ org \ springframework \ restdocs \ spring-restdocs-mockmvc \ 2.0.5 .RELEASE \ spring-restdocs-mockmvc-2.0.5.RELEASE.jar; C: \ Users \ Oscar Haglund.m2 \ repository \ org \ springframework \ restdocs \ spring-restdocs-core \ 2.0.5.RELEASE \ spring-restdocs -core-2.0.5.RELEASE.jar; C: \ Users \ Oscar Haglund.m2 \ repository \ com \ fasterxml \ jackson \ core \ jackson-databind \ 2.9.5 \ jackson-databind-2.9.5.jar; C : \ Users \ Oscar Haglund.m2 \ repository \ com \ fasterxml \ jackson \ core \ jackson-annotations \ 2.9.0 \ jackson-anno tations-2.9.0.jar; C: \ Users \ Oscar Haglund.m2 \ repository \ com \ fasterxml \ jackson \ core \ jackson-core \ 2.9.5 \ jackson-core-2.9.5.jar; C: \ Usuários \ Oscar Haglund.m2 \ repository \ org \ mockito \ mockito-junit-jupiter \ 3.5.10 \ mockito-junit-jupiter-3.5.10.jar; C: \ Users \ Oscar Haglund.m2 \ repository \ org \ mockito \ mockito-core \ 3.5.10 \ mockito-core-3.5.10.jar; C: \ Usuários \ Oscar Haglund.m2 \ repository \ net \ bytebuddy \ byte-buddy \ 1.10.13 \ byte-buddy-1.10.13. jar; C: \ Users \ Oscar Haglund.m2 \ repository \ net \ bytebuddy \ byte-buddy-agent \ 1.10.13 \ byte-buddy-agent-1.10.13.jar; C: \ Users \ Oscar Haglund.m2 \ repository \ org \ objenesis \ objenesis \ 3.1 \ objenesis-3.1.jar; C: \ Users \ Oscar Haglund.m2 \ repository \ org \ junit \ platform \ junit-platform-launcher \ 1.7.0 \ junit-platform-launcher- 1.7.0.jar; C: \ dev \ eclipse \ configuration \ org.eclipse.osgi \ 259 \ 0.cp; C: \ dev \ eclipse \ configuration \ org.eclipse.osgi \ 257 \ 0.cp "- patch-module "com.spacemetric.spring.jpmstest = C: \ dev \ source \ spring-jpms-test \ target \ test-classes" --add-read com.spacemetric.spring.jpmstest = ALL-UNNAMED org. eclipse.jdt.internal.junit.runner.RemoteTestRunner -version 3 -port 55245 -testLoaderClass org.eclipse.jdt.internal.junit5.runner.JUnit5TestLoader -loaderpluginname org.eclipse.jdt.junit5.emruntetrime -classing .jpmstest.TestControllerTest
Respostas
Em primeiro lugar colocar o module-info.javano src/main/java, não src/test/java. Além disso, mudei ligeiramente para:
module spring.jpms.test {
requires spring.core;
requires spring.context;
requires spring.beans;
requires spring.security.config;
requires spring.security.web;
requires spring.webmvc;
requires spring.security.core;
requires javax.servlet.api;
requires spring.web;
opens com.spacemetric.spring.jpmstest;
}
Mas de qualquer maneira, isso resolve apenas "parcialmente" porque:
Bem-vindo a uma realidade bastante crua de modulese spring(ou ferramentas em geral). Dê uma olhada aqui, onde as pessoas têm os mesmos problemas . A única solução viável que encontrei é fazer:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version>
<configuration>
<useModulePath>false</useModulePath>
</configuration>
</plugin>
Isso funciona com mvn clean install(e junit5), não tentei ou joguei o suficiente intellijpara fazer funcionar.