I have the given situtation: This is the interface I am implementing:
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME
property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(value = MasterDevice.class, name = "COMPUTER"),
@JsonSubTypes.Type(value = SlaveDevice.class, name = "FLASH_DRIVE"),
})
interface DeviceType{
String getName();
}
The interface is used by two enums:
public enum MasterDevice implements DeviceType{
COMPUTER("Computer");
private String name;
public MasterDevice(String name){
this.name=name;
}
@Override public String getName(){return this.name;}
}
The second one is for devices you can attach to the MasterDevice
.
public enum SlaveDevice implements DeviceType{
FLASH_DRIVE("USB Drive");
private String name;
public SlaveDevice(String name){
this.name=name;
}
@Override public String getName(){return this.name;}
}
The POJO that I want to deserialize is:
public class DeviceInformation{
private DeviceType type;
}
And the json String I want to deserialize look like this:
String info = "{\"type\":\"COMPUTER\"}";
ObjectMapper mapper = new ObjectMapper();
DeviceInformation deviceInfo = mapper.readValue(info, DeviceInformation.class);
All research was proposing implementing a custom deserializer for the DeviceType which I am not keen to do since it seems so bad to maintain.
Exception in thread "main" com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Missing type id when trying to resolve subtype of [simple type, class DeviceType]: missing type id property '@type' (for POJO property 'type')`
It seems like Jackson searches for an type property on the DeviceType which of course it does not have. How do I tell Jackson that the Enum selection is based on the enum value (COMPUTER, FLASH_DRIVE)?
I think you're expecting too many levels to be collapsed for you simply by giving a bunch of things the same field and property names.
The JSON required for your current setup would be:
String info = "{\"type\": {\"type\": \"COMPUTER\", \"COMPUTER\": null}}";
Here, the outer "type" is for DeviceInformation, the inner "type:COMPUTER" pair are for DeviceType polymorphism of MasterDevice. And the final "COMPUTER" is to instantiate MasterDevice.COMPUTER (this last bit of weirdness feels like a bug with the Jackson implementation).
To make it more obvious what's going on, here's a simplified version with some renaming:
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
property = "type"
)
@JsonSubTypes({
@JsonSubTypes.Type(value = MasterDevice.class, name = "MASTER"),
@JsonSubTypes.Type(value = SlaveDevice.class, name = "SLAVE"),
})
interface DeviceType {
}
public enum MasterDevice implements DeviceType {
LAPTOP, SERVER;
}
public enum SlaveDevice implements DeviceType {
FLASH_DRIVE, WEBCAM;
}
public class DeviceInformation {
public DeviceType deviceType;
}
Then:
String info = "{\"deviceType\": {\"type\": \"MASTER\", \"SERVER\": null}}";
ObjectMapper mapper = new ObjectMapper();
DeviceInformation deviceInfo = mapper.readValue(info, DeviceInformation.class));
If you want something more elegant, then you'll likely need a custom serializer.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.