While migrating a project of mine from JPA2 to Avaje Ebean, I encountered a issue, I wasn’t expecting.
Avaje Ebean does not support the JPA EntityListener Annotations, like
@PrePersist,
@PostPersist,
@PreUpdate,
@PostUpdate,
@PostLoad
Some nice folks on the Ebean Mailinglist directed me to some Documentation about EntityListeners in Ebean including a helpful forum link which finally pointed me to the BeanPersistController Interface in the Ebean Java API .
With that Information, I was able to create a EntityListener that enables the use of the JPA EntityListener Annotations with Ebean.
This Gist shows how I’ve done it:
package models.sgcore; | |
import com.avaje.ebean.event.BeanPersistAdapter; | |
import com.avaje.ebean.event.BeanPersistRequest; | |
import javax.annotation.PreDestroy; | |
import javax.persistence.*; | |
import java.lang.reflect.InvocationTargetException; | |
import java.lang.reflect.Method; | |
import java.util.HashMap; | |
import java.util.Map; | |
import java.util.Set; | |
import java.util.TreeMap; | |
/** | |
* This is a <code>BeanPersistController</code> that looks for methods annotated with the JPA Annotations | |
* <code>@PrePersist</code> | |
* <code>@PostPersist</code> | |
* <code>@PreUpdate</code> | |
* <code>@PostUpdate</code> | |
* <code>@PreDestroy</code> | |
* <code>@PostLoad</code> | |
* | |
* registers those methods with this Listener and calls them when necessary. | |
*/ | |
public class SGBeanPersistController extends BeanPersistAdapter { | |
private Map<String,Method> prePersistMap = new TreeMap<String, Method>(); | |
private Map<String,Method> postPersistMap = new TreeMap<String, Method>(); | |
private Map<String,Method> preUpdateMap = new TreeMap<String, Method>(); | |
private Map<String,Method> postUpdateMap = new TreeMap<String, Method>(); | |
private Map<String,Method> preDestroyMap = new TreeMap<String, Method>(); | |
private Map<String,Method> postLoadMap = new TreeMap<String, Method>(); | |
@Override | |
public boolean isRegisterFor(Class<?> aClass) { | |
if(aClass.getAnnotation(Entity.class) != null){ | |
System.out.println("Registering a Entity; Type is " + aClass.toString()); | |
Method[] methods = aClass.getMethods(); | |
boolean hasListener = false; | |
for(Method m : methods) | |
{ | |
// System.out.println("looking if method " + m.toString() + " has Annotation on it. "); | |
if(m.isAnnotationPresent(PrePersist.class)) | |
{ | |
prePersistMap.put(aClass.getName(), m); | |
hasListener = true; | |
} | |
if(m.isAnnotationPresent(PostPersist.class)) | |
{ | |
postPersistMap.put(aClass.getName(), m); | |
hasListener = true; | |
} | |
if(m.isAnnotationPresent(PreDestroy.class)) | |
{ | |
preDestroyMap.put(aClass.getName(), m); | |
hasListener = true; | |
} | |
if(m.isAnnotationPresent(PreUpdate.class)) | |
{ | |
preUpdateMap.put(aClass.getName(), m); | |
hasListener = true; | |
} | |
if(m.isAnnotationPresent(PostUpdate.class)) | |
{ | |
postUpdateMap.put(aClass.getName(), m); | |
hasListener = true; | |
} | |
if(m.isAnnotationPresent(PostLoad.class)) | |
{ | |
postLoadMap.put(aClass.getName(), m); | |
hasListener = true; | |
} | |
} | |
return hasListener; | |
} | |
return false; | |
} | |
private void getAndInvokeMethod(Map<String,Method> map, Object o) | |
{ | |
Method m = map.get(o.getClass().getName()); | |
if(m != null) | |
try { | |
m.invoke(o); | |
} catch (IllegalAccessException e) { | |
e.printStackTrace(); | |
} catch (InvocationTargetException e) { | |
e.printStackTrace(); | |
} | |
} | |
@Override | |
public boolean preInsert(BeanPersistRequest<?> request) { | |
getAndInvokeMethod(prePersistMap, request.getBean()); | |
return super.preInsert(request); | |
} | |
@Override | |
public boolean preDelete(BeanPersistRequest<?> request) { | |
getAndInvokeMethod(preDestroyMap, request.getBean()); | |
return super.preDelete(request); | |
} | |
@Override | |
public boolean preUpdate(BeanPersistRequest<?> request) { | |
getAndInvokeMethod(preUpdateMap, request.getBean()); | |
return super.preUpdate(request); | |
} | |
@Override | |
public void postDelete(BeanPersistRequest<?> request) { | |
// there is no @PostDestroy annotation in JPA 2 | |
super.postDelete(request); | |
} | |
@Override | |
public void postInsert(BeanPersistRequest<?> request) { | |
getAndInvokeMethod(postPersistMap, request.getBean()); | |
super.postInsert(request); | |
} | |
@Override | |
public void postUpdate(BeanPersistRequest<?> request) { | |
getAndInvokeMethod(postUpdateMap, request.getBean()); | |
super.postUpdate(request); | |
} | |
@Override | |
public void postLoad(Object bean, Set<String> includedProperties) { | |
getAndInvokeMethod(postLoadMap, bean); | |
super.postLoad(bean, includedProperties); | |
} | |
} |
Questions? Comments? Forks?
I appreciate any kind of feedback!