RestTemplate & Jackson - персонализирано десериализиране на JSON?

Уеб услугата връща празен низ вместо NULL, което води до срив на Jackson. Така че създадох персонализиран анализатор и се опитвам да го анализирам ръчно? Някаква идея как мога да постигна това?

Какво правя грешно тук? Всичко, което се опитвам да направя, е да анализирам 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
в повечето случаи не трябва да правя нищо за десериализиране, това е специален случай, когато лоши данни идват от сървъра, който срива анализите, тъй като анализаторът очаква обектна структура, но отговорът е празен низ (за конкретно поле в резултата). Така че това е заобиколно решение за десериализация само на 1 от моделите, които имам в приложението си. В останалата част от приложението не трябва да правя нищо, за да десериализирам 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() от съответния конвертор (избран от шаблона за почивка въз основа на отговора Content-Type) се извиква при десериализация на обект. - person nilesh; 19.02.2013