Marek Wiącek opened SPR-13829 and commented
Spring 4.2.4 fails to load a configuration class due to a security exception (see below). 4.2.3 is not affected by this bug.
java.lang.IllegalStateException: Cannot load configuration class: org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration
at org.springframework.context.annotation.ConfigurationClassPostProcessor.enhanceConfigurationClasses(ConfigurationClassPostProcessor.java:410)
at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanFactory(ConfigurationClassPostProcessor.java:263)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:284)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:130)
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:678)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:520)
at org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:668)
at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:634)
at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:682)
at org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:553)
at org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:494)
at org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:136)
at javax.servlet.GenericServlet.init(GenericServlet.java:212)
at org.mortbay.jetty.servlet.ServletHolder.initServlet(ServletHolder.java:440)
at org.mortbay.jetty.servlet.ServletHolder.getServlet(ServletHolder.java:339)
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:487)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1166)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:316)
at org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter.doFilter(AbstractPreAuthenticatedProcessingFilter.java:116)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.appengine.api.socket.dev.DevSocketFilter.doFilter(DevSocketFilter.java:74)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.appengine.tools.development.ResponseRewriterFilter.doFilter(ResponseRewriterFilter.java:128)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.appengine.tools.development.HeaderVerificationFilter.doFilter(HeaderVerificationFilter.java:34)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.appengine.api.blobstore.dev.ServeBlobFilter.doFilter(ServeBlobFilter.java:63)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.apphosting.utils.servlet.TransactionCleanupFilter.doFilter(TransactionCleanupFilter.java:43)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.appengine.tools.development.StaticFileFilter.doFilter(StaticFileFilter.java:125)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.appengine.tools.development.DevAppServerModulesFilter.doDirectRequest(DevAppServerModulesFilter.java:366)
at com.google.appengine.tools.development.DevAppServerModulesFilter.doDirectModuleRequest(DevAppServerModulesFilter.java:349)
at com.google.appengine.tools.development.DevAppServerModulesFilter.doFilter(DevAppServerModulesFilter.java:116)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388)
at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418)
at com.google.appengine.tools.development.DevAppEngineWebAppContext.handle(DevAppEngineWebAppContext.java:98)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
at com.google.appengine.tools.development.JettyContainerService$ApiProxyHandler.handle(JettyContainerService.java:512)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
at org.mortbay.jetty.Server.handle(Server.java:326)
at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:923)
at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:547)
at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:212)
at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:409)
at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)
Caused by: java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "accessClassInPackage.sun.reflect.annotation")
at java.security.AccessControlContext.checkPermission(AccessControlContext.java:474)
at java.security.AccessController.checkPermission(AccessController.java:685)
at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)
at com.google.appengine.tools.development.DevAppServerFactory$CustomSecurityManager.checkPermission(DevAppServerFactory.java:429)
at java.lang.SecurityManager.checkPackageAccess(SecurityManager.java:1525)
at sun.reflect.misc.ReflectUtil.checkPackageAccess(ReflectUtil.java:188)
at sun.reflect.misc.ReflectUtil.checkPackageAccess(ReflectUtil.java:164)
at java.lang.reflect.Proxy.getInvocationHandler(Proxy.java:822)
at org.springframework.core.annotation.AnnotationUtils.synthesizeAnnotation(AnnotationUtils.java:1364)
at org.springframework.core.annotation.AnnotationUtils.findAnnotation(AnnotationUtils.java:498)
at org.springframework.core.annotation.AnnotationUtils.findAnnotation(AnnotationUtils.java:563)
at org.springframework.context.annotation.BeanAnnotationHelper.isBeanAnnotated(BeanAnnotationHelper.java:35)
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.isMatch(ConfigurationClassEnhancer.java:487)
at org.springframework.context.annotation.ConfigurationClassEnhancer$ConditionalCallbackFilter.accept(ConfigurationClassEnhancer.java:190)
at org.springframework.cglib.proxy.Enhancer.emitMethods(Enhancer.java:898)
at org.springframework.cglib.proxy.Enhancer.generateClass(Enhancer.java:509)
at org.springframework.cglib.transform.TransformingClassGenerator.generateClass(TransformingClassGenerator.java:33)
at org.springframework.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanFactoryAwareGeneratorStrategy.generate(ConfigurationClassEnhancer.java:249)
at org.springframework.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:231)
at org.springframework.cglib.proxy.Enhancer.createHelper(Enhancer.java:378)
at org.springframework.cglib.proxy.Enhancer.createClass(Enhancer.java:318)
at org.springframework.context.annotation.ConfigurationClassEnhancer.createClass(ConfigurationClassEnhancer.java:135)
at org.springframework.context.annotation.ConfigurationClassEnhancer.enhance(ConfigurationClassEnhancer.java:107)
at org.springframework.context.annotation.ConfigurationClassPostProcessor.enhanceConfigurationClasses(ConfigurationClassPostProcessor.java:400)
Affects: 4.2.4
Issue Links: - #18497 AnnotationUtils#synthesizeAnnotation prevents startup on Google App Engine ("is duplicated by") - #18271 SynthesizedAnnotation is not visible from class loader - #18403 Automated smoke test for GAE compatibility
Referenced from: commits https://github.com/spring-projects/spring-framework/commit/acecda7153efccaf1f99d1a7002d7f3c8945b698, https://github.com/spring-projects/spring-framework/commit/aecb8b6c6bd3c63ac3f609c2340edd57f7e3f8c8
Comment From: spring-projects-issues
Juergen Hoeller commented
This was caused by #18271 where we more defensively handle synthesized proxy generation... at the expense of checking the proxy's InvocationHandler
instead of just our own marker annotation. Since that seems to be a SecurityManager
-sensitive operation, possibly not just on Google App Engine, I've moved that check beyond the isSynthesizable
point in order to only check actually synthesizable annotations that way. I've also added a general catch (SecurityException
block for that particular operation, like we have in other places for Google App Engine purposes already.
This will be ready for testing in tonight's 4.2.5.BUILD-SNAPSHOT
. It would be great if you could give it a try once available...
Juergen
Comment From: spring-projects-issues
Marek Wiącek commented
GAE SDK is available in Maven repos and GAE Gradle plugin supports running automated functional tests. It should therefore be easy to implement an automated sanity test that deploys a hello world MVC app to GAE DevServer to make sure that there are no compatibility issues.
If that sounds like a good idea, I can create a pull request on GitHub.
Comment From: spring-projects-issues
Marek Wiącek commented
Sure, I will test the snapshot build tonight.
Comment From: spring-projects-issues
Juergen Hoeller commented
For an even simpler arrangement, I eventually dropped the entire InvocationHandler
check to begin with. Our subsequent isSynthesizable
check is a quite effective filter anyway, so in that particular spot, we can never run into a situation where an actually synthesizable annotation (for the purposes of our affected method here) can be pre-synthesized without the SynthesizedAnnotation
marker. So the only expense we have is a ConcurrentReferenceHashMap
lookup for that isSynthesizable
check now but that's perfectly acceptable; it's not worth having a SecurityException
-sensitive check just to bypass that map lookup.
Juergen
Comment From: spring-projects-issues
Juergen Hoeller commented
A new 4.2.5 snapshot will be available in about 1.5 hours now.
As for an automated smoke test against the GAE SDK, that's a fine idea! Please create a separate JIRA issue for it, as a task to consider such a test setup.
Comment From: spring-projects-issues
Marek Wiącek commented
Problem is fixed in 4.2.5.BUILD-20151229.205308-8, thanks.