Spring Boot lombok builder和Jackson的反序列化问题,无法构造[...]的示例,没有字符串参数构造函数/工厂方法进行反序列化

rjzwgtxy  于 2023-01-17  发布在  Spring
关注(0)|答案(1)|浏览(239)

这是我遇到的一个问题的简化版本。给定这些类:

@Value
@Jacksonized
@Builder(builderClassName = "Builder", setterPrefix = "with")
public class Limits {
  Limit minimum;
  Limit maximum;
}
@Value
@Jacksonized
@Builder(builderClassName = "Builder", setterPrefix = "with")
public class Limit {
  @JsonValue
  String value;
}

和这个代码:

Limits limits = Limits.builder()
  .withMinimum(Limit.builder().withValue("One-Day").build())
  .withMaximum(Limit.builder().withValue("One-Year").build())
  .build();

System.out.println(objectMapper.writeValueAsString(limits));

它按预期工作,并给出以下输出:

{
  "minimum": "One-Day",
  "maximum": "One-Year"
}

但是,当我尝试反序列化相同的JSON字符串时,如下所示:

String json = """
  {"minimum":"One-Day","maximum":"One-Year"}
  """;

objectMapper.readValue(json, Limits.class);

出现以下错误:

Cannot construct instance of `Limit$Builder` (although at least one Creator exists):
no String-argument constructor/factory method to deserialize from String value ('One-Day')
at [Source: (String)"{"minimum":"One-Day","maximum":"One-Year"}"; line: 1, column: 12]

有没有一种方法可以在不改变数据模型或JSON的情况下使它工作?
我尝试将@JsonCreator添加到Limit的构建器中,如下所示,但出现相同的错误

@Value
@Jacksonized
@Builder(builderClassName = "Builder", setterPrefix = "with")
public class Limit {
  @JsonValue
  String value;

  public static final class Builder {
    @JsonCreator
    public Builder withValue(String value) {
      this.value = value;
      return this;
    }
  }
}

感谢任何关于我可能错过的东西的输入。

mqkwyuun

mqkwyuun1#

Jackson不支持@JsonCreator与构建器的组合。@JsonCreator基本上是这样说的:带注解的方法构造了一个新示例,将JSON值作为实参传递给它的单个形参,但这对构建器不起作用,因为没有这样的方法可以同时完成这两个任务(有两个独立的方法,一个用于接收JSON值,另一个用于构造示例)。
但是,在您的情况下,有一个简单的变通方法,不会失去不变性。只需将@JsonCreator放在一个全参数构造函数上,如下所示:

@Value
@AllArgsConstructor(onConstructor_ = {@JsonCreator})
public class Limit {
    @JsonValue
    String value;
}

如果您愿意,可以保留@Builder,但没有必要这样做。

相关问题