Spring NoSuchBeanDefinitionException al cambiar a JPMS (Java Platform Module System)

Oct 02 2020

Estoy intentando migrar un proyecto grande a JPMS (Java Platform Module System).

Contiene algunos componentes de Spring que me están dando algunos problemas. He creado un repositorio de prueba para demostrar el problema. Cuando elimino el archivo module-info.java, funciona bien, como lo muestra la prueba en TestControllerTest.java . Sin embargo, si agrego el module-info.java, deja de funcionar con la siguiente excepción:

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 … 

El seguimiento de la pila parece indicar que ApplicationContextno puede encontrar la @Autowiredimplementación. Abrí todo el módulo para una reflexión profunda. Mi conjetura muy poco educada es que esto podría estar relacionado con la ruta de clases versus la ruta del módulo, pero no sé qué hacer al respecto.

El archivo module-info.java es el siguiente:

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;
}

La siguiente es la línea de comando utilizada por Eclipse para ejecutar la prueba (según lo solicitado):

C: \ Archivos de programa \ 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: \ Usuarios \ 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: \ Users \ 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 \ rapidxml \ jackson \ core \ jackson-databind \ 2.9.5 \ jackson-databind-2.9.5.jar; C : \ Usuarios \ Oscar Haglund.m2 \ repository \ com \ rapidxml \ jackson \ core \ jackson-annotations \ 2.9.0 \ jackson-anno tations-2.9.0.jar; C: \ Users \ Oscar Haglund.m2 \ repository \ com \ rapidxml \ jackson \ core \ jackson-core \ 2.9.5 \ jackson-core-2.9.5.jar; C: \ Users \ 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: \ Users \ 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 \ repositorio \ 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-reads 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.runtime com -classNombre .jpmstest.TestControllerTest

Respuestas

1 Eugene Oct 02 2020 at 19:30

Primero que nada ponga el module-info.javain src/main/java, no in src/test/java. También lo he cambiado ligeramente a:

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;

}

Pero de todos modos, esto se resuelve solo "parcialmente" porque:

Bienvenido a una realidad bastante cruda de modulesy spring(o herramientas en general). Eche un vistazo aquí, donde la gente tiene los mismos problemas . La única solución viable que encontré es hacer:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>3.0.0-M5</version>
    <configuration>
        <useModulePath>false</useModulePath>
    </configuration>
</plugin>

Esto funciona con mvn clean install(y junit5), no he probado ni jugado lo suficiente intellijpara que funcione.