在日常工作中经常遇到需要在不同JavaBean之间进行拷贝属性值的情况,而在有些情况下两个JavaBean之间的属性名是不一致的,这样就只能每次自己手动写一些方法进行转换,这里提供两种方式进行转换,两种方式各有优缺点:第一种方式使用cglib进行动态生成,缺点是需要手动维护一个映射关系;第二种方式使用JDK8的函数式接口,缺点是不同javaBean之间进行转换就需要写一个转换方法。
public class UserDTO{
private String userName;
private Integer userAge;
//省略getter/setter
}
public class UserVO{
private String name;
private Integer age;
//省略getter/setter
}
1.使用cglib方式:
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import net.sf.cglib.beans.BeanGenerator;
import net.sf.cglib.beans.BeanMap;
public class CGlibBean {
/**
* 实体Object
*/
public Object object = null;
/**
* 属性map
*/
public BeanMap beanMap = null;
public CGlibBean() {
super();
}
public CGlibBean(Map<String,Class> propertyMap) {
this.object = generateBean(propertyMap);
this.beanMap = BeanMap.create(this.object);
}
/**
* 给bean属性赋值
* @param property
* @param value
*/
public void setValue(String property ,Object value) {
beanMap.put(property, value);
}
/**
* 通过属性名得到属性值
* @param property
* @return
*/
public Object getValue(String property) {
return beanMap.get(property);
}
/**
* 得到该实体bean对象
* @return
*/
public Object getObject() {
return this.object;
}
//生成bean
@SuppressWarnings("rawtypes")
private Object generateBean(Map<String,Class> propertyMap) {
BeanGenerator generator = new BeanGenerator();
Set keySet = propertyMap.keySet();
for(Iterator i = keySet.iterator();i.hasNext();) {
String key = (String) i.next();
generator.addProperty(key, (Class)propertyMap.get(key));
}
return generator.create();
}
}
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.beanutils.PropertyUtils;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
public class BeanUtils {
private static final ObjectMapper mapper = new ObjectMapper();
static {
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
}
/**
* 根据源对象content转换成目标对象,源对象支持集合类型,但源对象中的实体类和目标对象中的实体类需要属性名相同
* @param content 源对象
* @param source 需要转换的目标集合类型
* @param param 目标集合类型里封装的实体类
* @return
*/
public static <T> T getCollectionBean(Object content, Class<?> collectionClass, Class<?>... elementClasses) {
if(content == null) {
return null;
}
String contentStr = null;
try {
contentStr = mapper.writeValueAsString(content);
JavaType javaType = mapper.getTypeFactory().constructParametricType(collectionClass, elementClasses);
return mapper.readValue(contentStr, javaType);
} catch(IllegalArgumentException | IOException e) {
}
return null;
}
/**
* 根据源对象obj转换成目标对象,不支持集合类型,源对象和目标对象属性名需要相同
* @param obj源对象
* @param valueType需要转换的目标集合类型
* @return
*/
public static <T> T getDataBeanWithType( Object obj, Class<T> valueType) {
String dataNode = null;
try {
dataNode = mapper.writeValueAsString(obj);
return mapper.readValue(dataNode, valueType);
} catch(IOException e) {
}
return null;
}
/**
* 拷贝bean的不同名称之间属性值,
* 需要手工维护一个bean之间不同属性名的映射关系,不支持源对象或目标对象为集合类型
* @param target 目标对象
* @param source 源对象
* @param param 源对象和目标对象的映射关系,其中key为源对象的属性名,value为目标对象的属性名
* @return 目标对象
* @throws ClassNotFoundException
* @throws IllegalArgumentException
* @throws IllegalAccessException
* @throws InvocationTargetException
* @throws NoSuchMethodException
*/
@SuppressWarnings("rawtypes")
public static Object getObject(Object target, Object source, Map<String, String> param) throws ClassNotFoundException,
IllegalArgumentException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
//获取源对象的属性名和值,属性名作为key,值作为value
Map<String,Object> sourceBeanMap = PropertyUtils.describe(source);
// 获取实体对象属性名数组
Field[] fields = source.getClass().getDeclaredFields();
// 属性名,属性类型
Map<String, Class> temp = new HashMap<>();
// 属性名,属性值
Map<String, Object> valueParam = new HashMap<>();
for (Field f : fields) {
// 设置访问权限,否则不能访问私有化属性
f.setAccessible(true);
// 若没有映射关系,则跳过继续寻找有映射关系的属性
if(null==param.get(f.getName()))
continue;
temp.put(param.get(f.getName()), Class.forName(f.getType().getName()));
for(Map.Entry<String, String> entry: param.entrySet()) {
if(entry.getKey().equals(f.getName())) {
Object value = sourceBeanMap.get(entry.getKey());
valueParam.put(param.get(f.getName()), value);
break;
}
}
}
// 根据参数生成CglibBean对象
CGlibBean cglibBean = new CGlibBean(temp);
for (Map.Entry<String, Object> entry : valueParam.entrySet()) {
cglibBean.setValue(entry.getKey(), entry.getValue());
}
Object object = cglibBean.getObject();
// 用object给目标对象赋值
PropertyUtils.copyProperties(target, object);
return target;
}
public static void main(String[] args) throws ClassNotFoundException, IllegalArgumentException,
IllegalAccessException, InvocationTargetException, NoSuchMethodException {
Map<String,String> mapping =new HashMap<>();
UserDTO source= new UserDTO();
UserVO target = new UserVO ();
source.setUserName("expireDate");
source.setUserAge(false);
mapping.put("userName", "name");//source field,target field,
mapping.put("userAge", "age");
target = (UserDTO )getObject(target, source, mapping);
System.out.println(target.toString());
}
}
第一种方式需要加上cglib的maven依赖:
<dependency>
<groupId>asm</groupId>
<artifactId>asm</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>asm</groupId>
<artifactId>asm-commons</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>asm</groupId>
<artifactId>asm-util</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>2.2.2</version>
</dependency>
2.使用JDK8的函数式接口:
在定义JavaBean时即提供转换方法,如:
public class UserDTO {
private String userName;
private Integer userAge;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public Integer getUserAge() {
return userAge;
}
public void setUserAge(Integer userAge) {
this.userAge = userAge;
}
public UserDTO convert(){
return ((Function<UserDTO,UserVO>) userDto ->{
UserVO userVo = new UserVO();
userVo.setAge(userDto.getUserAge());
userVo.setName(userDto.getUserName());
})
}
}
这样需要进行转换时,直接调用convert()方法即可。