BerndGit BerndGit - 1 month ago 5
Java Question

How to implement a callback when entity is persisted?

I have a very simple entity, as:

@Entity
public class entityA {

@Id
@GeneratedValue(strategy = GenerationType.TABLE)
private Long id;

public entityA(){}

}


As far as I understood the value
id
is only set if the entity is persisted. Is this correct?

Since I want to propagate the value of the
id
to some observers, this only makes sense after the item is persisted. So I need some kind of callback (something like
void onPersit()
) in
entityA
. The method
entityA.onPersit()
shall be automatically be executed if the entity is persisted. How to implement this?

(How) can an entity determin it's own status. E.g. is there some kind of
this.isPersisted()
or
this.isDetached()
?

Answer

If I where you, I would go with the solution that is available in the JPA specification, the @PostPersist annotation. Your entity would look like this:

@Entity
public class entityA {

    @Id
    @GeneratedValue(strategy = GenerationType.TABLE)
    private Long id;

    public entityA(){}

    @PostPersist
    public void onPersit() {
      // logic to perform after the entity has been persisted
    }

}

The Java Persistence 2.1 Specification explains the functionality like this:

The PostPersist and PostRemove callback methods are invoked for an entity after the entity has been made persistent or removed. These callbacks will also be invoked on all entities to which these operations are cascaded. The PostPersist and PostRemove methods will be invoked after the database insert and delete operations respectively. These database operations may occur directly after the persist, merge, or remove operations have been invoked or they may occur directly after a flush operation has occurred (which may be at the end of the transaction). Generated primary key values are available in the PostPersist method.

The above quote also answers your question if the generated primary key is only available after insertion to the database. Your assumption was right, but it will be available in the method annotated @PostPersist.


Regarding the question about having methods on the entity to check its state, the naive way is to check whether the @Id field is null or not. If the code is written by the book (i.e. doesn't modify the field itself), this will work.

However, there is a more sophisticated to achieve this, as proposed in this answer:

@Transient
private boolean persisted;

@PostLoad
@PostPersist
public void setPersisted() {
  persisted = true;
}

By using the @PostLoad and @PostPersist callbacks, this makes sure that the persisted field is set correctly. Again, you need to be sure you don't modify the field outside of this method. The @Transient annotation makes sure that the field is not a candidate for serialization, and as such is not persistent.

Either of these solutions could be placed in an abstract entity class for reusage across entities.