通过 getter 和 setter 更新 pojo 的通用方法
Generic way to update pojos via getters and setters
假设我的 POJO 具有 getter 和 setter 不同类型。我想编写一些通用算法,用于根据仅通过 lambda 定义 getters 和 setters 将数据从一个更新到另一个。
我正在尝试以这种方式创建它
private static final Map<Function<Entity, Object>, BiConsumer<Entity, Object>> ACCESSORS = new HashMap
<Function<Entity, Object>, BiConsumer<Entity, Object>>() {{
put(Entity::getAreaCode, Entity::setAreaCode);
}});
然后我遍历所有将目标实体应用于它们的条目,如果 getter 的结果不为空,那么我想为其他实体应用相应的 setter。
但它不会工作,因为 Object 不能转换为 String。我想将它用于不同的类型,不仅是字符串,还有整数等...
是否可以通过一些简单的方法解决而无需创建特殊转换器并将其与每个条目相关联?
使用类似
的东西
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
中处理,但不再是通用签名的一部分,因此不需要为 [=14 声明=].它甚至更高效,因为它可以处理原始数据类型而无需装箱开销。
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);
};
}
copyAll
方法不变。这甚至允许将永远不能 null
的属性的无条件复制与条件复制混合。
我知道你已经有了答案,但对于将来需要这样的东西的人:我已经围绕这个上下文开发了一个小型库 - 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"
]
*/
假设我的 POJO 具有 getter 和 setter 不同类型。我想编写一些通用算法,用于根据仅通过 lambda 定义 getters 和 setters 将数据从一个更新到另一个。 我正在尝试以这种方式创建它
private static final Map<Function<Entity, Object>, BiConsumer<Entity, Object>> ACCESSORS = new HashMap
<Function<Entity, Object>, BiConsumer<Entity, Object>>() {{
put(Entity::getAreaCode, Entity::setAreaCode);
}});
然后我遍历所有将目标实体应用于它们的条目,如果 getter 的结果不为空,那么我想为其他实体应用相应的 setter。
但它不会工作,因为 Object 不能转换为 String。我想将它用于不同的类型,不仅是字符串,还有整数等...
是否可以通过一些简单的方法解决而无需创建特殊转换器并将其与每个条目相关联?
使用类似
的东西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
中处理,但不再是通用签名的一部分,因此不需要为 [=14 声明=].它甚至更高效,因为它可以处理原始数据类型而无需装箱开销。
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);
};
}
copyAll
方法不变。这甚至允许将永远不能 null
的属性的无条件复制与条件复制混合。
我知道你已经有了答案,但对于将来需要这样的东西的人:我已经围绕这个上下文开发了一个小型库 - 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"
]
*/