【问题标题】:How can I Serialize/De-serialize a Boolean Value from FasterXML\Jackson as an Int?如何将 FasterXML\Jackson 中的布尔值序列化/反序列化为 Int?
【发布时间】:2016-03-21 17:34:48
【问题描述】:

我正在为一个返回 Boolean 值作为“0”和“1”的服务器编写 JSON 客户端。当我尝试运行我的 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 Client Line
注 1: 这是使用 Spring 3.2
注 2: toJSONString() - 是使用 Jackson 序列化我的参数对象的辅助方法
注意 3:读取结果对象时发生异常

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

【问题讨论】:

  • 请添加您客户的相关代码。
  • 你可以为那些返回类似return "1".equals(stringRepresentation);的值定义getter方法。

标签: java json spring jackson fasterxml


【解决方案1】:

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

【讨论】:

  • 其实你不需要 Deserializer:Jackson 会自动将 0/1 反序列化为 Boolean POJO 属性,无需任何注释。在我的事件中,我也不需要序列化器,因为我正在调用的服务器正在接受并转换该字段的真/假文字。无论如何,我都会奖励赏金。
  • @AndrewSpencer 谢谢,我很感激这个奖项。 :) 需要明确的是,如果属性以 number 而不是 string 的形式出现,Jackson 似乎会自动反序列化该属性。
  • 上帝禁止被反序列化的 JSON 不包含该字段,或者它包含并且值为空。 Jackson 将抛出一个包装好的 NPE,如下所示:Failed conversion object com.fasterxml.jackson.databind.JsonMappingException: (was java.lang.NullPointerException)
【解决方案2】:

除了自定义反序列化器,您还可以简单地使用如下设置器:

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

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

如果你必须同时支持BooleanString,你可以指出值是Object,然后检查你可能会得到什么。

getter 方法 (Boolean) 和 setter (StringObject) 甚至应该有不同的类型。

【讨论】:

  • 适用于可变对象。如果我们的 POJO 是不可变的,我们就不能使用这个方法。
  • @galcyurio 相同的想法适用于@JsonCreator 带注释的构造函数和工厂方法也很有价值(或等效于 Builder-approach)。
猜你喜欢
  • 2013-09-16
  • 2023-04-02
  • 1970-01-01
  • 2012-08-19
  • 2015-05-19
  • 2017-10-20
  • 1970-01-01
  • 2016-10-16
  • 1970-01-01
相关资源
最近更新 更多