Джексон - десериализация с помощью Builder без аннотации

Можно ли использовать Джексона для десериализации класса значений (final, без сеттеров), который имеет только конструктор all args и Builder? Я не могу использовать JsonDeserialize и JsonPOJOBuilder, так как пытаюсь десериализовать модель, определенную в клиентской библиотеке, поэтому я не могу добавлять аннотации. Могу ли я указать застройщику использовать другой способ?


person gta0004    schedule 24.10.2017    source источник
comment
Просто реализуйте свой собственный JsonDeserializer   -  person rkosegi    schedule 24.10.2017
comment
@rkosegi Я предполагаю, что нет более простого способа сделать это без простого перечисления всех имен полей и ручного вызова построителя?   -  person gta0004    schedule 24.10.2017
comment
у вас есть несколько типов объектов, которые нужно десериализовать, или только один?   -  person rkosegi    schedule 24.10.2017
comment
У меня есть 3 разных типа, которые мне нужно десериализовать   -  person gta0004    schedule 24.10.2017
comment
Затем либо создайте 3 разных реализации JsonDeserializer, либо используйте более надежный подход с отражением.   -  person rkosegi    schedule 24.10.2017
comment
Если ваша модель содержит несколько атрибутов, таких как атрибуты, которые вы хотите сериализовать, и атрибуты, которые вам не нужно сериализовать, тогда JsonDeserialize с JsonIgnore будет хорошим вариантом.   -  person Pradeep    schedule 24.10.2017


Ответы (2)


Вы можете попробовать использовать MixIn.

Я создал один образец для вашего варианта использования:

Исходный класс:

final class Sample {

    final int id;

    Sample(int id) {
        this.id = id;
    }
}

MixIn (укажите конструктор без аргументов с такими же аргументами):

@JsonAutoDetect(fieldVisibility = Visibility.ANY, getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE)
abstract class SampleMixin {
    @JsonCreator
    public SampleMixin(@JsonProperty("id") int id) {
    }
}

Десерилизация:

ObjectMapper mapper = new ObjectMapper();
mapper.addMixIn(Sample.class, SampleMixin.class);
Sample sample = mapper.readValue(json, Sample.class);
person Sachin Gupta    schedule 24.10.2017
comment
На самом деле я пошел дальше и использовал @JsonDeserialize(builder = ...) на MixIn, и это сработало! Таким образом, мне не нужно наносить на карту все поля. Спасибо! - person gta0004; 24.10.2017

Вы можете. Строитель должен соответствовать определенным требованиям. Например, его методы для полей должны иметь определенный префикс, например, «с» или «набор».

Вот класс DTO и его построитель без каких-либо аннотаций Джексона:

public class DtoBuilderWithFinalFieldsWithoutJackson {

  public final String stringValue;

  private DtoBuilderWithFinalFieldsWithoutJackson(final String stringValue){
    this.stringValue = stringValue;
  }

  public static Builder builder(){
    return new Builder();
  }

  public static class Builder {
    private String stringValue;

    public Builder withStringValue(String stringValue) {
      this.stringValue = stringValue;
      return this;
    }
    public DtoBuilderWithFinalFieldsWithoutJackson build() {
      return new DtoBuilderWithFinalFieldsWithoutJackson(stringValue);
    }
  }
}

Без каких-либо дополнительных усилий с помощью настраиваемого объекта по умолчанию вы можете сериализовать этот объект dto. Вы несете ответственность за создание экземпляра. Джексону нужен только доступ к полям. В нашем случае это публичное поле.

Если для десериализации используется DTO, вам необходимо настроить собственный объект:

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setAnnotationIntrospector(new JacksonAnnotationIntrospector(){
  @Override
  public Class<?> findPOJOBuilder(AnnotatedClass ac) {
    //set analogue of: @JsonDeserialize(builder = DtoBuilderWithFinalFieldsWithoutJackson.Builder.class)
    if (DtoBuilderWithFinalFieldsWithoutJackson.class.equals(ac.getRawType())) {
      return DtoBuilderWithFinalFieldsWithoutJackson.Builder.class;
    } else {
      return super.findPOJOBuilder(ac);
    }
  }
  @Override
  public JsonPOJOBuilder.Value findPOJOBuilderConfig(AnnotatedClass ac) {
    if (DtoBuilderWithFinalFieldsWithoutJackson.class.equals(ac.getRawType())) {
      //both build and with - are default in this case:
      //set analogue of @JsonPOJOBuilder(buildMethodName = "build", withPrefix = "with")
      return new JsonPOJOBuilder.Value("build", "with");
    } else {
      return super.findPOJOBuilderConfig(ac);
    }
  }
});

и используйте этот настроенный CustomObject в своих реализациях. Вот тест и полный пример можно найти здесь: DtoBuilderWithFinalFieldsWithoutJackson test

person Alexandr    schedule 12.12.2019