我可以使用 Lombok @Builder 传递父类作为参数吗?

问题描述 投票:0回答:3

我想创建一个新的

Child
实例传递一个
Parent
和其他附加参数。

例如如果我有:

public class Parent {
    public String param1;
    public String param2;
    // many parameters
    public String paramN;
}

public class Child extends Parent {
    public String subValue;
}

使用 lombok,是否有一个构建器可以让我创建一个

Child
实例,将
Parent
和缺失值作为参数传递?

如果我能写这样的话会更容易:

Parent p = Parent.builder()
                 .param1("a")
                 .param2("b")
                 // many parameters
                 .paramN("b")
                 .build();
Child c = Child.builder(p).subValue("c").build();
java lombok
3个回答
3
投票

常规的

@Builder
在这里是不够的,因为你正在处理类层次结构。然而,
@SuperBuilder
正是为这种情况而制作的。

@SuperBuilder
生成加载了泛型的复杂代码。如果不深入了解
@SuperBuilder
生成的代码,这使得该解决方案难以理解。你应该考虑一下这是否值得。

这是解决方案(Lombok >= 1.18.16):

@SuperBuilder(toBuilder = true)
public static class Parent {
    public String param1;
    public String param2;
    // many parameters
    public String paramN;

    public abstract static class ParentBuilder<C extends Parent, B extends Parent.ParentBuilder<C, B>> {
        protected B $fillValuesFromParent(Parent instance) {
            $fillValuesFromInstanceIntoBuilder(instance, this);
            return self();
        }
    }
}

@SuperBuilder(toBuilder = true)
public static class Child extends Parent {
    public String subValue;

    public static ChildBuilder<?, ?> toBuilder(Parent p) {
        return new ChildBuilderImpl().$fillValuesFromParent(p);
    }
}

toBuilder
上的新
Child
方法创建了一个新的
ChildBuilderImpl
(调用
Child
时将创建一个
build()
实例)。为了从给定的
Parent p
中填充值,它从
$fillValuesFromParent
调用新的
ParentBuilder
方法。此方法进一步委托对方法
$fillValuesFromInstanceIntoBuilder
的调用,该方法由 Lombok 生成并执行将字段值实际复制到新构建器实例。

还要注意方法上的

$
前缀。这基本上是说:我是一个实现细节;除非你知道自己在做什么,否则不要使用我,我可能会在下一个 Lombok 版本上中断,恕不另行通知。


2
投票

其他答案并不能真正使您的客户端代码简单地重用您已有的父实例。但这是可行的。你有两个选择:

困难的是编写您想要的自定义注释。您甚至可以使其通用,以便它适用于具有父/子层次结构的任何类。看看这个example。如果您有勇气,可以在 Lombok 的 github 页面上提出功能请求。

选项二是为孩子编写自定义生成器。请参阅此处的示例。在初始化步骤的自定义构建器中,您将读取传入的父实例,并仅设置继承的字段。


0
投票

另一种可能对关注此线程的人有用的方法是利用像 MapperStruct 这样的映射库。使用 MapperStruct,您可以定义一个映射器接口,如下所示:

@Mapper
public interface PetMapper {
   Dog toDog(Pet pet);
}

定义映射器后,您可以像这样在代码中使用它:


private static final PetMapper mapper;

...

public void myFunction(Pet pet) {
    mapper.toDog(pet).toBuilder().id("My ID").build();
}


private static final PetMapper mapper;

...

public void myFunction(Pet pet) {
    mapper.toDog(pet).setId("My ID");
}

这样,您可以轻松地在不同对象之间进行映射,并根据需要修改生成的对象。

更新

这里的想法是让映射器处理从父类(或其兄弟类)创建新对象子对象,然后使用该映射对象,您可以使用其设置器来设置自定义属性,或者您可以使用 toBuilder( )(请注意,调用 .build() 后 toBuilder 将创建一个新对象)。

© www.soinside.com 2019 - 2024. All rights reserved.