Сериализация Objectify Keys с использованием Gson - PullRequest
2 голосов
/ 09 августа 2011

Кто-нибудь смог сериализовать / десериализовать объекты, используя gson, у которых есть поля Key (objectify)?

Я пытаюсь использовать gson для этого, но, похоже, у нескольких людей в сети возникли проблемы с сериализациейПридумайте ключи.Любые советы?

Когда я пытаюсь это сделать, я получаю следующую ошибку при десериализации:

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)

Ответы [ 2 ]

2 голосов
/ 20 августа 2012

Я сделал это как часть пакета резервного копирования в одном моем проекте.Это определенно работает для меня сейчас.

Попробуйте специализацию объекта сериализатора Gson (de) его создателем:

/** 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.Но это может быть изменено путем отражения после извлечения ключа в методе десериализации, если это необходимо.Это может потребоваться при перемещении данных из 1-го приложения GAE в другое.Для меня идентификатор приложения в ключах в настоящее время нулевой.Если не для вас, свяжитесь со мной.Я опубликую соответствующий код.

  2. Этот код работает и для старых Gson.Если использовать 2.1, подклассы TypeAdapter будут лучше и быстрее.Это очень похоже на этот код, и вам нужно реализовать 2 метода.Но это решение работает только со старыми версиями.

0 голосов
/ 03 декабря 2013

Мне удалось решить эту проблему, просто используя встроенные в 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<?> entityKey = new DAO().fact().stringToKey(serializedKey), что было решено простым изменением типа с <?> на <Entity>.

Если, однако, вам нужно сериализовать необработанные низкоуровневые объекты Key, методы, упомянутые вОтвет выше теперь находится в KeyFactory, а не в Key.У вас все еще будут проблемы, потому что AppIdNamespace является временным, закрытым, и нет методов для установки этих полей в ключе после десериализации.

...