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!