如何在Lombok构建器中的构造函数之后运行代码

时间:2016-06-22 12:55:11

标签: java lombok

我有一个类,我想使用Lombok.Builder,我需要预处理一些参数。像这样:

@Builder
public class Foo {
   public String val1;
   public int val2;
   public List<String> listValues;

   public void init(){
       // do some checks with the values.
   }
}

通常我会在NoArg构造函数上调用init(),但是对于生成的构建器,我无法这样做。有没有办法让生成的构建器调用此init?例如,build()会生成如下代码:

public Foo build() {
   Foo foo = Foo(params....)
   foo.init();
   return foo;
}

我知道我可以手动编码all args构造函数,构建器会通过它调用它,我可以在那里调用init

但这是一个次优解决方案,因为我的课程可能偶尔会添加新字段,这也意味着更改构造函数。

4 个答案:

答案 0 :(得分:8)

经过多次试验和结束错误后,我找到了合适的解决方案:扩展生成构建器并自己调用init()

示例:

@Builder(toBuilder = true, builderClassName = "FooInternalBuilder", builderMethodName = "internalBuilder")
public class Foo {

   public String val1;
   public int val2;
   @Singular public List<String> listValues;

   void init() {
      // perform values initialisation
   }

   public static Builder builder() {
      return new Builder();
   }

   public static class Builder extends FooInternalBuilder {

      Builder() {
         super();
      }

      @Override public Foo build() {
         Foo foo = super.build();
         foo.init();
         return foo;
      }
   }
}

答案 1 :(得分:5)

@Builder中,您可以手动添加构造函数,让它进行初始化,并将rsync -xyz --foo=bar some_files user@remote.com:remote_dir 放在构造函数上。我知道您已经知道这一点,但我认为这是正确的解决方案,您不会忘记添加参数,因为您确实想要在构建器中使用代码。

披露:我是一名lombok开发者。

答案 2 :(得分:4)

我偶然发现了同样的问题。但另外,我想向构建器添加一个方法buildOptional(),以便在每次需要时不重复Optional.of(Foo)。这不适用于之前发布的方法,因为链式方法返回FooInternalBuilder个对象;并将buildOptional()放入FooInternalBuilder将错过init()中的Builder方法执行...

另外,我个人不喜欢2个构建器类的存在。

以下是我所做的事情:

@Builder(buildMethodName = "buildInternal")
@ToString
public class Foo {
    public String val1;
    public int val2;
    @Singular  public List<String> listValues;

    public void init(){
        // do some checks with the values.
    }    

    /** Add some functionality to the generated builder class */
    public static class FooBuilder {
        public Optional<Foo> buildOptional() {
            return Optional.of(this.build());
        }

        public Foo build() {
            Foo foo = this.buildInternal();
            foo.init();
            return foo;
        }
    }
}

您可以使用以下主要方法进行快速测试:

public static void main(String[] args) {
    Foo foo = Foo.builder().val1("String").val2(14)
            .listValue("1").listValue("2").build();
    System.out.println(foo);

    Optional<Foo> fooOpt = Foo.builder().val1("String").val2(14)
            .listValue("1").listValue("2").buildOptional();
    System.out.println(fooOpt);
}

这样做让我们添加我想要的内容:

  • 添加init()方法,该方法在每个对象构建后自动执行
  • 添加新字段不需要额外的工作(就像单独编写的构造函数一样)
  • 可以添加其他功能(包括init()执行)
  • 保留完整 @Builder注释带来的标准功能
  • 不要公开其他构建器类

即使你在我想分享这个解决方案之前解决了你的问题。它有点短,并添加了(对我而言)不错的功能。

答案 3 :(得分:0)

这对我有用,不是一个完整的解决方案,但快速简便。

@Builder
@AllArgsConstructor
public class Foo {
   @Builder.Default
   int bar = 42;
   Foo init() {
      // perform values initialisation
     bar = 451;   // replaces 314
     return foo;
   }
   static Foo test() {
       return new FooBuilder()  // defaults to 42
           .bar(314)  // replaces 42 with 314
           .build()
           .init();   // replaces 314 with 451
   }
}