Thursday, October 29, 2009

Developing Java applications with GAE SDK 1.2.6 and javaagent turned off

Since version 1.2.6 Google AppEngine SDK in development mode requires to run JVM with javaagent.

If you don't do this you'll get the following exception:



java.lang.RuntimeException: Unable to locate the App Engine agent.
Please use dev_appserver, KickStart, or set the jvm flag:
"-javaagent:<sdk_root>/lib/agent/appengine-agent.jar"
at com.google.appengine.tools.development.DevAppServerFactory.testAgentIsInstalled(102)
at com.google.appengine.tools.development.DevAppServerFactory.createDevAppServer(77)
at com.google.appengine.tools.development.DevAppServerFactory.createDevAppServer(38)
at com.google.appengine.tools.development.DevAppServerMain$StartAction.apply(153)
at com.google.appengine.tools.util.Parser$ParseResult.applyArgs(Parser.java:48)
at com.google.appengine.tools.development.DevAppServerMain.(DevAppServerMain.java:113)
at com.google.appengine.tools.development.DevAppServerMain.main(89)
Caused by: java.lang.NoClassDefFoundError: com/google/appengine/tools/development/agent/AppEngineDevAgent
at com.google.appengine.tools.development.DevAppServerFactory.testAgentIsInstalled(98)
... 6 more



But if you do you may get very strange behaviour of your app. Here's a few of mines I get developing with Tapestry 5.2.0.0-SNAPSHOT:


java.lang.ClassFormatError: Invalid length 65050 in LocalVariableTable
in class file org/apache/tapestry5/corelib/components/Form
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(Unknown Source)
at java.lang.ClassLoader.defineClass(Unknown Source)
at javassist.Loader.findClass(Loader.java:379)
at org.apache.tapestry5.internal.services.ComponentInstantiatorSourceImpl$PackageAwareLoader.findClass(94)
...



I've found a discussion where similiar problem was caused by multiple versions of javassist on CLASSPATH. I tried to find them, but I had only one of it.

The other exception is due to previous.



org.apache.tapestry5.ioc.internal.util.TapestryException:
Failure creating embedded component 'sendInvite' of dmitrygusev.ping.pages.Index:
java.lang.ClassNotFoundException: caught an exception while obtaining a class
file for org.apache.tapestry5.corelib.components.Form"
[at context:Index.tml, line 23]
at org.apache.tapestry5.internal.pageload.ComponentAssemblerImpl.createEmbeddedAssembler(316)
at org.apache.tapestry5.internal.pageload.PageLoaderImpl.startComponent(740)

...

Caused by: java.lang.RuntimeException: Class org.apache.tapestry5.corelib.components.Form contains field(s)
(_$bindingSource, _$environment, _$onActionInfo, _$resources, _$type, _$type_0, _$type_1)
that are not private. You should change these fields to private, and add accessor methods if needed.
at org.apache.tapestry5.internal.services.InternalClassTransformationImpl.verifyFields(293)
at org.apache.tapestry5.internal.services.InternalClassTransformationImpl.preloadMemberNames(255)
at org.apache.tapestry5.internal.services.InternalClassTransformationImpl.(151)
at org.apache.tapestry5.internal.services.ComponentClassTransformerImpl.transformComponentClass(163)
at $ComponentClassTransformer_1249f7f3976.transformComponentClass(...)
at org.apache.tapestry5.internal.services.ComponentInstantiatorSourceImpl.onLoad(205)
at javassist.Loader.findClass(Loader.java:340)
... 95 more



This all very strange, because when deployed to Google AppEgine there is no such errors, and this is very similiar to problem with a Security Manager I wrote about in a previous post.

To fix it I had to not specify javaagent on JVM start, but to avoid that "Unable to locate the App Engine agent" exception, I created the following class:


package com.google.appengine.tools.development.agent;

public class AppEngineDevAgent {

public static Object getAgent()
{
return null;
}

}


and putted it to my project:



Now I can run my project without javaagent. Please note, that you may still need to apply patch to Security Manager (its compatible with 1.2.2-6 GAE SDKs) to avoid other potential issues developing with GAE SDK.

Its also okay to deploy your app with this class to GAE, since it won't conflict with GAE environment.