1. 程式人生 > >JavaBean之間不同屬性名拷貝的方式

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()方法即可。