8

We have an app running on App Engine and using Spring framework. Recently we have added some new features that are based on AOP. We decided to use @AspectJ style hence we added <aop:aspectj-autoproxy> into our XML based configuration and implemented respective aspects. Everything is working OK on development server, however, when deployed to the cloud environment we get java.lang.StackOverflowError every time the app is being initialized.

The bean that cannot be created and causes the error is configuration class annotated with @Configuration annotation. It seems that basically any configuration bean can cause the error.

Below you can see the corresponding stack trace.

org.springframework.web.context.ContextLoader initWebApplicationContext: Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'objectifyConfig' defined in URL [jar:file:/base/data/home/apps/{app-id}/8.372375422460842231/WEB-INF/lib/{app-name}-1.0-SNAPSHOT.jar!/{path-to-class}/ObjectifyConfig.class]: Initialization of bean failed; nested exception is java.lang.StackOverflowError
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:529)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:296)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:293)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:628)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:389)
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:294)
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:112)
at org.mortbay.jetty.handler.ContextHandler.startContext(ContextHandler.java:548)
at org.mortbay.jetty.servlet.Context.startContext(Context.java:136)
at org.mortbay.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1250)
at org.mortbay.jetty.handler.ContextHandler.doStart(ContextHandler.java:517)
at org.mortbay.jetty.webapp.WebAppContext.doStart(WebAppContext.java:467)
at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)
at com.google.apphosting.runtime.jetty.AppVersionHandlerMap.createHandler(AppVersionHandlerMap.java:219)
at com.google.apphosting.runtime.jetty.AppVersionHandlerMap.getHandler(AppVersionHandlerMap.java:194)
at com.google.apphosting.runtime.jetty.JettyServletEngineAdapter.serviceRequest(JettyServletEngineAdapter.java:134)
at com.google.apphosting.runtime.JavaRuntime$RequestRunnable.run(JavaRuntime.java:446)
at com.google.tracing.TraceContext$TraceContextRunnable.runInContext(TraceContext.java:435)
at com.google.tracing.TraceContext$TraceContextRunnable$1.run(TraceContext.java:442)
at com.google.tracing.CurrentContext.runInContext(CurrentContext.java:186)
at com.google.tracing.TraceContext$AbstractTraceContextCallback.runInInheritedContextNoUnref(TraceContext.java:306)
at com.google.tracing.TraceContext$AbstractTraceContextCallback.runInInheritedContext(TraceContext.java:298)
at com.google.tracing.TraceContext$TraceContextRunnable.run(TraceContext.java:439)
at com.google.apphosting.runtime.ThreadGroupPool$PoolEntry.run(ThreadGroupPool.java:251)
at java.lang.Thread.run(Thread.java:724)
Caused by: java.lang.StackOverflowError
at java.util.concurrent.ConcurrentSkipListSet.contains(ConcurrentSkipListSet.java:214)
at sun.misc.URLClassPath$LoaderSearchCursor.nextLoader(URLClassPath.java:598)
at sun.misc.URLClassPath.getLoader(URLClassPath.java:365)
at sun.misc.URLClassPath.findResource(URLClassPath.java:213)
at java.net.URLClassLoader$2.run(URLClassLoader.java:551)
at java.net.URLClassLoader$2.run(URLClassLoader.java:549)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findResource(URLClassLoader.java:548)
at com.google.apphosting.runtime.security.UserClassLoader.findResource(UserClassLoader.java:723)
at java.lang.ClassLoader.getResource(ClassLoader.java:1142)
at com.google.apphosting.runtime.security.UserClassLoader$3.run(UserClassLoader.java:757)
at com.google.apphosting.runtime.security.UserClassLoader$3.run(UserClassLoader.java:751)
at java.security.AccessController.doPrivileged(Native Method)
at com.google.apphosting.runtime.security.UserClassLoader.findResource(UserClassLoader.java:751)
at java.lang.ClassLoader.getResource(ClassLoader.java:1142)
at com.google.apphosting.runtime.security.UserClassLoader$3.run(UserClassLoader.java:757)
at com.google.apphosting.runtime.security.UserClassLoader$3.run(UserClassLoader.java:751)
at java.security.AccessController.doPrivileged(Native Method)
at com.google.apphosting.runtime.security.UserClassLoader.findResource(UserClassLoader.java:751)
at java.lang.ClassLoader.getResource(ClassLoader.java:1142)
at com.google.apphosting.runtime.security.UserClassLoader$3.run(UserClassLoader.java:757)
at com.google.apphosting.runtime.security.UserClassLoader$3.run(UserClassLoader.java:751)
at java.security.AccessController.doPrivileged(Native Method)
at com.google.apphosting.runtime.security.UserClassLoader.findResource(UserClassLoader.java:751)
at java.lang.ClassLoader.getResource(ClassLoader.java:1142)
...

Update: I put the issue into the App Engine issue tracker along with the sample app that demonstrates the problem. Please follow the link to see details.

pgiecek
  • 7,970
  • 4
  • 39
  • 47
  • Can you give a small reproducible example? – Sotirios Delimanolis Dec 16 '13 at 16:18
  • I'm experiencing the same problem. I actually developed a `@DatastoreTransactional` annotation (`@Transactional` for the low level datastore API). Works perfectly with local dev server, and production app engine server seems to trip over its own foot during class loading. – Michael Técourt Jan 16 '14 at 09:15
  • Well, it seems that Google is not interested in that issue. At least based on their issue tracker. However, I found out that in our case the issue is caused by combination of AOP and `@Configuration` annotated classes. If you can get rid of them and use just e.g. `@Component` classes then it can help. – pgiecek Jan 16 '14 at 09:33
  • 1
    Now I remember this video that I watched not so long ago, that basically discourages GAE users from using AOP (and other Spring features) by saying that it's not efficient on the App Engine runtime : http://www.youtube.com/watch?v=lFarE1hH0ss ... I didn't know it meant that it would crash – Michael Técourt Jan 16 '14 at 14:41
  • I ran several tests on my app with App Engine 1.9.7, you can safely mark this as solved with your own answer. – Michael Técourt Aug 19 '14 at 12:30
  • Great, I will mark it as solved. It took only 8 months to fix it. ;-) – pgiecek Aug 19 '14 at 13:09

3 Answers3

3

It seems that the issue has been fixed in App Engine version 1.9.7. See more details here.

pgiecek
  • 7,970
  • 4
  • 39
  • 47
1

A stack overflow usually indicates an infinite loop. With aspectj you could have this in the following case:

Class Logger {
 @Autowired
 ConfigService conf;
 //... used for logging intercepted methods
}

Class ConfigServiceImpl implements ConfigService {
 //... this is used to retrieve config
}

If you now use aspectj expressions that says: I want to log my configServiceImpl then you will also have infinite loop when using the configService:

  • intercepted by logger
  • configservice injected in logger tries to retrieve logging config ...
  • ==> that configservice is intercepted by logger and story repeats

I cannot explain why it is working on your local setup and not on app engine. Or why it is only when you are using @Configuration but I think you should look in the direction of a "circular dependency" like this.

ruben056
  • 112
  • 8
  • Yes it's probably such a problem. I've done AOP before though and my use case is not really complex, it runs without problems on any other server -- even the GAE local one. This issue has been accepted by the GAE team : https://code.google.com/p/googleappengine/issues/detail?id=10413&q=Type%3DDefect&sort=-id&colspec=ID%20Type%20Component%20Status%20Stars%20Summary%20Language%20Priority%20Owner%20Log – Michael Técourt Mar 18 '14 at 09:46
  • And check out this video, the GAE developer gets picked on by a Spring guy about this kind of matter : http://www.youtube.com/watch?v=lFarE1hH0ss – Michael Técourt Mar 18 '14 at 09:47
  • This is not probably the case. I implemented very simple demonstration of the problem and attached it to the issue reported in GAE issue tracker. You can find it [here](https://code.google.com/p/googleappengine/issues/detail?id=10413&q=Type%3DDefect&sort=-id&colspec=ID%20Type%20Component%20Status%20Stars%20Summary%20Language%20Priority%20Owner%20Log). There is not an infinite loop. At least I cannot see it. – pgiecek Jul 08 '14 at 07:02
1

This is either because of infinite recursion, or because your stack is just too big. Try bumping up your stack size to see if that solves the problem (using, for example, -Xss1m). If this does not help, then you may have infinite recursion. See also:

Java stack overflow error - how to increase the stack size in Eclipse?

Community
  • 1
  • 1
Zeki
  • 5,107
  • 1
  • 20
  • 27
  • It's an issue specific to the Google App Engine production runtime -- it does not even occur with the development server (neither in eclipse or command line). The issue has been acknowledged by Google : https://code.google.com/p/googleappengine/issues/detail?id=10413&q=Type%3DDefect&sort=-id&colspec=ID%20Type%20Component%20Status%20Stars%20Summary%20Language%20Priority%20Owner%20Log – Michael Técourt Apr 20 '14 at 22:13