Java: полиморфная десанциализация JSON от Jackson объекта с свойством интерфейса?
Я использую Jackson ObjectMapper
для десериализации представления JSON объекта, который содержит интерфейс в качестве одного из его свойств. Здесь можно увидеть упрощенную версию кода:
https://gist.github.com/sscovil/8735923
В принципе, у меня есть класс Asset
с двумя свойствами: type
и properties
. Модель JSON выглядит так:
{
"type": "document",
"properties": {
"source": "foo",
"proxy": "bar"
}
}
Свойство properties
определяется как интерфейс под названием AssetProperties
, и у меня есть несколько классов, которые его реализуют (например, DocumentAssetProperties
, ImageAssetProperties
). Идея состоит в том, что файлы изображений имеют разные свойства (высота, ширина), чем файлы документов, и т.д.
Я отработал примеры из этой статьи, прочитал документы и вопросы здесь, на SO и за ее пределами, и экспериментировал с различными конфигурациями в @JsonTypeInfo
параметры аннотации, но не смогли взломать эту гайку. Любая помощь будет принята с благодарностью.
Совсем недавно исключение, которое я получаю, следующее:
java.lang.AssertionError: Could not deserialize JSON.
...
Caused by: org.codehaus.jackson.map.JsonMappingException: Could not resolve type id 'source' into a subtype of [simple type, class AssetProperties]
Спасибо заранее!
РЕШЕНИЕ:
Благодаря большому спасибо @Michał Ziober, я смог решить эту проблему. Я также мог использовать Enum в качестве идентификатора типа, который занимал часть Googling. Вот обновленный Gist с рабочим кодом:
https://gist.github.com/sscovil/8788339
Ответы
Ответ 1
Вы должны использовать JsonTypeInfo.As.EXTERNAL_PROPERTY
вместо JsonTypeInfo.As.PROPERTY
. В этом случае ваш класс Asset
должен выглядеть следующим образом:
class Asset {
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.EXTERNAL_PROPERTY,
property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(value = ImageAssetProperties.class, name = "image"),
@JsonSubTypes.Type(value = DocumentAssetProperties.class, name = "document") })
private AssetProperties properties;
public AssetProperties getProperties() {
return properties;
}
public void setProperties(AssetProperties properties) {
this.properties = properties;
}
@Override
public String toString() {
return "Asset [properties("+properties.getClass().getSimpleName()+")=" + properties + "]";
}
}
См. также мой ответ в этом вопросе: Jackson JsonTypeInfo.As.EXTERNAL_PROPERTY не работает должным образом.