如何设计依赖于业务代码的 JPA 实体 setter?

How can I design an JPA entity setter that depends on business code?

我有以下实体:

@Entity
public class User {

    @Id
    private Integer id;

    private String username;
    private String password;

}

要设置密码,必须提供明文密码,但实际存储的密码是明文密码的哈希值。问题是实际的哈希计算是业务相关的。更具体地说,我有以下接口和会话 Bean:

public interface PasswordHash {
    String hash(String password);
}

@Stateless
public class UserManager {

    @Inject
    private PasswordHash phash;

    public void changeUserPassword(User user, String newPassword) {
        String passwordHash = phash.hash(newPassword);
        /*Set password of 'user'*/
    }
}

有没有办法为User实体的'password'字段设计一个setter,这样UserManager就可以改​​变它的值,但是其他人做不到?如果不可能,是否有另一种方法可以安全地设置密码,而不会将 PasswordHash 接口暴露给客户端?请注意,实体 class 无法使用 CDI,因此我无法将 PasswordHash 的实例直接注入其中。

处理此问题的一种方法是不直接从您的服务层公开用户实体,仅在内部将其用于持久性。您通常最终所做的基本上是复制一些实体,并来回复制内容。这些 "copied" 类 有时称为数据传输对象。有像 Dozer 这样的工具可以使这更容易,尽管可以说不是更漂亮。

第二种方法是对抗企业Java,避免这些Anemic Objects。但是迟早,您可能必须进行编程查找,因为正如您所说,实体未启用 CDI。这也不是很好,但至少你得到了一些更面向对象的东西。