2
votes

I am trying to write a simple app which has Event Entitys.

Adding an event entity to the cloud through the auto-generated endpoint API works, as well as retrieving the event by it's id. The problem is when i try to update the event. the eventInCloud is the same as i see useing the datastore viewer. I add another element to it's list of strings called Participants and try to update it in the datastore. Here is the code:

try {
        Event eventInCloud = endpoint.getEvent(eventLocal.getId()).execute();
        eventInCloud.getParticipants().add("[email protected]");
        endpoint.updateEvent(eventInCloud).execute();
    } catch (IOException e) {
        e.printStackTrace();
    }

The error message i see in eclipse is:

06-30 18:53:07.415: W/System.err(3448): com.google.api.client.googleapis.json.GoogleJsonResponseException: 503 Service Unavailable 06-30 18:53:07.415: W/System.err(3448): { 06-30 18:53:07.415: W/System.err(3448): "code" : 503, 06-30 18:53:07.415: W/System.err(3448): "errors" : [ { 06-30 18:53:07.415: W/System.err(3448): "domain" : "global", 06-30 18:53:07.415: W/System.err(3448): "message" : "java.lang.NullPointerException", 06-30 18:53:07.415: W/System.err(3448): "reason" : "backendError" 06-30 18:53:07.415: W/System.err(3448): } ], 06-30 18:53:07.415: W/System.err(3448): "message" : "java.lang.NullPointerException" 06-30 18:53:07.415: W/System.err(3448): } 06-30 18:53:07.415: W/System.err(3448): at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:111) 06-30 18:53:07.415: W/System.err(3448): at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:38) 06-30 18:53:07.415: W/System.err(3448): at com.google.api.client.googleapis.services.AbstractGoogleClientRequest$1.interceptResponse(AbstractGoogleClientRequest.java:312) 06-30 18:53:07.415: W/System.err(3448): at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:1042) 06-30 18:53:07.415: W/System.err(3448): at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:410) 06-30 18:53:07.415: W/System.err(3448): at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:343) 06-30 18:53:07.415: W/System.err(3448): at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:460) 06-30 18:53:07.415: W/System.err(3448): at com.evman.model.Events.updateEventInCloud(Events.java:83) 06-30 18:53:07.415: W/System.err(3448): at com.evman.model.Events.access$1(Events.java:69) 06-30 18:53:07.415: W/System.err(3448): at com.evman.model.Events$UpdateEventTask.doInBackground(Events.java:107) 06-30 18:53:07.415: W/System.err(3448): at com.evman.model.Events$UpdateEventTask.doInBackground(Events.java:1) 06-30 18:53:07.415: W/System.err(3448): at android.os.AsyncTask$2.call(AsyncTask.java:287) 06-30 18:53:07.415: W/System.err(3448): at java.util.concurrent.FutureTask.run(FutureTask.java:234) 06-30 18:53:07.415: W/System.err(3448): at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230) 06-30 18:53:07.415: W/System.err(3448): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080) 06-30 18:53:07.415: W/System.err(3448): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573) 06-30 18:53:07.415: W/System.err(3448): at java.lang.Thread.run(Thread.java:856)

And the error i get on the server side is this:

com.google.api.server.spi.SystemService invokeServiceMethod: null java.lang.NullPointerException at com.google.appengine.api.datastore.KeyTranslator.convertToPb(KeyTranslator.java:49) at com.google.appengine.api.datastore.AsyncDatastoreServiceImpl.doBatchGetBySize(AsyncDatastoreServiceImpl.java:316) at com.google.appengine.api.datastore.AsyncDatastoreServiceImpl.get(AsyncDatastoreServiceImpl.java:280) at com.google.appengine.api.datastore.DatastoreServiceImpl$1.runInternal(DatastoreServiceImpl.java:68) at com.google.appengine.api.datastore.DatastoreServiceImpl$1.runInternal(DatastoreServiceImpl.java:65) at com.google.appengine.api.datastore.TransactionRunner.runInTransaction(TransactionRunner.java:29) at com.google.appengine.api.datastore.DatastoreServiceImpl.get(DatastoreServiceImpl.java:65) at com.google.appengine.api.datastore.DatastoreServiceImpl.get(DatastoreServiceImpl.java:55) at com.google.appengine.datanucleus.WrappedDatastoreService.get(WrappedDatastoreService.java:60) at com.google.appengine.datanucleus.EntityUtils.getEntityFromDatastore(EntityUtils.java:665) at com.google.appengine.datanucleus.DatastorePersistenceHandler.fetchObject(DatastorePersistenceHandler.java:543) at org.datanucleus.state.JDOStateManager.loadFieldsFromDatastore(JDOStateManager.java:1638) at org.datanucleus.state.JDOStateManager.loadUnloadedFieldsInFetchPlan(JDOStateManager.java:1363) at org.datanucleus.state.JDOStateManager.detach(JDOStateManager.java:2718) at org.datanucleus.ObjectManagerImpl.performDetachOnCloseWork(ObjectManagerImpl.java:4571) at org.datanucleus.ObjectManagerImpl.performDetachOnClose(ObjectManagerImpl.java:4534) at org.datanucleus.ObjectManagerImpl.close(ObjectManagerImpl.java:1105) at org.datanucleus.api.jpa.JPAEntityManager.close(JPAEntityManager.java:193) at com.evman.eventmanager.EventEndpoint.containsEvent(EventEndpoint.java:165) at com.evman.eventmanager.EventEndpoint.updateEvent(EventEndpoint.java:123) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:45) at com.google.api.server.spi.SystemService.invokeServiceMethod(SystemService.java:320) at com.google.api.server.spi.SystemServiceServlet.execute(SystemServiceServlet.java:122) at com.google.api.server.spi.SystemServiceServlet.doPost(SystemServiceServlet.java:80) 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 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:483) at com.google.tracing.TraceContext$TraceContextRunnable$1.run(TraceContext.java:490) at com.google.tracing.TraceContext.runInContext(TraceContext.java:777) at com.google.tracing.TraceContext$DoInTraceContext.runInContext(TraceContext.java:754) at com.google.tracing.TraceContext$AbstractTraceContextCallback.runInInheritedContextNoUnref(TraceContext.java:345) at com.google.tracing.TraceContext$AbstractTraceContextCallback.runInInheritedContext(TraceContext.java:337) at com.google.tracing.TraceContext$TraceContextRunnable.run(TraceContext.java:487) at java.lang.Thread.run(Thread.java:722)

And off-course the generated backend code is:

@ApiMethod(name = "updateEvent")
public Event updateEvent(Event event) {
    EntityManager mgr = getEntityManager();
    try {
        if (!containsEvent(event)) {
            throw new EntityNotFoundException("Object does not exist");
        }
        mgr.persist(event);
    } finally {
        mgr.close();
    }
    return event;
}

private boolean containsEvent(Event event) {
    EntityManager mgr = getEntityManager();
    boolean contains = true;
    try {
                    // added the following if for the first time when i add the entity
        if(event.getKey()==null){
            return false;
        }
        Event item = mgr.find(Event.class, event.getKey());
        if (item == null) {
            contains = false;
        }
    } finally {
        mgr.close();
    }
    return contains;
}

Any help would be greatly appreciated!

2
For your updateEvent backend method, you need to ensure that you are retreiving the entity with the required id , adding the new fields to this entity and then inserting the entity with the same id so that it gets updated.tony m
As you can see, i am retrieving an event object from the cloud (successfully) and using the same exact object for the updateEvent method that fails. So the id is the same.Evgeny Erlihman
there is some error in how the entity is being retrieved in your updateevent method. please add the code for the method containsEvent()tony m
Dome. Line 165 is mgr.close()Evgeny Erlihman

2 Answers

1
votes

The issue seems to be arising in the containsEvent() method. From your local, after editing eventsincloud, you are passing a JSON to your endpoint method updateEvent. This then calls containsEvent, passing on a JSON as the parameter event and here you are calling the method getKey() on event. The app engine method getKey() is to be used for getting key value from an entity instance and not from a JSON representation of an entity. You can modify your updateEvent to query an entity by its Id , similar to getEvent . You can either find the id in your cloud or get it at local as you do in eventLocal.getId(), which is a local method for getting Id stored in your JSON. Then in your endpoint method, you can use the id to query the required entity (a working code should be already in place in getEvent) and then add the new values to the retreived entity and then save back the entity.

1
votes

Tony's answer helped me realize that i used the Key in a wrong way.

i had:

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Key key;

what i think caused problems. As soon as i changed it to:

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

The problems went away.