JavaBean之间不同属性名拷贝的方式

在日常工作中经常遇到需要在不同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()方法即可。

发布了46 篇原创文章 · 获赞 13 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/luliuliu1234/article/details/84141595
今日推荐