How to inject a spring's service bean into a JPA Entity?

11,917

What's the corresponding eventListeners in JPA's world ?

JPA has Entity Listeners (and Callback Methods). From the JPA 2.0 specification:

3.5 Entity Listeners and Callback Methods

A method may be designated as a lifecycle callback method to receive notification of entity lifecycle events. A lifecycle callback method can be defined on an entity class, a mapped superclass, or an entity listener class associated with an entity or mapped superclass. An entity listener class is a class whose methods are invoked in response to lifecycle events on an entity. Any number of entity listener classes can be defined for an entity class or mapped superclass.

(...)

The entity listener class must have a public no-arg constructor.

Entity listeners are stateless. The lifecycle of an entity listener is unspecified.

The following rules apply to lifecycle callbacks:

  • Lifecycle callback methods may throw unchecked/runtime exceptions. A runtime exception thrown by a callback method that executes within a transaction causes that transaction to be marked for rollback.
  • Lifecycle callbacks can invoke JNDI, JDBC, JMS, and enterprise beans.
  • In general, the lifecycle method of a portable application should not invoke EntityMan- ager or Query operations, access other entity instances, or modify relationships within the same persistence context. A lifecycle callback method may modify the non-relationship state of the entity on which it is invoked.

(...)

3.5.1 Lifecycle Callback Methods

Entity lifecycle callback methods can be defined on an entity listener class and/or directly on an entity class or mapped superclass.

Lifecycle callback methods are annotated with annotations designating the callback events for which they are invoked or are mapped to the callback event using the XML descriptor.

The annotations used for callback methods on the entity class or mapped superclass and for callback methods on the entity listener class are the same. The signatures of individual methods, however, differ.

Callback methods defined on an entity class or mapped superclass have the following signature:

void <METHOD>()

Callback methods defined on an entity listener class have the following signature:

void <METHOD>(Object)

The Object argument is the entity instance for which the callback method is invoked. It may be declared as the actual entity type.

The callback methods can have public, private, protected, or package level access, but must not be static or final.

(...)

Here is an example (from the spec):

@Entity
@EntityListeners(com.acme.AlertMonitor.class)
    public class Account {
    Long accountId;
    Integer balance;
    boolean preferred;
    @Id
    public Long getAccountId() { ... }
    ...
    public Integer getBalance() { ... }
    ...
    @Transient // because status depends upon non-persistent context
    public boolean isPreferred() { ... }
    ...
    public void deposit(Integer amount) { ... }
    public Integer withdraw(Integer amount) throws NSFException {... }

    @PrePersist
    protected void validateCreate() {
        if (getBalance() < MIN_REQUIRED_BALANCE)
            throw new AccountException("Insufficient balance to open an account");
    }

    @PostLoad
    protected void adjustPreferredStatus() {
        preferred = (getBalance() >= AccountManager.getPreferredStatusLevel());
    }
}

public class AlertMonitor {
    @PostPersist
    public void newAccountAlert(Account acct) {
        Alerts.sendMarketingInfo(acct.getAccountId(), acct.getBalance());
    }
}

In your case, you'll probably want PostLoad callback methods.

See also the Chapter 6. Entity listeners and Callback methods in the Hibernate Entity Manager documentation.

But to put it simply, what you want to do is not that simple with JPA and using AspectJ class weaving with the @Configurable annotation might be the best option.

References

  • JPA 2.0 Specification
    • Section 3.5 "Entity Listeners and Callback Methods"
Share:
11,917

Related videos on Youtube

smallufo
Author by

smallufo

A Java/Kotlin programmer twitter : http://twitter.com/smallufo

Updated on May 03, 2022

Comments

  • smallufo
    smallufo over 1 year

    My problem is very similar to this one : Injecting fields via Spring into entities loaded by Hibernate

    The difference is that , I am using JPA2 entities , not hibernate . While the underlayer is still hibernate (3.5.5).

    My spring version is 3.0.4.

    What's the corresponding eventListeners in JPA's world ?

    Sample code from the original post :

    class Student {
       int id; //loaded from DB
       String name; //loaded from DB
       int injectedProperty; //Inject via Spring
       transient Service serviceImpl; //Inject via Spring
    }
    

    I know there may be aspectJ's solutions , but I'd rather like a pure-java solution. Thanks.

  • smallufo
    smallufo about 13 years
    Hi , thanks. But I still cannot inject a service object into the 'AlertMonitor' in this example.
  • Devanshu Mevada
    Devanshu Mevada about 13 years
    @smallufo The Entity Listener is not a Spring bean so you'll have to use either the @Configurable annotation (so you just moved the problem to the listerner) or perform a "lookup".
  • Devanshu Mevada
    Devanshu Mevada about 13 years
    @smallufo Just in case, also have a look at jblewitt.com/blog/?p=129. But to put it simply, what you want to do is not that easy to do with JPA.
  • smallufo
    smallufo about 13 years
    Thank you , it seems aspectj is the only solution now , and it's another framework binding to the Entity class ... sigh ... Hoping future spec can address this problem.
  • Alfredo Osorio
    Alfredo Osorio about 10 years
    @PascalThivent so practically DDD is just theory. So dissapointed :(, whenever I try to apply DDD things get complicated because I cannot inject services into the entity.
  • MirMasej
    MirMasej about 8 years
    @AlfredoOsorio I disagree. JPA Entity != DDD entity. It seems to be practical to have them that way (if you decided to use JPA), but you pay the price. I don't remember how it was resolved by Vernon Vaughn in his "Implementing DDD" book where he has domain entities as JPA entities. Maybe he didn't use any services (domain nor infrastructure) in the entities, they're rarely needed there after all.