Reputation: 1180
I have a json object with a lot of properties (~80 properties) I want to deserialize in a POJO without creating manually all the properties. I was able to do this by using the @JsonAnySetter
with a Map
property like described here.
Now I want to make this work by making my POJO immutable using Lombok.
I tried this but it does only deserialize the id
and code
properties. Any idea on how to make it work?
@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);
}
}
Upvotes: 8
Views: 4731
Reputation: 8042
Update 2021-02-01: Lombok v1.18.16
Starting with v1.18.16, Lombok automatically copies @JsonAnySetter
to the @Singular
methods in builder. In combination with @Jacksonized
you can simply use this code:
@Value
@Jacksonized
@Builder
class Product {
private String id;
private String code;
@JsonAnySetter
@Singular("any")
private Map<String, Object> any;
}
Older Lombok versions
For previous Lombok version, this requires some customization of the generated builder class.
Customizing a lombok builder can be done by simply adding its inner class header to your class. Lombok detects that there is already a builder class and just adds all the things that are not already present. This means you can add your own methods, and if those happen to have the same name than a method that lombok would generate, lombok skips this method.
With this approach, we replace the builder's setter method for "any", adding the required @JsonAnySetter
to it. I use a LinkedHashMap
as map in case the order is relevant; you can use a regular HashMap
if it's not.
Furthermore, we replace the build()
method to make sure the map you supply to the constructor is immutable. I use Guava's ImmutableMap
here. This will make the created instance an immutable value.
@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));
}
}
}
Upvotes: 13