簡體   English   中英

在 Lombok 的構建器中使用自定義 setter

[英]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$valuepassword$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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM