Backend Development 10 min read

Why You Should Stop Using Lombok’s @Builder and Prefer @Accessors

The article explains the pitfalls of Lombok’s @Builder annotation—such as loss of default values, mutable builders, and limited applicability—and demonstrates how using @Accessors with chainable setters provides a safer, more flexible alternative for Java backend development.

Code Ape Tech Column
Code Ape Tech Column
Code Ape Tech Column
Why You Should Stop Using Lombok’s @Builder and Prefer @Accessors

The author revisits previous warnings about Lombok’s @Builder annotation, highlighting a major pitfall where default values are lost and noting that @Builder often gives a false impression of following the builder pattern.

Scenario reproduction : The article presents a class definition without @Builder and a usage example, followed by the same class annotated with @Builder and its usage, showing how the generated code differs and how default values can disappear.

package io.gitrebase.demo;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class APIResponse
{
    private T payload;
    private Status status;
}
package io.gitrebase.demo;

import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@Slf4j
@RestControllerAdvice(assignableTypes = io.gitrebase.demo.RestApplication.class)
public class ApplicationExceptionHandler {
    @ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR)
    public APIResponse handleException(Exception exception) {
        log.error("Unhandled Exception", exception);
        Status status = new Status();
        status.setResponseCode("RESPONSE_CODE_IDENTIFIER");
        status.setDescription("Bla Bla Bla");
        APIResponse response = new APIResponse();
        response.setStatus(status);
        return response;
    }
}

Why @Builder is discouraged : The generated builder cannot differentiate required from optional parameters, is mutable (violating the immutable builder principle), ties to concrete types, and is only suitable for objects with many optional fields, making it error‑prone.

Alternative solution – @Accessors : The author recommends Lombok’s @Accessors annotation with chain = true as the primary replacement. A class definition using @Data and @Accessors is shown, followed by the compiled class code that includes fluent setter methods.

package io.gitrebase.demo;

import lombok.Data;
import lombok.experimental.Accessors;

@Data
@Accessors(chain = true)
public class APIResponse
{
    private T payload;
    private Status status;
}
package io.gitrebase.demo;

import lombok.experimental.Accessors;

@Accessors(chain = true)
public class APIResponse
{
    private T payload;
    private Status status;
    public T getPayload() { return this.payload; }
    public APIResponse
setPayload(T payload) { this.payload = payload; return this; }
    public Status getStatus() { return this.status; }
    public APIResponse
setStatus(Status status) { this.status = status; return this; }
}

Usage example with @Accessors demonstrates creating a response object via chained setters, eliminating the need for @Builder.

package io.gitrebase.demo;

import lombok.extern.slf4j.Slf4j;
import lombok.var;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@Slf4j
@RestControllerAdvice(basePackageClasses = io.gitrebase.demo.RestApplication.class)
public class ApplicationExceptionHandler {
    @ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR)
    public APIResponse handleException(Exception exception) {
        log.error("Unhandled Exception", exception);
        var status = new Status().setResponseCode("RESPONSE_CODE_IDENTIFIER").setDescription("Bla Bla Bla");
        return new APIResponse().setStatus(status);
    }
}

The article also notes that @Accessors resides in the experimental Lombok package, but argues it is stable and unlikely to be removed; even if it were, developers can manually implement fluent setters.

Inspiration: Readers are encouraged to inspect generated source code, understand Lombok’s behavior, and think critically about using annotations, as misuse can lead to subtle bugs.

References: Links to the original articles "千万不要再随便使用 lombok 的 @Builder 了!" and "Oh !! Stop using @Builder" are provided.

JavaBackend DevelopmentLombokBuilder PatternBuilderAccessors
Code Ape Tech Column
Written by

Code Ape Tech Column

Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.