Заставьте @JsonAnySetter работать с @Value Lombok - PullRequest
2 голосов
/ 12 апреля 2020

У меня есть json объект с множеством свойств (~ 80 свойств). Я хочу десериализовать в POJO, не создавая вручную все свойства. Я смог сделать это, используя @JsonAnySetter со свойством Map, как описано здесь .

Теперь я хочу сделать эту работу, сделав мой POJO неизменяемым с помощью Lombok. Я пробовал это, но он десериализует только свойства 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);
   }

}

1 Ответ

2 голосов
/ 13 апреля 2020

На данный момент это требует некоторой настройки сгенерированного класса компоновщика. (Я расскажу о том, как это, вероятно, улучшится в одной из следующих версий lombok, в конце этого ответа.)

Настройку компоновщика lombok можно выполнить, просто добавив его внутренний заголовок класса к вашему. учебный класс. Lombok обнаруживает, что класс строителя уже существует, и просто добавляет все, чего еще нет. Это означает, что вы можете добавить свои собственные методы, и если они имеют то же имя, что и метод, который генерирует lombok, lombok пропускает этот метод.

При таком подходе мы заменяем метод-установщик компоновщика на «любой msgstr ", добавив к нему требуемый @JsonAnySetter. Я использую LinkedHashMap в качестве карты на случай, если порядок уместен; Вы можете использовать обычный HashMap, если это не так.

Кроме того, мы заменим метод build(), чтобы убедиться, что карта, которую вы предоставляете конструктору, является неизменной. Я использую Guava's 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));
        }

    }
}

Lombok имеет встроенную поддержку неизменяемых карт с использованием аннотации @Singular. Более того, он создает точный метод, который нужен Джексону для установки «любого значения», ему просто не хватает аннотации @JsonAnySetter. К сожалению, @Singular не поддерживает , не поддерживает настройку, поэтому мы не можем добавить @JsonAnySetter к этому методу. Существует некоторая текущая работа , которая направлена ​​на автоматическое копирование аннотаций Джексона (включая @JsonAnySetter) в методы установки сборщика. Это полностью исключило бы необходимость настройки строителя в этом случае. Я обновлю этот ответ, когда эта функция будет выпущена.

...