Jackson JSON User Group

JSON in Java the Right Way -- Action, Jackson!

How to handle cyclic references in a bidirectional many to many relationship

I'm having a bidirectional many to many relationship in my entities. See the example below:

public class Collaboration {

    @JsonManagedReference("COLLABORATION_TAG")
    private Set<Tag> tags;

}

public class Tag {

    @JsonBackReference("COLLABORATION_TAG")
    private Set<Collaboration> collaborations;

}

When I try to serialize this to JSON, I'm getting the following exception: "java.lang.IllegalArgumentException: Can not handle managed/back reference 'COLLABORATION_TAG': back reference type (java.util.Set) not compatible with managed type (foo.Collaboration).

Actually, I know this makes sense because the javadoc explicitly states that you can't use @JsonBackReference on Collections. My question is, how should I address this problem? What I've done for now is remove the @JsonManagedReference annotation on the parent side, and added the @JsonIgnore on the child side. Could someone tell me what the side effects are of this approach? Are there any other suggestions?

Tags: JsonBackReference, JsonManagedReference, spring-data-neo4j

Views: 3949

Reply to This

Replies to This Discussion

You can not use managed references for many-to-many relationships: there has to be single parent, which limits this to one-to-one and one-to-many (parent/children) cases.

What you may want to check out instead is the new 2.0 feature, @JsonIdentityInfo, which allows all kinds of Object Identity. It is used similar to how @JsonTypeInfo is for polymorphic types; that is, anything that needs to be referenced using identity (meaning, multiple references point to a single instance) needs to be annotated with it. Annotation can be added to either type (class), or reference property.

In your case, I think you would need to add annotation to `Tag` and `Collaboration` types; and then references should work for entries in Sets.

Thanks for the suggestion, but when I place this annotation on both entities, it will practicly pull all data from my database. E.g. a tag has collaborations and a collaboration has tags. These tags have collaborations which have other tags, and so on...

The problem that I'm facing is that I only want to show one level of "depth". So for a collaboration, I want to show its tags (and not their corresponding collaborations). For a tag, I want to show its collaborations (on not their corresponding tags).

Any idea on how to solve this? Thanks.

Hey, I have exactly the same problem, but haven't found the problem until now. I need the infinite loop for both serializations to stop at the first layer. 

There seemed to be a way to use @ManyToMany annotations (http://ankeetmaini.wordpress.com/2012/07/26/json-troubleshooting-ci...), but I can't access those annotations in my project. Idk why, maybe they where part of an older version of jackson?

maybe that helps you and if yes, maybe you know why "@ManyToMany" are not accessible for me (but @ManagedReference and @Backreference are)

@ManyToMany is a Hibernate (or JPA) specific annotation and has nothing to do with Jackson. I'm trying to solve this with Jackson annotations only, but this functionality seems to be lacking. Doesn't anyone know a solution to this problem? We can't be the first ones with this requirement... ;-)


Thanks!

Forward/backward references do not and will not support many-to-many mappings for technical reasons -- there is no "parent" object to fill in, so mechanism used can not be extended.

But as to full traversal, I would recommend using Jackson Hibernate module, and making sure it does not force eager loading (I forget name of the method in module but it's there). This should prevent loading of values of lazy-loaded properties, if that would help.

As I'm not using Hibernate, but (Spring Data) Neo4j, this is not relevant for me. I do have the @Fetch annotation on the related entities which ensures that the entities will be eagerly fetched. I need this annotation, because I want to show all entities with a depth of one. As a side effect, if I use the @JsonIdentityInfo, a huge part of my database will be fetched...

So still no clue on how to solve this. :-(

Jackson does not provide a way to prune by depth, so you'd need custom code here, probably a custom serializer.

RSS

© 2014   Created by Tatu Saloranta.   Powered by

Badges  |  Report an Issue  |  Terms of Service