You need to enable JavaScript to run this app. 如何批量转换并赋值Java对象属性,避免手动逐个调用set方法?
优惠活动
大模型
产品
解决方案
定价
更多

如何批量转换并赋值Java对象属性,避免手动逐个调用set方法?

解决方案

方案1:JDK原生反射实现(无第三方依赖,实现最简单)

直接通过JDK自带的反射能力遍历两个对象的所有目标字段,统一应用转换逻辑:

import java.lang.reflect.Field;
import java.math.BigDecimal;

public class SummaryConverter {
    public static <T> void convertAllNumericFields(T current, T previous) {
        Field[] fields = current.getClass().getDeclaredFields();
        for (Field field : fields) {
            // 自定义过滤规则:只处理数值类型字段,排除不需要计算的字段(如主键、月份字段等)
            Class<?> fieldType = field.getType();
            if ((fieldType != int.class && fieldType != Integer.class
                && fieldType != long.class && fieldType != Long.class
                && fieldType != double.class && fieldType != Double.class
                && fieldType != BigDecimal.class)
                || "id".equals(field.getName())
                || "month".equals(field.getName())) {
                continue;
            }
            field.setAccessible(true);
            try {
                Object currentVal = field.get(current);
                Object previousVal = field.get(previous);
                // 调用你原有的自定义转换方法
                Object convertedVal = NumUtil.getFormattedValue(currentVal, previousVal);
                field.set(current, convertedVal);
            } catch (IllegalAccessException e) {
                throw new RuntimeException("字段转换失败:" + field.getName(), e);
            }
        }
    }
}

改造后的业务代码:

public Summary addSummary(Summary current) {
   Summary previous = getPreviousSummary(getPreviousMonth());
   // 一行完成所有字段转换
   SummaryConverter.convertAllNumericFields(current, previous);
   return current;
}

提示:如果Summary类存在继承自父类的字段,需要补充递归遍历父类字段的逻辑,直到遍历到Object类为止,避免父类字段被漏掉。

方案2:Spring BeanWrapper实现(适合已集成Spring的项目,代码更简洁)

如果项目已经依赖Spring框架,可以用Spring提供的BeanWrapper工具,不需要自己处理字段访问、类型适配等基础问题:

import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import java.beans.PropertyDescriptor;

public class SummaryConverter {
    public static void convertWithBeanWrapper(Summary current, Summary previous) {
        BeanWrapper currentWrapper = new BeanWrapperImpl(current);
        BeanWrapper previousWrapper = new BeanWrapperImpl(previous);
        for (PropertyDescriptor pd : currentWrapper.getPropertyDescriptors()) {
            String fieldName = pd.getName();
            // 过滤不需要处理的属性
            if ("class".equals(fieldName) || "id".equals(fieldName) || "month".equals(fieldName)) {
                continue;
            }
            // 只处理可读可写的数值类型属性
            if (pd.getReadMethod() == null || pd.getWriteMethod() == null 
                || !Number.class.isAssignableFrom(pd.getPropertyType())) {
                continue;
            }
            Object currentVal = currentWrapper.getPropertyValue(fieldName);
            Object previousVal = previousWrapper.getPropertyValue(fieldName);
            Object convertedVal = NumUtil.getFormattedValue(currentVal, previousVal);
            currentWrapper.setPropertyValue(fieldName, convertedVal);
        }
    }
}

方案3:MapStruct实现(性能最优,编译期校验,适合生产高并发场景)

如果对性能要求高,不想承担反射的运行时开销,可以用MapStruct编译期自动生成转换代码,性能和手动编写set方法几乎一致,同时支持编译期字段合法性校验:

import org.mapstruct.Context;
import org.mapstruct.Mapper;
import org.mapstruct.Named;
import org.mapstruct.TargetProperty;
import org.mapstruct.factory.Mappers;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;

@Mapper
public interface SummaryMapper {
    SummaryMapper INSTANCE = Mappers.getMapper(SummaryMapper.class);

    // 单条注解即可适配所有字段,不需要逐个配置映射关系
    @org.mapstruct.Mapping(target = ".", source = "current", qualifiedByName = "convertField")
    Summary convert(Summary current, @Context Summary previous);

    @Named("convertField")
    default Object convertField(Summary current, @Context Summary previous, @TargetProperty String fieldName) {
        BeanWrapper currentWrapper = new BeanWrapperImpl(current);
        BeanWrapper previousWrapper = new BeanWrapperImpl(previous);
        return NumUtil.getFormattedValue(currentWrapper.getPropertyValue(fieldName), previousWrapper.getPropertyValue(fieldName));
    }
}

业务代码使用方式:

public Summary addSummary(Summary current) {
   Summary previous = getPreviousSummary(getPreviousMonth());
   return SummaryMapper.INSTANCE.convert(current, previous);
}

内容的提问来源于stack exchange,提问作者Mankind1023

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.11 08:03:03