Search code examples
jakarta-eejpa-2.0mappedsuperclassentitylistenerstable-per-class

Entity listener on a @MappedSuperclass does not work?


Background

I am using EclipseLink (version 2.3.2.v20111125-r10461, implementation provider for the JPA 2.0 specification).

Consider this @MappedSuperclass, called Person:

@MappedSuperclass
@EntityListeners({Listener.class})
public abstract class Person implements Serializable
{
    @Id @GeneratedValue
    private Long id;
}

He is abstract and has a listener (Listener) attached to him. Here is the listener implementation:

public class Listener
{
    @PrePersist
    public void sayHi(Person person) {
        System.out.println("Hi!");
    }
}

Then we have an Employee class that extends Person:

@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Employee extends Person
{
    private int salary;
}

Employee is still abstract and not meant to be instantiated. However, Employee is thought of as possibly being part of a relationship and thus annotated @Entity. The hierarchy continues with a non-abstract entity called PartTimeEmployee:

@Entity
public class PartTimeEmployee extends Employee
{
    private int hoursWorked;
}

PartTimeEmployee is meant to be instantiated. Let's try that and see what happens! All seem to work fine except one minor detail. The entity listener registered on @MappedSuperclass Person is not called. The listener is not even called if we move up the @EntityListeners annotation from Person to Employee.

One fix

Move the @EntityListeners annotation all the way to PartTimeEmployee and he shall be called. Hmm.

Another fix

We can keep the listener registered on Person and the listener will be called like intended, if we completely leave out the @Inheritance annotation on Employee. But then of course, I get a single table strategy which I don't want to have. Likewise we can be a little bit more explicit and change the strategy value from InheritanceType.TABLE_PER_CLASS to InheritanceType.SINGLE_TABLE and the listener will be called. Only problem of course is that my database schema will not look the way I want it to.

So, the core of the problem here is the @Inheritance annotation (more specifically; changing strategy to one table per class) on the Employee class, which makes EclipseLink forget all about entity listeners in the hierarchy.

That is not at all what I had expected. What is it that I do not understand?


Solution

  • I think you might have found an EclipseLink bug, they're common with inheritance annotations.

    I suggest upgrading to latest version of EclipseLink, your version is over a year old. If that doesn't work then you'll have to annotate your derived classes with your listener.

    If you're feeling particularly adventurous you can implement a SessionCustomizer which will add listeners to classes at start-up.