Using Lombok Annotations for ORM Entities, Builder, Wither, and Accessors in Java
This article explains how Lombok annotations such as @Data, @Builder, @Wither, and @Accessors can simplify Java bean creation for ORM entities, builder pattern utilities, wither-style object modification, and fluent accessor methods, while addressing common pitfalls like missing constructors and default values.
Using Java to write classes often involves creating boilerplate code for beans. Lombok provides annotations that reduce this overhead and make code more elegant.
ORM Entity
For a Java bean used as an ORM entity or for XML/JSON mapping, it needs a no‑args constructor, setter methods for deserialization, and getter methods for serialization. The @Data annotation automatically generates @Getter @Setter @RequiredArgsConstructor @ToString @EqualsAndHashCode , which is sufficient for simple entity classes.
@Data
public class UserBean {
private Integer id;
private String userName;
}Builder
The builder pattern is frequently used in utility classes. Applying @Builder creates a private all‑args constructor and fluent setter‑like methods that return the object itself. However, without a getter, the built object cannot expose its fields, and serialization may fail.
UserBean u = UserBean.builder()
.id(1001)
.userName("polly")
.build();
System.out.println(u);Adding @ToString or @Getter resolves the serialization issue. To support JSON conversion with Jackson, a no‑args constructor is also required, which can be added via @NoArgsConstructor . Combining annotations such as @Builder @Data @AllArgsConstructor(access = AccessLevel.PRIVATE) @NoArgsConstructor yields a functional builder.
@Builder
@Data
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@NoArgsConstructor
public class UserBean {
private Integer id;
private String userName;
private List
addresses;
}When a collection field is present, @Singular simplifies adding elements individually.
@Builder
@Data
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@NoArgsConstructor
public class UserBean {
private Integer id;
private String userName;
@Singular
private List
favorites;
}
UserBean u = UserBean.builder()
.id(1001)
.userName("polly")
.favorite("music")
.favorite("movie")
.build();To keep default field values when using a builder, annotate the field with @Default .
@Builder
@Data
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@NoArgsConstructor
public class UserBean {
private Integer id;
private String userName;
@Default
private String example = "123456";
}Wither
The @Wither annotation (now deprecated in favor of @With ) generates methods that return a new instance with a modified field, similar to the builder but for incremental changes. It is useful for immutable objects.
@Wither
@AllArgsConstructor
public class ApiClient {
private String appId;
private String appKey;
private String endpoint = "http://api.pollyduan.com/myservice";
}
ApiClient client1 = new ApiClient(null, null, null);
Object client2 = client1.withAppId("10001")
.withAppKey("abcdefg")
.withEndpoint("http://127.0.0.1/");Combining @RequiredArgsConstructor with @Wither allows mandatory fields while keeping optional ones with defaults.
@RequiredArgsConstructor
@Wither
@AllArgsConstructor
public class ApiClient {
@NonNull private String appId;
@NonNull private String appKey;
private String endpoint = "http://api.pollyduan.com/myservice";
}Accessors
The @Accessors annotation creates fluent or chainable getter/setter methods. With fluent = true , methods are named after the field; with chain = true , setters return this for chaining.
@Accessors(fluent = true)
@Data
public class UserBean {
private Integer id;
private String userName;
private String password;
}
UserBean u = new UserBean()
.id(10001)
.userName("polly")
.password("123456");
u.userName("Tom");
System.out.println(u.userName()); @Accessors(chain = true)
@Data
public class UserBean {
private Integer id;
private String userName;
private String password;
}
UserBean u = new UserBean()
.setId(10001)
.setUserName("polly")
.setPassword("123456");
u.setUserName("Tom");
System.out.println(u.getUserName());Selected Java Interview Questions
A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.