You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Lombok @SuperBuilder实现子类对象转换并保留父类字段

问题解答

Lombok原生支持情况

Lombok的@SuperBuilder目前不支持直接通过父类Builder跨子类传递状态,哪怕父类是抽象类也不行。原因是每个子类的Builder都是Lombok自动生成的专属实现:ChildA.toBuilder()返回的是ChildA.ChildABuilder(继承自Parent.ParentBuilder),但ChildB的Builder并没有提供方法来接收并拷贝这个ParentBuilder里的字段值——Lombok没有为跨子类的属性拷贝生成对应的逻辑。

可行解决方案

方案1:反射工具类(适配父类字段增删)

写一个通用工具类,通过反射读取父类的所有字段,将源实例的父类字段值拷贝到目标子类的Builder中。这种方式不需要修改现有类结构,且父类字段增删时自动适配:

import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class ParentFieldCopier {
    // 拷贝父类字段到目标Builder
    @SuppressWarnings("unchecked")
    public static <B> B copyParentFields(Parent source, B targetBuilder) {
        Field[] parentFields = Parent.class.getDeclaredFields();
        for (Field field : parentFields) {
            field.setAccessible(true);
            try {
                // 拼接Builder的setter方法名,比如parentProp -> setParentProp
                String setterName = "set" + capitalize(field.getName());
                Method setter = targetBuilder.getClass().getMethod(setterName, field.getType());
                setter.invoke(targetBuilder, field.get(source));
            } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                throw new RuntimeException("Failed to copy parent field: " + field.getName(), e);
            }
        }
        return targetBuilder;
    }

    // 首字母大写工具方法
    private static String capitalize(String name) {
        if (name == null || name.isEmpty()) return name;
        return name.substring(0, 1).toUpperCase() + name.substring(1);
    }
}

使用方式:

ChildA childA = ChildA.builder().parentProp("parentValue").childAProp("childA").build();

ChildB childB = ParentFieldCopier.copyParentFields(childA, ChildB.builder())
        .childBProp("childB")
        .build();

方案2:自定义父类Builder方法(类型安全但需同步字段)

如果父类字段变动不频繁,可以在父类的Builder中添加自定义方法,让子类Builder继承该方法来拷贝父类字段:

@NonFinal
@SuperBuilder(toBuilder = true)
public abstract class Parent {
    String parentProp;

    // 父类Builder添加从Parent实例拷贝字段的方法
    public abstract static class ParentBuilder<C extends Parent, B extends ParentBuilder<C, B>> {
        public B fromParent(Parent parent) {
            this.parentProp = parent.parentProp;
            return self();
        }
    }
}

使用方式:

ChildA childA = ChildA.builder().parentProp("parentValue").childAProp("childA").build();

ChildB childB = ChildB.builder()
        .fromParent(childA)
        .childBProp("childB")
        .build();

⚠️ 注意:这种方式需要在父类新增字段时,手动同步fromParent方法的代码,无法自动适配字段变化。

方案3:第三方库MapStruct(最优推荐)

如果允许引入第三方库,MapStruct是更优的选择:它会在编译期自动生成类型安全的拷贝代码,支持继承结构,父类字段增删时自动更新拷贝逻辑,且无需反射或手动维护代码。

首先添加MapStruct依赖(以Maven为例):

<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct</artifactId>
    <version>1.5.5.Final</version>
</dependency>
<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct-processor</artifactId>
    <version>1.5.5.Final</version>
    <scope>provided</scope>
</dependency>

定义转换器接口:

import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;

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

    // 自动拷贝父类字段,忽略子类独有的childBProp(后续手动设置)
    @Mapping(target = "childBProp", ignore = true)
    ChildB convertChildAToChildB(ChildA childA);

    // 重载方法,直接设置childBProp
    default ChildB convertChildAToChildB(ChildA childA, String childBProp) {
        ChildB childB = convertChildAToChildB(childA);
        childB.setChildBProp(childBProp);
        return childB;
    }
}

使用方式:

ChildA childA = ChildA.builder().parentProp("parentValue").childAProp("childA").build();

ChildB childB = ParentChildConverter.INSTANCE.convertChildAToChildB(childA, "childB");

方案对比

方案自动适配父类字段变化类型安全性能代码维护成本
反射工具类✅❌一般低(仅维护工具类)
自定义父类Builder方法❌✅优中(字段变化需同步)
MapStruct第三方库✅✅优极低(编译期自动生成)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 22:04:59