shmoula
shmoula

Reputation: 1083

Deserializing JSON with multiple types in one field

I would like to deserialize JSON (with Jackson 1.9.11 and RestTemplate 1.0.1), in which one field may have more type meanings, for example:

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

or

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

Either one or other case works correctly with one setter of specific type (String od custom Response class), but when I put into my entity bean overriden setter to be able to handle both cases, exception is thrown:

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]

I was thinking about three solutions, but I did not get any of them working:

EDIT: how it works now

Setter in entity bean:

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

Deserialize method in 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;
}

Upvotes: 16

Views: 15806

Answers (1)

aymeric
aymeric

Reputation: 3895

The only way to achieve that is to use a custom deserializer.

Here is an example:

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

And here is how to write (how I would write it at least) the deserializer:

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

}

Upvotes: 14

Related Questions