Updated 2018-11-10: Lombok 1.18.4 released

Updated 2020-10-18: Lombok 1.18.16 released

Lombok 1.18.16 contains the new @Jacksonized annotation. With it, you can simply write:

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "type")
@JsonSubTypes({
  @JsonSubTypes.Type(value = SubA.class),
  @JsonSubTypes.Type(value = AnotherSub.class)
})
@Jacksonized
@SuperBuilder
// more annotations...
public abstract class AbstractA {

    @JsonProperty
    protected final String superProperty;
}

@Jacksonized
@SuperBuilder
@JsonTypeName("SubA")
// more annotations...
public class SubA extends AbstractA {

    @JsonProperty
    private final String fieldA;
}

This will automatically insert all necessary Jackson annotations and do some adjustments to the generated builder. No need to customized anymore.

For earlier Lombok versions between 1.18.4 and 1.18.12, this is the way to go:

For Lombok's @Builder and @SuperBuilder to work with Jackson, you have to add the builder class header manually and place a @JsonPOJOBuilder(withPrefix="") on it. Lombok will then generate only the remainder of the builder class. This is necessary because Jackson's default is that the builder's setter methods have "with" as prefix, but Lombok's builders don't have any prefix (and Lombok is not and will probably never be configurable in this regard).

When @SuperBuilder was introduced in Lombok 1.18.2, it was not customizable (i.e., you could not manually add the builder class header). As a result, using @SuperBuilder with Jackson was not easily possible.

This changed with Lombok 1.18.4 (see this pull request): @SuperBuilder is now (at least partially) customizable, and this allows us to add the annotation. Beware that the code generated by @SuperBuilder is quite complex and heavily loaded with generics. To avoid accidentally messing up the code, you should have a look at the delombok output and copy/paste the class header from there. Here, you need add the builder implementation class header and put the annotation on it:

@JsonPOJOBuilder(withPrefix="")
static final class SubABuilderImpl extends SubABuilder<SubA, SubABuilderImpl> {
}

Note that you have to broaden the visibility of SubABuilderImpl to at least package-private.

The @JsonDeserialize annotation must also refer to the builder implementation class, not the abstract builder:

@JsonDeserialize(builder = SubA.SubABuilderImpl.class)
Answer from Jan Rieke on Stack Overflow
🌐
Project Lombok
projectlombok.org › api › lombok › experimental › SuperBuilder
SuperBuilder (Lombok)
The SuperBuilder annotation creates a so-called 'builder' aspect to the class that is annotated with @SuperBuilder, but which works well when extending.
Lombok
Project Lombok is a java library that automatically plugs into your editor and build tools, spicing up your java. Never write another getter or equals method again, with one annotation your class has a fully featured builder, Automate your logging variables, and much more · See it on Youtube ...
@Data
For example, if you already have a method with signature equals(AnyType param), no equals method will be generated, even though technically it might be an entirely different method due to having different parameter types. The same rule applies to the constructor (any explicit constructor will prevent @Data from generating one), as well as toString, equals, and all getters and setters. You can mark any constructor or method with @lombok...
@Builder
This includes the builder itself: ... to be injected already exist. You may not put any other method (or constructor) generating lombok annotation on a builder class though; for example, you can not put @EqualsAndHashCode on the builder class....
lombok.experimental
The SuperBuilder annotation creates a so-called 'builder' aspect to the class that is annotated with @SuperBuilder, but which works well when extending. ... Put on any method or constructor to make lombok pretend it doesn't exist, i.e., to generate a method which would otherwise be skipped ...
🌐
Lars-sh
lars-sh.github.io › lombok-annotations › apidocs › lombok › experimental › SuperBuilder.html
SuperBuilder (Lombok Annotations 1.18.48-SNAPSHOT API)
Prefix to prepend to 'set' methods ... not include a prefix. For example, a method normally generated as someField(String someField) would instead be generated as withSomeField(String someField) if using @SuperBuilder(setterPrefix = "with")....
Top answer
1 of 2
24

Updated 2018-11-10: Lombok 1.18.4 released

Updated 2020-10-18: Lombok 1.18.16 released

Lombok 1.18.16 contains the new @Jacksonized annotation. With it, you can simply write:

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "type")
@JsonSubTypes({
  @JsonSubTypes.Type(value = SubA.class),
  @JsonSubTypes.Type(value = AnotherSub.class)
})
@Jacksonized
@SuperBuilder
// more annotations...
public abstract class AbstractA {

    @JsonProperty
    protected final String superProperty;
}

@Jacksonized
@SuperBuilder
@JsonTypeName("SubA")
// more annotations...
public class SubA extends AbstractA {

    @JsonProperty
    private final String fieldA;
}

This will automatically insert all necessary Jackson annotations and do some adjustments to the generated builder. No need to customized anymore.

For earlier Lombok versions between 1.18.4 and 1.18.12, this is the way to go:

For Lombok's @Builder and @SuperBuilder to work with Jackson, you have to add the builder class header manually and place a @JsonPOJOBuilder(withPrefix="") on it. Lombok will then generate only the remainder of the builder class. This is necessary because Jackson's default is that the builder's setter methods have "with" as prefix, but Lombok's builders don't have any prefix (and Lombok is not and will probably never be configurable in this regard).

When @SuperBuilder was introduced in Lombok 1.18.2, it was not customizable (i.e., you could not manually add the builder class header). As a result, using @SuperBuilder with Jackson was not easily possible.

This changed with Lombok 1.18.4 (see this pull request): @SuperBuilder is now (at least partially) customizable, and this allows us to add the annotation. Beware that the code generated by @SuperBuilder is quite complex and heavily loaded with generics. To avoid accidentally messing up the code, you should have a look at the delombok output and copy/paste the class header from there. Here, you need add the builder implementation class header and put the annotation on it:

@JsonPOJOBuilder(withPrefix="")
static final class SubABuilderImpl extends SubABuilder<SubA, SubABuilderImpl> {
}

Note that you have to broaden the visibility of SubABuilderImpl to at least package-private.

The @JsonDeserialize annotation must also refer to the builder implementation class, not the abstract builder:

@JsonDeserialize(builder = SubA.SubABuilderImpl.class)
2 of 2
5

A working solution in Eclipse, note that the Lombok IntelliJ integration is not supporting all features, therefore the code compiles fine in Eclipse and with javac but IntelliJ thinks it's broken but executes the code without an issue.

public static ObjectMapper createObjectMapper() {

    final ObjectMapper mapper = new ObjectMapper();
    mapper.setAnnotationIntrospector(new JacksonAnnotationIntrospector() {

        @Override
        public JsonPOJOBuilder.Value findPOJOBuilderConfig(final AnnotatedClass ac) {
            if (ac.hasAnnotation(JsonPOJOBuilder.class)) {
                return super.findPOJOBuilderConfig(ac);
            }
            return new JsonPOJOBuilder.Value("build", "");
        }
    });

    return mapper;
}

public static void main(final String[] args) throws Exception {
    final ObjectMapper objectMapper = createObjectMapper();

    final String serializedForm = objectMapper.writeValueAsString(SubA.builder().build());
    System.out.println(serializedForm);
    final SubA anA = objectMapper.readValue(serializedForm, SubA.class);
    System.out.println(anA);
}


@Getter
@EqualsAndHashCode(callSuper = true)
@Accessors(fluent = true, chain = true)
@SuperBuilder
@JsonDeserialize(builder = SubA.SubABuilderImpl.class)
@JsonTypeName("SubA")
public static class SubA extends AbstractA {

    @JsonProperty
    private final String fieldA;
}


@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
@JsonSubTypes({
    @JsonSubTypes.Type(value = SubA.class)
})
@Getter
@Accessors(fluent = true, chain = true)
@SuperBuilder
public static abstract class AbstractA {

    @JsonProperty
    protected final String superProperty;
}
🌐
Baeldung
baeldung.com › home › java › lombok @builder with inheritance
Lombok @Builder with Inheritance | Baeldung
May 11, 2024 - As we noted earlier, version 1.18 of Lombok introduced the @SuperBuilder annotation.
🌐
Project Lombok
projectlombok.org › features › SuperBuilder
@SuperBuilder
... (discouraged) If you want your ... usage where all options are changed from their defaults: @SuperBuilder(buildMethodName = "execute", builderMethodName = "helloWorld", toBuilder = true, setterPrefix = "set")...
🌐
Code Like A Girl
code.likeagirl.io › java-why-lomboks-superbuilder-is-so-useful-0e6c34e61861
Java — Why Lombok’s @Superbuilder Is So Useful | by Cleopatra Douglas | Code Like A Girl
November 4, 2024 - @SuperBuilder @AllArgsConstructor @NoArgsConstructor @Data @JsonInclude(JsonInclude.Include.NON_NULL) public abstract class BaseResponse { private String message; private Boolean success; }
🌐
GitHub
github.com › projectlombok › lombok › blob › master › website › templates › features › experimental › SuperBuilder.html
lombok/website/templates/features/experimental/SuperBuilder.html at master · projectlombok/lombok
You can customize most of the code generated by <code>@SuperBuilder</code>, except for internal methods (e.g. <code>self()</code>). You have to make sure that the builder class declaration headers match those that would have been generated by lombok.
Author: projectlombok
🌐
Medium
medium.com › @drivaspedro › java-lombok-builder-annotation-with-inheritance-6541087040f2
Java Lombok Builder Annotation With Inheritance | by Drivaspedro | Medium
December 23, 2022 - @SuperBuilder public class Person ... } // Then instantiate the class like this: Developer developer = Developer .builder() .name("Drivas") .language("Java") .build(); This feature was introduced on the Lombok 1.18 ...
Find elsewhere
🌐
GitHub
github.com › projectlombok › lombok › issues › 2966
Call child constructor using @SuperBuilder · Issue #2966 · projectlombok/lombok
September 18, 2021 - @lombok.experimental.SuperBuilder(buildMethodName = "create", setterPrefix = "with", toBuilder = true) @lombok.NoArgsConstructor(access = AccessLevel.PROTECTED) @MappedSuperclass public abstract class BaseEntity { protected UUID id; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) protected Long DbId; public UUID getId() { return id; } public Long getDbId() { return DbId; } } @lombok.Getter @lombok.experimental.SuperBuilder(builderMethodName = "createChild", buildMethodName = "create", setterPrefix = "with", toBuilder = true) @lombok.NoArgsConstructor(access = AccessLevel.PROTECTED) @En
Author: projectlombok
🌐
Google Groups
groups.google.com › g › project-lombok › c › YuG1h1eB93U
Depending on a generic SuperBuilder
to Project Lombok · I have a base entity which has a couple of properties and the concrete implementation with a couple of extra ones. On top of that I need the base class to access "self" of the child which I do through generics. Here is a simplified example of what I am trying: @Data · @SuperBuilder(toBuilder = true) @ToString(callSuper = true) public abstract class Entity<ENTITY extends Entity<ENTITY, BUILDER>, BUILDER extends Entity.EntityBuilder<ENTITY, BUILDER, ENTITY, BUILDER>> implements Mutable<ENTITY> { //... public abstract ENTITY mutate(Consumer<Context<ENTITY, BUILDER>> context) { var builder = createBuilder(); context.accept(new Context<>(self(), builder)); return builder.build(); } protected abstract ENTITY self(); protected abstract BUILDER createBuilder(); } @Data ·
🌐
Malevanyy
malevanyy.com › 2019 › 11 › how-i-discovered-superbuilder-in-lombok
How I discovered @SuperBuilder in Lombok – Andrey Malevanyy's blog
November 5, 2019 - This code made me think that there should be a better way to do this. And there is. I tried to reinvent the wheel when there already was a proper solution for a hierarchical builder using Lombok. It is called @SuperBuilder.
🌐
Google Groups
groups.google.com › g › project-lombok › c › Xrgh6Yy24ag
@SuperBuilder needs to be finalized.
Given Oracle's lack of desire to bring Java up to the features .Net developers are used to, I was creating a base class with the common properties. @Builder failed to do the required access to my "properties". @SuperBuilder does. Currently @SuperBuilder is in the "experimental" phase.
🌐
GitHub
github.com › projectlombok › lombok › blob › master › src › core › lombok › experimental › SuperBuilder.java
lombok/src/core/lombok/experimental/SuperBuilder.java at master · projectlombok/lombok
import lombok.Singular; · /** * The SuperBuilder annotation creates a so-called 'builder' aspect to the class that is annotated with {@code @SuperBuilder}, but which works well when extending.
🌐
KapreSoft
kapresoft.com › java › 2021 › 12 › 27 › lombok-builders-and-copy-constructors.html
Lombok • Builders and Copy Constructors | KapreSoft
December 27, 2021 - @Data @SuperBuilder(toBuilder=true) public class SuperUser extends User { } @Data @SuperBuilder(toBuilder=true) public class User { } For an immutable Parent/Child relationship, a minor change should suffice by unwrapping some @Value compounded ...
Top answer
1 of 2
5

AFAIK, @Data generates a @NoArgsConstructor, which is just wrong. Actually, @Data is wrong per se, as it's meant for mutable classes; @Value would be better, but it can't deal with the super constructor either.

So remove @Data, add @Getter, @EqualsAndHashCode, @ToString and whatever you need. Don't forget to add callSuper=true in the subclass.


This is effectively the constructor that Lombok should be constructing and invoking on the SuperBuilder.build() operation.

public Child(
    final String userId,
    final Instant requestingTime,
    final Instant beginningDate,
    final Instant endingDate,
    final Collection<String> fields) {

    super(userId, requestingTime);
    this.beginningDate = beginningDate;
    this.endingDate = endingDate;
    this.fields= fields;
}

No, that's not how SuperBuilder works. This is actually Lombok can't do as it can't see the super fields. Instead, the builder uses something like

public Child(ChildBuilder b) {    
    super(b);
    this.beginningDate = b.beginningDate;
    this.endingDate = b.endingDate;
    this.fields= b.fields;
}

You can believe what Jan Rieke says, he wrote it.

2 of 2
0

@Data annotation implicitly generate code for below mentioned functionalities:


  • setter
  • getter
  • toString
  • equallAndHashCode
  • constructor(for required arguments only)

It means constructor declaration of loombok will generate code for Parent class will be as mentioned below:

Person(String userId, Instant requestingTime)

Similarly for Child class:

Child(Instant beginningDate, Instant endingDate, Collection fields)


Now as your program is throwing exception that

Parent() is undefined in parent class.

Please annotate your class with :

@NoArgsConstructor

This will generate required default constructor.

🌐
Google Groups
groups.google.com › g › project-lombok › c › EnuIz70QZtM
Using @SuperBuilder and @With annotations
@Getter @EqualsAndHashCode(callSuper = true) @SuperBuilder(toBuilder = true) @Document(collection = "examples")
🌐
GitHub
github.com › vajpai › springboot-superbuilder
GitHub - vajpai/springboot-superbuilder: Lombok @SuperBuilder demo application · GitHub
This project is build on Spring Boot 2.1.0 and lombok experimental version v1.18.2 for @SuperBuilder.
Top answer
1 of 3
23

I recently tried customizing @SuperBuilder using Lombok 1.18.8 and IntelliJ, and it worked fine. The only issue I faced was, I lost ability to use toBuilder flag in SuperBuilder - @SuperBuilder(toBuilder=true).

Below is the code to override @SuperBuilder methods.

public static abstract class ChildBuilder<C extends Child, B extends ChildBuilder<C, B>>
        extends ParentBuilder<C, B> {

    private LocalDate date;

    public B date(String dateStr) {
        this.date = LocalDate.parse(dateStr);
        return self();
    }
}

I added my working code here: Customize SuperBuilder in Lombok

2 of 3
9

When @SuperBuilder was introduced in 1.18.2, customising it was not possible. If you try, Lombok 1.18.2 gives you the error message SuperBuilder does not support customized builders.

However, Lombok 1.18.4 added limited customisation possibilities of @SuperBuilder. (It's limited because you cannot modify setter methods, but you can add your own methods and modify build() and builder().)

The generated @SuperBuilder code is quite complex and differs from @Builder. To avoid accidently messing up the generics-loaded builder code, you should start by copying the builder class header from the delombok output. In your case (adding a new setter method), customize the abstract builder class ParentBuilder (and not the ParentBuilderImpl). Have a look at the delomboked code to find out how your setter should be defined, especially the return type.

This is the customized builder code for your example:

public abstract static class ParentBuilder<C extends Parent, B extends ParentBuilder<C, B>> {
    public B setAllTo(final int value) {
       return a(value).b(value);
    }
}

With Lombok 1.18.4, this compiles and works as expected.