0

I'm trying to use ObjectMapper to deserialize json but got some problem. Probably what I want is not possible with ObjectMapper but I will ask anyway for a good approach. Let' say I have a class with the list of objects like this:

public class SomeClass {

    ArrayList<BaseClass> list;
}
public class BaseClass {
    String id;
    String type;
}
public class MyClass1 extends BaseClass{

}
public class MyClass2 extends BaseClass{

}

And a json like this:

{
    "list": [
      {
        "id": "1",
        "type": "MyClass1",
      },
      {
        "id": "2",
        "type": "MyClass2",
      },
      {
        "id": "3",
        "type": "MyClass1",
      }
    ]
}

The question is how to tell ObjectMapper to create and put to the list not a BaseClass objects but MyClass1, MyClass2... objects depends on the value of "type"? Is that possible?

Olivier
  • 13,283
  • 1
  • 8
  • 24
Bitlejuce Do
  • 163
  • 3
  • 14

3 Answers3

2

You can make this happen simply using Jackson annotations:

@JsonTypeInfo(use = NAME, property = "type")
@JsonSubTypes(
  @Type(MyClass1.class, name = "MyClass1"),
  @Type(MyClass2.class, name = "MyClass2")
)
public class BaseClass {
  String id;
}

You may also want to look into other values for use, such as CLASS or MINIMAL_CLASS.

Jorn
  • 20,612
  • 18
  • 79
  • 126
2

See jackson polymorphic type handling annotations

You should be able to do something like

@JsonTypeInfo(
   use = JsonTypeInfo.Id.NAME, 
   include = As.PROPERTY, 
   property = "type"
)
@JsonSubTypes({
   @JsonSubTypes.Type(value = MyClass1.class, name = "MyClass1"),
   @JsonSubTypes.Type(value = MyClass2.class, name = "MyClass2")
})
public class BaseClass {
    String id;
    String type;
}
lance-java
  • 25,497
  • 4
  • 59
  • 101
-1

You may try to create a customer Mapper, something like:

public class CustomDeserializer extends JsonDeserializer<BaseClass> {
    @Override
    public BaseClass deserialize(JsonParser jp, DeserializationContext ctxt) 
      throws IOException, JsonProcessingException {
        ObjectCodec oc = jp.getCodec();
        JsonNode node = oc.readTree(jp);
        String type = node.get("type").asText();
        String id = node.get("id").asText();
        
        if ("MyClass1".equals(type)) {
            MyClass1 myClass1 = new MyClass1();
            myClass1.id = id;
            myClass1.type = type;
            return myClass1;
        } else if ("MyClass2".equals(type)) {
            MyClass2 myClass2 = new MyClass2();
            myClass2.id = id;
            myClass2.type = type;
            return myClass2;
        }
        return null; // or throw an exception
    }
}
public class SomeClass {
    @JsonDeserialize(contentUsing = CustomDeserializer.class)
    ArrayList<BaseClass> list;
}
Yahor Barkouski
  • 1,361
  • 1
  • 5
  • 21
  • 1
    Why does everyone always recommend custom mappers when Jackson has features to support structures like this out of the box? So complicated... – Jorn Aug 14 '23 at 11:55
  • This is also a working solution, but I would prefer annotation, anyway thanks! – Bitlejuce Do Aug 14 '23 at 14:36