2

I've a class which I don't have the ability to modify but would like to have a builder for it. I'm using Lombok.

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Getter
@Setter
@ToString
public class SampleClass {
    private String a;
    private String b;
}

To have a builder for this, I create a BuilderClass:

@Builder
public class SampleClassBuilder {
    private String x;
    private String y;

    public SampleClass build() {
        SampleClass sampleClass = new SampleClass();
        sampleClass.setA(x + "testX");
        sampleClass.setB(y + "textY");
        return sampleClass;
    }
}

To use it, I will need to do:

SampleClass sampleClass = SampleClassBuilder.builder().x("x -- ").y("y---").build().build();

Is there a way to override build method to return SampleClass to avoid doing build.build?

user1692342
  • 5,007
  • 11
  • 69
  • 128

2 Answers2

0

I do not think that Lombok can do this: return another object from Builder. It even cannot call super in the builder.

Probably you could define your own build not using Lombok:

public class SampleBuilder {
    private String x;
    private String y;

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

    private SampleBuilder() {
    }

    public SampleBuilder x(String x) {
        this.x = x;
        return this;
    }

    public SampleBuilder y(String y) {
        this.y = y;
        return this;
    }

    public SampleClass build() {
        SampleClass sampleClass = new SampleClass();
        sampleClass.setA(x + "testX");
        sampleClass.setB(y + "textY");
        return sampleClass;
    }
}

And in your client code, you can see Lombok's like usage of builder:

SampleClass obj = SampleBuilder.builder().x("x").y("y").build();
Oleg Cherednik
  • 17,377
  • 4
  • 21
  • 35
  • Yeah, I was thinking of writing a custom builder like how you mentioned, but wanted to know if there was any alternate way with Lombok. Guess I'll have to go with this option. – user1692342 May 23 '18 at 05:59
  • Anfortunately, Lombok is not so smart. It can do some very common tasks. – Oleg Cherednik May 23 '18 at 06:00
  • Yeah. The closest I got to was https://stackoverflow.com/questions/37968696/how-to-run-code-after-constructor-in-a-lombok-builder But then I can't change the return type while overriding – user1692342 May 23 '18 at 06:01
0

If you just need to have custom builder's setters (like .x(...) .y(...) but not custom .build()), you can just add SampleClassBuilder as static inner class to override some Lombok setter methods.

@Builder // <--- Put @Builder at the SampleClass itself, not at Builder class
@ToString
class SampleClass { // Lombok will internally create SampleClassBuilder

    private String x;
    private String y;
    private int a,b,c;
    private String z;

    public static class SampleClassBuilder{ // Need to name like this to override Lombok class
        public SampleClassBuilder x(String x){
            this.x = x + "testX"; // Lombok will also create `this.x` for this builder class (also y,a,b,c,z)
            return this;
        }
        public SampleClassBuilder y(String y){
            this.y = y + "testY";
            return this;
        }
        public SampleClassBuilder z(String z){
            this.z = this.x + this.y; // *`.z()` must be called lastly if refer to other fields
            return this;
        }
    }

To use it, you can simply do this:

SampleClass sample = SampleClass.builder().x("One").z(null).y("Two").a(1).b(2).c(3).build();
System.out.println(sample); // SampleClass(x=OnetestX, y=TwotestY, a=1, b=2, c=3, z=OnetestXnull)

*Please note that using this pattern, .z(...) needs to be called after others; otherwise, the value will be wrong as z="OnetestXnull" because y is null at that time.

To overcome this issue:

  • You can append this.z(null) into method x() and y()
  • Or, use another pattern here: https://stackoverflow.com/a/65773183/2710335 to avoid putting this.z(null) everywhere (Eg. this.z = this.x + this.y + this.a + this.b + this.c + ...;).
Northnroro
  • 525
  • 1
  • 6
  • 10