【问题标题】:Serializing Objectify Keys using Gson使用 Gson 序列化 Objectify 键
【发布时间】:2011-10-22 20:11:35
【问题描述】:

是否有人能够使用具有 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)

【问题讨论】:

  • 查看 com.rewardly.mailfoo.ajaxcalls.UpdateEntity.doPost 及其处理的 JSON 片段会有所帮助。
  • 不确定是否可以完成(希望其他人可以提出解决方法),但如果不能,您可以查看 Jackson。一些用户致力于让 Objectify 密钥工作(我假设成功,应该很容易验证)。

标签: json google-app-engine gson objectify


【解决方案1】:

我能够通过简单地使用 Objectify 的内置 DAOBase.fact().stringToKey()DAOBase.fact().keyToString() 方法来解决这个问题。

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

我自己的问题来自于必须在 Java 6 下编译,因为我一直使用 Key&lt;?&gt; entityKey = new DAO().fact().stringToKey(serializedKey),只需将类型从 &lt;?&gt; 更改为 &lt;Entity&gt; 即可解决。

但是,如果您需要序列化原始的低级 Key 对象,则上述答案中提到的方法现在位于 KeyFactory 中,而不是位于 Key 上。您仍然会遇到麻烦,因为 AppIdNamespace 是临时的、私有的,并且没有方法可以在反序列化后的密钥上设置这些字段。

【讨论】:

    【解决方案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 应用程序 标识符。但是可以通过key后的反射来改变 如果需要,在反序列化方法中检索。可能需要 将数据从第一个 GAE 应用程序移动到另一个应用程序时。为了我, 键中的应用标识符现在为空。如果不是为了你, 联络我。我将发布适当的代码。

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

    【讨论】:

      猜你喜欢
      • 2012-07-13
      • 1970-01-01
      • 1970-01-01
      • 2022-01-01
      • 2013-04-19
      • 2023-01-19
      • 1970-01-01
      • 2011-12-04
      • 2013-07-18
      相关资源
      最近更新 更多