package org.test4j.hamcrest.matcher.property.reflection;
import org.test4j.module.Test4JException;
/**
* Utility class for handling Hibernate proxies during the comparison.
* <p/>
* Every operation is performed through reflection to avoid a direct link to
* Hibernate. This way you do not need Hibernate in the classpath to use the
* reflection comparator.
*
*/
@SuppressWarnings({ "rawtypes" })
public class HibernateUtil {
/**
* The hibernate proxy type, null if the class is not found in the classpath
*/
protected static Class hibernateProxyClass;
static {
try {
hibernateProxyClass = Class.forName("org.hibernate.proxy.HibernateProxy");
} catch (ClassNotFoundException e) {
// hibernate not found in the classpath
hibernateProxyClass = null;
}
}
/**
* Checks whether the given ojbect is a HibernateProxy instance.
*
* @param object
* The object
* @return True if the object is a proxy
*/
public static boolean isHibernateProxy(Object object) {
return hibernateProxyClass != null && hibernateProxyClass.isInstance(object);
}
/**
* Checks whether the given proxy object has been loaded.
*
* @param object
* The object or proxy
* @return True if the object is a proxy and has been loaded
*/
public static boolean isUninitialized(Object object) {
if (!isHibernateProxy(object)) {
return false;
}
return (Boolean) invokeLazyInitializerMethod("isUninitialized", object);
}
/**
* Gets the class name of the proxied object
*
* @param object
* The object or proxy
* @return The class name of the object, null if the object is null
*/
public static String getEntitiyName(Object object) {
if (!isHibernateProxy(object)) {
return object == null ? null : object.getClass().getName();
}
return (String) invokeLazyInitializerMethod("getEntityName", object);
}
/**
* Gets the unique identifier of the given proxy object.
*
* @param object
* The object or proxy
* @return The identifier or null if the object was not a proxy
*/
public static Object getIdentifier(Object object) {
if (!isHibernateProxy(object)) {
return null;
}
return invokeLazyInitializerMethod("getIdentifier", object);
}
/**
* Gets (and loads) the wrapped object out of a given hibernate proxy.
* <p/>
* If the given object is not a proxy or if Hibernate is not found in the
* classpath, this method just returns the given object. If the given object
* is a proxy, the proxy is initialized (loaded) and the un-wrapped object
* is returned.
*
* @param object
* The object or proxy
* @return The uproxied object or the object itself if it was no proxy
*/
public static Object getUnproxiedValue(Object object) {
// check whether object is a proxy
if (!isHibernateProxy(object)) {
return object;
}
// found a proxy, load and un-wrap
return invokeLazyInitializerMethod("getImplementation", object);
}
/**
* Invokes the given method on the LazyInitializer that is associated with
* the given proxy.
*
* @param methodName
* The method to invoke, not null
* @param proxy
* The hibernate proxy instance, not null
* @return The result value of the method call
*/
@SuppressWarnings("unchecked")
protected static Object invokeLazyInitializerMethod(String methodName, Object proxy) {
try {
Object lazyInitializer = hibernateProxyClass.getMethod("getHibernateLazyInitializer").invoke(proxy);
return lazyInitializer.getClass().getMethod(methodName).invoke(lazyInitializer);
} catch (Throwable e) {
throw new Test4JException("Unable to invoke method on lazy initializer of Hibernate proxy. Method: "
+ methodName + ", proxy: " + proxy, e);
}
}
}