Библиотека Jackson JSON: как создать экземпляр класса, содержащего абстрактные поля
Я хочу преобразовать строку JSON в объект java, но класс этого объекта содержит абстрактные поля, которые Джексон не может создать, и не создает объект. Каков самый простой способ рассказать об определенной по умолчанию реализации абстрактного класса, например
setDefault(AbstractAnimal.class, Cat.class);
или принять решение о классе реализации на основе имени атрибута JSON, например. для объекта JSON:
{
...
cat: {...}
...
}
Я бы просто сказал:
setImpl("cat", Cat.class);
Я знаю, что в Jackson можно встроить информацию о классе внутри JSON, но я не хочу усложнять формат JSON, который я использую. Я хочу решить, какой класс использовать, просто установив класс реализации по умолчанию или имя атрибута ('cat') - как в библиотеке XStream, где вы пишете:
xStream.alias("cat", Cat.class);
Есть ли способ сделать это, особенно в одной строке, или требуется какой-то еще код?
Ответы
Ответ 1
Существует несколько способов; до версии 1.8, возможно, самый простой способ:
@JsonDeserialize(as=Cat.class)
public abstract class AbstractAnimal { ... }
чтобы принять решение на основе атрибута, лучше всего использовать с помощью @JsonTypeInfo
, который автоматически встраивается (при записи) и использует информацию о типе.
Существует несколько типов информации типа (имя класса, логическое имя типа), а также механизмы включения (as-included-property, as-wrapper-array, as-wrapper-object). Эта страница: https://github.com/FasterXML/jackson-docs/wiki/JacksonPolymorphicDeserialization объясняет некоторые из концепций.
Ответ 2
Полноценный ответ с очень ясным примером можно найти здесь: fooobar.com/questions/195692/...
Джексон ссылается на это как на полиморфную десериализацию.
Это определенно помогло мне с моей проблемой. У меня был абстрактный класс, который я сохранял в базе данных, и мне нужно было его развязать с конкретным экземпляром класса (понятно).
Он покажет вам, как правильно аннотировать родительский абстрактный класс и как обучать джексону, как выбрать среди доступных кандидатов подкласса во время выполнения при размашировании.
Ответ 3
проблема может быть решена с помощью аннотации @JsonDeserialize для абстрактного класса, относящейся к исключениям Джексона. Проблемы и решения https://www.baeldung.com/jackson-exception
Ответ 4
Если вы не хотите загрязнять свой 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);