Project Lombok’s @Builder annotation and generics

Some time ago I’ve written about Project Lombok’s @Builder annotation. When used, it will automatically create a builder for your Java POJOs. Lately, I’ve had some trouble using it on generic classes. Initially I thought that Lombok might need some improvements in this area, but it turned out that I was just using it wrong.

Consider the following non-generic example:

@Builder
public class Entity {
  private String body;
}

You use the generated builder in this way:

Entity entity = Entity.builder().body("body").build();

If you want the body to be of a generic type, it looks like that:

@Builder
public class Entity {
  private T body;
}

In this case, the compiler will need some help to correctly choose types when using the builder:

Entity entity = Entity.builder().body("body").build()

Note the explicit type statement <String> right in front of the builder() method invocation. This is used to help the compiler choose the type for the created builder object. It’s necessary because we don’t directly assign the result of the builder() invocation to a correctly typed builder variable.

I’m using Intellij as an IDE and there’s a pretty nice Lombok plugin for it. You can, for example, use it to de-lombok your code. Unfortunatly, for the @Builder annotation the de-lomboked code isn’t handling the the type variables correctly and you end up with compiler errors:

public class Entity {

    private T body;

    @java.beans.ConstructorProperties({"body"})
    Entity(T body) {
        this.body = body;
    }

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

    public static class EntityBuilder {
        private T body;

        EntityBuilder() {
        }

        public Entity.EntityBuilder body(T body) {
            this.body = body;
            return this;
        }

        public Entity build() {
            return new Entity(body);
        }

        public String toString() {
            return "de.rpr.EntityBuilder(body=" + this.body + ")";
        }
    }
}

As you can see, the de-lomboked EntityBuilder uses the same type variable name T, causing the compiler to complain that T is not accessible from a static context. Also, the build() method itself doesn’t make use of the generic constraint as well. This is an error in the Lombok plugin, not in Lombok. But it led me on the wrong way thinking that Lombok has issues when using generics.

TL;DR

Lombok’s @Builder annotation is great and deals correctly with generics. Be careful when looking at de-lomboked code from the Intellij Lombok plugin – it might not exactly produce the same code that Lombok generates.

25 thoughts on “Project Lombok’s @Builder annotation and generics

  1. I’ve set up a quick maven project using Java 8 and lombok 1.16.6, it works for me. Maybe easier to spot the problem with your complete project… If you like, create a github repo and I’ll clone and have a quick look…

  2. So I’ve cloned and looked up your class. Then changed “result” to T. It still works without a problem for me… :-/
    public class ServiceResponse < T > {
    public enum Status { OK, ERROR }
    private Status status;
    private List < String > responseMessages;
    private T result;
    public static void main(String[] args) {
    ServiceResponse build = ServiceResponse.builder().result(EventRule.builder().description(“test”).build()).build();
    System.out.println(build.getResult());
    }
    }
    Is that what you want?

  3. No, this isn’t what I’m looking for, actually. In your example, the getter “getResult” still returns a “java.lang.Object”. I want to avoid type casting. How can I do that by using Lombok builders?

  4. Ah, alright, got you. Small glitch on my side, try this:
    ServiceResponse < EventRule > result = ServiceResponse
    .< EventRule >builder()
    .result(EventRule.builder().description(“test”).build())
    .build();
    EventRule rule = result.getResult();
    Note the use of the explicit type definition when creating the builder and on the resulting ServiceResponse. You basically have to hint the compiler a bit…
    Hope that helps!

  5. Still doesn’t work for me, man. Can’t assign the built object to parameterized variable. It still expects “java.lang.Object” type. Can you please take a look again at the Github repo? I’ve made some changes that actually works to avoid type casting, but it makes the code a bit weird.
    Thanks again!

  6. Hmm, I don’t see the changes that you are talking about… Anyway, I can’t think of a reason why this wouldn’t work for you. Maybe a IDE thing? I’m using Intellij Community Edition…
    It’s getting late here, I’ll have to leave it that for today. Good luck! Feel free to update me once you solved your problem!

  7. Hello,
    I’m having the same issue here.
    What have you make to make IntelliJ does not complain about the builder? There is a way to ignore it?

    • There’s two things you might need for lombok to work correctly in Intellij. First, install the Lombok plugin, you can find it in the general plugins repository. Then there’s this Intellij setting “Setting – Compiler – Annotation Processors – Enable annotation processing”, make sure you have it set to enabled. Good luck!

  8. So it’s all good if you call build this way :
    Entity entity = Entity.builder().body(“body”).build();
    but if you want to add parts that you compute and call build later :
    Entity.EntityBuilder builder = Entity.builder().body(“body”);
    //this gives me an error

    • What’s the error then? Try using explicit generics:
      Entity.EntityBuilder < String > builder = Entity. < String > builder().body(“body”);

  9. Hi, I think you have a typo, and this is the first result on Google for “lombok builder generics”. May help to update in case people are looking how to use builders with generics.
    Entity entity = Entitybuilder().body(“body”).build()
    should be
    Entity entity = Entity.builder().body(“body”).build() – period after Entity.

  10. I have the same issue. Alexandre Cardoso code compiles but is marked red in IntelliJ: Incompatible types Required AR.Entity , Found AR.Entity . The problem occurs on my Mac OSX machine (El Capitan). However, everything is fine on my Ubuntu 16.10.
    I am wondering how can I fix this on my Mac? (I have lombok plugin installed, annotation processor turned on, Intellij IDEA is the same for both machines: 2016.1.3 Ultimate June 2016)

Leave a Reply to Alexandre Cardoso Cancel reply

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