I have a setup like this:
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "dishName", defaultImpl = Food.class)
@JsonSubTypes(value = {
@Type(name = "fries", value = Fries.class),
@Type(name = "burger", value = Burger.class)
})
public class Food {
private String dishName;
@Override
public String toString() {
return dishName + ", type: " + this.getClass().getName();
}
}
public class Fries extends Food { /*...*/ }
public class Burger extends Food { /*...*/ }
public class TryItOut {
private static String foodString = "[ { \"dishName\":\"burger\" }, { \"dishName\":\"fries\" }, { \"dishName\":\"cabbage\" } ]";
public static void main(String[] args) {
ObjectMapper m = new ObjectMapper();
try {
Food[] food = m.readValue(foodString, Food[].class);
for (Food dish : food) {
System.out.println(dish);
}
} catch (IOException e) {
System.out.println("something went wrong");
e.printStackTrace();
}
}
}
I want to use this to deserialize json whiches content I cannot influence (so no option to add "proper" type information). The problem I have is that apparently the dishName
json property is used to determine the subtype all right, but it is not deserialized into the java field. Is there a way to achieve that, too? In other words: the main method prints
null, type: Burger
null, type: Fries
null, type: Food
on the console, but I want it to print
burger, type: Burger
fries, type: Fries
cabbage, type: Food
this is particularly nasty because there is no way for me to find out later on that the last object is cabbage. That nullifies the benefits of the default implementation.
EDIT:
@Evil Raat 's answer does the trick. For the sake of completeness: the dishName
field in the Food
class needs the @JsonProperty
Annotation for this example to work. The working example thus looks like this:
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "dishName", defaultImpl = Food.class, visible = true)
@JsonSubTypes(value = {
@Type(name = "fries", value = Fries.class),
@Type(name = "burger", value = Burger.class)
})
public class Food {
@JsonProperty
private String dishName;
@Override
public String toString() {
return dishName + ", type: " + this.getClass().getName();
}
}
public class Fries extends Food { /*...*/ }
public class Burger extends Food { /*...*/ }
public class TryItOut {
private static String foodString = "[ { \"dishName\":\"burger\" }, { \"dishName\":\"fries\" }, { \"dishName\":\"cabbage\" } ]";
public static void main(String[] args) {
ObjectMapper m = new ObjectMapper();
try {
Food[] food = m.readValue(foodString, Food[].class);
for (Food dish : food) {
System.out.println(dish);
}
} catch (IOException e) {
System.out.println("something went wrong");
e.printStackTrace();
}
}
}
To maintain the value of the property you used for the Deserialization, you just have to set the visible property to true on the @JsonSubTypes annotation:
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "dishName", defaultImpl = Food.class, visible = true)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With