4
votes

My android-appengine-endpoint project is setup entirely by android studio. Therefore I don't mess around with anything: I just let android studio add my AppEngine module to my android project. Now I am getting a java.lang.NoClassDefFoundError. Do I have to set somethings in gradle or configure somethings in android studio to get rid of this error? Basically when I try to test my app I get the exception.

Code:

Note: Instead of calling ofy inside my endpoint class, UserDao is a place where all the ofy data access calls are made. You can compare my code to this tutorial

public class UserDao extends OfyService {
    public static void persist(User user) {
        ofy().save().entities(user).now();
    }
    public static User getById(long id) {
        return ofy().load().type(User.class).id(id).now();
    }
    public static List<User> getByTwitterId(Long twitterId) {
        return ofy().load().type(User.class).filter("twitterId", twitterId).list();
    }
}

public class OfyService {
    public OfyService() {}

    static {
        ObjectifyService.register(User.class);
        ObjectifyService.register(Food.class);
        ObjectifyService.register(Pet.class);
    }

    public static Objectify ofy() { return ObjectifyService.ofy(); }

    public static ObjectifyFactory factory() {
        return ObjectifyService.factory();
    }
}

The actual error as seen from the App Engine Console:

com.google.api.server.spi.SystemService invokeServiceMethod: exception occurred while calling backed method
java.lang.NoClassDefFoundError: Could not initialize class com.mycompany.server.data.dao.UserDao
    at com.mycompany.server.utils.Authenticator.verifyAccount(Authenticator.java:22)
    at com.mycompany.server.endpoint.server.getFood(server.java:105)
    at sun.reflect.GeneratedMethodAccessor22.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:44)
    at com.google.api.server.spi.SystemService.invokeServiceMethod(SystemService.java:359)
    at com.google.api.server.spi.SystemServiceServlet.execute(SystemServiceServlet.java:160)
    at com.google.api.server.spi.SystemServiceServlet.doPost(SystemServiceServlet.java:118)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
    at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1166)
    at com.googlecode.objectify.ObjectifyFilter.doFilter(ObjectifyFilter.java:48)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    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 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.HttpConnection.handle(HttpConnection.java:404)
    at com.google.tracing.TraceContext$TraceContextRunnable.runInContext(TraceContext.java:437)
    at com.google.tracing.TraceContext$TraceContextRunnable$1.run(TraceContext.java:444)
    at com.google.tracing.CurrentContext.runInContext(CurrentContext.java:230)
    at com.google.tracing.TraceContext$AbstractTraceContextCallback.runInInheritedContextNoUnref(TraceContext.java:308)
    at com.google.tracing.TraceContext$AbstractTraceContextCallback.runInInheritedContext(TraceContext.java:300)
    at com.google.tracing.TraceContext$TraceContextRunnable.run(TraceContext.java:441)
    at java.lang.Thread.run(Thread.java:745)

Every post I see here seem to be talking about WEB-INF\lib. Well Android Studio has not created any lib directory inside my WEB-INF. So both Android Studio and App Engine are from Google. Therefore I am at a lost there.

My webapp/WEB-INF has only three files in it:

  • web.xml
  • logging.properties
  • appengine-web.xml

Here is an image of my dependencies in case it helps:

enter image description here

2
I write the actual app engine source: entities, endpoints, ofy. I just don't decide what goes inside WEB-INF. As for UserDao, it is an OfyService subclass, not an entity. So I don't know what's going on there. - Katedral Pillon
The only difference with UserDao (vs the other OfyService subclasses) is that one of its static methods throw an exception: IllegalStateException - Katedral Pillon
UserDao is not an entity. It does not have the @Entity annotation. By subclass I mean public class UserDao extends OfyService where OfyService is simply a wrapper for ObjectifyService, I am simply following the best practice recommended structure. - Katedral Pillon
I refactor the UserDao class and remove the Exception. That did it. I was having one of the satic methods throw an exception in a certain case. That was the cause of the problem. - Katedral Pillon
In the stack-trace I see com.googlecode.objectify.ObjectifyFilter, and I conclude that Gradle has downloaded Objectify without problems. What class is missing then? - naXa

2 Answers

2
votes

Since you are using Cloud Endpoint, do this:

  1. In your Endpoint class, create a constructor.
  2. In the constructor, call new OfyService().

The reason this may work is that you will have loaded all your objectify related classes way way before you need to use them (i.e. way before a client makes a first call). Right now you are loading them right before you need them . And delays in the App-Engine class loader may be what's killing you. The sad thing is, the structure you are using is very popular and so most people use it that way: and yet there is no guarantee that it will always work. It's a race condition thing. App-engine can be very slow to load classes. Lucky (or unlucky) for you, you find the problem early. People should give you some upvotes for your pains :).

1
votes

As I find out from our discussion Objectify fails to register classes for an unknown reason.

Perhaps,

  1. you have incorrect annotations on one of your data classes (provide a source code of User, Food, Pet for further investigation);
  2. or call OfyService methods from another thread at the same time (which is unlikely).