FrederikVds
FrederikVds

Reputation: 568

How to handle forward references during JSON deserialisation?

I have to parse a JSON like this in Jackson:

"people": [
    {
        "personId": 1,
        "name": "An",
        "friends": [{"personId": 2}]
    },
    {
        "personId": 2,
        "name": "Bob",
        "friends": [{"personId": 1}]
    }
]

This should result in An's friends array containing Bob, and Bob's friends array containing An. I'm using this decorator on the Person class:

@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "personId")

The problem is that, during deserialisation, Jackson sets the first person in An's friends to null, as Bob hasn't been parsed yet. What's the best way to work around this?

Upvotes: 0

Views: 110

Answers (1)

mle
mle

Reputation: 2550

If you have the possibility to slightly preprocess your JSON, so that the references are pure ints, the following approach would be the easiest for you:

@Data
@NoArgsConstructor
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "personId")
public class People {
    private int personId;
    private String name;
    private List<People> friends;
}

A little test for the deserialization:

public class ForwardReferenceTest {
    @Test
    void forwardReference() throws JsonProcessingException {
        String json = "{\"people\": [\n" +
                "    {\n" +
                "        \"personId\": 1,\n" +
                "        \"name\": \"An\",\n" +
                "        \"friends\": [2]\n" +
                "    },\n" +
                "    {\n" +
                "        \"personId\": 2,\n" +
                "        \"name\": \"Bob\",\n" +
                "        \"friends\": [1]\n" +
                "    }\n" +
                "]}";

        Map<String, List<People>> people = new ObjectMapper().readValue(json, new TypeReference<Map<String, List<People>>>() {
        });
        assertThat(people.get("people").get(1).getFriends().get(0).getPersonId()).isEqualTo(1);
    }
}

Could you give this a try?

Upvotes: 2

Related Questions