Аргументы конструктора и проблема десериализации данных Spring

Использование данных Spring с MongoDB.

Проблема заключается в создании экземпляра bean-компонента, полученного из Mongo, потому что конструктор имеет некоторый аргумент, который фактически находится внутри вложенного объекта. Стойкость не проблема. Поиск есть.

Структура класса показана ниже, где B вложен внутри A. A устанавливает B, создавая его экземпляр, используя один из параметров конструктора.

Класс А

Class A{
 int prop1;
 B b; 

 @JsonCreator
 public A(  @JsonProperty int prop1, @JsonProperty  int prop2){
  this.prop1 = prop1;
  this.b = new B(prop2);
 }
}

Класс B, который вложен внутри A

Class B(){
 int prop2;

 @JsonCreator
 public B(@JsonProperty int prop2){
  this.prop2 = prop2;
 }
}

Когда объект получен REST API в приведенной ниже форме Json:

 {"prop1":"Hello1","prop2":"Hello2"}

Spring Controller получает его и корректно сопоставляет с объектом A. Поскольку Spring по умолчанию использует конструктор без аргументов, я использовал аннотацию jsoncreator для конструктора arg, и он без проблем добавляется в MongoDB.

Данные хранятся в следующем формате в соответствии с правильной структурой компонента.

      {"prop1":"Hello1","b":{"prop2":"Hello2"}}

Переходя к проблеме: ошибка возникает, когда я пытаюсь получить данные из Mongo. В нем говорится:

 org.springframework.data.mapping.model.MappingException: No property prop2 
 found on entity class A to bind constructor parameter to

Как я могу сказать SpringData использовать объект B, который содержит prop2, при получении его из SpringData? (Возможно, это невозможно)

Я подумал, что, возможно, добавление еще одного конструктора поможет, когда я использую объект B в качестве одного из аргументов конструктора, как показано ниже:

   public A(int prop1, B b){
       ......
       ......
   }

Добавление еще одного конструктора работает с ObjectMapper, но опять же не с SpringData.

На этот раз выбрасывается новое исключение:

      org.springframework.data.mapping.model.MappingInstantiationException: 
      Failed to instantiate A using constructor NO_CONSTRUCTOR with 
      arguments. 

Я проверил указанную выше ошибку, когда список используется/не используется, но я пробовал оба способа и не решил.

Обратите внимание: я использую объект B как вложенный, поскольку он содержит общие свойства, которые будут использоваться множеством других bean-компонентов (может быть абстрактный класс, но мне нужно будет попробовать это позже, но почему-то абстрактный класс кажется ограничивающим)

Как SpringData создает объект A?


person DragonZoned    schedule 15.11.2017    source источник


Ответы (1)


Похоже на оплошность.

Надо было использовать лучшие термины в поиске. Нашел бы правильный ответ. На всякий случай, если кто-то столкнется с этой проблемой...

Некоторые поиски привели меня к следующему вопросу:

Как именно spring-data-mongodb обрабатывает конструкторы при регидратации объектов?

В приведенном выше вопросе упоминается несколько вещей, которые дали мне решение. Ответ заключается в использовании другого конструктора для десериализации из SpringData в bean-компонент. Этот конструктор должен быть аннотирован:

    @PersistenceConstructor

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

        @PersistenceConstructor
        public A(int prop1, B b){
         ......
         ......
        }

Итак, теперь у меня есть 2 конструктора, один с @jsoncreator, а другой с @PersistenceConstructor. Но, чтобы добавить, этот другой конструктор может быть закрытым также, если у вас нет другого использования для него, кроме как для извлечения из SpringData, и он не будет использоваться в коде никем, таким образом оставляя вашу бизнес-логику нетронутой. Следовательно, ниже также будет работать:

        @PersistenceConstructor
        private A(int prop1, B b){
         ......
         ......
        }
person DragonZoned    schedule 15.11.2017