I have a custom setter in my Lombok-based POJO:
@Data @Builder public class User { private static final PasswordEncoder ENCODER = new BCryptPasswordEncoder(); private String password = null; public void setPassword(String password) { Assert.notNull(password); this.password = ENCODER.encode(password); }
but when I use the Lombok generated builder:
User user = User.builder() .password(password) .build();
my custom setter is not invoked, and so the password is not encoded. This makes me sad.
My custom setter is, of course, invoked when I use it directly:
public void changePassword(String password, User user) { user.setPassword(password); }
What can I do to have Lombok's builder use my custom setter?
We already have a full introduction into Lombok's features. @Data generates all the boilerplate that is normally associated with a simple POJO (Plain Old Java Object): getters for all fields, setters for all non-final fields, and appropriate toString, equals and hashCode implementations, and a constructor.
The @Builder annotation produces complex builder APIs for your classes. @Builder lets you automatically produce the code required to have your class be instantiable with code such as: Person. builder()
1. @Builder. The @Builder annotation produces complex builder APIs for the annotated POJO classes. For example, if we annotate a class Article annotated with @Builder annotation, we can create Article instances using builder API.
The builder pattern simplifies the creation of objects. It also simplifies the code as your do not have to call a complex constructor or call several setter methods on the created object. The builder pattern can be used to create an immutable class.
Per the documentation for @Builder
: Just define enough skeleton yourself. In particular, Lombok will generate a class UserBuilder
, fields mirroring the User
fields, and builder methods, and you can provide any or all of this yourself.
@Builder public class User { private static final PasswordEncoder ENCODER = new BCryptPasswordEncoder(); private String username; private String password; public static class UserBuilder { public UserBuilder password(String password) { this.password = ENCODER.encode(password); return this; } } }
I've accepted chrylis's answer but for completeness, here's are some ways to minimize customization and duplication.
Custom setter and builder with static helper
A static helper can be used to shares most of the set password functionality across the custom User.UserBuilder::password
method and the custom User::setPassword
method:
@Data @Builder public class User { private static final PasswordEncoder ENCODER = new BCryptPasswordEncoder(); private String password = null; public void setPassword(String password) { this.password = _encodePassword(password); } public static class UserBuilder { public UserBuilder password(String password) { this.password = _encodePassword(password) return this; } } private static String _encodePassword(String password) { Assert.notNull(password); return ENCODER.encode(password); } }
Custom setter and constructor
A custom constructor can use User::setPassword
which is invoked by the Lombok generated User.UserBuilder::build()
:
@Data @Builder public class User { private static final PasswordEncoder ENCODER = new BCryptPasswordEncoder(); private String password = null; User(String password) { setPassword(password); } public void setPassword(String password) { Assert.notNull(password); this.password = ENCODER.encode(password); } }
Custom setter and constructor with static helper
Or, a little more elegantly, with a custom constructor and a static helper method:
@Data @Builder public class User { private static final PasswordEncoder ENCODER = new BCryptPasswordEncoder(); private String password = null; User(String password) { _encodePassword(password, this); } public void setPassword(String password) { _encodePassword(password, this); } private static _encodePassword(String password, User user) { Assert.notNull(password); user.password = ENCODER.encode(password); } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With