Общий способ обновления pojos через геттеры и сеттеры - PullRequest
0 голосов
/ 21 января 2019

Допустим, у меня есть POJO с геттерами и сеттерами разных типов. Я хочу написать некоторый общий алгоритм для обновления данных от одного к другому, основанный на простом определении геттеров и сеттеров через лямбды. Я пытаюсь создать это таким образом

private static final Map<Function<Entity, Object>, BiConsumer<Entity, Object>> ACCESSORS = new HashMap
        <Function<Entity, Object>, BiConsumer<Entity, Object>>() {{
    put(Entity::getAreaCode, Entity::setAreaCode);
}});

Затем я просматриваю все записи, применяя к ним целевую сущность, и если результат получения не равен нулю, я хочу применить соответствующий установщик для другой сущности.

Но это не сработает, потому что Object не может быть преобразован в String. И я хочу использовать его для разных типов не только String, но и Integer, и т.д ...

Разрешается ли в каком-то простом подходе без создания специального конвертера и связывания его с каждой записью?

Ответы [ 2 ]

0 голосов
/ 28 мая 2019

Я знаю, что у вас уже есть ответ, но для тех, кому понадобится что-то подобное в будущем: я разработал небольшую библиотеку для этого контекста - datus .

Вот пример, которыйпоказывает некоторые из его особенностей:

class Person {
  //getters + setters omitted for brevity
  private String firstName;
  private String lastName;
}

class PersonDTO {
  //getters + setters + empty constructor omitted for brevity
  private String firstName;
  private String lastName;
}

  //the mutable API defines a mapping process by multiple getter-setter steps
  Mapper<Person, PersonDTO> mapper = Datus.forTypes(Person.class, PersonDTO.class).mutable(PersonDTO::new)
      .from(Person::getFirstName).into(PersonDTO.setFirstName)
      .from(Person::getLastName)
      .given(Objects::nonNull, ln -> ln.toUpperCase()).orElse("fallback")
      .into(PersonDTO::setLastName)
      .from(/*...*/).into(/*...*/)
      .build();

  Person person = new Person();
person.setFirstName("firstName");
    person.setLastName(null);
    PersonDTO personDto = mapper.convert(person);
/*
    personDto = PersonDTO [
        firstName = "firstName",
        lastName = "fallback"
    ]
*/
    person.setLastName("lastName");
    personDto = mapper.convert(person);
/*
    personDto = PersonDTO [
        firstName = "firstName",
        lastName = "LASTNAME"
    ]
*/
0 голосов
/ 21 января 2019

Используйте что-то вроде

private static final List<BiConsumer<Entity,Entity>> ACCESSORS =
    Collections.unmodifiableList(Array.asList(
        (src,dst) -> dst.setAreaCode(src.getAreaCode()),
        (src,dst) -> dst.setOtherProperty(src.getOtherProperty())
        /* etc */
));

Затем вы можете перебрать список и применить каждую операцию к двум объектам, например

static final void copyAll(Entity src, Entity dst) {
    ACCESSORS.forEach(op -> op.accept(src, dst));
}

Ключевым моментом является то, что фактическое значение свойстваТип обрабатывается внутри каждого BiConsumer, но больше не является частью общей сигнатуры и, следовательно, не должен быть объявлен для ACCESSORS.Это еще более эффективно, так как он может обрабатывать примитивные типы данных без дополнительных затрат.

Map не была подходящей структурой данных для этой задачи, так как для этих функций никакой значимый поиск не мог быть выполнен,так что это структура данных, предназначенная только для итерации.

Вы можете интегрировать логику «копировать только при ненулевом» с универсальным вспомогательным методом:

private static final List<BiConsumer<Entity,Entity>> ACCESSORS =
    Collections.unmodifiableList(Arrays.asList(
        copyWhenNonNull(Entity::getAreaCode, Entity::setAreaCode),
        copyWhenNonNull(Entity::getOtherProperty, Entity::setOtherProperty)
        /* etc */
));
private static <E,V> BiConsumer<E,E> copyWhenNonNull(
    Function<? super E, ? extends V> getter, BiConsumer<? super E, ? super V> setter) {
    return (src,dst) -> {
        V value = getter.apply(src);
        if(value != null) setter.accept(dst, value);
    };
}

The copyAll метод не меняется.Это даже позволяет смешивать безусловное копирование свойств, которое никогда не может быть null с условным копированием.

...