【问题标题】:Custom Deserializer to map a String to a boolean value自定义反序列化器将字符串映射到布尔值
【发布时间】:2020-08-08 06:14:41
【问题描述】:

我正在通过 RestTemplate 进行外部调用,如下所示:

ResponseEntity<Response> response = template.exchange("some.endpoint.com", HttpMethod.POST, request, MyClass.class);

API返回一个String格式的布尔值,如下:("0" or "1")

{
    "some_lengthy_key_name" : "1"
}

我正在尝试将此响应映射到以下类。

@Getter
@JsonDeserialize(builder = MyClass.MyClassBuilder.class)
@Builder
public class MyClass{
    @JsonProperty("some_lengthy_key_name")
    private final boolean isValid;
}

Jackson 似乎对此不以为然,并抛出以下错误(可以理解):

不能从字符串“1”反序列化布尔类型的值,只有“真” 或“假”识别。

我不想继续将其捕获为字符串,然后再修改值。 相反,更愿意选择进行自定义反序列化并进行以下操作:

public class Deserializer extends JsonDeserializer<Boolean> {
    @Override
    public Boolean deserialize(JsonParser parser, DeserializationContext context) throws IOException {
        return !"0".equals(parser.getText());
    }
}

我现在已将 MyClass 中的字段注释如下:

@Getter
@JsonDeserialize(builder = MyClass.MyClassBuilder.class)
@Builder
public class MyClass{
    @JsonDeserialize(using = Deserializer.class)
    @JsonProperty("some_lengthy_key_name")
    private final boolean isValid
}

但不幸的是,这也不起作用并引发相同的错误。 我能得到一些关于我在这个自定义反序列化中做错了什么的建议吗?谢谢。

【问题讨论】:

  • 尝试使用布尔值而不是布尔值
  • @CodeScale 不与布尔值进行比较。

标签: java spring spring-boot jackson


【解决方案1】:

你不能使用final,而使用Boolean类型代替boolean

@Getter
@Setter
public class MyClass{
    @JsonDeserialize(using = Deserializer.class)
    @JsonProperty("some_lengthy_key_name")
    private Boolean isValid; //<= You did not use final, and use Boolean type instead of boolean
}

【讨论】:

  • 在使用布尔值和带或不带final时同样的错误。
【解决方案2】:

您不需要任何自定义反序列化器,只需使用自定义 setter 方法覆盖属性,然后使用 @JsonProperty 注释该方法。另请注意,jackson 使用getterssetters 进行序列化和反序列化,因此您不能将变量声明为final

@Getter
@Setter
class MyClass{

   private boolean isValid;

   @JsonProperty("some_lengthy_key_name")
   public void setIsValid(String value) {
      isValid = "1".equals(value);
   }
}

jackson 中还有另一种方法可以使用构造函数进行反序列化以防止对象的不变性,请查看此以获取更多信息information

@Getter
@Setter
@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
public class MyClass{

   private final boolean isValid;

   public MyClass(@JsonProperty("some_lengthy_key_name") String name) {
      this.isValid = "1".equals(name);
}

【讨论】:

  • 道歉。在我试图使代码看起来简洁的过程中,我错过了提到对象使用 builder 因此使用 final。我已经编辑了问题以包括如何将构建器添加到上述类。喜欢您的解决方案,但我不想使用构建器,因此无法使用设置器。
  • 你可以使用Builder而不用声明变量为final,builder会正常工作你可以试试@karvai
  • 我已按照您的建议,将 JsonProperty 注释移至 setter 方法。没有像以前那样的错误,但映射没有发生。我知道该值应该为真,但取而代之的是假,我认为这是因为它被设置为默认值。另外,这个解决方案现在还开辟了一种公共设置方法,我试图避免它保持不可变。老实说,我仍在考虑自定义反序列化。
  • 尝试使用构造方法@karvai
  • 它现在可能适用于单个字段,但预计该响应中会出现更多字段(略超过 10 个)并且会添加更多字段。我不想为此进行构造函数初始化。抱歉,我并不是要否定你的建议。我四处修补并注意到如果 MyClass 不使用构建器 + 没有类级别 @JsonDeserialize 注释而是坚持使用 Get/Set,我上面的自定义反序列化工作。想知道是否有一种方法可以使用构建器并且仍然可以进行上述自定义反序列化工作。
猜你喜欢
  • 2019-06-09
  • 2019-07-03
  • 1970-01-01
  • 2017-10-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-27
相关资源
最近更新 更多