Jackson-databind: RFE: allow missing of type id if target value is concrete

Created on 29 Jul 2017  路  11Comments  路  Source: FasterXML/jackson-databind

@JsonTypeInfo( use = JsonTypeInfo.Id.NAME,  include = JsonTypeInfo.As.PROPERTY, property = "type")
@JsonSubTypes({@JsonSubTypes.Type(value = Dog.class, name = "dog"), @JsonSubTypes.Type(value = Cat.class, name = "cat")})
public abstract class Animal {
    private String sound;

    public String getSound() {
        return sound;
    }

    public void setSound(String sound) {
        this.sound = sound;
    }
}

public class Dog extends Animal {
}

public class Cat extends Animal {
}

public static void main(String[] args) throws IOException {
        Animal animal = new ObjectMapper().readValue("{ \"type\": \"cat\", \"sound\": \"mew\" }", Animal.class); // everything ok
        System.out.println(animal.getSound());

        Cat cat = new ObjectMapper().readValue("{ \"sound\": \"mew\" }", Cat.class); // exception
        System.out.println(cat.getSound()); 
    }
}

Exception:

com.fasterxml.jackson.databind.JsonMappingException: Unexpected token (END_OBJECT), expected FIELD_NAME: missing property 'type' that is to contain type id  (for class Cat)
 at [Source: { "sound": "mew" };

When json is mapped to parent class is ok to send "type" property, but when is mapped to child class, the "type" property must not be required.

3.x most-wanted

Most helpful comment

I actually found a way to achieve this. There is a MapperFeature that already exists for this:
mapper.configure(MapperFeature.USE_BASE_TYPE_AS_DEFAULT_IMPL, true);
this will allow Cat cat = new ObjectMapper().readValue("{ \"sound\": \"mew\" }", Cat.class); to not throw the exception.

All 11 comments

This works as expected: type id is required if polymorphic type handling is enabled and there is no defaultImpl to use. Type id not just something nice-to-have extra; it is absolutely required by the system.

I will re-phrase this, however, to request that use of type id could be made optional.
Exact requirements for then this can be made (or, conversely, there are cases where this could not work, f.ex. if type is abstract) would need to be figured out.
One option would be to allow @JsonTypeInfo specify that type id is indeed optional; another to add a DeserializationFeature. Third to just change behavior in 3.x to do best-effort attempt if id is missing, and fail if it turns out it can not be done.

Is there a way I can get this functioning in the current version? I have some JSON generated by an external mapper that will use type info for some serialization but not for certain types, so my jackson mapper throws an exception:

Caused by: com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Missing type id when trying to resolve subtype of [map type; class java.util.Map, [simple type, class java.lang.Object] -> [simple type, class java.lang.Object]]: missing type id property '@class'

is this issue resolved now?

@xc350 I try to not to be rude here but... what do you think? Open issue on issue tracker tends to indicate that the problem still exists. And this is the case here, to the best of my knowledge.

Can I request this feature to be added? If I specifically asked the json string to be parsed into the concrete type Cat cat = new ObjectMapper().readValue("{ \"sound\": \"mew\" }", Cat.class);, it would be nice that I don't need to include the type info in the json itself.

@jinmeiliao you do not need to request it: this is an open RFE. It has already been requested.

Being OSS project, whether it will be implemented depends on if anyone with interest and time is willing to implement it.

I actually found a way to achieve this. There is a MapperFeature that already exists for this:
mapper.configure(MapperFeature.USE_BASE_TYPE_AS_DEFAULT_IMPL, true);
this will allow Cat cat = new ObjectMapper().readValue("{ \"sound\": \"mew\" }", Cat.class); to not throw the exception.

@jinmeiliao this is extremely helpful, thank you!

Another option would be to register a _mixin_ for the given target that instructs the unmarshal to ignore the super type and construct the target on its sole context.

This means that no explicit type metadata is included, and typing is purely done using contextual information possibly augmented with other annotations.

@JsonTypeInfo( use = JsonTypeInfo.Id.NONE )
public class CatMixin {
}

...

mapper.addMixIn(Cat.class, CatMixin.class);

Any update on this issue?

@TolgaDaSilva No updates.

Was this page helpful?
0 / 5 - 0 ratings