Package net.sourceforge.javautil.common.reflection.proxy

Source Code of net.sourceforge.javautil.common.reflection.proxy.ReflectiveObjectProxy

package net.sourceforge.javautil.common.reflection.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Proxy;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import net.sourceforge.javautil.common.ReflectionUtil;
import net.sourceforge.javautil.common.exception.ThrowableManagerRegistry;

/**
* This is a standard implementation of {@link ReflectiveProxy}. It respects the use of {@link ReflectiveWrapper} and
* {@link ReflectiveConstructor} on proxy interfaces.
*
* @author elponderador
*/
public class ReflectiveObjectProxy extends ReflectiveProxy {
 
  /**
   * This will attempt to load the class via the {@link ReflectiveWrapper} annotation on the interface,
   * and optionally and instance of it in order to facility declaration use.
   *
   * @param newInstance True if a new instance of the class should be created, otherwise this will be a static method interface using
   * only the class
   *
   * @see #createProxy(ClassLoader, Class, Object)
   */
  public static <T> T createProxy (ClassLoader cl, Class<T> iface, boolean newInstance) {
    ReflectiveWrapper wrapper = iface.getAnnotation(ReflectiveWrapper.class);
    if (wrapper != null) {
      Class target = ReflectionUtil.getClass(wrapper.value(), cl);
      return createProxy(cl, iface, newInstance ? ReflectionUtil.newInstance(target, new Class[0]) : target);
    }
    throw new IllegalArgumentException("Could not determine wrapped class from : " + iface);
  }
 
  /**
   * @param <T> The type of Proxy to be returned.
   * @param cl The {@link ClassLoader} to be used for boundary loading.
   * @param iface The interface that defines the proxy.
   * @param target The boundary object that will be the target of the real method invocations.
   * @return A proxy that can be used to invoke boundary methods.
   */
  public static <T> T createProxy (ClassLoader cl, Class<T> iface, Object target) {
    return (T) Proxy.newProxyInstance(cl, new Class[] { iface }, new ReflectiveObjectProxy(target));
  }
 
  /**
   * @param proxy The proxy object
   * @return The actual target object, behind the proxy
   */
  public static Object getTargetObject (Object proxy) {
    InvocationHandler ih = Proxy.getInvocationHandler(proxy);
    if (ih instanceof ReflectiveObjectProxy) {
      return ((ReflectiveObjectProxy)ih).object;
    } else
      throw new IllegalArgumentException(proxy + " is not handled by ReflectiveObjectProxy");
  }
 
  /**
   * This can be used in order to indirectly instantiate a boundary class and at the same time
   * return a typed proxy for interacting with the new instance. Interfaces must use the {@link ReflectiveConstructor}
   * for defining constructors.
   *
   * @param <T> The type of Proxy to be returned.
   * @param proxyCL The {@link ClassLoader} for the proxy.
   * @param cl The {@link ClassLoader} for boundary loading.
   * @param iface The interface that defines the proxy.
   * @param parameters The parameters to pass to the constructor call.
   * @return A proxy that wraps the new instance of the boundary class.
   */
  public static <T> T newInstance (ClassLoader proxyCL, ClassLoader cl, Class<T> iface, Object... parameters) {
    try {
      if (!iface.isInterface() || iface.getAnnotation(ReflectiveConstructor.class) == null)
        throw new IllegalArgumentException(iface + " must be a reflective wrapper.");
     
      ReflectiveConstructor c = iface.getAnnotation(ReflectiveConstructor.class);
      if (c == null)
        throw new IllegalArgumentException("This wrapper does not support new instance construction");
     
      Class[] types = c.parameterTypes();
      for (int s=0; s<types.length; s++) types[s] = translateParameterType(cl, types[s]);
     
      Object[] args = new Object[parameters.length];
      for (int o=0; o<parameters.length; o++) args[o] = translateArgument(parameters[o]);
       
      return createProxy(proxyCL, iface, ReflectionUtil.newInstance(cl.loadClass( c.type() ), types, args));
    } catch (ClassNotFoundException e) {
      throw ThrowableManagerRegistry.caught(e);
    }
  }
 
  /**
   * This, utilizing {@link ReflectiveWrapper}, allows on to easily translate proxy types to boundary types.
   *
   * @param cl The {@link ClassLoader} to load boundary classes.
   * @param parameterType The type to be passed, possibly a proxy type
   * @return The boundary type class represented by the parameterType, or just passes on the parameterType
   */
  public static Class translateParameterType(ClassLoader cl, Class parameterType) {
    ReflectiveWrapper wrapper = (ReflectiveWrapper) parameterType.getAnnotation(ReflectiveWrapper.class);
    return wrapper == null ? parameterType : ReflectionUtil.getClass(wrapper.value(), cl);
  }
 
  /**
   * @param argument The regular or proxy object
   * @return The possibly translated boundary object
   */
  public static Object translateArgument (Object argument) {
    if (argument != null && Proxy.isProxyClass(argument.getClass())) {
      InvocationHandler ih = Proxy.getInvocationHandler(argument);
      if (ih instanceof ReflectiveProxy) {
        return ((ReflectiveProxy)ih).getTarget();
      }
    }
    return argument;
  }
 
  private Object object;
  private Class clazz;
  private ClassLoader cl;
  private Map<String, Class> interfaces = new HashMap<String, Class>();

  /**
   * @param object The object to wrap
   */
  public ReflectiveObjectProxy(Object object) {
    this.object = object;
    this.clazz = object instanceof Class ? (Class) object : object.getClass();
    this.cl = clazz.getClassLoader();
  }

  @Override protected Class getClassForMethod(Method method) { return clazz; }

  @Override protected Object getObjectForMethod(Method method) { return object; }

  @Override protected boolean isMethodStatic(Method method, Class[] realTypes) throws NoSuchMethodException {
    if (object instanceof Class) return true;
    return Modifier.isStatic( clazz.getMethod(method.getName(), realTypes).getModifiers() );
  }

  @Override protected Object createProxyForResult(Object result, Class returnType, Method method) {

    // For collections, we need to get the parameterized type to see if any type of automatic mapping might be necesary.
    if (returnType == List.class) {
      Class clazz = (Class) ((ParameterizedType) method.getGenericReturnType()).getActualTypeArguments()[0];
      if (clazz.isInterface() && clazz.getAnnotation(ReflectiveWrapper.class) != null) return new ReflectiveList( this, (List) result, clazz );
    } else if (returnType == Map.class) {
      Class clazz = (Class) ((ParameterizedType) method.getGenericReturnType()).getActualTypeArguments()[1];
      if (clazz.isInterface() && clazz.getAnnotation(ReflectiveWrapper.class) != null) return new ReflectiveMap( (Map) result, this, clazz );
    } else if (returnType == Set.class) {
      Class clazz = (Class) ((ParameterizedType) method.getGenericReturnType()).getActualTypeArguments()[0];
      if (clazz.isInterface() && clazz.getAnnotation(ReflectiveWrapper.class) != null) return new ReflectiveSet( (Set) result, this, clazz );
    } else if (returnType == Collection.class) {
      Class clazz = (Class) ((ParameterizedType) method.getGenericReturnType()).getActualTypeArguments()[0];
      if (clazz.isInterface() && clazz.getAnnotation(ReflectiveWrapper.class) != null) return new ReflectiveCollection( (Collection) result, this, clazz );
    } else if (returnType == Iterator.class) {
      Class clazz = (Class) ((ParameterizedType) method.getGenericReturnType()).getActualTypeArguments()[0];
      if (clazz.isInterface() && clazz.getAnnotation(ReflectiveWrapper.class) != null) return new ReflectiveIterator( this, clazz, (Iterator) result );
    }

    // We now try to get the interface automatically or from the manually mapped lookup
    Class iface = returnType != null && returnType.isInterface() && returnType.getAnnotation(ReflectiveWrapper.class) != null ? returnType : this.interfaces.get(result.getClass());
    return iface == null ? null : createProxy(Thread.currentThread().getContextClassLoader(), iface, result);
   
  }

  @Override protected Object mapArgument(Object argument, Method method) {
    return translateArgument(argument);
  }

  @Override protected Class mapParameterType(Class parameterType, Method method) {
    return translateParameterType(cl, parameterType);
  }

  @Override protected Object getTarget() { return object; }

  /**
   * @return The boundary class loader
   */
  public ClassLoader getClassLoader () { return cl; }
  /**
   * @param cl The boundary class loader
   */
  public void setClassLoader(ClassLoader cl) { this.cl = cl; }
 
  /**
   * This will allow users of this proxy to manually declare class mapping for defaults or where
   * the proxy will not be able to map it automatically.
   *
   * @param resultType The type (class name) to be wrapped/proxied.
   * @param iface The proxy interface for the type
   */
  public void wrapResults (String resultType, Class iface) { this.interfaces.put(resultType, iface); }

}
TOP

Related Classes of net.sourceforge.javautil.common.reflection.proxy.ReflectiveObjectProxy

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.