2015-12-15 21 views
11

Piszę klienta Json dla serwera, który zwraca wartości Boolean jako "0" i "1". Kiedy próbuję uruchomić mój klient JSON I obecnie uzyskać następujący wyjątek:W jaki sposób można Serializować/Deserializować wartość logiczną z FasterXML Jackson jako Int?

HttpMessageNotReadableException: Could not read JSON: Can not construct instance of java.lang.Boolean from String value '0': only "true" or "false" recognized 

Więc jak mogę konfiguracji FasterXML \ Jackson poprawnie analizować coś takiego:

{ 
    "SomeServerType" : { 
    "ID" : "12345", 
    "ThisIsABoolean" : "0", 
    "ThisIsABooleanToo" : "1" 
    } 
} 

Próbka Pojo na:

@JsonInclude(JsonInclude.Include.NON_NULL) 
@JsonPropertyOrder({"someServerType"}) 
public class myPojo 
{ 
    @JsonProperty("someServerType") 
    SomeServerType someServerType; 

    @JsonProperty("someServerType") 
    public SomeServerType getSomeServerType() { return someServerType; } 

    @JsonProperty("someServertype") 
    public void setSomeServerType(SomeServerType type) 
    { someServerType = type; } 
} 

@JsonInclude(JsonInclude.Include.NON_NULL) 
@JsonPropertyOrder({"someServerType"}) 
public class SomeServerType 
{ 
    @JsonProperty("ID") 
    Integer ID; 

    @JsonProperty("ThisIsABoolean") 
    Boolean bool; 

    @JsonProperty("ThisIsABooleanToo") 
    Boolean boolToo; 

    @JsonProperty("ID") 
    public Integer getID() { return ID; } 

    @JsonProperty("ID") 
    public void setID(Integer id) 
    { ID = id; } 

    @JsonProperty("ThisIsABoolean") 
    public Boolean getThisIsABoolean() { return bool; } 

    @JsonProperty("ThisIsABoolean") 
    public void setThisIsABoolean(Boolean b) { bool = b; } 

    @JsonProperty("ThisIsABooleanToo") 
    public Boolean getThisIsABooleanToo() { return boolToo; } 

    @JsonProperty("ThisIsABooleanToo") 
    public void setThisIsABooleanToo(Boolean b) { boolToo = b; } 
} 

Reszta Client Linia
Uwaga 1: ten korzysta Wiosna 3,2
Uwaga 2: toJSONString() - jest to metoda pomocnika, który wykorzystuje Jackson serializować moje parametry obiektów
Uwaga 3: Wyjątek dzieje na czytanie w obiekt wynik

DocInfoResponse result = restTemplate.getForObject(docInfoURI.toString() 
            + "/?input={input}", 
            DocInfoResponse.class, 
            toJSONString(params)); 
+0

Proszę dodać odpowiedni kod klienta. – Alfabravo

+0

Możesz zdefiniować metody pobierające dla tych wartości, które zwracają coś w stylu 'return" 1 ".equals (stringRepresentation);'. – Titus

Odpowiedz

22

Jak wspomniano i wspominano o odpowiedzi Paulo Pedroso, będziesz musiał przetasować swój własny niestandardowy JsonSerializer i JsonDeserializer. Po utworzeniu musisz dodać adnotacje i @JsonDeserialize do swojej własności; określenie klasy, która ma być używana dla każdego.

Podałem poniżej mały (mam nadzieję, że prosty) przykład. Ani implementacja serializera, ani deserializera nie są super solidne, ale powinno zacząć.

public static class SimplePojo { 

    @JsonProperty 
    @JsonSerialize(using=NumericBooleanSerializer.class) 
    @JsonDeserialize(using=NumericBooleanDeserializer.class) 
    Boolean bool; 
} 

public static class NumericBooleanSerializer extends JsonSerializer<Boolean> { 

    @Override 
    public void serialize(Boolean bool, JsonGenerator generator, SerializerProvider provider) throws IOException, JsonProcessingException { 
     generator.writeString(bool ? "1" : "0"); 
    } 
} 

public static class NumericBooleanDeserializer extends JsonDeserializer<Boolean> { 

    @Override 
    public Boolean deserialize(JsonParser parser, DeserializationContext context) throws IOException, JsonProcessingException { 
     return !"0".equals(parser.getText()); 
    }  
} 

@Test 
public void readAndWrite() throws JsonParseException, JsonMappingException, IOException { 
    ObjectMapper mapper = new ObjectMapper(); 

    // read it 
    SimplePojo sp = mapper.readValue("{\"bool\":\"0\"}", SimplePojo.class); 
    assertThat(sp.bool, is(false)); 

    // write it 
    StringWriter writer = new StringWriter(); 
    mapper.writeValue(writer, sp); 
    assertThat(writer.toString(), is("{\"bool\":\"0\"}")); 
} 
+1

W rzeczywistości nie potrzebujesz Deserializera: Jackson automatycznie przekształci z postaci szeregowej 0/1 do Boolowskiej właściwości POJO, bez żadnej adnotacji. I w moim przypadku też nie potrzebowałem Serializera, ponieważ serwer, który wywołuję, akceptuje i konwertuje prawdziwe/fałszywe literały dla tego pola. I tak przyznam nagrodę. –

+2

@AndrewSpencer Dzięki, doceniam nagrodę. :) Aby było jasne, Jackson wydaje się automatycznie deserializować właściwość, jeśli przychodzi jako ** **, ale nie jako ** string **. – callmepills

2

Zamiast niestandardowego Deserializatora, można też po prostu mieć setter stylu:

public void setThisIsABoolean(String str) { 
    if ("0".equals(str)) { 
    bool = false; 
    } else { 
    bool = true; 
    } 
} 

ponieważ metoda może domagać innego rodzaju niż to, czego używać wewnętrznie.

Jeśli musisz obsługiwać zarówno Boolean, jak i String, możesz wskazać wartość jako Object i sprawdzić, co możesz zyskać.

Powinien być nawet możliwy inny typ metody gettera (Boolean) i setera (String lub Object).