Home > front end >  How can I combine polymorphism with unwrapping in Jackson?
How can I combine polymorphism with unwrapping in Jackson?

Time:12-20

I'm writing annotated model classes for json serialization/deserialization using jackson.

I have a json that contains a map, where the key is an enum and the value can be different types (including arrays) depending on key value.

A simplified example, this is what I need:

{
 "key1": "string value",
 "key2": [{"id":"1", "value": "test1"}, {"id":"2", "value": "test2"}]
}

I have tried, and I get this:

{
  "KEY1": {"value": "string value"},
  "KEY2": {"list": [{"id": "1", "value": "test1"}, {"id": "2", "value": "test2"}]}
}

So, unwrapping does not work.

Could anyone tell me what I am doing wrong ?

Here is the code:

public class Main {

    public static void main(String[] args) throws Exception {

        HashMap<Keys, ValueType> map = new HashMap<>();

        map.put(Keys.KEY1, new StringValue("string value"));

        map.put(Keys.KEY2, new ListValue( Arrays.asList(new Element[] {
                new Element("1", "test1"),
                new Element("2", "test2")
        } )));

        ObjectMapper objectMapper = new ObjectMapper();
        String s = objectMapper.writeValueAsString(map);

        System.out.println(s);

    }
}

public enum Keys {

    KEY1("key1"),
    KEY2("key2");

    private String value;

    Keys(String s) {
        this.value = s;
    }
}

public interface ValueType {

}

public class StringValue implements ValueType {

    @JsonUnwrapped
    private String value;

    public StringValue(String value) {
        this.value = value;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }
}

public class ListValue implements ValueType {

    @JsonUnwrapped
    private List<Element> list;

    public ListValue(List<Element> list) {
        this.list = list;
    }

    public List<Element> getList() {
        return list;
    }

    public void setList(List<Element> list) {
        this.list = list;
    }
}

public class Element {

    @JsonProperty
    private String id;
    @JsonProperty
    private String value;

    public Element(String id, String value) {
        this.id = id;
        this.value = value;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }
}

CodePudding user response:

You can annotate the classes' getters methods with the JsonValue annotation that indicates that the value of annotated accessor is to be used as the single value to serialize for the instance, instead of the usual method of collecting properties of value:

public class StringValue implements ValueType {

    @JsonUnwrapped
    private String value;

    public StringValue(String value) {
        this.value = value;
    }
    @JsonValue //<-- added annotation to the original getter method
    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }
}

public class ListValue implements ValueType {

    @JsonUnwrapped
    private List<Element> list;

    public ListValue(List<Element> list) {
        this.list = list;
    }

    @JsonValue //<-- added annotation to the original getter method
    public List<Element> getList() {
        return list;
    }

    public void setList(List<Element> list) {
        this.list = list;
    }
}
  • Related