同属性类之间复制

本文介绍了一种在Java中实现不同Bean之间的属性复制的方法,特别关注于如何处理原Bean字段少于目标Bean字段的情况,并提供了将JSON字符串转换为List<Map<String, Object>>的具体实现。

原Bean: source
目标Bean: target
如果copy的话需要注意
1、同属性之间类的复制,我这里source的String对应到target为List<Map<String,Object>>>的话,做了特殊处理
2、场景是原Bean的字段少于目标Bean的字段

    private String firstSettleType;
    private String lastSettleType;
    private int firstSettleDate;
    private int lastSettleDate;
    private BigDecimal orderAmount;
    private String currency;
    private String remark;
    private String pledgeBonds;		//json串

转为

	private String lastSettleType;
    private int firstSettleDate;
    private int lastSettleDate;
    private BigDecimal orderAmount;
    private String currency;
    private String remark;
    private List<Map<String,Object>> pledgeBonds;
package com.hundsun.cj.util;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hundsun.cj.command.BankOutrightIssueCommand;
import com.hundsun.cj.command.ExchangeRepoIssueCommand;
import com.hundsun.cj.command.PrimaryOrderIssueCommand;
import com.hundsun.cj.common.CommonException;
import com.hundsun.cj.domain.request.BankOutrightIssueRequest;
import com.hundsun.cj.domain.request.ExchangeRepoIssueRequest;
import com.hundsun.cj.domain.request.PrimaryOrderIssueRequest;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;
import java.util.function.DoubleToIntFunction;

/**
 * bean相关的工具类
 * @author luzh32717
 * @date 2020/10/14 9:36
 * @version 1.0
 */
public class MyBeanUtil {
    /**
     * 复制属性相同的两个类, 前提是两个类都重载了setter/getter方法
     * @param source 源类
     * @param target 目标类
     * @return T 目标类型
     * @throws CommonException 公共异常
     */
    public static<T> T copy(Object source,T target) throws CommonException {
        if(source == null || target == null){
            throw new CommonException("-1","同属性bean复制时入参不能为空!");
        }
        Field[] declaredFields = source.getClass().getDeclaredFields();
        Class<?> targetClass = target.getClass();
        if(declaredFields.length <= 0 || declaredFields.length > targetClass.getDeclaredFields().length){
            throw new CommonException("-1","同属性bean复制时入参违法!");
        }
        for(Field declaredField : declaredFields){
            declaredField.setAccessible(true);
            Field targetField = null;
            try {
                targetField = targetClass.getDeclaredField(declaredField.getName());
                targetField.setAccessible(true);
                if(targetField.getType().equals(declaredField.getType())){
                    targetField.set(target,declaredField.get(source));
                }//当存在Request为String但Command中类型为List的相同名称的字段
                else if(targetField.getType().toString().contains("java.util.List") && declaredField.getType().toString().contains("java.lang.String")){
                    targetField.set(target,jsonToObjectList((String) declaredField.get(source)));
                }else{
                    throw new CommonException("-1","同属性bean复制时存在名称相同但类型不同的字段");
                }
            } catch (NoSuchFieldException e) {
                LOGGER.debug(declaredField.getName()+"没找到");
            } catch (IllegalAccessException e){
                throw new CommonException("-1","同属性bean复制时: " + e.getMessage());
            }
        }
        return target;
    }

    /**
     * 将json串转换为List<Map<String,Object>>>
     * @param json json串
     * @return List<Map<String,Object>>>
     * @throws CommonException 公共类型的异常
     */
    public static List<Map<String,Object>> jsonToObjectList(String json) throws CommonException{
        List<Map<String,Object>> list = null;
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            list = objectMapper.readValue(json, new TypeReference<List<Map<String,Object>>>(){});
        } catch (IOException e) {
            throw new CommonException("-1","String字段转List<Map<String,Object>>>字段异常: " + e.getMessage());
        }
        return list;
    }

    public static void main(String[] args) throws CommonException {
        PrimaryOrderIssueRequest primaryOrderIssueRequest = new PrimaryOrderIssueRequest();
        primaryOrderIssueRequest.setCombNo("1");
        primaryOrderIssueRequest.setOrderPrices("[{\"price\":\"10.12\",\"amount\":\"500000\"},{\"price\":\"10.18\",\"amount\":\"500000\"}]");
        PrimaryOrderIssueCommand copy = copy(primaryOrderIssueRequest, new PrimaryOrderIssueCommand());
        System.out.println(copy);
        System.out.println(copy.getOrderPrices().toString());
    }
}
package com.hundsun.cj.common;

import com.hundsun.cj.constant.Errors;
import lombok.Data;

@Data
public class CommonException extends Exception{
    private String  exceptionCode;
    private String exceptionMsg;

    public CommonException(){
        super();
    }
    public CommonException(String exceptionMsg){
        super(exceptionMsg);
    }
    public CommonException(String exceptionCode,String exceptionMsg){
        this(exceptionMsg);
        this.exceptionMsg = exceptionMsg;
        this.exceptionCode = exceptionCode;
    }
    public CommonException(Errors errors){
        this(errors.getCode(),errors.getMsg());
    }
}

package com.hundsun.cj.constant;

/**
 * @author hspcadmin
 */

public enum Errors{
     /**
      *   Http调用异常
      */
     ERROR_HTTP_REQUEST("000001", "发送报文失败/解析报文失败"),
     ERROR_GET_RES_NULL("000002", "发送Get的Http请求异常.response为空"),
     ERROR_POST_RES_NULL("000002", "发送Post的Http请求异常.response为空"),
     ERROR_GET_EXCEPTION("000003", "发送Get请求时发生异常.异常信息:"),
     ERROR_POST_EXCEPTION("000004", "发送Post请求时发生异常.异常信息:"),
     ERROR_TRANS_EXCEPTION("000005", "数据转换发生异常.异常信息:"),
     ERROR_CJHX_AUTH_FAIL("4001", "未经身份认证"),
     ERROR_CJHX_NOT_METHOD("4002", "请求方法不支持"),
     ERROR_CJHX_NOT_RESOURCE("4004", "请求的资源不存在"),
     ERROR_CJHX_NOT_CLIENT("4006", "clientId参数不存在"),
     ERROR_CJHX_NOT_SIGN("4008", "signature参数不存在"),
     ERROR_CJHX_TIMEOUT("4009", "请求超时"),
     ERROR_CJHX_NOT_TIMESTMP("4010", "时间戳参数不存在"),
     ERROR_CJHX_SIGN_FAIL("4011", "签名校验失败"),
     ERROR_CJHX_SERVICE_FAIL("5000", "服务内部错误"),
     ERROR_CJHX_SERVICE_STOP("5001", "接口暂时服务访问,请重试")
     ;


     private String code;
     private String msg;

     Errors(String code, String msg) {
          this.code = code;
          this.msg = msg;
     }

     public String getCode() {
          return this.code;
     }

     public String getMsg() {
          return this.msg;
     }

     public static String getMsg(String code) {
          for (Errors ele : values()) {
               if(ele.getCode().equals(code)) {
                    return ele.getMsg();
               }
          }
          return "未定义错误信息";
     }
}

<think>好的,用户想要在Java复制列表之间属性的工具或工具库。我需要先理解用户的具体需求。用户提到的是“复制列表之间属性”,可能是指将一个列表中的对象的属性复制到另一个列表中的不对象上,例如源列表和目标列表中的对象型不,但某些属性名称或型相,需要进行映射复制。 首先,我应该考虑常见的Java工具库中是否有这样的功能。常见的工具库包括Apache Commons BeanUtils、Spring Framework的BeanUtils,以及Dozer等映射框架。用户可能希望使用现有的工具,而不是自己编写代码。 然后,我需要回忆相关的引用内容。用户提供的引用中提到了JDK的java.util包,特别是集合库,还有Spring的BeanUtils、ClassUtils、ReflectionUtils,以及Apache Commons的DigestUtils。其中,引用[2]提到了BeanUtils.findDeclaredMethod和PropertyDescriptor的使用,这可能与属性复制相关。引用[3]提到了java.util.Objects,但主要是基Object的方法。引用[4]提到了Apache Commons的DigestUtils,可能不相关。 接下来,我应该分析可能的解决方案。对于列表属性复制,通常的做法是遍历源列表,对每个元素复制属性到目标元素,然后将目标元素添加到新列表中。这里需要两个步骤:对象属性复制和列表遍历处理。 在对象属性复制方面,Spring的BeanUtils.copyProperties方法常用于复制属性。Apache Commons BeanUtils也有似的方法。如果属性名称或型不一致,可能需要更高级的映射工具,比如Dozer或ModelMapper,但这些可能需要额外的配置或映射定义。 对于列表处理,可以使用Java 8的Stream API结合属性复制工具,例如使用stream().map()来处理每个元素,然后收集到新列表中。或者使用Apache Commons Collections等工具库中的集合处理方法。 用户可能需要的是一个工具,将这两个步骤封装起来,提供一个简单的方法,如ListUtils.copyProperties(sourceList, targetClass),自动完成列表的遍历和属性复制。 现在需要检查用户提供的引用是否有相关内容。引用[2]中的Spring BeanUtils和PropertyDescriptor可能相关,因为它们可以用于动态获取和设置属性。例如,使用BeanUtils.findPropertyForMethod来获取属性描述符,进而复制属性。但用户需要的是列表级别的复制,可能需要结合这些工具自行封装。 此外,引用[4]提到了org.apache.commons.collections.ListUtils,但不确定是否有直接的属性复制方法。可能需要查看Apache Commons BeanUtils的BeanToList似工具,但常见的可能是需要自己实现循环。 综合来看,可能的推荐包括: 1. 使用Spring Framework的BeanUtils.copyProperties结合Stream API: List<Target> targetList = sourceList.stream() .map(source -> { Target target = new Target(); BeanUtils.copyProperties(source, target); return target; }) .collect(Collectors.toList()); 2. Apache Commons BeanUtils的PropertyUtils.copyProperties方法,用法似。 3. 使用ModelMapper库,它支持列表的映射: ModelMapper modelMapper = new ModelMapper(); List<Target> targetList = sourceList.stream() .map(source -> modelMapper.map(source, Target.class)) .collect(Collectors.toList()); 但需要添加ModelMapper依赖。 4. 如果属性名称不,可能需要使用DozerMapper,它支持XML或注解配置映射关系。 用户可能需要知道这些工具的存在以及基本用法,时指出需要处理异常,如型不匹配或属性不存在的情况。此外,需要注意性能问题,特别是在处理大型列表时,循环内的反射操作可能较慢,可以考虑使用缓存或预编译的映射。 在用户提供的引用中,Spring的BeanUtils和Apache的BeanUtils都被提及,因此应该优先推荐这些,尤其是Spring的BeanUtils,因为它在Spring应用中广泛使用,且可能更常见。而ModelMapper或Dozer可能需要额外引入依赖,但功能更强大。 总结回答的结构应该是:先介绍手动循环结合属性复制的工具方法,然后列举常用的工具库,如Spring BeanUtils、Apache Commons BeanUtils、ModelMapper、Dozer等,并提供代码示例。时,提醒性能考虑和异常处理。</think>在Java中实现列表属性复制通常需要结合对象属性复制工具与集合处理,以下是常用工具及实现方式: ### 一、基础手动实现(适合简单场景) ```java public static <S, T> List<T> copyListProperties(List<S> source, Class<T> targetClass) { return source.stream().map(s -> { try { T t = targetClass.newInstance(); BeanUtils.copyProperties(s, t); // Spring BeanUtils return t; } catch (Exception e) { throw new RuntimeException("属性复制失败", e); } }).collect(Collectors.toList()); } ``` 使用示例: ```java List<UserDTO> userDTOList = copyListProperties(userList, UserDTO.class); ``` ### 二、主流工具库 #### 1. **Spring Framework BeanUtils** 适用于属性复制: ```java // 单个对象复制 UserDTO dto = new UserDTO(); BeanUtils.copyProperties(userEntity, dto); // 需要处理异常 // 列表复制 List<UserDTO> dtos = userEntities.stream() .map(entity -> { UserDTO dto = new UserDTO(); BeanUtils.copyProperties(entity, dto); return dto; }).collect(Collectors.toList()); ``` > 特性:仅复制名称和型相属性[^2] #### 2. **Apache Commons BeanUtils** ```java UserDTO dto = new UserDTO(); PropertyUtils.copyProperties(dto, userEntity); // 需要处理异常 ``` > 注意:方法参数顺序与Spring相反(目标在前,源在后)[^4] #### 3. **ModelMapper(推荐复杂映射)** 需添加依赖: ```xml <dependency> <groupId>org.modelmapper</groupId> <artifactId>modelmapper</artifactId> <version>2.4.4</version> </dependency> ``` 列表复制实现: ```java ModelMapper modelMapper = new ModelMapper(); List<UserDTO> dtos = modelMapper.map(userEntities, new TypeToken<List<UserDTO>>(){}.getType()); ``` 支持特性: - 深度映射(如`user.address.street`) - 型自动转换 - 自定义字段映射规则 #### 4. **Dozer(适合复杂对象树)** 需添加依赖: ```xml <dependency> <groupId>net.sf.dozer</groupId> <artifactId>dozer</artifactId> <version>5.5.1</version> </dependency> ``` 配置映射文件后使用: ```java Mapper mapper = DozerBeanMapperBuilder.buildDefault(); List<UserDTO> dtos = userEntities.stream() .map(entity -> mapper.map(entity, UserDTO.class)) .collect(Collectors.toList()); ``` ### 三、性能优化建议 1. **避免循环内反射**:使用字节码增强工具(如Javassist)预生成拷贝代码 2. **批量操作**:对10万级以上数据量建议使用并行流: ```java List<UserDTO> dtos = userEntities.parallelStream()... ``` 3. **对象池技术**:复用目标对象减少GC压力[^1] ### 四、特殊场景处理 #### 属性名称不一致时(ModelMapper示例): ```java modelMapper.addMappings(new PropertyMap<UserEntity, UserDTO>() { @Override protected void configure() { map(source.getCreateTime(), destination.registerTime); } }); ``` #### 忽略特定属性: ```java modelMapper.createTypeMap(UserEntity.class, UserDTO.class) .addMappings(mapper -> mapper.skip(UserDTO::setPassword)); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值