[英]Use custom setter in Lombok's builder
我的基於 Lombok 的 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);
}
但是當我使用 Lombok 生成的構建器時:
User user = User.builder()
.password(password)
.build();
我的自定義設置器沒有被調用,所以密碼沒有被編碼。 這讓我很難過。
當然,當我直接使用它時,會調用我的自定義 setter:
public void changePassword(String password, User user) {
user.setPassword(password);
}
我該怎么做才能讓 Lombok 的構建器使用我的自定義 setter?
根據@Builder
的文檔:只需自己定義足夠的骨架。 特別是,Lombok 將生成一個類UserBuilder
、映射User
字段的字段和構建器方法,您可以自己提供其中的任何或全部。
@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;
}
}
}
我已經接受了chrylis的回答,但為了完整起見,這里有一些方法可以最大限度地減少定制和重復。
帶有靜態助手的自定義 setter 和 builder
靜態幫助器可用於跨自定義User.UserBuilder::password
方法和自定義User::setPassword
方法共享大部分設置密碼功能:
@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);
}
}
自定義 setter 和構造函數
自定義構造函數可以使用User::setPassword
,它由 Lombok 生成的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);
}
}
帶有靜態幫助器的自定義 setter 和構造函數
或者,更優雅一點,使用自定義構造函數和靜態輔助方法:
@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);
}
}
您正在使用 setPassword 而不是構建器的 set 方法。
這是對我有用的:
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());
}
}
結果是: User(username=This is my username, password=ENCRIYP Password)
不是問題的真正答案,而是一個邊緣情況,讓我花了很長時間來找到問題。
如果您在具有Builder.Default
值的字段上使用帶有自定義設置器的Builder
,則生成的構建器類中的字段名稱與原始字段不同。 事實上,您將有兩個字段而不是一個: password$value
和password$set
。
不過,您可以通過這種方式在自定義設置器中使用它們:
public UserBuilder password(String password) {
this.password$value = ENCODER.encode(password);
this.password$set = true;
return this;
}
棘手的部分是,如果您使用原始字段名稱,Intellij IDEA 不會警告您(好像一切都很好,但當然不會編譯)。 已經向插件提交了錯誤報告。
我在工作中遇到過這種情況。 下面是我想出來的。 這個想法是覆蓋 Lombok 的protected User(User.UserBuilder b)
方法
@Data
@Builder
public class User {
private static final PasswordEncoder ENCODER = new BCryptPasswordEncoder();
private String password;
private Integer otherField;
protected User(final User.UserBuilder<?, ?> b) {
setPassword(b.password);
otherField = b.otherField;
}
public void setPassword(String password) {
Assert.notNull(password);
this.password = ENCODER.encode(password);
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.