You shouldn't mix lombok @Builder with static inner Builder class. If it is possible to get rid of Builder class, the next code should work.

RequestMessage:

@Getter
@ToString
@EqualsAndHashCode(callSuper = true)
@SuperBuilder(toBuilder = true)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class RequestMessage extends MyDTO {
    private final String name;

    @Override
    public String emitSerializedPayload() throws JsonProcessingException {
    return null;
    }
    public RequestMessage(String myAccountId, String name) {
        super(myAccountId);
        this.name = name;
}
}

MyDTO:

@Data
@SuperBuilder(toBuilder = true)
public abstract class MyDTO implements Serializable {
    @JsonIgnore private final ObjectMapper objectMapper = new ObjectMapper();
    protected String myAccountId;

    protected MyDTO() {}

    public MyDTO(String myAccountId) {
       this.myAccountId = myAccountId;
    }

    public static int hashCode(Object... objects) {
        return Arrays.deepHashCode(objects);
    }

    public static boolean equal(Object o1, Object o2) {
        // implementation of equals method
        return false;
    }
    public abstract String emitSerializedPayload() throws JsonProcessingException;
}

Test:

@Test
void name() {
    String myName = "myName";
    String myAccountId = "myAccountId";
    var request = RequestMessage.builder().name(myName).myAccountId(myAccountId).build();
    System.out.println("request = " + request);
    RequestMessage requestMessage = new RequestMessage(myAccountId, myName);
}
    
Answer from Andrei on Stack Overflow
🌐
Baeldung
baeldung.com › home › java › lombok @builder with inheritance
Lombok @Builder with Inheritance | Baeldung
May 11, 2024 - Note that we have to annotate all classes. @SuperBuilder cannot be mixed with @Builder within the same class hierarchy.
🌐
Project Lombok
projectlombok.org › api › lombok › experimental › SuperBuilder
SuperBuilder (Lombok)
It is similar to @Builder, except it is only legal on types, is less configurable, but allows you to extends other builder-able classes. NB: @SuperBuilder has been moved to the main package; update your lombok dependencies and search/replace all import lombok.experimental.SuperBuilder to import ...
🌐
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 - Builder Inheritance: Standard @Builder works well for single classes but struggles with inheritance. @SuperBuilder extends this capability, allowing you to create builder…
🌐
Google Groups
groups.google.com › g › project-lombok › c › Xrgh6Yy24ag
@SuperBuilder needs to be finalized.
Explanation: `@SuperBuilder` adds a whole bevy of type annotations to make it work, and that implementation detail leaks out, we can't prevent that from happening. It is useful to be able to explain in simple terms what Builder actually does, and SuperBuilder makes it way more complicated to do so.
🌐
Lars-sh
lars-sh.github.io › lombok-annotations › apidocs › lombok › experimental › SuperBuilder.html
SuperBuilder (Lombok Annotations 1.18.48-SNAPSHOT API)
It is similar to @Builder, except it is only legal on types, is less configurable, but allows you to extends other builder-able classes. All classes in the hierarchy must be annotated with @SuperBuilder. Lombok generates 2 inner 'builder' classes, which extend the parent class' builder class ...
🌐
Project Lombok
projectlombok.org › features › SuperBuilder
@SuperBuilder
@SuperBuilder was promoted to the main lombok package since lombok v1.18.48. The @SuperBuilder annotation produces complex builder APIs for your classes. In contrast to @Builder, @SuperBuilder also works with fields from superclasses. However, it only works for types.
🌐
Nuhmans
nuhmans.com › article › using-lombok-s-builder-vs-superbuilder-for-inheritance-in-java › 54
Using Lombok's @Builder vs @SuperBuilder for Inheritance in Java
October 15, 2024 - You likely meant @SuperBuilder for handling inheritance. ... Generates a builder pattern for the class it's applied to. Doesn't handle inheritance well (child class builders don't inherit parent class fields).
Find elsewhere
🌐
GitHub
github.com › projectlombok › lombok › issues › 2209
[PROMOTION] @SuperBuilder - promote out of experimental · Issue #2209 · projectlombok/lombok
August 20, 2019 - If we ever have resolution, @builder on its own makes @SuperBuilder almost entirely irrelevant.
🌐
Medium
medium.com › @drivaspedro › java-lombok-builder-annotation-with-inheritance-6541087040f2
Java Lombok Builder Annotation With Inheritance | by Drivaspedro | Medium
December 23, 2022 - The Lombok @Builder annotation produces complex builder APIs for your classes. It can be used in the class, constructor or methods. Example: @Builder public class Person { private String name; } // Then instantiate the class like this: Person person = Person.builder().name("Drivas").build(); projectlombok.org · If you need to extend a class that is annotated with @Builder, you will need to add the @SuperBuilder annotation on the child class and change the @Builter annotation to @SuperBuilder in the ancestor class.
🌐
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 ·
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;
}
🌐
GitHub
github.com › rzwitserloot › lombok › issues › 2224
[FEATURE] implements in Builder/SuperBuilder · Issue #2224 · projectlombok/lombok
August 30, 2019 - without this feature we can't implement SuperBuilder at all, and need to use boilerplate for regular Builder: @Builder(implements=custom.Builder.class) class Bean { public static abstract class BeanBuilder implements custom.Builder<Bean> {} String a, b, c; { BeanBuilder.class.isAssignableFrom(custom.Builder.class) => **true** } as an option default interface LombokBuilder can be provided ·
Author: projectlombok
🌐
Medium
medium.com › javarevisited › do-more-with-less-java-lombok-and-experimental-features-8d71d0bcb27c
Do More with Less Java — Lombok and Experimental Features | by Jayson GCS | Javarevisited | Medium
June 2, 2022 - Introduction Stable Features — Logging — Constructor and Accessor — Builder — Cleanup — ToString Experimental Features — SuperBuilder — Tolerate — Jacksonized — FieldNameConstants · Java is known to be a “wordy” programming language, developers often have to get past some boilerplate code before getting down to writing actual business logic. Project Lombok is a mature compile time library that aims to reduce or minimise repetitive code in Java to improve developer experience.
🌐
Google Groups
groups.google.com › g › project-lombok › c › VcgBsprEe5k
toBuilder for SuperBuilder
The reason for that construction is that you cannot access instance.field1 from the abstract builder's $fillValuesFrom(), because C technically is an intersection class, which is not a nested class of the annotated type any more.
🌐
Joseph Gan's Blog
bwgjoseph.com › joseph gan's blog › #lombok › can you use lombok tobuilder on an abstract class?
Can you use Lombok toBuilder on an Abstract Class?
December 30, 2022 - If you have an abstract class with various subclasses, and you need to define some values through builder method, you won't be able to do so by default because Lombok does not know if all the subclasses are annotated with toBuilder but we can force all subclasses to implement toBuilder method. To make it simple, we only have an abstract class with 2 subclasses, and a couple of fields. @SuperBuilder(toBuilder = true) public abstract class AddressDO { private String id; private String street; private String postalCode; private String unit; } @SuperBuilder(toBuilder = true) public class HomeAddressDO extends AddressDO { private boolean isRental; } @SuperBuilder(toBuilder = true) public class OfficeAddressDO extends AddressDO { private String building; }