Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JPA @Transient fields being cleared before @PreUpdate method is called

I have an User Entity class that I'm trying to do password hashing for. I thought that the easiest way to do this would be to create a password field annotated with @Transient and a hashed password field that is set just before the object is persisted with a method annotated with @PrePersist and @PreUpdate.

So I have something like this:

@Transient
private String password;

private String hashedPassword;

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

This works perfectly fine when an entity is persisted. The password field is still set by the time hashPassword is called, and a value for hashedPassword is calculated and stored.

However, the same isn't true for an update - even if a new value for password is set just before merging the entity, the field is null by the time hashPassword is called. Why is this? Shouldn't the values of transient fields stick around at least until the entity is persisted?

(I'm using EclipseLink 2.0.0 btw, if it makes any difference)

like image 685
robbles Avatar asked Aug 05 '10 00:08

robbles


People also ask

What does the annotation @transient on a field or property of an entity mean?

@Transient annotation in JPA or Hibernate is used to indicate that a field is not to be persisted or ignore fields to save in the database. @Transient exist in javax. persistence package. It is used to annotate a property or field of an entity class, mapped superclass, or embeddable class.

What does @transient mean in spring?

What is @Transient annotation in Spring? @Transient annotation is used to mark a field to be transient for the mapping framework, which means the field marked with @Transient is ignored by mapping framework and the field not mapped to any database column (in RDBMS) or Document property (in NOSQL).


2 Answers

I solved this by setting updatable und insertable to false on the "transient" field, so in your case this would be:

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

Therefore a table @column is required (which is kind of ugly) but it will never be filled (which was important in my case for security reasons).

I tested against Hibernate 4.3.4.Final and it worked for me. The field value was useable in my EntityLister @PrePersist and @PreUpdate methods but was not stored in the database.

Hope that helps anybody having similar problems.

like image 172
Jan Ziegler Avatar answered Oct 04 '22 20:10

Jan Ziegler


As mentioned in the above answer, this is by design in the spec. EclipseLink contains an event (postMerge) that is not part of the JPA spec that should be called in the right point in the cycle for you. In EclipseLink 2.1 The Descriptor Event Adaptor class can be registered using the regular @EventListeners annotation, pre 2.1 you will need to add the even using EclipseLink native 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();
    }
}
like image 37
Peter Krogh Avatar answered Oct 04 '22 19:10

Peter Krogh