2012-12-15 12 views
6

Chciałbym deserializowania JSON (z Jackson 1.9.11 i RestTemplate 1.0.1), w którym jedno pole może mieć więcej znaczeń typu, na przykład:deserializacji JSON z wielu typów w jednym polu

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

lub

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

albo jeden albo drugi przypadek działa poprawnie z jednym seter specyficznego typu (String oD klasy zwyczaj Response), ale kiedy mogę umieścić w moim podmiot fasoli nadpisane seter, aby móc obsłużyć obu przypadkach jest wyjątek :

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] 

Myślałam o trzy rozwiązania, ale nie dostałem żadnej z nich pracuje:

  • używając tylko setter ciąg i wewnątrz użytku ObjectMapper aby wycofać ten ciąg, jeśli nie jest równa „error” , ale kiedy ten JS Array przychodzi, nie jest ciągiem, więc nie jest używany żaden Setter String :(.
  • używać obsługi polimorficznych typów (adnotacja @JsonTypeInfo) z własnym rozszerzeniem JsonDeserializer - nadal próbuję to zrozumieć i wdrożyć.
  • utworzyć listę HttpMessageConverter i umieścić wewnątrz wszystkich konwerterów wiadomości, mogę używać. Ale uważam, że ten krok jest niepotrzebny, ponieważ używa się tylko MappingJacksonHttpMessageConverter, czy mam rację?

EDIT: jak to działa teraz

Seter w podmiot fasoli:

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

metoda Cofnięcie w 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; 
} 
+0

polecam użyć Jackson parser dla strony serwera manipulowanie obiektami JSON –

+0

Pracuję po stronie klienta, serwer nie jest moją firmą :( – shmoula

Odpowiedz

7

Jedynym sposobem osiągnięcia tego jest użycie niestandardowy deserializer.

Oto przykład:

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

A oto jak pisać (jak bym go napisać co najmniej) Deserializator:

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 

} 
+0

Zgadzam się, próbuję zrobić to w podobny sposób, jak napisałem (z @JsonDeserialize (using = ResponseDataDeserializer.class)), więc jeśli go uruchomię, zaznaczę twoją odpowiedź :) – shmoula

+0

OK, działa w ten sposób, działający kod dołączony do oryginalnego pytania. Dziękuję Ci. – shmoula

Powiązane problemy