Missing property 'type' while De/Serialization of Map the contains mixed subtype - polymorphism

Viewed 414

I have an object called Animal with two subclasses, Monkey and Lion, I used JsonTypeInfo to support subtype detection, and I suppose on serializing JsonTypeInfo should automatically put property called 'type' depending on the class.

Animal Class

import java.io.Serializable;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
@JsonSubTypes({
        @JsonSubTypes.Type(value = Lion.class, name = "Lion"),
        @JsonSubTypes.Type(value = Monkey.class, name = "Monkey")
})
public class Animal implements Serializable {
    
    String name;

    public Animal(String name) {
        super();
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Animal other = (Animal) obj;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }

}

Lion Class


public class Lion extends Animal{

    public Lion(String name) {
        super(name);
    }

}


Monkey Class


public class Monkey extends Animal{

    public Monkey(String name) {
        super(name);
    }

}

Main Function

    public static void main(String[] args) throws JsonGenerationException, JsonMappingException, IOException {
        Map<String,Animal> animals = new HashMap<String, Animal>();
        animals.put("Bob", new Lion("Bob"));
        animals.put("Alice", new Monkey("Alice"));
        StringWriter sw = new StringWriter();
        ObjectMapper mapper = new ObjectMapper();
        mapper.setSerializationInclusion(Include.NON_NULL);
        mapper.writeValue(sw, animals);
        String animlasStr = sw.toString();
        Map<String,Animal> dAnimalMap = mapper.readValue(animlasStr, new TypeReference<Map<String, Animal>>() {});
        assert dAnimalMap.get("Alice") instanceof Monkey;
    }

But when I am deserializing a map of animals it is not working!!, It throws the following exception, the type property is missing.

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

I tried to both type referencing and visible property, I got the same results.

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type" , visible =true)
1 Answers

Instead of: mapper.writeValue(sw, animals); use mapper.writerFor(new TypeReference<Map<String, ? extends Animal>>() {}).writeValue(sw, animals);

And instead of: mapper.readValue(animlasStr, new TypeReference<Map<String, Animal>>() {}); use: mapper.readValue(animlasStr, new TypeReference<Map<String, ? extends Animal>>() {});

with empty constructors in all the classes

Related