I was playing around with Spring MVC framework and wanted to test it on Google’s AppEngine. (GAE). I found out that the process is not as straight forward as I thought.
I was following this article here to configure spring for Appengine. But even then I stumbled across a couple of cases that took a lot of time for me to understand and fix them.
Configuring Spring Framework
The article above described how you can configure Spring 3.0 framework whereas I wanted to use the latest 3.1 release. There are a few gotchas with the choice of version you make and their interaction with Google Appengine:
Spring 3.0
Spring 3.0.0.M2 requires ASM Library version 2.1 (asm-2.1 and asm-commons-2.1). Google AppEngine SDK 1.4.2 comes with ASM library 3.1 which has a slightly different argument list for classes like ClassVisitor etc. If you follow the article (that I pointed above) as is and if you are using the latest Google AppEngine SDK version 1.4.2 – the moment you start your app in Eclipse it will throw an error similar to:
com.google.appengine.tools.development.agent.impl.Transformer transform SEVERE: Unable to instrument org.apache.xerces.xni.parser.XMLDocumentScanner. Security restrictions may not be entirely emulated.
or:
Unable to instrument org.apache.xerces.impl.Constants$ArrayEnumeration. Security restrictions may not be entirely emulated.
The error might be a bit misleading and might distract you from looking at the actual problem which is related to the order Eclipse loads library files. Eclipse has loaded ASM 2.1 from the library classpath and is trying to run your GAE server using that library (which has a reference to a class in ASM that doesn’t exist in version 2.1). An easy way to verify this is to run the app from command-line rather than using eclipse:
dev_appserver.sh --port=8888 ~/workspace/springApp/war/
This loads and runs GAE server using a different classpath order. It should run the server just fine unless you have done something really weird. To learn more about running appserver outside eclipse, follow details here.
In practice, this means that you will be able to deploy the application on GAE and it will work just fine. The only thing is you wont be able to run/debug in Eclipse which will ofcourse effect your productivity but nevertheless your application itself is fine.
If you replace asm-2.1 library with the asm-3.1 library for running this version of spring framework, you will manage to start up your application and GAE will no longer complain. However this time Spring framework will blow up complaining about calling a method that doesn’t accept ClassVisitor as it’s parameter – which is true as that specific override is no longer available in 3.1. In this case, your application is broken.
org.springframework.beans.factory.BeanDefinitionStoreException: Unexpected exception parsing XML document from ServletContext resource [/WEB-INF/dispatcher-servlet.xml]; nested exception is java.lang.NoSuchMethodError: org.objectweb.asm.ClassReader.accept(Lorg/objectweb/asm/ClassVisitor;Z)V
Spring 3.1
The latest Spring version (at the time of writing this article) is 3.1.0.M1. The good thing about this version is that it will work with ASM 3.1 library which avoids us hacking Eclipse classpath to resolve conflicts between spring and GAE.
The bare minimum files that you will need to run your spring app (both locally and live) are:
- asm-3.1.jar
you can grab the same one used by GAE from the SDK (appengine-java-sdk-1.4.2/lib/tools/orm/asm-3.1.jar) - asm-commons-3.1.jar
- org.springframework.asm-3.1.0.M1.jar
- org.springframework.beans-3.1.0.M1.jar
- org.springframework.context-3.1.0.M1.jar
- org.springframework.core-3.1.0.M1.jar
- org.springframework.expression-3.1.0.M1.jar
- org.springframework.web-3.1.0.M1.jar
- org.springframework.web.servlet-3.1.0.M1.jar
- commons-logging.jar (read below)
Commons Logging
The other dependency for spring framework is Apache commons logging library. If your application is working just fine locally (inside or outside eclipse) but it fails to run when you deploy it to GAE with an error that seems to be pointing to Spring framework not being found or loaded successfully. Something on the lines of “org.springframework.DispatcherServlet class not found”; then chances are that the commons logging library is not being picked up properly. If it fails to load commons logging library than it will not proceed to load other spring framework libraries (missing dependency).
To fix this the commons-logging library must be renamed exactly to “commons-logging.jar” (you can’t use any other name). If you’re interested in knowing why its this way then read here.
Hope this helps you get your Spring app up and running. Let me know if you have any comments or feedback.