Montag, 4. Januar 2016

Jackson @JsonIdentityInfo, ObjectIdGenerators, bidirectional references

Recently we had a big issue with sending JSON in our Java Web App with Jackson. We had a pretty complex entity model and bidirectional references and used therefore @JsonIdentityInfo. @JsonManagedReference and @JsonBackReference didn't work because it was bidirectional.
At first we had the problem with duplicate properties:

{
    "links": [{
            "id": 2,
            "section1": {
                ...
            },
            "section2": {
                ...
            },
            "listLinkLabel": [{
                    "linkLabel": 1,
                    "linkLabel": "after"
                }]
        }, {
            "id": 5,
            "section1": {
                ...
            },
            "section2": {
                ...
            },
            "listLinkLabel": [{
                    "linkLabel": 2,
                    "linkLabel": "before"
                }, {
                    "linkLabel": 3,
                    "linkLabel": "overlap"
                }, 1]
        }, {
            "id": 3,
            "section1": {
                ...
            },
            "section2": {
                ...
            },
            "listLinkLabel": [3]
        }
}

As you can see linkLabel appears twice. This was because we used an IntSequenceGenerator on a String attribute:

@Entity
@JsonIdentityInfo(
        generator = ObjectIdGenerators.IntSequenceGenerator.class,
        property = "linkLabel")
public class LinkLabel implements Serializable {

    private static final long serialVersionUID = 1L;
    @Id
    @JsonFormat(shape = JsonFormat.Shape.STRING)
    @Column(name = "LinkLabel")
    @GeneratedValue(strategy = GenerationType.AUTO)
    private String linkLabel;

Then we had the problem that with the once encountered objects in the JSON are replaced by there ids with @JsonIdentityInfo:

{
    "objects": [{
            "id": 1,
            "otherObj": [{
                    "id": 1,
                    ...
                }, {
                    "id": 3,
                    ...
                }]
        },
            "id": 2,
            "otherObj": [1] <-- referencing otherObj with id 1
    ]
}


This is the Java Entity:


@Entity
@JsonIdentityInfo(
        generator = ObjectIdGenerators.IntSequenceGenerator.class,
        property = "linkLabel")
public class LinkLabel implements Serializable {
   //...
}

This behavior was a big problem on the JavaScript/ AngularJS client side. Fortunately we found the Jackson-Jsog plugin https://github.com/jsog/jsog-jackson. It can handle bidirectional references easily and can be used on client side as well.
So the code now looks like this:
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.voodoodyne.jackson.jsog.JSOGGenerator;

@Entity
@JsonIdentityInfo(generator=JSOGGenerator.class)
public class LinkLabel implements Serializable {

    private static final long serialVersionUID = 1L;
    @Id
    @Column(name = "LinkLabel")
    @GeneratedValue(strategy = GenerationType.AUTO)
    private String linkLabel;

}

Simply add it in your pom.xml and on client side in your bower.json. It works like a charm!

Keine Kommentare:

Kommentar veröffentlichen