如何将FasterXML\Jackson中的布尔值序列化/反序列化为整数?

23

我正在为服务器编写 JSON 客户端,该服务器将 布尔 值作为 "0" 和 "1" 返回。 当我尝试运行我的 JSON 客户端时,我目前会收到以下异常:

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

那我应该如何设置 FasterXML\Jackson 来正确解析类似于以下内容的数据:

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

样本 Pojo:

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

REST客户端代码
注意1:这里使用的是Spring 3.2版本。
注意2:toJSONString()是一个帮助方法,它使用Jackson库将我的参数对象进行序列化。
注意3:异常发生在读取结果对象时。

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

请添加您客户相关的代码。 - Alfabravo
你可以为这些值定义getter方法,返回类似于return "1".equals(stringRepresentation);的内容。 - Titus
2个回答

45

正如Paulo Pedroso的回答所提到并引用的那样,您需要自己编写定制的JsonSerializerJsonDeserializer。一旦创建完成,您需要将@JsonSerialize@JsonDeserialize注解添加到属性中,并指定要使用的类。

下面是一个简单(希望是直接了当的)示例。虽然序列化器和反序列化器实现不是非常强大,但这应该能让您入门。

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\"}"));
}

5
实际上,您不需要使用反序列化器:Jackson会自动将0/1反序列化为Boolean POJO属性,无需任何注释。而且在我的情况下,我也不需要序列化器,因为我调用的服务器可以接受并转换该字段的true/false文本字面量。无论如何,我仍会授予奖励。 - Andrew Spencer
3
谢谢,我很感激这个奖项 :) 明确地说,如果传入的属性是一个数字,Jackson似乎会自动反序列化该属性,但如果传入的属性是一个字符串,则不会。 - callmepills
不知道上帝会不会眷顾我们,当我们反序列化 JSON 后,发现其并没有包含该字段,或者是包含该字段但值为空时。Jackson 会抛出一个异常,它看起来像这样:转换对象失败:com.fasterxml.jackson.databind.JsonMappingException:(原因是 java.lang.NullPointerException) - snakedog

5

除了自定义反序列化器,你也可以简单地使用setter方法:

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

因为你的方法可以声明与内部使用的不同类型。

如果你必须支持BooleanString两种类型,你可以指示值是一个Object,并检查你可能会得到什么。

甚至可以为getter方法(Boolean)和setter方法(StringObject)设置不同的类型。


适用于可变对象。如果我们的POJO是不可变的,我们就不能使用这种方法。 - galcyurio
1
@galcyurio 同样的想法也适用于使用@JsonCreator注释的构造函数和工厂方法,对于Builder模式也有相应的等效方法。 - StaxMan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接