Десериализация JSON с несколькими типами в одном поле

Я хотел бы десериализовать JSON (с Jackson 1.9.11 и RestTemplate 1.0.1), в котором одно поле может иметь больше значений типа, например:

    {"responseId":123,"response":"error"}

or

    {"responseId":123,"response":{"foo":"bar", ... }}

Либо тот, либо другой случай работает правильно с одним сеттером определенного типа (String od custom Response class), но когда я помещаю в свой переопределенный сеттер сущностного компонента, чтобы иметь возможность обрабатывать оба случая, возникает исключение:

Caused by: org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [xxxx.templates.ExportResponse] and content type [application/json;charset=utf-8]

Я думал о трех решениях, но ни одно из них не сработало:

  • используя только установщик String, а внутри используйте ObjectMapper для демаршалирования этой строки, если она не равна «ошибке», но когда приходит этот JS-массив, это не строка, поэтому установщик String не используется :(.
  • используйте обработку полиморфного типа (@аннотация JsonTypeInfo) с собственным расширением JsonDeserializer - я все еще пытаюсь понять это и реализовать.
  • создайте список HttpMessageConverter и поместите внутрь все преобразователи сообщений, которые я могу использовать. Но я думаю, что этот шаг не нужен, потому что используется только MappingJacksonHttpMessageConverter, я прав?

РЕДАКТИРОВАТЬ: как это работает сейчас

Сеттер в объектном компоненте:

@JsonDeserialize(using = ResponseDeserializer.class)
public void setResponse(Object responseObject) {
    if(responseObject instanceof Response)
        response = (Response) responseObject;
}

Метод десериализации в ResponseDeserializer:

public Response deserialize(JsonParser parser, DeserializationContext context) throws IOException, JsonProcessingException {
    Response response = new Response();

    if(JsonToken.START_OBJECT.equals(parser.getCurrentToken())) {
        ObjectMapper mapper = new ObjectMapper();
        response = mapper.readValue(parser, Response.class);
    } else
        throw new JsonMappingException("Unexpected token received.");

    return response;
}

person shmoula    schedule 15.12.2012    source источник
comment
Я рекомендую вам использовать синтаксический анализатор Jackson для обработки объектов JSON на стороне сервера.   -  person Bhavik Ambani    schedule 15.12.2012
comment
Я работаю на стороне клиента, сервер не мое дело :(   -  person shmoula    schedule 15.12.2012


Ответы (1)


Единственный способ добиться этого — использовать собственный десериализатор.

Вот пример:

ObjectMapper mapper = new ObjectMapper();
SimpleModule testModule = new SimpleModule("MyModule", new Version(1, 0, 0, null));
testModule.addDeserializer(Response.class, new ResponseJsonDeserializer());
mapper.registerModule(testModule);

А вот как написать (как бы я написал по крайней мере) десериализатор:

class ResponseJsonDeserializer extends JsonDeserializer<Response>  {
  @Override
  public Responsedeserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
    Response response = new Response();
    if(jp.getCurrentToken() == JsonToken.VALUE_STRING) {
        response.setError(jp.getText());
    } else {
       // Deserialize object
    }
    return response;
  }
}

class Response {
   private String error;
   private Object otherObject; // Use the real type of your object

   public boolean isError() {
      return error != null;
   }

   // Getters and setters

}
person aymeric    schedule 15.12.2012
comment
Я согласен, я пытаюсь сделать это примерно так, как я писал (с @JsonDeserialize(using = ResponseDataDeserializer.class)), поэтому, если я запущу его, я отмечу ваш ответ :) - person shmoula; 15.12.2012
comment
Хорошо, это работает так, рабочий код прикреплен к исходному вопросу. Спасибо. - person shmoula; 15.12.2012