Specifying JPA entity listeners separately being independent of its associated entity
Asked Answered
C

2

2

Entity listeners are commonly placed over respective entity classes such as,

@Entity
@EntityListeners(EntityListener.class)
public class Entity implements Serializable {

    //...
}

Applications may use one or more class libraries for sharing common functionalities across different projects/modules. In addition to the EE module, class libraries basically also require entities to be present on the compile-time class-path as a dependency i.e entities are present in both the places namely a class library and an EE module in an enterprise application. As such, the class EntityListener in the given example needs to be present on the compile-time class-path of a class library (it cannot only be added to the EE module).

If entity listeners were not to be tightly-coupled with respective entities and be specified separately then, there would be no need to add this dependency (listeners) to a class library i.e. entity listeners would then be present only in the EE project where EJBs are perfectly eligible for injection using @Inject.

Is there any possibility to separate this annotation @EntityListeners(EntityListener.class) from its associated entity so that it can be declared separately in a separate place? There should not be need to tightly couple this annotation with its respective entity.

Using GlassFish 4.1 having EclipseLink 2.6.0 (JPA 2.1).


This is required as there is a problem injecting EJBs into such entity listeners available in class libraries using the CDI specific artifact @Inject. EJBs could otherwise be injected by using @Inject into listeners, if the listeners were present in the EE project (module) only (but not in a class library).

Cumshaw answered 18/9, 2015 at 12:46 Comment(0)
C
3

One way to take the annotation @EntityListeners away from an entity is using both XML and annotation approaches together. Mixing and matching the XML descriptor and metadata annotations is perfectly valid and documented.

In order to override that annotation, one will have to register entity listeners in a file called orm.xml[1] as follows.

<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings version="2.1"
                 xmlns="http://xmlns.jcp.org/xml/ns/persistence/orm"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence/orm orm_2_1.xsd">

    <entity class="com.example.entity.Entity">
        <entity-listeners>
            <entity-listener class="com.example.entity.listeners.EntityListener"/>
        </entity-listeners>
    </entity>

    <!--Other listeners-->

</entity-mappings>

The corresponding listener class may then be left untouched with annotations as follows.

public class EntityListener {

    @PostPersist
    @PostUpdate
    @PostRemove
    public void onChange(Entity entity) {

        // Do something with the entity.
    }
}

Those callbacks may vary depending upon the functional requirement.


One may, if necessary, also define callbacks as XML elements avoiding callback annotations in the listener class such as,

<entity class="com.example.entity.Entity">
    <entity-listeners>
        <entity-listener class="com.example.entity.listeners.EntityListener">
            <post-persist method-name="onChange"/>
            <post-update method-name="onChange"/>
            <post-remove method-name="onChange"/>
        </entity-listener>
    </entity-listeners>
</entity>

Those three annotations namely @PostPersist, @PostUpdate and @PostRemove in the listener class are now not required, since they are registered in the XML descriptor.


[1] IDEs like NetBeans do not seem to have wizard support for generating the orm.xml file. In NetBeans projects, one will need to create an XML file manually under src/conf (or any other custom configured location) so that the application builder can place that file under META-INF/orm.xml while building/deploying the application.

Cumshaw answered 19/9, 2015 at 9:22 Comment(0)
L
3

Yes, you can define the default entity listener with xml.

Lexielexigraphy answered 18/9, 2015 at 14:54 Comment(3)
What is to be done in the default listener which receives all events of all entities in the current persistence unit?Cumshaw
Heard of if statement? :) Or a map (entity instance type -> your custom listener implementation)? After all, that's more or less the way JPA provider registers and finds the listeners; it's just a convenience that they provide the shortcuts to define it on the entities directly.Lexielexigraphy
I accepted my own answer as it actually functioned for me.Cumshaw
C
3

One way to take the annotation @EntityListeners away from an entity is using both XML and annotation approaches together. Mixing and matching the XML descriptor and metadata annotations is perfectly valid and documented.

In order to override that annotation, one will have to register entity listeners in a file called orm.xml[1] as follows.

<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings version="2.1"
                 xmlns="http://xmlns.jcp.org/xml/ns/persistence/orm"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence/orm orm_2_1.xsd">

    <entity class="com.example.entity.Entity">
        <entity-listeners>
            <entity-listener class="com.example.entity.listeners.EntityListener"/>
        </entity-listeners>
    </entity>

    <!--Other listeners-->

</entity-mappings>

The corresponding listener class may then be left untouched with annotations as follows.

public class EntityListener {

    @PostPersist
    @PostUpdate
    @PostRemove
    public void onChange(Entity entity) {

        // Do something with the entity.
    }
}

Those callbacks may vary depending upon the functional requirement.


One may, if necessary, also define callbacks as XML elements avoiding callback annotations in the listener class such as,

<entity class="com.example.entity.Entity">
    <entity-listeners>
        <entity-listener class="com.example.entity.listeners.EntityListener">
            <post-persist method-name="onChange"/>
            <post-update method-name="onChange"/>
            <post-remove method-name="onChange"/>
        </entity-listener>
    </entity-listeners>
</entity>

Those three annotations namely @PostPersist, @PostUpdate and @PostRemove in the listener class are now not required, since they are registered in the XML descriptor.


[1] IDEs like NetBeans do not seem to have wizard support for generating the orm.xml file. In NetBeans projects, one will need to create an XML file manually under src/conf (or any other custom configured location) so that the application builder can place that file under META-INF/orm.xml while building/deploying the application.

Cumshaw answered 19/9, 2015 at 9:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.