Zankhna
Zankhna

Reputation: 4563

com.google.appengine.repackaged.org.codehaus.jackson.map.JsonMappingException while implementing One-To-Many bidirectional relationship App Engine

I want to implement One-To-Many bidirectional relationship for my app engine application.Below are my entities :

@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
}

Here, at first object of UserMaster is persisted and after that when i try to persis object of FeedMaster it throws java.io.IOException: com.google.appengine.repackaged.org.codehaus.jackson.map.JsonMappingException exception.

Error log :

    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)

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

I searched a lot but couldn't find any solution for that. I referred stackoverflow link but here, they are saying to remove getter setter for UserMaster in FeedMaster but if i remove this then i'll not be able to access UserMaster data through my FeedMaster object. Please help me to solve issue. Thank you.

Upvotes: 2

Views: 1214

Answers (2)

Creos
Creos

Reputation: 2525

You probably have figured this out, but one possibility is that you are using "key" as the member field name of your @Id. I've read about 4-5 different tutorials on appengine in the past few hours and recall seeing somewhere they specifically point out not to use the word "key" for your key as it claches with the internal data store impl. (The way I ended up on this thread is I'm trying to figure out another issue with JsonMappingException, so few resources on these errors...)

Try changing

private Key key;

to

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

and see if that fixes it.

Upvotes: 0

svpino
svpino

Reputation: 1994

What's happening here is that the Jackson library is finding a loop that can't be converted to JSON. At the time of returning this object, you have to decide where are you going to return the relationship, and where not to.

Your code implies that you can access FeedMaster from UserMaster, and UserMaster from FeedMaster. That's perfectly fine at your application level, but when you are serializing this object graph to JSON, you'll have to let one of the relationships go because it will cause and endless loop on the JSON representation.

To do this, you can use the @JsonIgnore annotation as follows:

import com.fasterxml.jackson.annotation.JsonIgnore; 

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

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

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

In this case, your JSON will give you access to all FeedMaster objects from UserMaster, but not to the UserMaster objects from FeedMaster.

Upvotes: 3

Related Questions