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

В любом случае, то, что происходит, - это поле в ответе JSON, в основном, это карта, но иногда совершенно неожиданно это список.

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

{
  "majorInfo" : {
    "a" : "b"
  },
  "minorInfo" : {
    "c" : "d"
  }
}

Но в редких случаях я получал список вместо карты или другое нарушение договора.

Например:

{
  "majorInfo" : {
    "a" : "b"
  },
  "minorInfo" : []
}

Я использую Джексона для сопоставления этого ответа с POJO. В случаях, когда договор нарушается, я получаю ошибку,

Исключение в потоке "main" com.fasterxml.jackson.databind.JsonMappingException: невозможно десериализовать экземпляр java.util.LinkedHashMap из токена START_ARRAY

В этом случае я также теряю информацию в поле majorInfo, даже если это соответствует условиям контракта. Есть ли способ игнорировать поле, если оно не соответствует контракту? В этом случае член majorInfo моего POJO будет правильно установлен, но член minorInfo будет иметь значение null.

Я знаю о @JsonIgnoreProperties (ignoreUnknown = true), но это всегда игнорирует поле minorInfo. Я только хотел бы, чтобы это игнорировалось, когда поле не соответствует контракту. Это возможно?

Я тоже пробовал

mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); 

Но это тоже не сработало.

Возможно ли другое решение? Внешний партнер не собирается менять свой API за нас, это точно. Итак, какое-нибудь работоспособное решение с нашей стороны?

Спасибо

Изменить: одно из решений - у меня есть POJO для обоих вариантов и помещаю код в блок try catch. Это могло сработать, если бы в ответе JSON было только одно поле, нарушающее контракт, и только одним определенным образом. Ответ, который я получаю, огромен, и это третье нарушение, которое я заметил на третьем поле. Я не могу продолжать ставить блоки try catch, и к третьему нарушению я понял, что лучше всего просто игнорировать поля, нарушающие его.

3
Paagalpan 23 Фев 2016 в 13:25

2 ответа

Лучший ответ

Я нашел решение, используя следующую ветку в качестве ссылки: Джексон: игнорирование свойств вместо создания исключения JsonMappingException

Я написал собственный десериализатор и использовал его, чтобы игнорировать ошибки.

public class CustomListingDeserializer extends JsonDeserializer<Map<String, Listing>>{

    public CustomListingDeserializer() {
        // TODO Auto-generated constructor stub
    }

    @Override
    public Map<String, Listing> deserialize(JsonParser arg0, DeserializationContext arg1)
            throws IOException, JsonProcessingException {

        ObjectMapper mapper = new ObjectMapper();
        JsonNode node = arg0.readValueAsTree();

        try
        {
            return mapper.readValue(node.toString(), new TypeReference<Map<String,Listing>>(){});

        }
        catch (JsonMappingException e)
        {
            System.out.println("Issue in deserializing : " + e.getMessage() + "for :" + node.toString());
        }
        catch (Exception e)
        {
            throw e;
        }
        // TODO Auto-generated method stub
        return null;
    }

}
3
Community 23 Май 2017 в 11:59

Вы можете написать свой собственный java-метод для преобразования входного json-файла в "стандартный" json-код, который соответствует контракту, а затем использовать для этого Jackson.

Что-то вроде:

private String transform(String input)
{
    String result = input;

    if (result.contains("\"minorInfo\" : []"))
    {
        result = result.replace("\"minorInfo\" : []", "");
    }

    return result;
}
1
Yoav Gur 23 Фев 2016 в 10:55