Действительно ли jackson не может десериализовать json в родовой тип?

Это повторяющийся вопрос, потому что следующие вопросы либо беспорядочны, либо вообще не отвечают:

десериализации-а-родовой тип-с jacksonом

ДЖЕКСОН-Deserialize-в- во время выполнения заданного classа

ДЖЕКСОН-Deserialize-используя унифицированный-class

ДЖЕКСОН-Deserialize-родовое classа переменного

Надеюсь, что этот вопрос, наконец, найдет ответ, который наглядно продемонстрирует это.

Наличие модели:

public class AgentResponse { private T result; public AgentResponse(T result) { this.result = result; } public T getResult() { return result; } } 

Вход JSON:

 {"result":{"first-client-id":3,"test-mail-module":3,"third-client-id":3,"second-client-id":3}} 

и два рекомендуемых способа десериализации типичных типов:

 mapper.readValue(out, new TypeReference<AgentResponse<Map>>() {}); 

или

 JavaType javaType = mapper.getTypeFactory().constructParametricType(AgentResponse.class, Map.class); mapper.readValue(out, javaType); 

jackson никогда не может иметь дело с родовым типом T, он показывает, что это Map из JavaType, но он находит аргумент конструктора типа объекта из-за стирания типа и выдает ошибку. Так это ошибка jacksonа, или я делаю что-то неправильно? Что еще является явной спецификацией TypeReference или JavaType?

 com.fasterxml.jackson.databind.JsonMappingException: No suitable constructor found for type [simple type, class com.fg.mail.smtp.AgentResponse<java.util.Map>]: can not instantiate from JSON object (need to add/enable type information?) at [Source: [email protected]; line: 1, column: 2] at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:164) at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:984) at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:276) at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:121) at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:2888) at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2064) 

Вам нужно добавить некоторые annotations к конструктору, чтобы сообщить jacksonу, как построить объект. Следующие работали для меня:

 public class AgentResponse { private T result; @JsonCreator public AgentResponse(@JsonProperty("result") T result) { this.result = result; } public T getResult() { return result; } } 

Без annotations @JsonCreator jackson не может знать, как назвать этот конструктор. И без annotations @JsonProperty jackson не знает, что первый аргумент конструктора сопоставляется с свойством result .

Я попытался использовать тот же подход, но я не аннотировал мой модельный class. Это сработало для меня.

Это мой модельный class

 public class BasicMessage implements Message { private MessageHeader messageHeader = new MessageHeader(); private T payload; public MessageHeader getHeaders() { return messageHeader; } public Object getHeader(String key) { return messageHeader.get(key); } public Object addHeader(String key, Object header) { return messageHeader.put(key, header); } public T getPayload() { return payload; } public void setPayload(T messageBody) { this.payload = messageBody; } } 

И я использовал следующий метод десериализации полезной нагрузки

 public static  BasicMessage getConcreteMessageType(String jsonString, Class classType) { try { ObjectMapper mapper = new ObjectMapper(); JavaType javaType = mapper.getTypeFactory().constructParametricType(BasicMessage.class, classType); return mapper.readValue(jsonString, javaType); } catch (IOException e) { } } 

где jsonString содержит объект BasicMessageObject в строке.

Строка JSON, которая должна быть десериализована, должна содержать информацию о типе параметра T
Вам нужно будет поместить annotations jacksonа на каждый class, который можно передать как параметр T в class AgentResponse чтобы информация типа о типе параметра T могла быть прочитана / записана в JSON-строку Jackson.

Предположим, что T может быть любым classом, который расширяет абстрактный class Result .

 public class AgentResponse { public Hits hits; } @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT) @JsonSubTypes({ @JsonSubTypes.Type(value = ImageResult.class, name = "ImageResult"), @JsonSubTypes.Type(value = NewsResult.class, name = "NewsResult")}) public abstract class Result { } public class ImageResult extends Result { } public class NewsResult extends Result { } 

Как только каждый из classа (или их общий супертип), который может быть передан как параметр T , аннотируется, jackson будет включать информацию о параметре T в JSON. Такой JSON можно затем десериализовать, не зная параметра T во время компиляции.
В этой документации по документации jacksonа говорится о полиморфной десериализации, но полезно также обратиться к этому вопросу.

  • Как избежать установки файлов политики JCE «Неограниченная сила» при развертывании приложения?
  • Текущее время в микросекундах в java
  • Преобразовать java.util.Date в строку
  • Невозможно изменить версию факела проекта Dynamic Web Module до 3.0?
  • Что входит в «Контроллер» в «MVC»?
  • Изменение размера с canvasом в jscrollpane в jsplitpane
  • Разница между & и && в Java?
  • Сортировка Java на основе констант Enum
  • Почему вам нужно вызывать URLConnection # getInputStream, чтобы иметь возможность записывать URLConnection # getOutputStream?
  • Как запустить maven из java?
  • Исключение нулевого указателя
  • Давайте будем гением компьютера.