У меня есть строка JSON, и я хочу десериализовать ее в объект Java с элементом данных интерфейса. Объект Java выглядит следующим образом:
public class Person {
private String id;
private String name;
private AddressInterface addr;
}
И Person, и AddressInterface являются сторонними классами, поэтому я не могу вносить в них какие-либо изменения.
Когда я использовал следующее для десериализации строки JSON,
objectMapper.readValue(json_file, Person.class)
Я получил следующее исключение. Это потому, что сопоставитель объектов не знает, как десериализовать поле AddressInterface. Может ли кто-нибудь дать мне знать, как в этом случае десериализовать строку в объект Person? Огромное спасибо.
abstract types either need to be mapped to
concrete types, have custom deserializer,
or be instantiated with additional type information
Интерфейс является абстрактным, поскольку он не может знать тип, реализующий интерфейс. Вы можете добавить поле для имени класса интерфейса и добавить пользовательскую десериализацию, которая будет извлекать правильный класс для использования.
@Locke Спасибо, но я не могу внести какие-либо изменения в интерфейс или класс Person.
Вы не реализовали правильную десериализацию в AddressInterface.java. Можете ли вы поделиться файлом кода, чтобы получить более подробную информацию о проблеме.
С библиотекой ГСОН вы можете избавиться от стандартных кодов!
Вы можете использовать библиотеку GSON по ссылке ниже!
https://www.tutorialspoint.com/gson/gson_quick_guide.htm
Возможно, у Gson уже есть встроенное решение этой проблемы, но моя первоначальная реакция заключается в том, что он столкнется с теми же проблемами.
проблема заключается в десериализации свойства AddressInterface, потому что это интерфейс, и я думаю, что objectMapper пытается инициализировать его конструктор по умолчанию, как показано ниже.
addr = new AddressInterface();
вы можете создать пустой конкретный класс, который наследует AddressInterface и использовать его вместо AddressInterface
public class Adress implements AddressInterface {
...
}
public class Person {
private String id;
private String name;
private Adress addr;
}
Спасибо. Но я не могу изменить класс Person. Это вне моего контроля.
как насчет создания собственного класса Person?
AddressInterface
является интерфейсом и считается абстрактным. Оба класса Foo
и Bar
могут реализовать AddressInterface
, но не смогут определить, в какой из них следует десериализовать данные.
Поместите интерфейс в обертку. Я просто предполагаю, так как не знаю контекста библиотеки, но, может быть, что-то вроде этого. Также, вероятно, здесь есть несколько опечаток, но это показывает общую идею.
public class AbstractSerializable<T> implements Deserialize {
private final String className;
private T obj;
public AbstractSerializable(T obj) {
this.obj = obj;
this.className = obj.getClass().getCardinalName();
}
@Override
public AbstractSerializable deserialize(ObjectMapper objectMapper) {
String clazz = input.readNext(String.class);
return objectMapper.readNext(Class.forName(clazz));
}
}
Редактировать: Это, вероятно, сломается, если вы попытаетесь поместить в него лямбду.
Редактировать 2: @Hadi Обратите внимание, что Gson упростит некоторые вещи, однако столкнется с теми же проблемами. Я нашел эта статья, в котором объясняется, как это исправить при использовании Gson. Он использует аналогичный подход к моему ответу, но у них гораздо лучшее объяснение.
Взгляните на это: baeldung.com/jackson-inheritance