package net.sourceforge.javautil.common.proxy.pojo;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import net.sourceforge.javautil.common.ReflectionUtil;
import net.sourceforge.javautil.common.proxy.AbstractProxy;
import net.sourceforge.javautil.common.proxy.AdaptableProxyHandlerAbstract;
import net.sourceforge.javautil.common.proxy.DefaultReturnValue;
import net.sourceforge.javautil.common.reflection.cache.ClassCache;
import net.sourceforge.javautil.common.reflection.cache.ClassDescriptor;
import net.sourceforge.javautil.common.reflection.cache.ClassMethod;
/**
* This allows an interface to be used along with annotations to invoke methods on a POJO
* that does not actually implement the interface. Interface proxy methods that do not
* have annotations set on them will simply be passed on to a method with the same name
* on the target POJO. Interface proxy methods that do have annotations will use those
* annotations to search for corresponding methods in the target POJO independent of the
* method name. Any methods not found will simply return.
*
* @author elponderador
* @author $Author: ponderator $
* @version $Id: PojoProxy.java 2700 2010-12-30 15:59:51Z ponderator $
*/
public class PojoProxy extends AbstractProxy {
/**
* Assumes current thread based class loader.
*
* @see #create(ClassLoader, Class, Object)
*/
public static <T> T create (Class<T> iface, Object pojo) {
return create(Thread.currentThread().getContextClassLoader(), iface, pojo);
}
/**
* @param <T> The type of proxy
* @param cl The class loader to use to create the proxy
* @param iface The interface of the type
* @param pojo The pojo target
* @return A proxy for invoking available methods on the pojo
*/
public static <T> T create (ClassLoader cl, Class<T> iface, Object pojo) {
return (T) Proxy.newProxyInstance(cl, new Class[] { iface }, new PojoProxy(pojo));
}
protected Object pojo;
protected ClassDescriptor pojoDescriptor;
public PojoProxy (Object pojo) {
this.pojo = pojo;
this.pojoDescriptor = ClassCache.getFor(pojo.getClass());
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Method target = this.adapters.size() > 0 ? this.adapter.translatedMethod(this, method, args) : method;
Pojo pojo = target.getAnnotation(Pojo.class);
if (pojo != null) {
ClassMethod cm = pojoDescriptor.getMethod(pojo.value());
if (cm != null) target = cm.getJavaMember(); else target = null;
} else {
ClassMethod cm = pojoDescriptor.findMethod(target.getName(), args);
if (cm != null) target = cm.getJavaMember(); else target = null;
}
Object returnValue = null;
if (target == null) {
DefaultReturnValue drv = method.getAnnotation(DefaultReturnValue.class);
if (drv != null) {
returnValue = drv.value();
} else {
returnValue = method.getReturnType().isPrimitive() ? ReflectionUtil.getPrimitiveDefault(method.getReturnType()) : null;
}
} else {
returnValue = super.invoke(proxy, target, args);
}
return method.getReturnType() == void.class ? null : ReflectionUtil.coerce(method.getReturnType(), returnValue);
}
@Override protected Object getTarget(Method method, Object[] args) {
return this.pojo;
}
}