title: Polymorphism with Jackson: How to use JsonTypeInfo, JsonSubTypes and JsonTypeId annoations if sub-type is extended and used explicitly?
body: <p>We have some JSON-POJOs with complex Type hierarchy and facing a problem with the type annotations:</p>
  
  <p>Small Example:</p>
  
  <ul>
  <li><code>SomeObjectA -&gt; ObjectA -&gt; AbstractObject</code></li>
  <li><code>ObjectContainer</code> holds <code>AbstractObject</code> (<code>ObjectA</code> or <code>ObjectB</code> only, never <code>SomeObjectA</code>)</li>
  <li><code>SomeObjectContainer</code> holds <code>SomeObjectA</code> only</li>
  </ul>
  
  <p>In our implementation <code>AbstractObject</code> will be some Geo-JSON-Object. <code>SomeObjectA</code> will extend Geo-JSON (with custom parameters instead of using <code>properties</code> map) but has to have same <code>type</code> as <code>ObjectA</code> would have.</p>
  
  <p>We are looing for the right/best way to annotate <code>AbstractObject</code> to fulfill our needs and to be used with Jackson.</p>
  
  <hr>
  
  <p>Version 1: Using <code>JsonTypeInfo</code> only:</p>
  
  <pre><code>import com.fasterxml.jackson.annotation.JsonSubTypes;
  import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
  import com.fasterxml.jackson.annotation.JsonTypeInfo;
  
  @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
  @JsonSubTypes({ //
          @Type(value = ObjectA.class, name = "MY_OBJECT_A"), //
          @Type(value = ObjectB.class, name = "MY_OBJECT_B") })
  public abstract class AbstractObject {
      public enum Type {
          MY_OBJECT_A, MY_OBJECT_B
      }
      public Type type;
  }
  
  public class ObjectA extends AbstractObject {
      public ObjectA() {
          type = Type.MY_OBJECT_A;
      }
      public String a;
  }
  
  public class ObjectB extends AbstractObject {
      public ObjectB() {
          type = Type.MY_OBJECT_B;
      }
      public String b;
  }
  
  public class ObjectContainer {
      public AbstractObject object;
  }
  
  public class SomeObjectA extends ObjectA {
      public String value;
  }
  
  public class SomeObjectContainer {
      public SomeObjectA object;
  }
  </code></pre>
  
  <p>Tests:</p>
  
  <pre><code>import static org.junit.Assert.assertEquals;
  import java.io.IOException;
  import org.junit.Test;
  import com.test.TestUtil;
  
  public class ObjectATest {
  
      @Test
      public void test() throws IOException {
          ObjectA object = new ObjectA();
  
          String json = TestUtil.OBJECT_MAPPER.writeValueAsString(object);
          System.out.println("json: " + json);
  
          ObjectA actual = TestUtil.OBJECT_MAPPER.readValue(json, ObjectA.class);
          System.out.println("actual: " + actual + "\n" + TestUtil.OBJECT_MAPPER.writeValueAsString(actual));
  
          assertEquals("duplicate type", -1, json.indexOf("type", json.indexOf("type") + 4));
      }
  }
  
  public class ObjectContainerTest {
  
      @Test
      public void test() throws IOException {
          ObjectContainer container = new ObjectContainer();
          container.object = new ObjectA();
          ((ObjectA) container.object).a = "test-a";
  
          String json = TestUtil.OBJECT_MAPPER.writeValueAsString(container);
          System.out.println("json: " + json);
  
          ObjectContainer actual = TestUtil.OBJECT_MAPPER.readValue(json, ObjectContainer.class);
          System.out.println("actual: " + actual + "\n" + TestUtil.OBJECT_MAPPER.writeValueAsString(actual));
          assertEquals("test-a", ((ObjectA) actual.object).a);
          assertEquals(ObjectA.class, actual.object.getClass());
  
          assertEquals("duplicate type", -1, json.indexOf("type", json.indexOf("type") + 4));
      }
  }
  
  public class SomeObjectContainerTest {
  
      @Test
      public void test() throws IOException {
          SomeObjectContainer container = new SomeObjectContainer();
          container.object = new SomeObjectA();
          container.object.a = "test-a";
          container.object.value = "test-value";
  
          String json = TestUtil.OBJECT_MAPPER.writeValueAsString(container);
          System.out.println("json: " + json);
  
          SomeObjectContainer actual = TestUtil.OBJECT_MAPPER.readValue(json, SomeObjectContainer.class);
          System.out.println("actual: " + actual + "\n" + TestUtil.OBJECT_MAPPER.writeValueAsString(actual));
          assertEquals(container.object.value, actual.object.value);
  
          assertEquals("duplicate type", -1, json.indexOf("type", json.indexOf("type") + 4));
      }
  }
  </code></pre>
  
  <p>Test output and results:</p>
  
  <pre><code>ObjectATest:
  json: {
    "type" : "MY_OBJECT_A",
    "type" : "MY_OBJECT_A"
  }
  FAILURE: java.lang.AssertionError: duplicate type expected:&lt;-1&gt; but was:&lt;33&gt;
  
  ObjectContainerTest:
  json: {
    "object" : {
      "type" : "MY_OBJECT_A",
      "type" : "MY_OBJECT_A",
      "a" : "test-a"
    }
  }
  FAILURE: java.lang.AssertionError: duplicate type expected:&lt;-1&gt; but was:&lt;53&gt;
  
  SomeObjectContainerTest:
  json: {
    "object" : {
      "type" : "SomeObjectA",
      "type" : "MY_OBJECT_A",
      "a" : "test-a",
      "value" : "test-value"
    }
  }
  FAILURE:  java.lang.AssertionError: duplicate type expected:&lt;-1&gt; but was:&lt;53&gt;
  </code></pre>
  
  <p>Version 1 seems to work but produces duplicate <code>type</code> parameters. - This may break some clients...?</p>
  
  <hr>
  
  <p>Version 2: Using <code>JsonTypeInfo</code> and <code>JsonTypeId</code>:</p>
  
  <pre><code>@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
  @JsonSubTypes({ //
          @Type(value = ObjectA.class, name = "MY_OBJECT_A"), //
          @Type(value = ObjectB.class, name = "MY_OBJECT_B") })
  public abstract class AbstractObject {
      public enum Type {
          MY_OBJECT_A, MY_OBJECT_B
      }
      @JsonTypeId
      public Type type;
  }
  </code></pre>
  
  <p>Test output and results:</p>
  
  <pre><code>ObjectATest:
  json: {
    "type" : "MY_OBJECT_A"
  }
  SUCCESS
  
  ObjectContainerTest:
  json: {
    "object" : {
      "type" : "MY_OBJECT_A",
      "a" : "test-a"
    }
  }
  SUCCESS
  
  SomeObjectContainerTest:
  json: {
    "object" : {
      "type" : "MY_OBJECT_A",
      "a" : "test-a",
      "value" : "test-value"
    }
  }
  ERROR: com.fasterxml.jackson.databind.JsonMappingException: Class com.test2.ObjectA not subtype of [simple type, class com.test2.SomeObjectA] (through reference chain: com.test2.SomeObjectContainer["object"])
  </code></pre>
  
  <p>Version 2 fails to read <code>SomeObjectContainer</code>.</p>
  
  <hr>
  
  <p>Also we were trying with the following annotations:</p>
  
  <pre><code>@JsonSubTypes({ //
          @Type(value = ObjectA.class, name = "MY_OBJECT_A"), //
          @Type(value = SomeObjectA.class, name = "MY_OBJECT_A"), //
          @Type(value = ObjectB.class, name = "MY_OBJECT_B") })
  </code></pre>
  
  <p>But this dit not help.</p>
  
  <hr>
  
  <p>Why Jackson cannot read <code>SomeObjectContainer</code>? - <code>object</code> must be <code>SomeObjectA</code> (or some of its sub classes) and will never be <code>SomeObjectA</code> nor <code>ObjectA</code>!</p>
  
  <p>How to solve this problem?
  Is there another annotation to put at <code>SomeObjectContainer.object</code>?</p>