2
votes

I am trying to migrate a large project to JPMS (Java Platform Module System).

It contains some Spring components that are giving me some trouble. I have created a test repo to demonstrate the issue. When I remove the module-info.java file it works just fine as shown by the test in TestControllerTest.java. However, if I add the module-info.java then it stops working with the following exception:

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 … 

The stack trace seems to indicate that the ApplicationContext is unable to find the @Autowired implementation. I have opened the entire module for deep reflection. My highly uneducated guess is that this might be related to the classpath versus modulepath but I am at a loss for what to do about it.

The module-info.java file is as follows:

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

The following is the command line used by Eclipse to run the test (as requested):

C:\Program Files\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:\Users\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\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-annotations-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:\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\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-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 -classNames com.spacemetric.spring.jpmstest.TestControllerTest

1
Your README talks about a module-info.java for „The test class“. Questions: (1) What is your use case that you need to have a module-info.java in your test directory? (2) What command should be run to produce the error? (3) Is this related at all to your other JPMS issue? TIA.deduper
…The stack trace seems to indicate that the ApplicationContext is unable to find the @Autowired implementation…“ — You've guessed incorrectly, I'm afraid. By the time you come back to me with answers to my questions, I might be in a position to elaborate on what I mean. TIA.deduper
(1) Apologies for the unclear readme. The module-info.java is for the source directory (src/main/java) and the minimal implementation I have created to showcase the exception I am getting in a much larger project. The readme refers to the unit test that can be run to produce the exception. (2) Run the unit test class in your IDE of choice. I have updated the original text to include the command used by Eclipse to run the test. (3) Only in as so far they have both occurred trying to convert the same repository. The issues occurred in different modules.oscar.haglund
(1)…The module-info.java is for the source directory (src/main/java)…“ — Maybe @Eugene might not have jumped to the wrong conclusion in his answer if your README read: „…TestControllerTest runs successfully if the module-info.java file is removed from src/main/java“ — „…(2) Run the unit test class in your IDE…“ — That's another revelation. You never mentioned an IDE originally. I built your MRE from a terminal. The test succeeded — „…the command used by Eclipse to run the test…“ — What are the Eclipse menu option steps to reproduce the error? You're new. You'll learn. TIAdeduper

1 Answers

1
votes

First of all put the module-info.java in src/main/java, not in src/test/java. Also I have slightly changed it to:

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;

}

But anyway, this solves only "partially" because:

Welcome to a rather crude reality of modules and spring (or tools in general). Have a look here, where people have the same problems. The only viable solution I found is to do :

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

This works with mvn clean install (and junit5), I haven't tried or played enough with intellij to make it work.