Десериализация JSON с несколькими типами в одном поле
Я хотел бы десериализовать JSON (с Jackson 1.9.11 и RestTemplate 1.0.1), в котором одно поле может иметь больше значений типа, например:
{"responseId":123,"response":"error"}
или
{"responseId":123,"response":{"foo":"bar", ... }}
либо один, либо другой случай работает правильно с одним сеттером определенного типа (String od custom Response class), но когда я помещаю в свой объект bean overriden setter, чтобы иметь возможность обрабатывать оба случая, возникает исключение:
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 setter и внутри используйте ObjectMapper для unmarshall этой строки, если она не равна "error", но когда этот массив JS приходит, это не строка, поэтому не используется string setter: (.
- используйте обработку полиморфного типа (@jsontypeinfo аннотация) с собственным расширением JsonDeserializer-я все еще пытаюсь понять это и реализовать.
- создать список HttpMessageConverter и поместить внутри всех сообщений конвертеры, я могу использовать. Но я думаю, что этот шаг не нужен, потому что используется только MappingJacksonHttpMessageConverter, я прав?
EDIT: как это работает сейчас
сеттер в Entity bean:
@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;
}
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
}