在调用@PreUpdate方法之前清除JPA @Transient字段

时间:2010-08-05 00:08:14

标签: java jpa eclipselink

我有一个User Entity类,我正在尝试进行密码散列。我认为最简单的方法是创建一个用@Transient注释的密码字段和一个哈希密码字段,该密码字段是在使用@PrePersist和@PreUpdate注释的方法持久化对象之前设置的。

所以我有这样的事情:

@Transient
private String password;

private String hashedPassword;

@PrePersist
@PreUpdate
private void hashPassword() {
    if(password != null) {
        hashedPassword = PasswordHasher.hashPassword(password);
    }
}

当实体被持久化时,这非常适用。密码字段仍然由调用hashPassword的时间设置,并且计算并存储hashedPassword的值。

但是,对于更新也是如此 - 即使在合并实体之前设置了密码的新值,该字段在调用hashPassword时也为空。为什么是这样?至少在实体持续存在之前,瞬态字段的值是否应该保持不变?

(我正在使用EclipseLink 2.0.0 btw,如果它有任何区别的话)

2 个答案:

答案 0 :(得分:5)

我通过在“transient”字段上将可更新可插入设置为false来解决此问题,因此在您的情况下,这将是:

@Column(name = "password", insertable = false, updatable = false)
private String password;

因此需要一个表@column(这有点难看)但它永远不会被填充(出于安全考虑,这在我的情况下很重要)。

我测试了Hibernate 4.3.4.Final,它对我有用。字段值可用于我的EntityLister @PrePersist和@PreUpdate方法,但未存储在数据库中。

希望能帮助任何有类似问题的人。

答案 1 :(得分:3)

如上面的答案所述,这是在规范中设计的。 EclipseLink包含一个事件(postMerge),它不属于JPA规范,应该在循环中的正确点为您调用。在EclipseLink 2.1中可以使用常规@EventListeners注释来注册Descriptor Event Adapter类,在2.1之前,您需要使用EclipseLink本机API添加它。

@EntityListeners({
    a.b.MyEventListener.class,
})

package a.b;

import org.eclipse.persistence.descriptors.DescriptorEvent;
import org.eclipse.persistence.descriptors.DescriptorEventAdapter;

public class MyEventListener extends DescriptorEventAdapter {

    public void postMerge(DescriptorEvent event) {
        //event.getSession();
        //event.getObject();
        //event.getOriginalObject();
    }
}