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 не работает должным образом.