JavaBean之間不同屬性名拷貝的方式
阿新 • • 發佈:2018-12-22
在日常工作中經常遇到需要在不同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()方法即可。