For your List
problem, this is the one time where you want to use a raw type. Declare the Cage
type argument as raw, instead of parameterized with a wildcard.
public class Zoo {
private List<Cage> cages = new LinkedList<Cage>();
// ... getters and setters similarly
}
With the wildcard, you are telling Jackson that it doesn't matter, so it uses its default, LinkedHashMap
. If you remove the wildcard and use a raw type, it will need to look for hints elsewhere. In this case, it will look at the actual Cage
implementation it uses.
Your JSON should look like this
String json = "{\"type\": \"LION\", \"animal\": {\"maneLength\" : 10}}";
Jackson will be able to determine that the animal
is a Lion
.
Through the type
it will know that it is a LionCage
and through the class definition of
public LionCage extends Cage<Lion>{
it will know that any reference to the type variable Animal
should actually be a Lion
.
I'm on Jackson 2.
But it works with Jackson 1 as well. Code below
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
import org.codehaus.jackson.annotate.JsonSubTypes;
import org.codehaus.jackson.annotate.JsonTypeInfo;
import org.codehaus.jackson.map.ObjectMapper;
public class Example {
public static void main(String[] args) throws Exception {
String json = "{\"type\": \"LION\", \"animal\": {\"maneLength\" : 10}}";
ObjectMapper om = new ObjectMapper();
Cage cage = om.readValue(json, Cage.class);
System.out.println(cage.getClass());
System.out.println(cage.getAnimal());
System.out.println(((Lion) cage.getAnimal()).getManeLength());
}
}
class Lion {
private int maneLength;
public int getManeLength() {
return maneLength;
}
public void setManeLength(int maneLength) {
this.maneLength = maneLength;
}
}
class LionCage extends Cage<Lion> {
public LionCage() {
super(AnimalType.LION);
}
}
class Tiger {
}
class TigerCage extends Cage<Tiger> {
public TigerCage() {
super(AnimalType.TIGER);
}
}
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonSubTypes({ @JsonSubTypes.Type(value = LionCage.class, name = "LION"),
@JsonSubTypes.Type(value = TigerCage.class, name = "TIGER"), })
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
abstract class Cage<Animal> {
public Cage(AnimalType type) {
this.setType(type);
}
public AnimalType getType() {
return type;
}
public void setType(AnimalType type) {
this.type = type;
}
public Animal getAnimal() {
return animal;
}
public void setAnimal(Animal animal) {
this.animal = animal;
}
private AnimalType type;
private Animal animal;
}
enum AnimalType {
LION, TIGER;
}
prints
class com.spring.LionCage
com.spring.Lion@15d16efc
10