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

Использование Spring Data с MongoDB.

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

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

Класс А

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. 

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

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

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

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){
         ......
         ......
        }
Другие вопросы по тегам