实现一对多双向关系时,com.google.appengine.repackaged.org.codehaus.jackson.map.JsonMappingException App Engine

时间:2014-03-12 12:51:05

标签: java android json google-app-engine google-cloud-datastore

我想为我的应用引擎应用实现一对多双向关系。我是我的实体:

@Entity
public class UserMaster {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Key key;
    private String userName;

    @OneToMany(mappedBy = "user")
    List<FeedMaster> feeds;

    getter()...setter() for all properties
}

@Entity
public class FeedMaster {
     @Id
    private String feedId;

    @ManyToOne(fetch = FetchType.LAZY)
    UserMaster user;

   getter()....setter() for both properties
}

此处,UserMaster的第一个对象是持久的,之后当我尝试FeedMaster的persis对象时,它会抛出java.io.IOException: com.google.appengine.repackaged.org.codehaus.jackson.map.JsonMappingException异常。

错误日志:

    Uncaught exception from servlet
java.io.IOException: com.google.appengine.repackaged.org.codehaus.jackson.map.JsonMappingException: (was java.lang.NullPointerException) (through reference chain: com.sampleregistrationapp.FeedMaster["user"]->com.sampleregistrationapp.UserMaster["key"]->com.google.appengine.api.datastore.Key["appId"])
    at com.google.api.server.spi.response.ServletResponseResultWriter.writeValueAsString(ServletResponseResultWriter.java:187)
    at com.google.api.server.spi.response.ServletResponseResultWriter.write(ServletResponseResultWriter.java:73)
    at com.google.api.server.spi.SystemService.invokeServiceMethod(SystemService.java:386)
    at com.google.api.server.spi.SystemServiceServlet.execute(SystemServiceServlet.java:124)
    at com.google.api.server.spi.SystemServiceServlet.doPost(SystemServiceServlet.java:82)
    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.google.apphosting.utils.servlet.ParseBlobUploadFilter.doFilter(ParseBlobUploadFilter.java:125)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at com.google.apphosting.runtime.jetty.SaveSessionFilter.doFilter(SaveSessionFilter.java:35)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at com.google.apphosting.utils.servlet.JdbcMySqlConnectionCleanupFilter.doFilter(JdbcMySqlConnectionCleanupFilter.java:60)
    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 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.runtime.jetty.AppVersionHandlerMap.handle(AppVersionHandlerMap.java:266)
    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 com.google.apphosting.runtime.jetty.RpcRequestParser.parseAvailable(RpcRequestParser.java:76)
    at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
    at com.google.apphosting.runtime.jetty.JettyServletEngineAdapter.serviceRequest(JettyServletEngineAdapter.java:146)
    at com.google.apphosting.runtime.JavaRuntime$RequestRunnable.run(JavaRuntime.java:446)
    at com.google.tracing.TraceContext$TraceContextRunnable.runInContext(TraceContext.java:437)
    at com.google.tracing.TraceContext$TraceContextRunnable$1.run(TraceContext.java:444)
    at com.google.tracing.CurrentContext.runInContext(CurrentContext.java:188)
    at com.google.tracing.TraceContext$AbstractTraceContextCallback.runInInheritedContextNoUnref(TraceContext.java:308)
    at com.google.tracing.TraceContext$AbstractTraceContextCallback.runInInheritedContext(TraceContext.java:300)
    at com.google.tracing.TraceContext$TraceContextRunnable.run(TraceContext.java:441)
    at com.google.apphosting.runtime.ThreadGroupPool$PoolEntry.run(ThreadGroupPool.java:251)

................................

我搜索了很多,但找不到任何解决方案。我提到了stackoverflow link,但是在这里,他们要在UserMaster中删除FeedMaster的getter setter,但如果我删除了这个,那么我将无法访问UserMaster数据我的FeedMaster对象。请帮我解决问题。谢谢。

2 个答案:

答案 0 :(得分:3)

这里发生的事情是Jackson库找到了一个无法转换为JSON的循环。在返回此对象时,您必须决定返回关系的位置以及不返回的位置。

您的代码意味着您可以从FeedMaster访问UserMaster,从UserMaster访问FeedMaster。这在您的应用程序级别上完全没问题,但是当您将此对象图序列化为JSON时,您必须让其中一个关系继续下去,因为它会导致JSON表示无限循环。

为此,您可以使用@JsonIgnore注释,如下所示:

import com.fasterxml.jackson.annotation.JsonIgnore; 

@Entity
public class FeedMaster {
   @Id
   private String feedId;

   @ManyToOne(fetch = FetchType.LAZY)
   UserMaster user;

   @JsonIgnore
   public UserMaster getUser() {
      ...
   }
}

在这种情况下,您的JSON将允许您访问FeedMaster中的所有UserMaster个对象,但不能访问来自UserMaster的{​​{1}}个对象。

答案 1 :(得分:0)

您可能已经想到了这一点,但有一种可能性是您使用“key”作为@Id的成员字段名称。在过去的几个小时里,我已经阅读了关于appengine的4-5个不同的教程,并回想一下他们特别指出的一个地方,他们没有在你的密钥中使用“key”这个词,因为它与内部数据存储impl有关。 (我最终在这个线程的方式是我试图找出JsonMappingException的另一个问题,因此这些错误的资源很少......)

尝试更改

private Key key;

private Key k; // obv use a better name such as id for real code (though k may be a reasonable convention in your codebase

并查看是否可以修复它。