Lombok’s @Builder annotation and inheritance

I’ve written about Project Lombok’s @Builder annotation before (see here and here). We’ve started using it in our project some time ago in favour of the code generation library PojoBuilder. One thing has bugged me though during that time: Lombok’s @Builder annotation won’t generate code for inherited fields. It turns out, there is a solution to this problem.

We have been using @Builder on the class itself, but you can also put it on a class’s constructor or on a static method. In that case, Lombok will create a setter method on the builder class for every parameter of the constructor/method. That means you can create a custom constructor with parameters for all the fields of the class including its superclass.

@AllArgsConstructor
public class Parent {
  private String a;
}

public class Child extends Parent {

  private String b;

  @Builder
  private Child(String a, String b){
    super(a);
    this.b = b;
  }
}

By setting the visibility of the constructor to private you can make sure that it is only available to Lombok (thanks to Mathias for the tip!). As a result you can then use the generated builder like this:

Child.builder().a("testA").b("testB").build()

The official documentation explains this, but it doesn’t explicitly point out that you can facilitate it in this way.

14 thoughts on “Lombok’s @Builder annotation and inheritance

  1. Great post Reinhard!
    Have you tried using @Builder on both parent and child? to me it complains about builder() not being able to override its parent’s.
    I don’t understand why Lombok should try overriding a static method ?!?!?

    • Thanks, Eduardo! I just rechecked, I don’t get that error, I just don’t get access to the parent classes builder methods through the child’s builder then. Maybe I don’t understand correctly what you are trying to do? If you like, send me a gist or something…

      • Hi again.
        I tried creating a very simple case to demonstrate but fortunately I didnt manage to reproduce the problem I was having back when I asked you. So I am afraid I won’t be able to provide you with a specific example of the problem I was running into.
        Thanks anyway.

  2. Kind of defeats the purpose of the builder, doesn’t it ?
    You create your builder in the first place to avoid long lines of setters and/or constructors with many arguments.

    • I agree it would be nicer if Lombok would have an option for considering superclasses, but since it doesn’t, I think it’s a useful and easy option for tackling this problem.

      • Thanks for the trick.
        I think it is fine if you hide the constructor – so I make it private and everybody has to use the builder to construct the object – I would suggest to change the example above.

  3. Although this is a nice workaround, it has two drawbacks.
    If you generate your superclass constructor using Lombok, the signature depends on the order of the fields as they appear in the declaration of the superclass. Not all developers are accustomed to the order of class members being significant, but when using Lombok, it is. Pray your unit tests catch this. But of course this applies to the @AllArgsConstructor annotation in general.
    Also, if you add a field to your superclass, you have to manually update all subclasses to add the new field to the superclass constructor invocation. So changes can result in labor-intensive work, which is not the idea of Lombok.

    • You’re absolutly right, using Lombok to create the superclass constructor could be a problem if fields have the same type, thanks for pointing that out. My main point was the use of @Builder on the subclass constructor, I didn’t think of that.
      Using strong typing (e.g. using a type EmailAddress instead of just String) could mitigate the problem, as the compiler should then complain about a changed signature. But I know this is rarely how people design their code.
      I’m not as concerned with the manual updating part, although I agree that the benefit of Lombok isn’t as obvious anymore.

Leave a Reply

Your email address will not be published. Required fields are marked *