2

有没有人能够使用具有 Key(对象化对象)字段的 gson 序列化/反序列化对象?

我正在尝试使用 gson 来执行此操作,但似乎网上有几个人在序列化 appengine 密钥时遇到了问题。有小费吗?

当我尝试这样做时,我在反序列化时收到以下错误:

java.lang.NullPointerException
    at com.google.appengine.api.datastore.KeyTranslator.convertToPb(KeyTranslator.java:55)
    at com.google.appengine.api.datastore.DataTypeTranslator$ReferenceType.setPropertyValue(DataTypeTranslator.java:680)
    at com.google.appengine.api.datastore.DataTypeTranslator.createPropertyValue(DataTypeTranslator.java:207)
    at com.google.appengine.api.datastore.DataTypeTranslator.createProperty(DataTypeTranslator.java:191)
    at com.google.appengine.api.datastore.DataTypeTranslator.addProperty(DataTypeTranslator.java:159)
    at com.google.appengine.api.datastore.DataTypeTranslator.addPropertiesToPb(DataTypeTranslator.java:142)
    at com.google.appengine.api.datastore.EntityTranslator.convertToPb(EntityTranslator.java:47)
    at com.google.appengine.api.datastore.AsyncDatastoreServiceImpl.doBatchPutBySize(AsyncDatastoreServiceImpl.java:475)
    at com.google.appengine.api.datastore.AsyncDatastoreServiceImpl.put(AsyncDatastoreServiceImpl.java:446)
    at com.googlecode.objectify.impl.AsyncObjectifyImpl.put(AsyncObjectifyImpl.java:255)
    at com.googlecode.objectify.impl.AsyncObjectifyImpl.put(AsyncObjectifyImpl.java:229)
    at com.googlecode.objectify.impl.ObjectifyImpl.put(ObjectifyImpl.java:126)
    at com.rewardly.mailfoo.dataaccess.DAO.storeEntity(DAO.java:36)
    at com.rewardly.mailfoo.ajaxcalls.UpdateEntity.doPost(UpdateEntity.java:38)
    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 com.rewardly.mailfoo.utils.UserFilter.doFilter(UserFilter.java:44)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at com.google.appengine.tools.development.HeaderVerificationFilter.doFilter(HeaderVerificationFilter.java:35)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at com.google.appengine.api.blobstore.dev.ServeBlobFilter.doFilter(ServeBlobFilter.java:58)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at com.google.apphosting.utils.servlet.TransactionCleanupFilter.doFilter(TransactionCleanupFilter.java:43)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at com.google.appengine.tools.development.StaticFileFilter.doFilter(StaticFileFilter.java:122)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at com.google.appengine.tools.development.BackendServersFilter.doFilter(BackendServersFilter.java:97)
    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 com.google.apphosting.utils.jetty.DevAppEngineWebAppContext.handle(DevAppEngineWebAppContext.java:70)
    at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
    at com.google.appengine.tools.development.JettyContainerService$ApiProxyHandler.handle(JettyContainerService.java:351)
    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.content(HttpConnection.java:938)
    at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:755)
    at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:218)
    at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
    at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:409)
    at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)
4

2 回答 2

2

我在我的一个项目中将它作为备份套件的一部分完成。它现在对我来说绝对有用。

尝试由其构建器专门化 Gson (de)serializer 对象:

/** Helper class for deserialization of Key
  * @copyright TrashOut, s.r.o. 2012 */
 @SuppressWarnings("rawtypes")
 public static class KeyAdapterSerializer implements JsonSerializer<Key>, JsonDeserializer<Key>, InstanceCreator<Key>  {
   @Override
   public JsonElement serialize(Key key, Type type, JsonSerializationContext serialContext) {
     return new JsonPrimitive(key.getString());
   }
   @Override
   public Key deserialize(JsonElement element, Type type,
       JsonDeserializationContext deserialContext) throws JsonParseException {
     Misc.log.warning(" element content " + element.getAsString());
     return Key.create(element.getAsString());
   }
   @Override
   public Key createInstance(Type type) {
     Misc.log.warning(" element content " + type.getClass());
     return Key.create(BlahBlah.class, 1L);
 /* FIXME: BlahBlah is ANY class storable by your Objectify = registred in DAO
 * (extending DAOBase; registered by OjectifyService.register(clazz) method) ;
 * This MUST return any existing Key -that class has NO nullary constructor; we
 * will change the key immediately after in deserialize method */
   }
 }

代码中的最终用法:

public static Gson gson = (new GsonBuilder()).serializeNulls()
.setPrettyPrinting().registerTypeAdapter(Key.class, new KeyAdapterSerializer()).create();
// creating Gson instance which will serialize all and prints nicely
// --> turn off setPrettyPrinting() for performance improvement
// see http://google-gson.googlecode.com/svn/trunk/gson/docs/javadocs/index.html
// for more preferences

String myObjectJsonStringRepresentation =gson.toJson(myObject);
// in String you have string representation of the all object -WITH THE KEY

为了完整性:

  1. 在 Key 对象中也有序列化的 GAE 应用程序标识符。但如果需要,可以在反序列化方法中检索密钥后通过反射对其进行更改。将数据从第一个 GAE 应用程序移动到另一个应用程序时可能需要它。对我来说,键中的应用标识符现在为空。如果不适合你,请联系我。我将发布适当的代码。

  2. 此代码也适用于较旧的 Gson。如果使用 2.1,TypeAdapter 子类化会更好更快。它与此代码非常相似,您需要实现 2 个方法。但是这个解决方案也适用于旧版本。

于 2012-08-20T09:44:50.457 回答
0

I was able to solve this problem by simply using Objectify's built-in DAOBase.fact().stringToKey() and DAOBase.fact().keyToString() methods.

String serializedKey = new DAO().fact().keyToString(entity.getKey());
      ...
Key<Entity> entityKey = new DAO().fact().stringToKey(serializedKey);

My own problems arose from having to compile under Java 6, because I had been using Key<?> entityKey = new DAO().fact().stringToKey(serializedKey), which was solved by simply changing the type from <?> to <Entity>.

If, however, you need to serialize the raw low-level Key objects, the methods mentioned in the above answer are now located in KeyFactory instead of on Key. You will still have trouble because AppIdNamespace is transient, private, and there are no methods to set those fields on the key post-deserialization.

于 2013-12-03T17:18:53.260 回答