Denys Kurochkin
Denys Kurochkin

Reputation: 1497

Unmarshall JSON to subtypes with different field type jackson

I receive a JSON array of objects which all have field content, but the type of this field may differ:

[
    {
        "id": "primaryBodyHeader",
        "type": "RichText",
        "content": "<h1>Alice's Adventures in Wonderland</h1>"
    },
    {
        "id": "1027",
        "type": "RichText",
        "content": {
            "value": "RVMtMTk=",
            "contentType": "DynamicContent"
        }
    }
]

And I have the bean:

public abstract class LandingPageContentItem {
    private String id;
    private String type;
    private String content;
}

At least I want to map content to a text field when it is a text (null for non-text content)

At most, I want to map different kinds of items to different subclasses according to the type of field content - TextContentItem, ComplexContentItem or so. @JsonSubTypes can't do this

Is there a way to do it without custom deserializer?

Upvotes: 1

Views: 873

Answers (2)

vsminkov
vsminkov

Reputation: 11250

If you don't know (or have no control of) what might be in content field then I'd suggest you to map raw com.fasterxml.jackson.databind.JsonNode like this

public static class LandingPageContentItem {
    private final String id;
    private final String type;
    private final JsonNode content;

    @JsonCreator
    public LandingPageContentItem(
            @JsonProperty("id") final String id, 
            @JsonProperty("type") final String type, 
            @JsonProperty("content") final JsonNode content) {
        this.id = id;
        this.type = type;
        this.content = content;
    }

    /* some logic here */
}

And then you can read it normally

ObjectMapper mapper = new ObjectMapper();
List<LandingPageContentItem> items = 
    mapper.readValue(node, new TypeReference<List<LandingPageContentItem>>() {});

Later on you can verify if JsonNode is of expected type.

if (content.isTextual()) {
    // do something with content.asText(); 
}

Upvotes: 2

Jon Peterson
Jon Peterson

Reputation: 2996

Without writing a custom deserializer, the best I can think of is:

public class LandingPageContentItem {
    private String id;
    private String type;
    private Object content;
}

Then just use if(item.content instanceof String) and if(item.content instanceof Map) to handle it from there.

Upvotes: 2

Related Questions