App-Engine throws a NullPointerException when a getByObjectId object is called that has been updated

I use google datastore to save data as objects of the model class - "zone". Recently, this model has been updated with more options. When I deployed the new code, calls to existing zone entities result in an error. Existing zone objects do not have a newly added parameter (marked in the zone class).

ERROR: Error in Service {} at com.tryout.cdapp.exceptions.handler.CNDApplicationExceptionHandler.(CNDApplicationExceptionHandler.java:30) on 2014-10-14 03:21:48,002 java.lang.NullPointerException at com.google.appengine.datanucleus.scostore.FKListStore.getIndexPropertyName(FKListStore.java:965) at com.google.appengine.datanucleus.scostore.FKListStore.getFilterPredicates(FKListStore.java:940) at com.google.appengine.datanucleus.scostore.FKListStore.listIterator(FKListStore.java:383) at com.google.appengine.datanucleus.scostore.FKListStore.listIterator(FKListStore.java:349) at com.google.appengine.datanucleus.scostore.FKListStore.iterator(FKListStore.java:342) at org.datanucleus.store.types.sco.backed.List.loadFromStore(List.java:304) at org.datanucleus.store.types.sco.backed.List.initialise(List.java:253) at org.datanucleus.store.types.sco.SCOUtils.createSCOWrapper(SCOUtils.java:253) at org.datanucleus.store.types.sco.SCOUtils.newSCOInstance(SCOUtils.java:139) at org.datanucleus.store.mapped.mapping.AbstractContainerMapping.replaceFieldWithWrapper(AbstractContainerMapping.java:396) at org.datanucleus.store.mapped.mapping.AbstractContainerMapping.postFetch(AbstractContainerMapping.java:414) at com.google.appengine.datanucleus.DatastorePersistenceHandler.fetchObject(DatastorePersistenceHandler.java:599) at org.datanucleus.state.JDOStateManager.loadFieldsFromDatastore(JDOStateManager.java:1638) at org.datanucleus.state.JDOStateManager.validate(JDOStateManager.java:3511) at org.datanucleus.ObjectManagerImpl.findObject(ObjectManagerImpl.java:3379) at org.datanucleus.api.jdo.JDOPersistenceManager.getObjectById(JDOPersistenceManager.java:1722) at org.datanucleus.api.jdo.JDOPersistenceManager.getObjectById(JDOPersistenceManager.java:1740) at com.tryout.cdapp.dao.impl.BaseDaoImpl.findById(BaseDaoImpl.java:103) at com.tryout.cdapp.service.impl.ZoneServiceImpl.getZoneById(ZoneServiceImpl.java:55) at com.tryout.cdapp.resource.ZoneResource.getById(ZoneResource.java:75) 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 org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:137) at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:280) at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:234) at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:221) at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:356) at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:179) at org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:220) at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:56) at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:51) 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:438) at com.google.tracing.TraceContext$TraceContextRunnable$1.run(TraceContext.java:445) at com.google.tracing.CurrentContext.runInContext(CurrentContext.java:220) at com.google.tracing.TraceContext$AbstractTraceContextCallback.runInInheritedContextNoUnref(TraceContext.java:309) at com.google.tracing.TraceContext$AbstractTraceContextCallback.runInInheritedContext(TraceContext.java:301) at com.google.tracing.TraceContext$TraceContextRunnable.run(TraceContext.java:442) at java.lang.Thread.run(Thread.java:724) 

This is the code in Dao -

 private final Class<T> persistentClass; public BaseDaoImpl() { persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; } public T findById(Serializable id) { PersistenceManager pm = PMF.get().getPersistenceManager(); try { T t = pm.getObjectById(persistentClass, id); t.toString(); return t; } finally { pm.close(); } } 

This is the code in service -

  public Zone getZoneById(String id) { Zone zone = zoneDao.findById(id); return zone; } 

This is the model class - "Zone"

 public class Zone implements Serializable { private static final long serialVersionUID = 3946928960755099560L; @PrimaryKey @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY) @Extension(vendorName = "datanucleus", key = "gae.encoded-pk", value = "true") private String id; @Persistent private String name; @Persistent private String siteId; @Persistent private String orgId; @Persistent(defaultFetchGroup = "true") private List<LocationCoordinates> locationCoordinates; @Persistent private Date created; @Persistent private String description; @Persistent private String urlExtension; @Persistent private Integer timeSpentThreshold; @Persistent private Double tuningNumber; @Persistent(defaultFetchGroup = "true") private HashMap<String, String> zonePayload; @Persistent(defaultFetchGroup = "true") private List<ZoneSignalValue> zoneSignalValueList; //Newly Added //Getters and Setters } 

How can i solve this? Thanks in advance.

+5
source share
3 answers

You need to update existing objects. You can refer to this document. https://cloud.google.com/appengine/articles/update_schema

+5
source

This problem only occurs with child / related entities that are later represented in the main entity. One alternative job, without having to update all objects with new child objects, is to move the properties of the child entities to the default selection groups, that is, @Persistent (defaultFetchGroup = "false"), and then correctly handle the exceptions when reading these new child objects.

I did it and it works for sure.

0
source

I had the same problem when I was trying to read newly added child objects in Old / existing parents via JDO. Access to the new child using the low-level data warehouse API is not a problem. This is a problem with JDO, since JDO does not model data models without a schema adequately in such scenarios. Two ways to solve this problem:

  1. [As @Krishnalal suggested] If you want to stick with reading JDO, then you MUST update all existing parent entities with the newly added children. Just set them to NULL for parents who no longer have them. It is better to do this by running some kind of script in the low-level Datastore GET / PUT APIs.

  2. Read these children using the low-level data warehouse GET API API methods. It will extract your entity with a full child tree, if there is no child property at all. Thus, when transforming an entity into some JAVA data model, say, POJO, you need to make several invalid or existing checks. You should be good at reading recently added descendants such as null from old parent entities.

Feel free to ask for code / sample help if still not clear.

0
source

Source: https://habr.com/ru/post/1204636/


All Articles