Джексон выдает исключение сопоставления ошибок, когда я пытаюсь десериализовать список объектов

#java #json #jackson

#Ява #json #джексон

Вопрос:

Я пытаюсь десериализовать огромную полезную нагрузку API. Эта полезная нагрузка содержит намного больше полей, чем мне нужно, и поэтому я использую @JsonIgnoreProperties(ignoreUnknown = true) . Однако в какой-то момент десериализация завершается ошибкой с сообщением об ошибке:

 com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.util.ArrayList out of FIELD_NAME token  at [Source: {  "objectEntries": [  {  "objectKey": "KDS-4300"  },  {  "objectKey": "KDS-4327"  }  ] }; line: 2, column: 3]   

Я нашел решения для этого случая, которые предполагали использование

 objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);  

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

Вот мои классы, которые являются целью десериализации.

 @JsonIgnoreProperties(ignoreUnknown = true) public class InsightQueryResult {  @JsonProperty("objectEntries")  private Listlt;ObjectEntrygt; objectEntries;   @JsonCreator  public InsightQueryResult(Listlt;ObjectEntrygt; objectEntries) {  this.objectEntries = objectEntries;  }   public Listlt;ObjectEntrygt; getObjectEntries() {  return objectEntries;  }   // equals, hashCode and toString }  
 @JsonIgnoreProperties(ignoreUnknown = true) public class ObjectEntry {  @JsonProperty("objectKey")  private String objectKey;   @JsonCreator  public ObjectEntry(String objectKey) {  this.objectKey = objectKey;  }   public String getObjectKey() {  return objectKey;  }  // equals, hashCode and toString }   

Вот модульный тест, в котором я его тестирую:

   @Test  public void shouldMapQueryResultToResultObject() throws IOException {  final Resource expectedQueryResult= new ClassPathResource("testQueryPayload.json");  final String expectedQueryResultData = new String(  Files.readAllBytes(expectedQueryResult.getFile().toPath())).trim();   final Listlt;ObjectEntrygt; objectEntries = Arrays.asList(new ObjectEntry("KDS-4300"), new ObjectEntry("KD-4327"));  final InsightQueryResult expectedQueryResult = new InsightQueryResult(objectEntries);   final InsightQueryResult result = objectMapper.readValue(expectedQueryResultData, InsightQueryResult.class);   assertThat(result).isEqualTo(expectedQueryResult);  }   

И вот полезная нагрузка, которую я хочу десериализовать

 // testQueryPayload.json {  "objectEntries": [  {  "objectKey": "KDS-4300"  },  {  "objectKey": "KDS-4327"  }  ] }  

Ответ №1:

Вы должны просто аннотировать параметры вашего @JsonCreator s.

 @JsonCreator public ObjectEntry(String objectKey) {  this.objectKey = objectKey; }  

становится

 @JsonCreator public ObjectEntry(@JsonProperty(value = "objectKey", required = true) String objectKey) {  this.objectKey = objectKey; }  

и то же самое касается другого конструктора.

Объяснение:

  • Сериализация: у вас есть экземпляр с полями, вы аннотируете поле @JsonProperty("name") (или получателем @JsonValue ), и это позволяет Джексону создавать строковый json из вашего экземпляра путем отражения.
  • Десериализация: следуя той же логике, когда вы аннотируете конструктор, @JsonCreator вы говорите Джексону, что это конструктор, который они должны использовать для создания вашего объекта из имеющейся у них строки Json. Однако либо вы даете им пустой конструктор (а затем, поразмыслив, они установят каждое поле позже), либо вы должны сообщить им, какое поле строки Json они должны использовать внутри каждого параметра конструктора.