简体   繁体   中英

Is it possible to use Lombok @Builder, starting from static method?

I want Lombok to take care of my builder API, while also having a constructor to start with.

I started out with a constructor on the @Data class combined with @Builder(toBuilder = true) , but that left me with forcing invalid or dummy values on final fields as well as a less expressive fluent API. I finally solved my situation using a static method, but I'm hoping Lombok has a better solution for my use case.

API using toBuilder

fooHandler.accept(new TweakedFoo(Foo.class, Mode.QUICK).toBuilder()
          .mappingOutcomeFor(FooOutcome.class)
          .mappingOutcome(toEvent(BarOutcome.class))
          .build()));

API using static method

fooHandler.accept(tweakFoo(Foo.class, Mode.QUICK)
          .mappingOutcomeFor(FooOutcome.class)
          .mappingOutcome(toEvent(BarOutcome.class))
          .build()));

See how the second setup flows better?

Respective Lombok setup (simplified)

@Data
@Builder(toBuilder = true)
public class TweakedFoo {

    private final Class<Foo> from;
    private final Mode mode;
    private final Class<?> to;

    public TweakedFoo(Class<Foo> from, Mode mode) {
        this.from = from;
        this.mode = mode;
        this.to = null; // eww
    }
}

And:

@Data
@Builder(builderMethodName = "useTweakedFooDotTweakedFooInsteadPlease")
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class TweakedFoo {

    private final Class<Foo> from;
    private final Mode mode;
    private final Class<?> to;

    public static TweakedFooBuilder tweakFoo(Class<Foo> from, Mode mode) {
        return TweakedFoo.useTweakedFooDotTweakedFooInsteadPlease()
                         .from(from)
                         .mode(mode);
    }

}

The actual parameters don't make much sense here, but this setup illustrates my real-world use case.

Not only is the second approach more concise, it needs no dummy constructor field initialization and also it hides the constructor so you can't get an instance other than through the builder. However, the second approach requires me to obscure the builder starting method Lombok generates in favor of my own static method.

Is there a better way with Lombok?

You can customize your builder() method by simply implementing it yourself:

@Data
@Builder
public class TweakedFoo {
    // ...
    public static TweakedFooBuilder builder(Class<Foo> from, Mode mode) {
        return new TweakedFooBuilder()
            .from(from)
            .mode(mode);
    }
    // ...
}

Lombok will not generate another builder() method in this case, because it recognizes the existing method with the same name. If you want the method to be named differently, eg tweakFoo , use @Builder(builderMethodName="tweakFoo") .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM