2

I have a Java-17 project using Spring Boot which I'm trying to modularize. To take full advantage of the modularization, I'm porting it to Spring Boot 3 milestone 4 and Spring 6 milestone 5.

The project is managed my Maven. I was able to get the project to compile. However, it fails to execute the standard contextLoads() test as generated by Spring Boot. The specific error message is:

[main] DEBUG org.springframework.boot.test.context.SpringBootTestContextBootstrapper - Could not load default TestExecutionListener [org.springframework.test.context.web.ServletTestExecutionListener]. Specify custom listener classes or make the default listener classes available.
java.lang.NoClassDefFoundError: jakarta/servlet/ServletContext

This error message is repeated twice more with different TestExecutionListener implementations, namely TransactionalTestExecutionListener and SqlScriptsTestExecutionListener, but Spring ultimately loads a number of TestExecutionListeners and tries to execute the test. However, the test fails:

java.lang.NoClassDefFoundError: org/springframework/beans/factory/aot/BeanFactoryInitializationAotProcessor
    [...series of java.base frames...]
    at spring.context@6.0.0-M5/org.springframework.context.annotation.AnnotationConfigUtils.registerAnnotationConfigProcessors(AnnotationConfigUtils.java:165)
    at spring.context@6.0.0-M5/org.springframework.context.annotation.AnnotationConfigUtils.registerAnnotationConfigProcessors(AnnotationConfigUtils.java:138)
    at spring.context@6.0.0-M5/org.springframework.context.annotation.AnnotatedBeanDefinitionReader.<init>(AnnotatedBeanDefinitionReader.java:88)
    at spring.context@6.0.0-M5/org.springframework.context.annotation.AnnotatedBeanDefinitionReader.<init>(AnnotatedBeanDefinitionReader.java:71)
    at spring.context@6.0.0-M5/org.springframework.context.annotation.AnnotationConfigApplicationContext.<init>(AnnotationConfigApplicationContext.java:69)
    at spring.boot@3.0.0-M4/org.springframework.boot.ApplicationContextFactory.lambda$static$0(ApplicationContextFactory.java:55)
    at org.springframework.boot.test.context.SpringBootContextLoader.lambda$loadContext$1(SpringBootContextLoader.java:120)
    at spring.boot@3.0.0-M4/org.springframework.boot.SpringApplication.createApplicationContext(SpringApplication.java:566)
    at spring.boot@3.0.0-M4/org.springframework.boot.SpringApplication.run(SpringApplication.java:309)
    at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:132)
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:98)
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:123)
    at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:124)
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:118)
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:83)
    at org.springframework.boot.test.autoconfigure.SpringBootDependencyInjectionTestExecutionListener.prepareTestInstance(SpringBootDependencyInjectionTestExecutionListener.java:43)
    at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:248)
    at org.springframework.test.context.junit.jupiter.SpringExtension.postProcessTestInstance(SpringExtension.java:138)
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeTestInstancePostProcessors$8(ClassBasedTestDescriptor.java:363)
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.executeAndMaskThrowable(ClassBasedTestDescriptor.java:368)
    at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeTestInstancePostProcessors$9(ClassBasedTestDescriptor.java:363)
    [...many more frames, mostly from junit and surefire...]
Caused by: java.lang.ClassNotFoundException: org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)

This problem is probably caused by some error in my module-info.java. The Spring modules I'm using are:

    requires spring.beans;
    requires spring.context;
    requires spring.boot.autoconfigure;
    requires spring.core;
    requires spring.boot;
    requires spring.oxm;
    requires spring.web;
    requires spring.ws.core;
    [...]
    opens [my module] to spring.core;
    exports [my module] to spring.beans, spring.context;

What am I missing? The application compiles and works fine with Spring 5.3 / Spring Boot 2.7, but I need to modularize it to be able to create an installer.

Piotr Sulecki
  • 103
  • 1
  • 9
  • Have you checked the release notes for spring 3.0.0-M1..M5... for needed changes... this is major release change... I expect things needed to be changed... I would first get the app working with 2.7.4... migrate it to 3.0.0-M5 and afterwards modularize it... (The question is why modularize ?)... – khmarbaise Oct 04 '22 at 13:51
  • The app is working perfectly fine with Spring Boot 2.7.4 and Spring Framework 5.3, even modularized. But we need to create an installer for it, and for jlink to work (as I understand) I need to have a modularized app, and Spring Boot 2.7 / Spring 5.3 are not. Or am I wrong here? – Piotr Sulecki Oct 04 '22 at 14:02
  • If you like to use jlink all the dependencies must be modules which is very unlikely at the moment ..furthermore the output shows that you are using spring boot 3.0.0-XX which changes things which should be fixed first (see release notes).. – khmarbaise Oct 07 '22 at 10:14

1 Answers1

2

The problem seems to be related with org.springframework:spring-beans:5.3.25, which does not include the required class yet. By accident, we had this version pinned in our build.gradle when migrating to Spring 3.0. This should not be necessary any more.

Thus, you could try removing spring-beans from your build.gradle or pom.xml, depending on whether you use Gradle oder Maven. This should already be sufficient. If not, you could try gradle dependencies or mvn dependency:tree (having the related plugin installed) to find out, if/where the old version is pulled in. Alternatively, you could explicitly include the newest version in your build.gradle or pom.xml.

ahuemmer
  • 1,653
  • 9
  • 22
  • 29
  • Many thanks! That fixed it for me as I have been updating SB from v2 to v3. Had spring-beans defined in my gradle and was banging my head against a brick wall to try and figure out what was going on. – Mike Jun 01 '23 at 12:18