9

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?

WannaBeGeek
  • 979
  • 14
  • 32
tstorms
  • 4,941
  • 1
  • 25
  • 47
  • 2
    You can use Jackson 2.0. See http://stackoverflow.com/questions/10065002/jackson-serialization-of-entities-with-birectional-relationships-avoiding-cyc – Eugene Retunsky Nov 29 '12 at 18:04
  • 1
    The `JsonIdentityInfo` annotation is lovely, thanks @EugeneRetunsky ! I found this page very useful to learn how that works: http://wiki.fasterxml.com/JacksonFeatureObjectIdentity – Simon Forsberg Sep 10 '13 at 21:40
  • I have tried `JsonManagedReference` and `JsonBackReference` none of them work. But, @SimonAndréForsberg 's given link is very interesting and works. – yas Aug 30 '15 at 14:54

2 Answers2

4

I ended up implementing the following solution.

One end of the relationship is considered to be the parent. It does not need any Jackson related annotation.

public class Collaboration {

    private Set<Tag> tags;

}

The other side of the relationship is implemented as follows.

public class Tag {

    @JsonSerialize(using = SimpleCollaborationSerializer.class)
    private Set<Collaboration> collaborations;

}

I'm using a custom serializer to will make sure that no cyclic references will occur. The serializer could be implemented like this:

public class SimpleCollaborationSerializer extends JsonSerializer<Set<Collaboration>> {

    @Override
    public void serialize(final Set<Collaboration> collaborations, final JsonGenerator generator,
        final SerializerProvider provider) throws IOException, JsonProcessingException {
        final Set<SimpleCollaboration> simpleCollaborations = Sets.newHashSet();
        for (final Collaboration collaboration : collaborations) {
            simpleCollaborations.add(new SimpleCollaboration(collaboration.getId(), collaboration.getName()));                
        }
        generator.writeObject(simpleCollaborations);
    }

    static class SimpleCollaboration {

        private Long id;

        private String name;

        // constructors, getters/setters

    }

}

This serializer will only show a limited set of the properties of the Collaboration entity. Because the "tags" property is omited, no cyclic references will occur.

A good read about this topic can be found here. It explains all possibilities when you're having a similar scenario.

tstorms
  • 4,941
  • 1
  • 25
  • 47
  • I have a similalr situation explained in http://stackoverflow.com/questions/28179369/spring-rest-json-can-not-handle-managed-back-reference-defaultreference-415 I still haven't managed to find a direct solution using annotations. – senseiwu Jan 30 '15 at 21:04
1

very handy interface implementation is provided in jackson 2 library as

@Entity
@JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="id")
public class Collaboration { ....

in maven

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.0.2</version>
</dependency>
Oleksii Kyslytsyn
  • 2,458
  • 2
  • 27
  • 43