【问题标题】:What is a good way for getter to setter mapping from simple java objects (POJOs). Can is use reflection for it?什么是从简单 Java 对象(POJO)的 getter 到 setter 映射的好方法。可以使用反射吗?
【发布时间】:2019-09-10 21:23:38
【问题描述】:
您好,我有两个相互独立的 java 对象,但共享相同的 getter 和 setter 方法。例如,我有一个 UserEntity 和 UserDTO 对象,我会将 UserEntity 中的所有 getter 值映射到 UserDTO 的所有 setter。
做这类事情的最佳方法是什么?我更喜欢用 java 反射来做,但我现在也想在外面有一些有用的框架实现。
【问题讨论】:
标签:
java
reflection
mapping
pojo
【解决方案1】:
有一个很棒的映射器库,叫做MapStruct,可以用来映射。
这是您的 UserEntity 和 UserDTO 的示例:
@Mapper
public interface UserMapper {
UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);
@Mapping
UserDTO userEntityToUserDTO(UserEntity user);
}
UserDTO userDto = UserMapper.INSTANCE.userEntityToUserDTO(userEntity);
它还支持兼容类型之间的转换,如果字段名称不同,还可以设置自定义映射。例如:
@Mapping(source = "userName", target = "name")
【解决方案2】:
这种需求通常最好使用“转换器”或“映射器”模式来实现。在 Java 中生成映射器的首选工具是 MapStruct,但还有许多其他工具。
使用反射通常不是最佳选择,因为它速度较慢,而且更难以跟踪和自定义(例如,如果需要在 JSON 中的字符串和 Java 中的 longs 之间转换字段)。
【解决方案3】:
使用反射和不使用外部库
您好,您可以检查源对象的所有 getter,并尝试在目标对象上找到所有对应的 setter。以下方法应该做到这一点:
/**
* Maps all getter of the source to all corresponding setter of the target
* @param target
* target object which should be set
* @param source
* source object to read from
* @return
* returns mapped target object or null if some error occurred
*/
private Object getterToSetter(Object target, Object source) {
try {
for(Method m: source.getClass().getMethods()){
// try to find for all getters in the source the corresponding setter on the target
if(m.getName().startsWith("get")){
Method setter;
try {
setter = target.getClass().getMethod("set" + m.getName().substring(3), m.getReturnType());
setter.invoke(target,m.invoke(source));
} catch (NoSuchMethodException e) {
//ignored target just haven't a setter for this field
}
}
}
// return value to support builder pattern
return target;
}catch (IllegalAccessException| InvocationTargetException e){
e.printStackTrace();
}
return null;
}
这是一个完整的 Main.class 示例,说明它是如何工作的:
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* @author Andreas Hauschild
*/
public class Main {
public static void main(String[] args) {
UserEntity userEntity = new UserEntity().setName("Waltraud").setLastName("Schmidt").setPassword("TopSecret");
UserDTO dto = (UserDTO) getterToSetter(new UserDTO(), userEntity);
System.out.println(dto.getName()); // prints "Waltraud"
System.out.println(dto.getLastName()); // prints "Schmidt"
}
/**
* Maps all getter of the source to all corresponding setter of the target
* @param target
* target object which should be set
* @param source
* source object to read from
* @return
* returns mapped target object or null if some error occurred
*/
private static Object getterToSetter(Object target, Object source) {
try {
for(Method m: source.getClass().getMethods()){
// try to find for all getters in the source the corresponding setter on the target
if(m.getName().startsWith("get")){
Method setter;
try {
setter = target.getClass().getMethod("set" + m.getName().substring(3), m.getReturnType());
setter.invoke(target,m.invoke(source));
} catch (NoSuchMethodException e) {
//ignored target just haven't a setter for this field
}
}
}
// return value to support builder pattern
return target;
}catch (IllegalAccessException| InvocationTargetException e){
e.printStackTrace();
}
return null;
}
public static class UserEntity {
String password;
String name;
String lastName;
public String getPassword() {
return password;
}
public UserEntity setPassword(String password) {
this.password = password;
return this;
}
public String getName() {
return name;
}
public UserEntity setName(String name) {
this.name = name;
return this;
}
public String getLastName() {
return lastName;
}
public UserEntity setLastName(String lastName) {
this.lastName = lastName;
return this;
}
}
public static class UserDTO {
String name;
String lastName;
public String getName() {
return name;
}
public UserDTO setName(String name) {
this.name = name;
return this;
}
public String getLastName() {
return lastName;
}
public UserDTO setLastName(String lastName) {
this.lastName = lastName;
return this;
}
}
}