Jackson InvalidDefinitionException: невозможно создать экземпляр, поскольку не найден конструктор без аргументов по умолчанию

У меня есть приложение, которое использует Spring Boot для обеспечения возможности REST. У меня возникла проблема с десериализацией ответа POST в POJO. Исключение составляет следующее:

org.springframework.http.converter.HttpMessageConversionException: Type definition error: [collection type; class uci.BoundedList, contains [simple type, class java.lang.Object]]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `uci.BoundedList` (no Creators, like default construct, exist): no default no-arguments constructor found

Тип BoundedList является частью API, созданного из схемы XML с помощью XJC. Я не могу контролировать, как генерируется этот класс. Оказывается, это подкласс java.util.ArrayList и имеет только один определенный конструктор:

public BoundedList(int minOccurs, int maxOccurs) {
    super();
    this.minOccurs = minOccurs;
    this.maxOccurs = maxOccurs;
}

Он не определяет конструктор без аргументов, на что, похоже, жалуется исключение.

Поскольку я не могу изменить этот класс, и он является неотъемлемой частью используемого мной API, что я могу сделать, чтобы обойти эту проблему? Могу ли я предоставить какой-то настраиваемый класс/интерфейс, который удовлетворит привязку данных Джексона? Какое-то другое возможное решение?

ОБНОВЛЕНИЕ:

Я попробовал ряд предложений, основанных на ответах, представленных ниже. Ни один из них не работает. Я изучаю подход "mix-in" и, признаюсь, не совсем понимаю, как он должен работать. Многие статьи, которые я читал, написаны просто, но все же это кажется небольшой «черной магией».

В любом случае, ниже приведены фрагменты того, что я пытался сделать на основе того, что я прочитал:

Класс «смешанный»:

public abstract class BoundedListMixin {
  @JsonCreator
  public BoundedListMixin(@JsonProperty("minOccurs") int minOccurs,
      @JsonProperty("maxOccurs") int maxOccurs) {}
}

Что было добавлено в существующий класс конфигурации:

@Configuration
@EnableAsync
@EnableScheduling
@ComponentScan("<package>")
public class ServiceConfigurer {
  @Bean
  @Primary
  public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) {
    ObjectMapper mapper = builder.createXmlMapper(false).build();
    mapper.addMixIn(BoundedList.class, BoundedListMixin.class);
    return mapper;
  }
}

Я могу подтвердить, что метод objectMapper() в классе конфигурации вызывается через отладчик.

Эта ссылка (https://dzone.com/articles/jackson-mixin-to-the-rescue) вводит еще одну грань, но, увы, и она не работает.

ОБНОВЛЕНИЕ:

Я заменил метод objectMapper() в ServiceConfigurer (выше) следующим:

  @Bean
  public Jackson2ObjectMapperBuilderCustomizer objectMapperCustomizer() {
    return new Jackson2ObjectMapperBuilderCustomizer() {
      @Override
      public void customize(Jackson2ObjectMapperBuilder builder) {
        builder.mixIn(BoundedList.class, BoundedListMixin.class);
      }
    };
  }

Я ВСЕ ЕЩЕ получаю ту же проблему. Проблема должна быть связана с каким-то другим вопросом.

ПРИМЕЧАНИЕ:

Я также должен уточнить, что эта проблема проявляется, когда я сделал вызов GET. У меня есть простая конечная точка REST, которая просто запрашивает у службы возврат POJO. Как ни странно, если я отправляю запрос из браузера, объект возвращается как JSON и отображается. Но когда он вызывается из кода, я получаю исключение выше.

ПОЛУЧИТЬ вызов:

RequestStatus statusMsg = template.getForObject("http://localhost:8080/rst/missionPlanning/data", RequestStatus.class);

person Joseph Gagnon    schedule 25.07.2019    source источник


Ответы (3)


Джексону нужен конструктор по умолчанию без параметров или аннотаций в параметрах конструктора, чтобы выяснить, какое поле в объекте JSON должно быть сопоставлено с параметром. Что-то вроде этого:

@JsonCreator
public BoundedList(@JsonProperty("min") int minOccurs, @JsonProperty("max") int maxOccurs) {
   // your code
}

Когда вы не можете изменить класс, вы можете использовать Jackson MixIns

abstract class MixIn {
   MixIn(@JsonProperty("min") int minOccurs, @JsonProperty("max") int maxOccurs) { }
}

и настройте его в картографе объектов следующим образом:

objectMapper.addMixInAnnotations(BoundedList.class, MixIn.class);

См. https://github.com/FasterXML/jackson-docs/wiki/JacksonMixInAnnotations подробности.

person spa    schedule 25.07.2019
comment
Предложенный вами подход MixIn (также предложенный @Mike ниже) звучит очень интересно и, похоже, может решить мою проблему. В чем я не уверен, так это в том, что это, кажется, что-то, что зарегистрировано в Джексоне ObjectMapper. Я явно не использую ObjectMapper в своей ситуации. Я использую RestTemplate для выполнения запроса POST, и возвращаемый объект — это место, где возникает проблема (по крайней мере, я так думаю). Как я мог (могу ли я?) привлечь к этому ObjectMapper (и микс-ин)? - person Joseph Gagnon; 25.07.2019
comment
Вот звонок: ResponseEntity<CommandStatus> response = template.postForEntity("http://localhost:8080/rst/missionPlanning/generateRoute", entity, CommandStatus.class); - person Joseph Gagnon; 25.07.2019
comment
Пример можно найти здесь: gdpotter.com/2017/05/ 24/custom-spring-mvc-jackson (вероятно, вы найдете гораздо больше в гугле). Идея состоит в том, что вы регистрируете свой собственный bean-компонент ObjectMapper. Spring Boot поможет вам в этом. - person spa; 25.07.2019
comment
Я попытался сделать, как было предложено (на самом деле несколько разных способов, основанных на том, что я нашел в гугле), и ни один из них, похоже, не работает. Я все еще получаю то же исключение. :( - person Joseph Gagnon; 25.07.2019
comment
Вот одна ссылка, которая кажется очень подходящей для моей ситуации. Однако это все еще не работает. blogs.jbisht.com/blogs/ 12.09.2016/ - person Joseph Gagnon; 25.07.2019
comment
@JosephGagnon Spring boot предоставляет сопоставитель объектов по умолчанию. Его можно настроить с помощью различных конфигураций приложения, и вы также можете создать bean-компонент типа Jackson2ObjectMapperBuilderCustomizer в своем приложении, чтобы применить любые примеси и другие настройки. - person Mike; 25.07.2019
comment
@JosephGagnon В этом ответе есть достойный пример: stackoverflow.com/a/48519868/657224 ... вам нужно будет позвонить jacksonObjectMapperBuilder.mixIn(...), чтобы установить собственный микс в классе для BoundedList. - person Mike; 25.07.2019

Самый простой способ — добавить аннотации Джексона к POJO, чтобы проинструктировать его, как десериализовать. Этот вопрос описывает это довольно хорошо.

Однако, поскольку ваш POJO создается автоматически, и вы не можете его изменить, есть 2 других варианта:

  1. Используйте настраиваемый десериализатор, чтобы вручную преобразовать полезную нагрузку JSON в экземпляр вашего POJO.
  2. Используйте микс -in, чтобы украсить POJO нужными аннотациями
person Mike    schedule 25.07.2019

Вы можете сопоставить его с другим типом, а затем преобразовать в ограниченный список.

person Artanis    schedule 25.07.2019