Search code examples
javajsonjacksonjackson-databind

"com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Could not resolve type id" when trying to deserialise subclass


I'm trying to implement JsonSubTypes, but I want to be able to include some graceful handling of unrecognised subtypes. I'm using Jackson 2.9.7, and updating isn't an option as there's some other classes depending on it.

Let's say this is my code:

@Value.Style(allParameters = true, typeImmutable = "*", typeImmutableEnclosing = "*Impl",
    defaults = @Value.Immutable(builder = false))
@Value.Enclosing
@JsonSerialize
@JsonDeserialize
public class JsonAnimal {


  @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "subClass", include = JsonTypeInfo.As.EXISTING_PROPERTY,
      visible = true, defaultImpl = UnmappedAnimal.class) //fixme create logger warning if this defaults to a Void
  @JsonSubTypes({
      @JsonSubTypes.Type(value = Dog.class, name = Dog.ANIMAL_TYPE),
      @JsonSubTypes.Type(value = Cat.class, name = Cat.ANIMAL_TYPE),
      @JsonSubTypes.Type(value = Fish.class, name = Fish.ANIMAL_TYPE),
      @JsonSubTypes.Type(value = Hamster.class,
          name = Hamster.ANIMAL_TYPE)
  public static abstract class Animal {
    public abstract String subClass();
    //other code
  }
  @Value.Immutable
  @JsonDeserialize
  public abstract static class Dog extends Animal {
    public static final String ANIMAL_TYPE = "dog";
    //dog-specific code
  }

  @Value.Immutable
  @JsonDeserialize
  public abstract static class Cat extends Animal {
    public static final String ANIMAL_TYPE = "cat";
    //cat-specific code
  }

  @Value.Immutable
  @JsonDeserialize
  public abstract static class Fish extends Animal {
    public static final String ANIMAL_TYPE = "fish";
    //fish-specific code
  }

  @Value.Immutable
  @JsonDeserialize
  public abstract static class Hamster extends Animal {
    public static final String ANIMAL_TYPE = "hamster";
    //hamster-specific code
  }

  public class UnmappedAnimal extends Animal { /**/ }

I implemented the subclasses because the "animal" object within the JSON payload would have different fields depending on what value "subClass" was, e.g. an animal of subClass "cat" would have a "livesLeft" field that no other subClass would have.

Now let's say I have this JSON payload coming in:

{
  "id": 123456,
  "animal": {
    "subType": "horse",
    /* everything else */
  }
}

This causes the following error:

com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Could not resolve type id 'horse' as a subtype of [simple type, class my.project.path.apiobject.JsonAnimal$Animal]: known type ids = dog, cat, fish, hamster] (for POJO property 'animal')

What do I do so that I can handle unmapped subtypes? Should I just use catch (InvalidTypeIdException) when parsing the JSON? I'll appreciate any help I can get with this.

EDIT: I should've also asked, my JSON parser's ObjectMapper has ACCEPT_CASE_INSENSITIVE_PROPERTIES and FAIL_ON_UNKNOWN_PROPERTIES enabled, but if I have a property called "SubClass" instead of "subClass", that doesn't get parsed.


Solution

  • If you configure your objectMapper implementation like this

    objectMapper.disable(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE);
    

    you can achieve a graceful handling. Fields with non resolvable subtypes will be deserialized to null then.