0
votes

I'm transitioning a working google-appengine project from objectify v5 to v6, which uses the new Google Cloud datastore endpoints. In my listener-class EntityRegistrar class I call ObjectifyService.init() which throws a NoClassDefFoudError. Maven dependencies for objectify v6.0.4 and guava v18 look OK and the project compiles OK in Eclipse using Java8, but I must be missing something.

I get the same error when trying to run on the local google cloud beta datastore emulator.

Any hints would be appreciated.

package org.chemvantage;

import java.util.Date;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

import com.googlecode.objectify.ObjectifyService;

public class EntityRegistrar implements ServletContextListener {

     public void contextInitialized(ServletContextEvent servletContextEvent) {
        System.out.println("Starting up: " + new Date());

        ObjectifyService.init();   // line 15

        ObjectifyService.register(Assignment.class);
        ObjectifyService.register(BLTIConsumer.class);
    }
}

Uncaught exception from servlet

java.lang.NoClassDefFoundError: com/googlecode/objectify/ObjectifyService at org.chemvantage.EntityRegistrar.contextInitialized(EntityRegistrar.java:15) at org.eclipse.jetty.server.handler.ContextHandler.callContextInitialized(ContextHandler.java:843) at org.eclipse.jetty.servlet.ServletContextHandler.callContextInitialized(ServletContextHandler.java:533) at org.eclipse.jetty.server.handler.ContextHandler.startContext(ContextHandler.java:816) at org.eclipse.jetty.servlet.ServletContextHandler.startContext(ServletContextHandler.java:345) at org.eclipse.jetty.webapp.WebAppContext.startWebapp(WebAppContext.java:1406) at com.google.apphosting.runtime.jetty9.AppEngineWebAppContext.startWebapp(AppEngineWebAppContext.java:175) at org.eclipse.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1368) at org.eclipse.jetty.server.handler.ContextHandler.doStart(ContextHandler.java:778) at org.eclipse.jetty.servlet.ServletContextHandler.doStart(ServletContextHandler.java:262) at org.eclipse.jetty.webapp.WebAppContext.doStart(WebAppContext.java:522) at com.google.apphosting.runtime.jetty9.AppEngineWebAppContext.doStart(AppEngineWebAppContext.java:120) at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68) at com.google.apphosting.runtime.jetty9.AppVersionHandlerMap.createHandler(AppVersionHandlerMap.java:240) at com.google.apphosting.runtime.jetty9.AppVersionHandlerMap.getHandler(AppVersionHandlerMap.java:178) at com.google.apphosting.runtime.jetty9.JettyServletEngineAdapter.serviceRequest(JettyServletEngineAdapter.java:120) at com.google.apphosting.runtime.JavaRuntime$RequestRunnable.dispatchServletRequest(JavaRuntime.java:722) at com.google.apphosting.runtime.JavaRuntime$RequestRunnable.dispatchRequest(JavaRuntime.java:685) at com.google.apphosting.runtime.JavaRuntime$RequestRunnable.run(JavaRuntime.java:655) at com.google.apphosting.runtime.JavaRuntime$NullSandboxRequestRunnable.run(JavaRuntime.java:847) at com.google.apphosting.runtime.ThreadGroupPool$PoolEntry.run(ThreadGroupPool.java:270) at java.lang.Thread.run(Thread.java:748)

1

1 Answers

1
votes

OK, thanks to anyone who was scratching their head over this on my behalf. I think I found the answer:

In order to deal with asynchronous datastore operations (especially ofy().sa ve() operations that are left in the background), one must include the following Java class, which extends ObjectifyFilter.

package org.chemvantage;

import javax.servlet.annotation.WebFilter;

import com.googlecode.objectify.ObjectifyFilter;

/**
 * Filter required by Objectify to clean up any thread-local transaction contexts and pending
 * asynchronous operations that remain at the end of a request.
 */
@WebFilter(urlPatterns = {"/*"})
public class ObjectifyWebFilter extends ObjectifyFilter {}

This is addition to the required definition of the ObjectifyFilter in your web.xml file.

<web-app>
  <filter>
    <filter-name>ObjectifyFilter</filter-name>
    <filter-class>com.googlecode.objectify.ObjectifyFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>ObjectifyFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
</web-app>

You need both, although it seems counterintuitive. I checked it by deleting one and then replacing it and deleting the other. It would be helpful to put this into the Objectify instructions for upgrading from v5 to v6.