Reputation: 4563
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
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
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