Библиотека JSON Джексона: как создать экземпляр класса, который содержит абстрактные поля - PullRequest
29 голосов
/ 30 марта 2011

Я хочу преобразовать строку JSON в объект java, но класс этого объекта содержит абстрактные поля, которые Джексон не может создать, и не создает объект.Как проще всего рассказать о некоторой реализации по умолчанию абстрактного класса, например

setDefault(AbstractAnimal.class, Cat.class);

, или принять решение о классе реализации на основе имени атрибута JSON, например.для объекта JSON:

{
    ...
    cat: {...}
    ...
}

я бы просто сказал:

setImpl("cat", Cat.class);


Я знаю, что в Джексоне возможно встроить информацию о классе в JSON, но я не хочуусложнить формат JSON, который я использую.Я хочу решить, какой класс использовать, просто установив класс реализации по умолчанию или по имени атрибута ('cat') - как в библиотеке XStream, где вы пишете:

xStream.alias("cat", Cat.class);

Есть ли способ сделатьтак, особенно в одну строку, или это требует еще немного кода?

Ответы [ 4 ]

40 голосов
/ 31 марта 2011

Есть несколько способов; до версии 1.8 возможно сделать самый простой способ:

@JsonDeserialize(as=Cat.class)
public abstract class AbstractAnimal { ... }

для принятия решения на основе атрибута, который лучше всего сделать с использованием @JsonTypeInfo, который выполняет автоматическое встраивание (при записи) и использование информации о типе.

Существует несколько видов информации о типе (имя класса, имя логического типа), а также механизмы включения (свойство as-enabled, массив as-wrapper, объект as-wrapper). Эта страница: https://github.com/FasterXML/jackson-docs/wiki/JacksonPolymorphicDeserialization объясняет некоторые концепции.

2 голосов
/ 03 июля 2017

Полноценный ответ с очень наглядным примером можно найти здесь: https://stackoverflow.com/a/30386694/584947

Джексон называет это полиморфной десериализацией.

Это определенно помогло мне с моей проблемой. У меня был абстрактный класс, который я сохранял в базе данных, и мне нужно было распаковать его в конкретный экземпляр класса (по понятным причинам).

Он покажет вам, как правильно аннотировать родительский абстрактный класс и как научить Джексона выбирать среди доступных кандидатов в подклассы во время выполнения при демаршалинге.

0 голосов
/ 01 февраля 2019

Если вы не хотите загрязнять ни свой JSON дополнительными полями, ни свои классы аннотациями, вы можете написать очень простой модуль и десериализатор, который использует нужный подкласс по умолчанию.Это более чем одна строка из-за некоторого стандартного кода, но это все еще относительно просто.

class AnimalDeserializer extends StdDeserializer<Animal> {
    public AnimalDeserializer() {
        super(Animal.class);
    }

    public Animal deserialize(JsonParser jsonParser, DeserializationContext context) throws IOException {
        return jsonParser.readValueAs(Cat.class);
    }
}

class AnimalModule extends SimpleModule {
    {
        addDeserializer(Animal.class, new AnimalDeserializer());
    }
}

Затем зарегистрируйте этот модуль для ObjectMapper и все (Zoo - это контейнерный класс, имеющий поле Animal).

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new AnimalModule());
return objectMapper.readValue(json, Zoo.class);
0 голосов
/ 09 августа 2018

проблема, которую можно решить с помощью аннотации @JsonDeserialize для абстрактного класса, относится к проблемам и решениям исключений Джексона https://www.baeldung.com/jackson-exception

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...