I have a custom setter in my Lombok-based POJO:
@Data
@Builder
public class User {
private static final PasswordEncoder ENCODER = new BCryptPasswordEncod
Not really an answer to the question, but an edge case that made me to spend quite some time to find the issue.
If you have Builder
with custom setter on a field with Builder.Default
value, the name of the field in the generated builder class is not the same as the original field. In fact you would have two fields instead of one: password$value
and password$set
.
Nevertheless you can use them in the custom setter in this way:
public UserBuilder password(String password) {
this.password$value = ENCODER.encode(password);
this.password$set = true;
return this;
}
The tricky part is that if you use the origianl field name, Intellij IDEA doesn't warn you about that (as if everything is fine, but of course it won't compile). Already submitted a bug report to the plugin.
You are using setPassword rather than the builder's set method.
Here is what worked for me:
import lombok.Builder;
import lombok.Data;
@Builder
@Data
public class User {
private String username;
private String password;
public static class UserBuilder {
private String password;
public UserBuilder password(String password ) {
this.password ="ENCRIYP " + password;
return this;
}
}
public static void main(String[] args) {
System.out.println(User.builder().username("This is my username").password("Password").build().toString());
}
}
The result was:
User(username=This is my username, password=ENCRIYP Password)
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);
}
}
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;
}
}
}