Skip to content

org.springframework.web.context.ContextLoader cannot be loaded in a native image #29905

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wilkinsona opened this issue Jan 30, 2023 · 0 comments
Assignees
Labels
in: web Issues in web modules (web, webmvc, webflux, websocket) status: backported An issue that has been backported to maintenance branches theme: aot An issue related to Ahead-of-time processing type: bug A general bug
Milestone

Comments

@wilkinsona
Copy link
Member

Affects: 6.0.x

Loading org.springframework.web.context.ContextLoader in a native image fails due to its class initializer trying to load org/springframework/web/context/ContextLoader.properties and failing as it's not present in the image. The problem used to be masked by Tomcat as it resource config such that all *.properties files were included in the image. This has been tightened up in Tomcat.

This failure was first seen with Spring HATEOAS:

java.lang.IllegalStateException: Could not load 'ContextLoader.properties': class path resource [org/springframework/web/context/ContextLoader.properties] cannot be opened because it does not exist
        at org.springframework.web.context.ContextLoader.<clinit>(ContextLoader.java:146) ~[na:na]
        at org.springframework.hateoas.server.core.PropertyResolvingMappingDiscoverer.resolveProperties(PropertyResolvingMappingDiscoverer.java:111) ~[na:na]
        at org.springframework.hateoas.server.core.PropertyResolvingMappingDiscoverer.getMapping(PropertyResolvingMappingDiscoverer.java:54) ~[na:na]
        at org.springframework.hateoas.server.core.CachingMappingDiscoverer.lambda$getMapping$0(CachingMappingDiscoverer.java:63) ~[na:na]
        at java.base@17.0.5/java.util.concurrent.ConcurrentMap.computeIfAbsent(ConcurrentMap.java:330) ~[hateoas:na]
        at org.springframework.hateoas.server.core.CachingMappingDiscoverer.getMapping(CachingMappingDiscoverer.java:63) ~[na:na]
        at org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo(WebMvcLinkBuilder.java:88) ~[hateoas:2.0.1]
        at org.springframework.hateoas.server.mvc.RepresentationModelAssemblerSupport.createModelWithId(RepresentationModelAssemblerSupport.java:98) ~[hateoas:2.0.1]
        at org.springframework.hateoas.server.mvc.RepresentationModelAssemblerSupport.createModelWithId(RepresentationModelAssemblerSupport.java:89) ~[hateoas:2.0.1]
        at com.example.hateoas.assembler.ManagerModelAssembler.toModel(ManagerModelAssembler.java:20) ~[hateoas:na]
        at com.example.hateoas.ManagerController.getById(ManagerController.java:39) ~[hateoas:na]
        at java.base@17.0.5/java.lang.reflect.Method.invoke(Method.java:568) ~[hateoas:na]
        at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:207) ~[hateoas:6.0.4]
        at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:152) ~[hateoas:6.0.4]
        at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) ~[hateoas:6.0.4]
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:884) ~[hateoas:6.0.4]
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) ~[hateoas:6.0.4]
        at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[hateoas:6.0.4]
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1080) ~[hateoas:na]
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:973) ~[hateoas:na]
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1011) ~[hateoas:na]
        at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:903) ~[hateoas:na]
        at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:705) ~[hateoas:6.0]
        at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885) ~[hateoas:na]
        at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:814) ~[hateoas:6.0]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:223) ~[na:na]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) ~[na:na]
        at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[hateoas:10.1.5]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) ~[na:na]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) ~[na:na]
        at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[hateoas:6.0.4]
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[hateoas:6.0.4]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) ~[na:na]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) ~[na:na]
        at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[hateoas:6.0.4]
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[hateoas:6.0.4]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) ~[na:na]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) ~[na:na]
        at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[hateoas:6.0.4]
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[hateoas:6.0.4]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) ~[na:na]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) ~[na:na]
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:177) ~[na:na]
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) ~[na:na]
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542) ~[hateoas:10.1.5]
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:119) ~[na:na]
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) ~[hateoas:10.1.5]
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) ~[na:na]
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357) ~[na:na]
        at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:400) ~[na:na]
        at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) ~[hateoas:10.1.5]
        at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:859) ~[na:na]
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1734) ~[na:na]
        at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) ~[hateoas:10.1.5]
        at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) ~[na:na]
        at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[na:na]
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[na:na]
        at java.base@17.0.5/java.lang.Thread.run(Thread.java:833) ~[hateoas:na]
        at org.graalvm.nativeimage.builder/com.oracle.svm.core.thread.PlatformThreads.threadStartRoutine(PlatformThreads.java:775) ~[hateoas:na]
        at org.graalvm.nativeimage.builder/com.oracle.svm.core.posix.thread.PosixPlatformThreads.pthreadStartRoutine(PosixPlatformThreads.java:203) ~[na:na]

It can be reproduced in any web app by trying to call ContextLoader at runtime. For example:

public static void main(String[] args) {
	SpringApplication.run(WebMvcApplication.class, args);
	System.out.println(org.springframework.web.context.ContextLoader.getCurrentWebApplicationContext());
}

The above main method will output the following at startup:

…
2023-01-30T20:47:15.526Z  INFO 8773 --- [           main] com.example.webmvc.WebMvcApplication     : Started WebMvcApplication in 0.075 seconds (process running for 0.094)
Exception in thread "main" java.lang.ExceptionInInitializerError
        at com.example.webmvc.WebMvcApplication.main(WebMvcApplication.java:11)
Caused by: java.lang.IllegalStateException: Could not load 'ContextLoader.properties': class path resource [org/springframework/web/context/ContextLoader.properties] cannot be opened because it does not exist
        at org.springframework.web.context.ContextLoader.<clinit>(ContextLoader.java:146)
        ... 1 more
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Jan 30, 2023
@sdeleuze sdeleuze self-assigned this Jan 31, 2023
@sdeleuze sdeleuze added type: bug A general bug theme: aot An issue related to Ahead-of-time processing and removed status: waiting-for-triage An issue we've not yet triaged or decided on labels Jan 31, 2023
@sdeleuze sdeleuze added this to the 6.0.5 milestone Jan 31, 2023
@jhoeller jhoeller added the in: web Issues in web modules (web, webmvc, webflux, websocket) label Jan 31, 2023
@jhoeller jhoeller assigned jhoeller and unassigned sdeleuze Jan 31, 2023
@github-actions github-actions bot added status: backported An issue that has been backported to maintenance branches and removed for: backport-to-5.3.x labels Jan 31, 2023
jhoeller added a commit that referenced this issue Jan 31, 2023

Unverified

This commit is not signed, but one or more authors requires that any commit attributed to them is signed.
Closes gh-29905

(cherry picked from commit a74b86e)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: web Issues in web modules (web, webmvc, webflux, websocket) status: backported An issue that has been backported to maintenance branches theme: aot An issue related to Ahead-of-time processing type: bug A general bug
Projects
None yet
Development

No branches or pull requests

4 participants