I'm trying to get a TimerTask
set up to remove entries from Google App Engine's dataStore periodically. So I set up a ServletContextListener
with a Timer
.
Inside the contextInitialized
, I have registered my Objectify classes:
ObjectifyService.register(Person.class);
However, when the task actually runs, it complains that no API environment has been set up:
Exception in thread "Timer-0" java.lang.NullPointerException: No API environment is registered for this thread.
at com.google.appengine.api.datastore.DatastoreApiHelper.getCurrentAppId(DatastoreApiHelper.java:80)
at com.google.appengine.api.datastore.DatastoreApiHelper.getCurrentAppIdNamespace(DatastoreApiHelper.java:90)
at com.google.appengine.api.datastore.Query.<init>(Query.java:214)
at com.google.appengine.api.datastore.Query.<init>(Query.java:143)
at com.googlecode.objectify.impl.cmd.QueryImpl.<init>(QueryImpl.java:72)
at com.googlecode.objectify.impl.cmd.LoadTypeImpl.createQuery(LoadTypeImpl.java:50)
at com.googlecode.objectify.impl.cmd.LoadTypeImpl.filter(LoadTypeImpl.java:58)
at myApp.MyServletContextListener$MyTask.run(MyServletContextListener.java:58)
at java.util.TimerThread.mainLoop(Timer.java:555)
at java.util.TimerThread.run(Timer.java:505)
Any ideas? I've tried changing the line that registers the class to ObjectifyService.factory().register(Person.class);
but it didn't seem to help.
From the documentation of
java.util.Timer
class:And peeking to the inner code of the
java.util.Timer
class, we can see that it basically instantiates the thread by invokingnew Thread()
.Meanwhile, from App Engine's documentation about the use of threads in their Java sandbox:
So what happened here is the
Timer
object instantiated their own thread, which then executes the Objectify queries, but since threads instantiated outside ThreadManager does not have the proper App Engine API environment set up for them, it throws an exception.You need to refactor your code to avoid using the Timer and TimerTask classes and use basic threads instead. For example, instead of using:
You could instead use: