2015-12-15 11 views
11

Sto scrivendo un client Json per un server che restituisce valori booleano come "0" e "1". Quando cerco di eseguire il mio client JSON Attualmente ottengo la seguente eccezione:In che modo è possibile serializzare/deserializzare un valore booleano da FasterXML Jackson come un Int?

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

Così come posso impostazione FasterXML \ Jackson per analizzare correttamente qualcosa come:

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

campione Pojo di:

@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; } 
} 

Resto client Linea
Nota 1: Questo sta usando Primavera 3.2
Nota 2: toJSONString() - è un metodo di supporto che utilizza Jackson a serializzare i miei parametri degli oggetti
Nota 3: l'eccezione avviene su lettura iN dell'oggetto risultato

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

Si prega di aggiungere il codice pertinente del cliente. – Alfabravo

+0

È possibile definire metodi getter per quei valori che restituiscono qualcosa come "return" 1 ".equals (stringRepresentation);'. – Titus

risposta

22

Poiché la risposta di Paulo Pedroso è menzionata e referenziata, è necessario eseguire il rollover personalizzato JsonSerializer e JsonDeserializer. Una volta creato, sarà necessario aggiungere le annotazioni @JsonSerialize e @JsonDeserialize alla proprietà; specificando la classe da utilizzare per ciascuno.

Ho fornito un piccolo esempio (auspicabilmente semplice) di seguito. Né il serializzatore né le implementazioni del deserializzatore sono super-robuste ma questo dovrebbe farti iniziare.

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

In realtà non è necessario il deserializzatore: Jackson deserializza automaticamente 0/1 in una proprietà POJO booleana, senza alcuna annotazione. E nel mio caso non avevo nemmeno bisogno del Serializer, dal momento che il server che sto chiamando accetta e converte letterali true/false per questo campo. Comunque sto assegnando la taglia. –

+2

@AndrewSpencer Grazie, apprezzo il premio. :) Per essere chiari, Jackson sembra deserializzare automaticamente la proprietà se arriva come ** numero ** ma non come ** stringa **. – callmepills

2

Invece di deserializer personalizzato, si potrebbe anche semplicemente avere un setter come:

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

dal momento che il metodo può pretendere di tipo diverso rispetto a quello che si usa internamente.

E se è necessario supportare sia Boolean e String, è possibile indicare il valore è un Object e verificare cosa si potrebbe ottenere.

Dovrebbe anche essere possibile avere un tipo diverso per metodo getter (Boolean) e setter (String o Object).