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).
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.