BeanCopier和BeanUtils实现对象复制,处理date类型

没有废话

先是BeanUtils的实现类型:

import java.lang.reflect.InvocationTargetException;
import java.util.Date;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.ConvertUtils;

import com.huateng.common.tools.ConvertTools;
import com.huateng.common.tools.subTools.form.ProductFormVo;
import com.huateng.common.tools.subTools.form.ProductFormVo1;

/**
 * @author Jira
 *
 */
public class LocalBeanUtils  extends BeanUtils {
    
    static {   
        ConvertUtils.register(new DateConvert(), java.util.Date.class);   
        ConvertUtils.register(new DateConvert(), java.sql.Date.class);   
        ConvertUtils.register(new DateConvert(), java.lang.String.class);
//        ConvertUtils.register(new DateConvert(), java.lang.Long.class);   //可以添加新的转换工具
    }   
 
   public static void copyProperties(Object dest, Object orig) {   
       try {   
            BeanUtils.copyProperties(dest, orig);   
        } catch (IllegalAccessException ex) {   
            ex.printStackTrace();   
        } catch (InvocationTargetException ex) {   
            ex.printStackTrace();   
        }   
    }
    
    public static void main(String...strings) throws Exception{
        ProductFormVo pf;
        Long l=System.currentTimeMillis();
        for (int i = 0; i < 100000; i++) {
            ProductFormVo1 p = new ProductFormVo1();
            p.setArticleId("a");
            p.setCreateStamp(new Date());
            p.setThruDate("2000-11-11 12:00:00");
            pf = new ProductFormVo();
            LocalBeanUtils.copyProperties(p, pf);
        }
        System.out.println(System.currentTimeMillis()-l);
    }

}

  它用到的DateConvert

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

import org.apache.commons.beanutils.Converter;

public class DateConvert implements Converter {

    public Object convert(Class arg0, Object arg1) {
        if (null == arg1)
            return null;
        /** 输入String ,输出Date */
        if (arg1 instanceof String && arg0 != java.lang.String.class) {
            String p = (String) arg1;
            if (p == null || p.trim().length() == 0) {
                return null;
            }
            try {

                SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                return df.parse(p.trim());
            } catch (Exception e) {
                try {
                    SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
                    return df.parse(p.trim());
                } catch (ParseException ex) {
                    return arg1;
                }
            }
        }/** 输入String ,输出String */
        else if (arg1 instanceof String && arg0 == java.lang.String.class) {
            return arg1;
        }/** 输入Date ,输出String */
        else if (arg1 instanceof java.util.Date) {
            try {
                SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                return df.format((java.util.Date) arg1);
            } catch (Exception e) {
                return null;
            }
        }/** 输入Date ,输出String */
        else if (arg1 instanceof java.sql.Date) {
            try {
                SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                return df.format((java.sql.Date) arg1);
            } catch (Exception e) {
                return null;
            }
        }
        return null;
    }

}

 

下面是BeanCopier:

 

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import net.sf.cglib.beans.BeanCopier;

import com.huateng.common.tools.subTools.DateConverterBeanCopier;
import com.huateng.common.tools.subTools.form.ProductFormVo;
import com.huateng.common.tools.subTools.form.ProductFormVo1;

/**
 * @author Jira
 *vo对象间的赋值操作
 *DateConverterBeanCopier 可以添加新的对象转换功能
 */
public class BeanCopierUtils {
    public static Map<String,BeanCopier> beanCopierMap = new HashMap<String,BeanCopier>();
    
    public static void copyProperties(Object source, Object target){
        String beanKey =  generateKey(source.getClass(), target.getClass());
        BeanCopier copier =  null;
        if(!beanCopierMap.containsKey(beanKey)){
             copier = BeanCopier.create(source.getClass(), target.getClass(), true);
             beanCopierMap.put(beanKey, copier);
        }else{
             copier = beanCopierMap.get(beanKey);
        }
        copier.copy(source, target, new DateConverterBeanCopier());
    }   
    private static String generateKey(Class<?> class1,Class<?>class2){
        return class1.toString() + class2.toString();
    }
    
    public static void main(String...strings){
        ProductFormVo pf;
        Long l=System.currentTimeMillis();
        for (int i = 0; i < 100000; i++) {
            ProductFormVo1 p = new ProductFormVo1();
            p.setArticleId("a");
            p.setCreateStamp(new Date());
            p.setThruDate("2000-11-11 12:00:00");
            pf = new ProductFormVo();
            BeanCopierUtils.copyProperties(p, pf);
        }
        System.out.println(System.currentTimeMillis()-l);
//        System.out.println(pf.getArticleId());
//        System.out.println(pf.getCreateStamp());
//        System.out.println(ConvertTools.formatDataStyle3(pf.getThruDate()));
    }
}

 它用到的DateConverterBeanCopier:

 

import java.text.ParseException;
import java.text.SimpleDateFormat;

/**
 * @author Jira
 *
 */
public class DateConverterBeanCopier implements net.sf.cglib.core.Converter
{
    public Object convert(Object arg1, Class arg0, Object context){
        if (arg1 instanceof String && arg0 != java.lang.String.class) {
            String p = (String) arg1;
            if (p == null || p.trim().length() == 0) {
                return null;
            }
            try {
                SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                return df.parse(p.trim());
            } catch (Exception e) {
                try {
                    SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
                    return df.parse(p.trim());
                } catch (ParseException ex) {
                    return arg1;
                }
            }
        }/** 输入String ,输出String */
        else if (arg1 instanceof String && arg0 == java.lang.String.class) {
            return arg1;
        }/** 输入Date ,输出String */
        else if (arg1 instanceof java.util.Date) {
            try {
                SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                return df.format((java.util.Date) arg1);
            } catch (Exception e) {
                return null;
            }
        }/** 输入Date ,输出String */
        else if (arg1 instanceof java.sql.Date) {
            try {
                SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                return df.format((java.sql.Date) arg1);
            } catch (Exception e) {
                return null;
            }
        }
        return null;
    }
}

 

<think>我们讨论的是在Java中循环复制一个对象的属性到另一个对象。根据之前的讨论,有几种方法可以实现,但用户特别提到“循环地”,这可能意味着在循环中对多个对象进行复制,或者是指通过循环属性来复制。然而,在Java中,我们通常不会显式地循环属性(通过反射循环字段)来复制,而是使用现有的工具方法,因为手动循环字段需要考虑很多因素(如访问权限、类型换等),而且效率较低。 但是,根据引用[1]引用[2],我们可以使用BeanUtils这样的工具来复制属性,它们内部使用了反射,实际上就是循环遍历属性并复制。另外,引用[3]提到了深拷贝的一种方法(序列化),但这里用户可能只需要浅拷贝。 因此,针对用户的问题,我们可以理解为:如何在Java中高效地将一个对象的属性复制到另一个对象(可能是批量复制,也可能是单个对象复制)。考虑到用户提到“循环”,可能是在一个集合中循环复制多个对象。 根据引用[5],我们有一个场景:将List<UserA>复制到List<UserB>,其中UserAUserB有部分相同属性。这可以看作是在循环中复制每个对象。 下面我将提供几种方法: 1. 使用Spring的BeanUtils在循环中复制单个对象 2. 使用Java 8的Stream API进行批量复制 3. 使用MapStruct进行编译时生成的映射(高效且类型安全) 方法1:使用Spring BeanUtils(适合单个对象复制,循环中多次调用) 假设我们有两个类,UserA(源对象UserB(目标对象),它们有一些相同名称类型的属性。 在循环中复制: ```java List<UserA> sourceList = ... // 源对象列表 List<UserB> targetList = new ArrayList<>(sourceList.size()); for (UserA source : sourceList) { UserB target = new UserB(); BeanUtils.copyProperties(source, target); targetList.add(target); } ``` 方法2:使用Java 8 Stream ```java List<UserB> targetList = sourceList.stream() .map(source -> { UserB target = new UserB(); BeanUtils.copyProperties(source, target); return target; }) .collect(Collectors.toList()); ``` 方法3:使用MapStruct(推荐用于高性能场景) 首先定义一个映射接口: ```java @Mapper public interface UserMapper { UserMapper INSTANCE = Mappers.getMapper(UserMapper.class); @Mapping(target = "someField", ignore = true) // 如果需要忽略某些字段 UserB toUserB(UserA source); } ``` 然后在循环中使用: ```java List<UserB> targetList = sourceList.stream() .map(UserMapper.INSTANCE::toUserB) .collect(Collectors.toList()); ``` 或者直接使用循环: ```java List<UserB> targetList = new ArrayList<>(); for (UserA source : sourceList) { targetList.add(UserMapper.INSTANCE.toUserB(source)); } ``` 注意:MapStruct在编译时会生成实现类,因此没有反射开销,性能接近手写代码。 如果用户需要深拷贝,那么需要确保嵌套对象也被复制。引用[3]提到通过序列化实现深拷贝,但要注意所有涉及的对象都必须实现Serializable接口。 深拷贝示例(使用Apache Commons Lang序列化工具): ```java import org.apache.commons.lang3.SerializationUtils; // 假设UserA实现了Serializable List<UserA> sourceList = ...; List<UserA> deepCopyList = new ArrayList<>(); for (UserA source : sourceList) { deepCopyList.add(SerializationUtils.clone(source)); } ``` 但是,这种方法会复制整个对象图(包括所有嵌套对象),而且性能较低。 总结: 1. 对于简单的属性复制(浅拷贝),使用Spring BeanUtils在循环中复制每个对象。 2. 对于需要高性能的场景,使用MapStruct。 3. 对于深拷贝,使用序列化(如Apache Commons Lang的SerializationUtils)或手动复制嵌套对象。 根据引用[1],我们还可以自定义换器来处理类型不匹配的问题,但上述方法中,MapStruct可以很方便地处理类型换(通过@Mapping配置)。 请根据实际需求选择合适的方法。 相关问题: 1. 如何实现Java对象的深拷贝(Deep Copy)? 2. Spring BeanUtilsApache BeanUtils的主要区别是什么? 3. 对象属性复制时如何处理类型不匹配的问题(如DateString)? 4. MapStruct在大型项目中如何配置使用? 5. 对象复制时如何优雅地忽略`null`值?</think>在Java中循环复制对象属性值到另一个对象,可以通过以下几种高效方式实现。这些方法都利用了Java的反射机制或工具库来简化操作,特别适合批量处理场景: ### 方法1:使用Spring BeanUtils(推荐) ```java import org.springframework.beans.BeanUtils; // 源对象列表 List<SourceObject> sourceList = ... // 目标对象列表 List<TargetObject> targetList = new ArrayList<>(); for (SourceObject source : sourceList) { TargetObject target = new TargetObject(); // 核心复制操作(属性名类型需匹配) BeanUtils.copyProperties(source, target); targetList.add(target); } ``` **特点**: - 自动匹配同名属性 - 浅拷贝(嵌套对象复制引用) - 排除属性:`BeanUtils.copyProperties(source, target, "id", "createTime")`[^1] ### 方法2:Apache Commons BeanUtils ```java import org.apache.commons.beanutils.BeanUtils; for (SourceObject source : sourceList) { TargetObject target = new TargetObject(); // 注意参数顺序:目标对象在前 BeanUtils.copyProperties(target, source); targetList.add(target); } ``` **依赖**: ```xml <dependency> <groupId>commons-beanutils</groupId> <artifactId>commons-beanutils</artifactId> <version>1.9.4</version> </dependency> ``` ### 方法3:手动反射实现(无依赖) ```java for (SourceObject source : sourceList) { TargetObject target = new TargetObject(); // 获取所有声明字段 Field[] fields = source.getClass().getDeclaredFields(); for (Field field : fields) { field.setAccessible(true); // 允许访问私有字段 Object value = field.get(source); // 获取源对象值 // 设置到目标对象(需处理异常) Field targetField = target.getClass().getDeclaredField(field.getName()); targetField.setAccessible(true); targetField.set(target, value); } targetList.add(target); } ``` **注意**: - 需处理`IllegalAccessException``NoSuchFieldException` - 性能较低,适合特殊场景[^4] ### 方法4:使用MapStruct(高性能) ```java @Mapper public interface ObjectMapper { ObjectMapper INSTANCE = Mappers.getMapper(ObjectMapper.class); TargetObject toTarget(SourceObject source); } // 使用 for (SourceObject source : sourceList) { targetList.add(ObjectMapper.INSTANCE.toTarget(source)); } ``` **优势**: - 编译时生成代码,无运行时反射开销 - 支持复杂类型换 - 性能接近手写代码[^1] ### 关键注意事项 1. **属性匹配规则**: - 默认按**同名属性**复制 - 不同类型需自定义换器(如DateString) 2. **深浅拷贝**: - 以上均为浅拷贝(嵌套对象共享引用) - 深拷贝需序列化实现(引用[^3]): ```java ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(source); ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); TargetObject target = (TargetObject) new ObjectInputStream(bis).readObject(); ``` 3. **性能优化**: - 高频场景用MapStruct或cglib BeanCopier - 低频场景用Spring BeanUtils 4. **特殊处理**: - 忽略null值:Spring的`BeanUtils.copyProperties()`会覆盖目标值 - 排除字段:通过参数显式排除 - 驼峰/下划线换:需自定义命名策略(引用[^2]) ### 最佳实践 ```mermaid graph TD A[开始循环] --> B{属性数量} B -->|少量| C[手动Setter] B -->|大量| D{性能要求} D -->|高| E[MapStruct] D -->|中| F[Spring BeanUtils] D -->|低| G[Apache BeanUtils] C --> H[结束] E --> H F --> H G --> H ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值