class EntityManagerFactoryWrapper implements InvocationHandler {
private EntityManagerFactory innerFactory;
public EntityManagerFactoryWrapper(EntityManagerFactory innerFactory) {
this.innerFactory = innerFactory;
}
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result;
try {
result = method.invoke(innerFactory, args);
} catch (InvocationTargetException e) {
throw e.getTargetException();
}
if (result instanceof EntityManager) {
EntityManager em = (EntityManager)result;
result = Proxy.newProxyInstance(EntityManagerFactoryWrapper.class.getClassLoader(),
new Class<?>[] { EntityManager.class }, new EntityManagerWrapper(em));
}
return result;
}
}
class EntityManagerWrapper implements InvocationHandler {
private EntityManager em;
public EntityManagerWrapper(EntityManager em) {
this.em = em;
}
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result;
try {
result = method.invoke(em, args);
} catch (InvocationTargetException e) {
throw e.getTargetException();
}
if (result instanceof Query) {
Query query = (Query)result;
result = Proxy.newProxyInstance(EntityManagerWrapper.class.getClassLoader(), getInterfaces(query),
new QueryWrapper(query));
}
return result;
}
static Class<?>[] getInterfaces(Object instance) {
Set<Class<?>> interfaces = new HashSet<>();
getInterfaces(instance.getClass(), interfaces);
return interfaces.toArray(new Class<?>[0]);
}
static void getInterfaces(Class<?> cls, Set<Class<?>> interfaces) {
if (cls.getSuperclass() != null) {
getInterfaces(cls.getSuperclass(), interfaces);
}
for (Class<?> iface : cls.getInterfaces()) {
interfaces.add(iface);
getInterfaces(iface, interfaces);
}
}
}
class QueryWrapper implements InvocationHandler {
private Query query;
public QueryWrapper(Query query) {
this.query = query;
}
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result;
try {
result = method.invoke(query, args);
} catch (InvocationTargetException e) {
throw e.getTargetException();
}
if (method.getName().equals("getResultList") && Query.class.isAssignableFrom(method.getDeclaringClass())) {
List<Object> list = new ArrayList<>();
for (Object element : (Iterable<?>)result) {
if (element instanceof HibernateProxy) {
Hibernate.initialize(element);
element = ((HibernateProxy)element).getHibernateLazyInitializer().getImplementation();
}
list.add(element);
}
result = list;
}
return result;
}
}