问题
I would like to initialize my local data store with some data using a regular Java program (I do not want to start the Development Server and call a service/servlet), and I'm getting the following exception
EXCEPTION :
Exception in thread "main" java.lang.NullPointerException: No API environment is registered for this thread.
at com.google.appengine.api.datastore.DatastoreApiHelper.getCurrentAppId(DatastoreApiHelper.java:108)
at com.google.appengine.api.datastore.DatastoreApiHelper.getCurrentAppIdNamespace(DatastoreApiHelper.java:118)
at com.google.appengine.api.datastore.Key.(Key.java:104)
at com.google.appengine.api.datastore.Key.(Key.java:88)
at com.google.appengine.api.datastore.Key.(Key.java:84)
at com.google.appengine.api.datastore.Entity.(Entity.java:122)
at com.google.appengine.api.datastore.Entity.(Entity.java:103)
at org.datanucleus.store.appengine.DatastoreFieldManager.(DatastoreFieldManager.java:187)
at org.datanucleus.store.appengine.DatastorePersistenceHandler.insertPreProcess(DatastorePersistenceHandler.java:338)
at org.datanucleus.store.appengine.DatastorePersistenceHandler.insertObjects(DatastorePersistenceHandler.java:251)
at org.datanucleus.store.appengine.DatastorePersistenceHandler.insertObject(DatastorePersistenceHandler.java:240)
at org.datanucleus.state.JDOStateManagerImpl.internalMakePersistent(JDOStateManagerImpl.java:3185)
at org.datanucleus.state.JDOStateManagerImpl.makePersistent(JDOStateManagerImpl.java:3161)
at org.datanucleus.ObjectManagerImpl.persistObjectInternal(ObjectManagerImpl.java:1298)
at org.datanucleus.ObjectManagerImpl.persistObject(ObjectManagerImpl.java:1175)
at org.datanucleus.jdo.JDOPersistenceManager.jdoMakePersistent(JDOPersistenceManager.java:669)
at org.datanucleus.jdo.JDOPersistenceManager.makePersistent(JDOPersistenceManager.java:694)
at com.stuff.server.GreetingServiceImpl.saveContact(GreetingServiceImpl.java:25)
at com.stuff.server.TestCase.testServerCallBack(TestCase.java:18)
at com.stuff.server.TestCase.main(TestCase.java:13)
TestCase.java
public class TestCase {
static GreetingServiceImpl greetingServiceImpl = new GreetingServiceImpl();
public static void main(String[] args) {
testServerCallBack();//line9
}
private static void testServerCallBack() {
Contacts contacts = new Contacts("this is", "awesome");
greetingServiceImpl.saveContact(contacts);//line:14
}
}
greeting.....impl.java
public class GreetingServiceImpl extends RemoteServiceServlet implements
GreetingService {
public String greetServer(String input) throws IllegalArgumentException {
return "";
}
@Override
public void saveContact(Contacts contacts) {
PersistenceManager pm = PMF.get().getPersistenceManager();
pm.makePersistent(contacts); //line:20
pm.close();
}
}
Is there a way to do this? How?
回答1:
Google provides a helper class that does exactly what you want - runs just enough code to work with the database, without launching the whole dev server. See the setUp and tearDown methods at http://code.google.com/appengine/docs/java/tools/localunittesting.html
回答2:
You have to setup a test Datastore Service for current thread. Basically you can do this:
private static void testServerCallBack() {
LocalServiceTestHelper helper =
new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig());
helper.setUp();
Contacts contacts = new Contacts("this is", "awesome");
greetingServiceImpl.saveContact(contacts);//line:14
}
That will initialize Database Service (a fake, for testing only) for this method only.
Or better you can do:
private final LocalServiceTestHelper helper =
new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig());
@Before
public void setUp() {
helper.setUp();
}
@After
public void tearDown() {
helper.tearDown();
}
So Database Service will work from all test methods.
Notice that if you're using different threads to access db, then you'll get a separate database for each thread. That's not what you want most likely. I mean helper.setUp() do setup a new separate Database Service for current thread, and all data stored into this db will be accessible only from current thread.
See more details at: http://code.google.com/appengine/docs/java/tools/localunittesting.html
回答3:
Just add those 3 libs (appart of the test one) to your classpath:
${SDK_ROOT}/lib/impl/appengine-api.jar
${SDK_ROOT}/lib/impl/appengine-api-labs.jar
${SDK_ROOT}/lib/impl/appengine-api-stubs.jar
This should fix the problem.
来源:https://stackoverflow.com/questions/5405211/initialize-local-datastore-exception-no-api-environment-is-registered-for-this