package com.fpi.spring.qaepb.cps.util; import java.beans.IntrospectionException; import java.beans.PropertyDescriptor; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import com.fpi.spring.qaepb.cps.entity.po.Project; import com.fpi.spring.qaepb.cps.entity.po.ProjectApproval; /** * bean的屬性拷貝工具類 * * @date 2013-12-17 * * @author yang_qiao * * @version 1.0 */ public class BeanUtils { private static final Log logger = LogFactory.getLog(BeanUtils.class); /** bean嵌套 */ private static final String NESTED = "."; /** * 複製bean的屬性(支持嵌套屬性,以點號分割) * * @param source * 拷貝屬性的源對象 * * @param dest * 拷貝屬性的目的地對象 * * @param includeProperties * 拷貝的屬性列表 * * @author yang_qiao * * @throws InvocationTargetException * * @throws IllegalAccessException * * @throws IllegalArgumentException * * @throws InstantiationException * * @throws IntrospectionException * * @date 2013-12-18 */ public static final void copyIncludeProperties(final Object source, Object dest, final String[] includeProperties) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, InstantiationException, IntrospectionException { if (includeProperties == null || includeProperties.length == 0) { throw new IllegalArgumentException("未傳入要拷貝的屬性列表"); } if (source == null) { throw new IllegalArgumentException("要拷貝的源對象爲空"); } if (dest == null) { throw new IllegalArgumentException("要拷貝的目的對象爲空"); } // 日誌信息 if (logger.isTraceEnabled()) { logger.trace("[source bean: " + source.getClass().getName() + " ]"); logger.trace("[destination bean: " + dest.getClass().getName() + " ]"); } // 拷貝 for (String property : includeProperties) { PropertyDescriptor sourcePropertyDescriptor = null; PropertyDescriptor destPropertyDescriptor = null; if (isSimpleProperty(property)) { // 簡單屬性 sourcePropertyDescriptor = getProperty(property, source); destPropertyDescriptor = getProperty(property, dest); if (sourcePropertyDescriptor == null) { throw new IllegalArgumentException("要拷貝的源對象不存在該屬性"); } if (destPropertyDescriptor == null) { throw new IllegalArgumentException("要拷貝到的目標對象不存在該屬性"); } copyProperty(property, source, dest); } else { // 嵌套bean屬性 Object target = dest; Object realSource = source; String[] nestedProperty = getNestedProperty(property); if (nestedProperty != null && nestedProperty.length > 1) { for (int i = 0; i < nestedProperty.length - 1; i++) { sourcePropertyDescriptor = getProperty( nestedProperty[i], realSource); destPropertyDescriptor = getProperty(nestedProperty[i], target); if (sourcePropertyDescriptor == null) { throw new IllegalArgumentException("要拷貝的源對象不存在該屬性"); } if (destPropertyDescriptor == null) { throw new IllegalArgumentException( "要拷貝到的目標對象不存在該屬性"); } Method readMethod = sourcePropertyDescriptor .getReadMethod(); realSource = readMethod.invoke(realSource); readMethod = destPropertyDescriptor.getReadMethod(); Method writeMethod = destPropertyDescriptor .getWriteMethod(); Object value = readMethod.invoke(target); if (value == null) { value = destPropertyDescriptor.getPropertyType() .newInstance(); writeMethod.invoke(target, value); } target = value; } final String prop = nestedProperty[nestedProperty.length - 1]; sourcePropertyDescriptor = getProperty(prop, realSource); destPropertyDescriptor = getProperty(prop, target); if (sourcePropertyDescriptor == null) { throw new IllegalArgumentException("要拷貝的源對象不存在該屬性"); } if (destPropertyDescriptor == null) { throw new IllegalArgumentException("要拷貝到的目標對象不存在該屬性"); } copyProperty(prop, realSource, target); } } } } /** * 複製bean的屬性(支持嵌套屬性,以點號分割) * * @param source * 拷貝屬性的源對象 * * @param dest * 拷貝屬性的目的地對象 * * @param includeProperties * 拷貝的屬性列表 * * @author yang_qiao * * @throws IntrospectionException * * @throws InvocationTargetException * * @throws IllegalAccessException * * @throws IllegalArgumentException * * @throws InstantiationException * * @throws ClassNotFoundException * * @throws IOException * * @date 2013-12-18 */ public static void copyProperties(final Object source, final Object dest, final String... excludeProperties) throws IntrospectionException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, InstantiationException, IOException, ClassNotFoundException { final Object backupSource = clone(dest); if (source == null) { throw new IllegalArgumentException("要拷貝的源對象爲空"); } if (dest == null) { throw new IllegalArgumentException("要拷貝的目的對象爲空"); } org.apache.commons.beanutils.BeanUtils.copyProperties(dest, source); // 還原排除的屬性值 revertProperties(backupSource, dest, excludeProperties); } /** * 從備份對象中還原屬性 * * @param backup * 備份bean * * @param target * 目標bean * * @param properties * 屬性列表 * * @author yang_qiao * * @throws InvocationTargetException * * @throws IllegalAccessException * * @throws IllegalArgumentException * * @throws IntrospectionException * * @throws InstantiationException * * @date 2013-12-18 */ private static void revertProperties(final Object backup, Object target, final String... properties) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, IntrospectionException, InstantiationException { if (properties == null || properties.length == 0) { return; } if (backup == null) { throw new IllegalArgumentException("備份對象爲空"); } if (target == null) { throw new IllegalArgumentException("目的對象爲空"); } // 日誌信息 if (logger.isTraceEnabled()) { logger.trace("[source bean: " + backup.getClass().getName() + " ]"); logger.trace("[destination bean: " + target.getClass().getName() + " ]"); } // 拷貝 for (String property : properties) { PropertyDescriptor sourcePropertyDescriptor = null; PropertyDescriptor destPropertyDescriptor = null; if (isSimpleProperty(property)) { // 簡單屬性 sourcePropertyDescriptor = getProperty(property, backup); destPropertyDescriptor = getProperty(property, target); if (sourcePropertyDescriptor == null) { throw new IllegalArgumentException("要拷貝的源對象不存在該屬性"); } if (destPropertyDescriptor == null) { throw new IllegalArgumentException("要拷貝到的目標對象不存在該屬性"); } copyProperty(property, backup, target); } else { // 嵌套bean屬性 Object targetObj = target; Object realBackup = backup; String[] nestedProperty = getNestedProperty(property); if (nestedProperty != null && nestedProperty.length > 1) { for (int i = 0; i < nestedProperty.length - 1; i++) { sourcePropertyDescriptor = getProperty( nestedProperty[i], realBackup); destPropertyDescriptor = getProperty(nestedProperty[i], targetObj); if (sourcePropertyDescriptor == null) { throw new IllegalArgumentException("要拷貝的源對象不存在該屬性"); } if (destPropertyDescriptor == null) { throw new IllegalArgumentException( "要拷貝到的目標對象不存在該屬性"); } Method readMethod = sourcePropertyDescriptor .getReadMethod(); realBackup = readMethod.invoke(realBackup); if (realBackup == null) { // 判斷備份對象嵌套屬性是否爲空 realBackup = sourcePropertyDescriptor .getPropertyType().newInstance(); } Method writeMethod = destPropertyDescriptor .getWriteMethod(); readMethod = destPropertyDescriptor.getReadMethod(); Object value = readMethod.invoke(targetObj); if (value == null) { value = destPropertyDescriptor.getPropertyType() .newInstance(); writeMethod.invoke(targetObj, value); } targetObj = value; } final String prop = nestedProperty[nestedProperty.length - 1]; sourcePropertyDescriptor = getProperty(prop, realBackup); destPropertyDescriptor = getProperty(prop, targetObj); if (sourcePropertyDescriptor == null) { throw new IllegalArgumentException("要拷貝的源對象不存在該屬性"); } if (destPropertyDescriptor == null) { throw new IllegalArgumentException("要拷貝到的目標對象不存在該屬性"); } copyProperty(prop, realBackup, targetObj); } } } } /** * 對象克隆 * * @author yang_qiao * * @date 2013-12-18 */ private static Object clone(final Object value) throws IOException, ClassNotFoundException { // 字節數組輸出流,暫存到內存中 ByteArrayOutputStream bos = new ByteArrayOutputStream(); // 序列化 ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(value); ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); // 反序列化 return ois.readObject(); } /** * 判斷是否爲簡單屬性,是,返回ture * * @author yang_qiao * * @date 2013-12-18 */ private static boolean isSimpleProperty(final String property) { return !property.contains(NESTED); } /** * 獲取目標bean的屬性 * * @author yang_qiao * * @date 2013-12-17 */ private static PropertyDescriptor getProperty(final String propertyName, final Object target) { if (target == null) { new IllegalArgumentException("查詢屬性的對象爲空"); } if (propertyName == null || "".equals(propertyName)) { new IllegalArgumentException("查詢屬性不能爲空值"); } PropertyDescriptor propertyDescriptor = null; try { propertyDescriptor = new PropertyDescriptor(propertyName, target.getClass()); } catch (IntrospectionException e) { logger.info("不存在該屬性"); return null; } return propertyDescriptor; } /** * 單個屬性複製--原數據源和目的數據源必需要有該屬性方可 * * @author yang_qiao * * @throws InvocationTargetException * * @throws IllegalAccessException * * @throws IllegalArgumentException * * @throws IntrospectionException * * @date 2013-12-17 */ public static void copyProperty(final String propertyName, final Object source, Object dest) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, IntrospectionException { PropertyDescriptor property; property = new PropertyDescriptor(propertyName, source.getClass()); Method getMethod = property.getReadMethod(); Object value = getMethod.invoke(source); property = new PropertyDescriptor(propertyName, dest.getClass()); Method setMethod = property.getWriteMethod(); setMethod.invoke(dest, value); } /** * 獲取嵌套Bean的屬性 * * @author yang_qiao * * @date 2013-12-18 */ public static String[] getNestedProperty(final String nestedProperty) { if (nestedProperty == null || "".equals(nestedProperty)) { new IllegalArgumentException("參數爲空值"); } return nestedProperty.split("\\" + NESTED); } public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, InstantiationException, IntrospectionException, IOException, ClassNotFoundException { Project oldProject = new Project(); Project newProject = new Project(); ProjectApproval projectApproval = new ProjectApproval(); projectApproval.setFirstCheckComment("jsoncheck"); projectApproval.setExplorationComment("shitCheck"); oldProject.setProjectApproval(projectApproval); oldProject.setBuildAddress("json"); oldProject.setContact("json"); final String[] includeProperties = new String[] { "contact", "projectApproval.firstCheckComment", "projectApproval.explorationComment" }; BeanUtils.copyIncludeProperties(oldProject, newProject, includeProperties); System.out.println(newProject.getContact()); System.out.println(newProject.getProjectApproval() .getFirstCheckComment()); System.out.println(newProject.getProjectApproval() .getExplorationComment()); System.out.println(newProject.getApprovalStatus()); System.out.println(newProject.getBuildAddress()); System.out.println("================================"); oldProject = new Project(); newProject = new Project(); projectApproval = new ProjectApproval(); projectApproval.setFirstCheckComment("jsoncheck_"); projectApproval.setExplorationComment("shitCheck_"); oldProject.setProjectApproval(projectApproval); oldProject.setBuildAddress("json_"); oldProject.setContact("json_"); final String[] excludeProperties = null; BeanUtils.copyProperties(oldProject, newProject, excludeProperties); System.out.println(newProject.getContact()); System.out.println(newProject.getProjectApproval() .getExplorationComment()); System.out.println(newProject.getProjectApproval() .getFirstCheckComment()); System.out.println(newProject.getApprovalStatus()); System.out.println(newProject.getBuildAddress()); } }