使@JsonAnySetter 与@Value Lombok 一起工作
Make @JsonAnySetter work with @Value Lombok
我有一个 json 对象,它有很多属性(~80 个属性)我想在 POJO 中反序列化而不手动创建所有属性。我能够通过使用 @JsonAnySetter
和 Map
属性 来做到这一点,就像 here.
中描述的那样
现在我想通过使用 Lombok 使我的 POJO 不可变来完成这项工作。
我试过了,但它只会反序列化 id
和 code
属性。知道如何让它发挥作用吗?
@Value
@Builder
@EqualsAndHashCode
@JsonDeserialize(builder = Product.ProductBuilder.class)
class Product {
@JsonProperty
private String id;
@JsonProperty
private String code;
@Getter(AccessLevel.NONE)
@Builder.Default
@JsonProperty
private Map<String, Optional<Object>> any = new HashMap<>();
@JsonAnyGetter
public Map<String, Optional<Object>> getAny(){
return this.any;
}
@JsonAnySetter
public void setAny(String key, Optional<Object> value){
this.any.put(key, value);
}
}
2021-02-01 更新:Lombok v1.18.16
从 v1.18.16 开始,Lombok 自动将 @JsonAnySetter
复制到构建器中的 @Singular
方法。结合 @Jacksonized
你可以简单地使用这个代码:
@Value
@Jacksonized
@Builder
class Product {
private String id;
private String code;
@JsonAnySetter
@Singular("any")
private Map<String, Object> any;
}
旧的 Lombok 版本
对于以前的 Lombok 版本,这需要对生成的构建器进行一些自定义 class。
自定义 lombok 构建器只需将其内部 class header 添加到您的 class 即可。 Lombok 检测到已经有一个构建器 class 并且只添加所有不存在的东西。这意味着您可以添加自己的方法,如果这些方法恰好与 lombok 生成的方法同名,lombok 将跳过此方法。
通过这种方法,我们将构建器的 setter 方法替换为“any”,并向其添加所需的 @JsonAnySetter
。我使用 LinkedHashMap
作为地图以防顺序相关;如果不是,你可以使用常规 HashMap
。
此外,我们替换了 build()
方法以确保您提供给构造函数的映射是不可变的。我这里用的是Guava的ImmutableMap
。这将使创建的实例成为不可变值。
@Value
@Builder
@JsonDeserialize(builder = Product.ProductBuilder.class)
class Product {
@JsonProperty
private String id;
@JsonProperty
private String code;
@Getter(onMethod_ = @JsonAnyGetter)
private Map<String, Object> any;
@JsonPOJOBuilder(withPrefix = "")
public static class ProductBuilder {
@JsonAnySetter
public ProductBuilder any(String anyKey, Object anyValue) {
if (this.any == null) {
this.any = new LinkedHashMap<String, Object>();
}
this.any.put(anyKey, anyValue);
return this;
}
public Product build() {
return new Product(id, code, any == null ? ImmutableMap.of() : ImmutableMap.copyOf(any));
}
}
}
我有一个 json 对象,它有很多属性(~80 个属性)我想在 POJO 中反序列化而不手动创建所有属性。我能够通过使用 @JsonAnySetter
和 Map
属性 来做到这一点,就像 here.
现在我想通过使用 Lombok 使我的 POJO 不可变来完成这项工作。
我试过了,但它只会反序列化 id
和 code
属性。知道如何让它发挥作用吗?
@Value
@Builder
@EqualsAndHashCode
@JsonDeserialize(builder = Product.ProductBuilder.class)
class Product {
@JsonProperty
private String id;
@JsonProperty
private String code;
@Getter(AccessLevel.NONE)
@Builder.Default
@JsonProperty
private Map<String, Optional<Object>> any = new HashMap<>();
@JsonAnyGetter
public Map<String, Optional<Object>> getAny(){
return this.any;
}
@JsonAnySetter
public void setAny(String key, Optional<Object> value){
this.any.put(key, value);
}
}
2021-02-01 更新:Lombok v1.18.16
从 v1.18.16 开始,Lombok 自动将 @JsonAnySetter
复制到构建器中的 @Singular
方法。结合 @Jacksonized
你可以简单地使用这个代码:
@Value
@Jacksonized
@Builder
class Product {
private String id;
private String code;
@JsonAnySetter
@Singular("any")
private Map<String, Object> any;
}
旧的 Lombok 版本
对于以前的 Lombok 版本,这需要对生成的构建器进行一些自定义 class。
自定义 lombok 构建器只需将其内部 class header 添加到您的 class 即可。 Lombok 检测到已经有一个构建器 class 并且只添加所有不存在的东西。这意味着您可以添加自己的方法,如果这些方法恰好与 lombok 生成的方法同名,lombok 将跳过此方法。
通过这种方法,我们将构建器的 setter 方法替换为“any”,并向其添加所需的 @JsonAnySetter
。我使用 LinkedHashMap
作为地图以防顺序相关;如果不是,你可以使用常规 HashMap
。
此外,我们替换了 build()
方法以确保您提供给构造函数的映射是不可变的。我这里用的是Guava的ImmutableMap
。这将使创建的实例成为不可变值。
@Value
@Builder
@JsonDeserialize(builder = Product.ProductBuilder.class)
class Product {
@JsonProperty
private String id;
@JsonProperty
private String code;
@Getter(onMethod_ = @JsonAnyGetter)
private Map<String, Object> any;
@JsonPOJOBuilder(withPrefix = "")
public static class ProductBuilder {
@JsonAnySetter
public ProductBuilder any(String anyKey, Object anyValue) {
if (this.any == null) {
this.any = new LinkedHashMap<String, Object>();
}
this.any.put(anyKey, anyValue);
return this;
}
public Product build() {
return new Product(id, code, any == null ? ImmutableMap.of() : ImmutableMap.copyOf(any));
}
}
}