RestTemplate и Jackson - пользовательская десериализация JSON?

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

Что я здесь делаю не так? Все, что я пытаюсь сделать, это проанализировать JSON на объект, как обычно. Имена полей добавляются к моим свойствам с помощью @JsonProperty, поэтому синтаксический анализатор должен знать, как их преобразовать.

public class InsertReplyDeserializer extends JsonDeserializer<ListingReply> {

    @Override
    public ListingReply deserialize(JsonParser jsonParser, DeserializationContext arg1)
            throws IOException, JsonProcessingException {

        ObjectCodec oc = jsonParser.getCodec();
        JsonNode node = oc.readTree(jsonParser);

        // If service returns "" instead of null return a NULL object and don't try to parse
        if (node.getValueAsText() == "")
            return null;


       ObjectMapper objectMapper = new ObjectMapper();
       ListingReply listingReply = objectMapper.readValue(node, ListingReply.class);


       return listingReply;
    }

}

person aryaxt    schedule 03.02.2013    source источник


Ответы (2)


Вот как я решил это

@Override
public MyObject deserialize(JsonParser jsonParser, DeserializationContext arg1)
        throws IOException, JsonProcessingException {

    ObjectCodec oc = jsonParser.getCodec();
    JsonNode node = oc.readTree(jsonParser);

    if (node.getValueAsText() == "")
        return null;

    MyObject myObject = new MyObject();
    myObject.setMyStirng(node.get("myString").getTextValue());

    JsonNode childNode = node.get("childObject");
    ObjectMapper objectMapper = new ObjectMapper();
    ChildObject childObject = objectMapper.readValue(childNode,
            ChildObject.class);

             myObject.setChildObject(childObject);
             return myObject;
}
person aryaxt    schedule 06.02.2013

Я не уверен, что вам нужно вручную разбирать ответ. Ваше решение будет работать, но, на мой взгляд, оно не оптимально. Поскольку похоже, что вы используете RestTemplate, вам лучше написать (или переместить код парсера) свой собственный конвертер сообщений. Затем добавьте этот конвертер в свой объект шаблона отдыха, который будет внутренне десериализовать значение за вас. Что-то в этом роде,

public class CustomHttpmsgConverter extends  AbstractHttpMessageConverter<Object> {
private ObjectMapper objectMapper = new ObjectMapper();
@Override
protected Object readInternal(Class clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
   InputStream istream = inputMessage.getBody();
   String responseString = IOUtils.toString(istream);
   if(responseString.isEmpty()) //if your response is empty
     return null;
   JavaType javaType = getJavaType(clazz);
   try {
       return this.objectMapper.readValue(responseString, javaType);
   } catch (Exception ex) {
    throw new HttpMessageNotReadableException(responseString);
    }
}

//add this converter to your resttemplate
    RestTemplate template = new RestTemplate();
    List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>();
    converters.add(new CustomHttpmsgConverter());
    template.setMessageConverters(converters);
person nilesh    schedule 17.02.2013
comment
в большинстве случаев мне не нужно ничего делать с десериализацией, это особый случай, когда неверные данные поступают с сервера, что приводит к сбою синтаксического анализа, потому что синтаксический анализатор ожидает структуру объекта, но ответ представляет собой пустую строку (для определенного поля в результате). Таким образом, это обходной путь для десериализации только одной из моделей, которые есть в моем приложении. В остальной части приложения мне не нужно ничего делать для десериализации JSON, все это автоматизировано RestTemplate и Jackson (с использованием аннотаций @JsonProperty). - person aryaxt; 18.02.2013
comment
Именно поэтому мое решение выше предлагает вам добавить этот специальный преобразователь в свой шаблон отдыха, который позаботится о пустой строке ответа, в свою очередь, исключив ручную десериализацию. Конвертеры предназначены именно для таких ситуаций. - person nilesh; 18.02.2013
comment
Ооооо, поэтому вместо того, чтобы обрабатывать ошибку при десериализации одного класса, вы перемещаете ее в MessageConverter, который затем применяется ко всему. Я попробую и отправлю ответ - person aryaxt; 19.02.2013
comment
Ты получил это. Взгляните на источник MappingJackson2HttpMessageConverter. Вы хотите сохранить все методы в своем настраиваемом конвертере точно так же, как MappingJackson2HttpMessageConverter, но переопределить readInternal () своим кодом / или моим кодом выше. readInternal () из соответствующего конвертера (выбранного шаблоном rest на основе ответа Content-Type) вызывается при десериализации объекта. - person nilesh; 19.02.2013