Ошибка при десериализации строки JSON в объект Java с элементом данных интерфейса

У меня есть строка 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

Взгляните на это: baeldung.com/jackson-inheritance

NiVeR 29.05.2019 18:25

Интерфейс является абстрактным, поскольку он не может знать тип, реализующий интерфейс. Вы можете добавить поле для имени класса интерфейса и добавить пользовательскую десериализацию, которая будет извлекать правильный класс для использования.

Locke 29.05.2019 18:26

@Locke Спасибо, но я не могу внести какие-либо изменения в интерфейс или класс Person.

jlp 29.05.2019 18:29

Вы не реализовали правильную десериализацию в AddressInterface.java. Можете ли вы поделиться файлом кода, чтобы получить более подробную информацию о проблеме.

A Nawaz Qadir 29.05.2019 18:25
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
4
47
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

С библиотекой ГСОН вы можете избавиться от стандартных кодов!

Вы можете использовать библиотеку GSON по ссылке ниже!

https://www.tutorialspoint.com/gson/gson_quick_guide.htm

Возможно, у Gson уже есть встроенное решение этой проблемы, но моя первоначальная реакция заключается в том, что он столкнется с теми же проблемами.

Locke 29.05.2019 18:42

проблема заключается в десериализации свойства 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. Это вне моего контроля.

jlp 29.05.2019 18:39

как насчет создания собственного класса Person?

Oğuzhan Aygün 29.05.2019 18:50
Ответ принят как подходящий

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. Он использует аналогичный подход к моему ответу, но у них гораздо лучшее объяснение.

Другие вопросы по теме