Skip to content

Polymorphism

Ahmad K. Bawaneh edited this page Dec 24, 2019 · 1 revision

Polymorphism

Domino-jackson supports polymorphism by per-class annotations: @JsonTypeInfo and @JsonSubTypes. We can have following hierarchy and mappers:

@JsonTypeInfo(use = Id.NAME, include = As.PROPERTY, visible = true)
@JsonSubTypes({
   @Type(value` = MyClassOne.class, name = "childclass"),
   @Type(value = MyClassTwo.class, name = "childclass2")})
interface MyBaseInterface {}

class MyClassOne implements MyBaseInterface {}
class MyClassTwo implements MyBaseInterface{}

@JSONMapper
interface ListMapper extends ObjectMapper<List<MyBaseInterface>>

class Foo {
      private MyBaseInterface objField;
      private Map<Integer, MyBaseInterface> mapField;
}

@JSONMapper
interface FooMapper extends ObjectMapper<Foo>;

The domino-jackson process beans annotated with @JsonTypeInfo and @JsonSubTypes and generate all needed serializers and deserializers for subtypes.

There are two limitations here:

  • The only supported option for @JsonTypeInfo is use=Id.NAME.
  • The base type and all subtypes can NOT be a generic types.

Bounded wildcards

Having polymorphism naturally leads to the need to have wildcards. but bounded wildcards are tricky, here is a working example :

@JsonTypeInfo(use = Id.NAME, include = As.PROPERTY, visible = true)
@JsonSubTypes({
   @Type(value` = MyClassOne.class, name = "childclass"),
   @Type(value = MyClassTwo.class, name = "childclass2")})
interface MyBaseInterface {}

class MyClassOne implements MyBaseInterface {}
class MyClassTwo implements MyBaseInterface{}

class Bar {
    List<? extends MyBaseInterface> myList;
    List<? extends Integer, ? extends MyBaseInterface> myMap;
}

@JSONMapper
interface BarMapper extends ObjectMapper<Bar>{}

But there is some limitations :

  • You can not use unbounded wildcards at all
  • You can not have JSONMapper/JSONReader/JSONWriter for type having wildcards or type parameters i.e.
@JSONMapper
interface BarMapper extends ObjectMapper<Bar<Integer>>{} //Valid
interface BarMapper extends ObjectMapper<Bar<Integer, List<Foo>>>{} //Valid
interface BarMapper extends ObjectMapper<Bar<Integer, List<?>>>{} //NOT Valid
interface BarMapper extends ObjectMapper<Bar<? extends Integer>>{} //NOT Valid
interface BarMapper extends ObjectMapper<Bar<List<? extends Integer>>>{} //NOT Valid
interface BarMapper extends ObjectMapper<Bar<T>>{} //NOT Valid
  • You can have generic collections with bounded wildcards. The bounds must be referenced in corresponding @JsonTypeInfo and @JsonSubType. Some examples:
@JsonTypeInfo(use = Id.NAME, include = As.PROPERTY, visible = true)
@JsonSubTypes({
   @Type(value` = MyClassOne.class, name = "childclass"),
   @Type(value = MyClassTwo.class, name = "childclass2")})
interface MyBaseInterface {}

class MyClassOne implements MyBaseInterface {}
class MyClassTwo implements MyBaseInterface{}

class Bar<T> {
      List<? extends T> list;
      Map<Integer, ? extends MyBaseInterface> map;
}

@JSONMapper
interface BarMapper extends ObjectMapper<Bar<MyBaseInterface>>{} 
  • You can not have member fields with type a custom generic class, declared with bounded wildcards i.e.
class Foo<T> {
   private List<T> data;
   
   public void setData(List<T> data) {
          this.data = data;
   }
   public List<T> getData() {
         return data;
   }
}
class Bar<T> {
    public List<? extends T> myList; //that is OK
    public Foo<T> myFoo; //that is OK
    public Foo<? extends Integer> myMember; // WON'T work
    public Foo<? extends T> myMember; // WON'T work
}

@JSONMapper
interface BarMapper extends ObjectMapper<Bar<Double>>{}