Exemple #1
0
 public void testMethodKey() throws Exception {
   MethodKey factory = (MethodKey) KeyFactory.create(MethodKey.class);
   Set methodSet = new HashSet();
   methodSet.add(factory.newInstance(Number.class, new Class[] {int.class}));
   assertTrue(methodSet.contains(factory.newInstance(Number.class, new Class[] {int.class})));
   assertTrue(!methodSet.contains(factory.newInstance(Number.class, new Class[] {Integer.class})));
 }
Exemple #2
0
 public void testSimple() throws Exception {
   MyKey mykey = (MyKey) KeyFactory.create(MyKey.class);
   assertTrue(
       mykey.newInstance(5, new int[] {6, 7}, false).hashCode()
           == mykey.newInstance(5, new int[] {6, 7}, false).hashCode());
 }
Exemple #3
0
  public void perform(ClassLoader loader) throws Throwable {

    KeyFactory.create(loader, MyKey.class, null);
  }
Exemple #4
0
 public void testEqualOtherClass() throws Exception {
   MyKey mykey = (MyKey) KeyFactory.create(MyKey.class);
   assertTrue(!mykey.newInstance(5, new int[] {6, 7}, false).equals(new Object()));
 }
Exemple #5
0
 public void testBooleanArray() throws Exception {
   BooleanArrayKey f = (BooleanArrayKey) KeyFactory.create(BooleanArrayKey.class);
   Object key1 = f.newInstance(new boolean[] {true, false, true});
   Object key2 = f.newInstance(new boolean[] {true, false, true});
   assertTrue(key1.equals(key2));
 }
Exemple #6
0
 public void testCharArray() throws Exception {
   CharArrayKey f = (CharArrayKey) KeyFactory.create(CharArrayKey.class);
   Object key1 = f.newInstance(new char[] {'a', 'b'});
   Object key2 = f.newInstance(new char[] {'a', '_'});
   assertTrue(!key1.equals(key2));
 }
/**
 * <b>DOCUMENTATION FROM APACHE AVALON DELEGATE CLASS</b>
 *
 * <p>Delegates are a typesafe pointer to another method. Since Java does not have language support
 * for such a construct, this utility will construct a proxy that forwards method calls to any
 * method with the same signature. This utility is inspired in part by the C# delegate mechanism. We
 * implemented it in a Java-centric manner.
 *
 * <h2>Delegate</h2>
 *
 * <p>Any interface with one method can become the interface for a delegate. Consider the example
 * below:
 *
 * <pre>
 *   public interface MainDelegate {
 *       int main(String[] args);
 *   }
 * </pre>
 *
 * <p>The interface above is an example of an interface that can become a delegate. It has only one
 * method, and the interface is public. In order to create a delegate for that method, all we have
 * to do is call <code>MethodDelegate.create(this, "alternateMain", MainDelegate.class)</code>. The
 * following program will show how to use it:
 *
 * <pre>
 *   public class Main {
 *       public static int main( String[] args ) {
 *           Main newMain = new Main();
 *           MainDelegate start = (MainDelegate)
 *               MethodDelegate.create(newMain, "alternateMain", MainDelegate.class);
 *           return start.main( args );
 *       }
 *
 *       public int alternateMain( String[] args ) {
 *           for (int i = 0; i < args.length; i++) {
 *               System.out.println( args[i] );
 *           }
 *           return args.length;
 *       }
 *   }
 * </pre>
 *
 * <p>By themselves, delegates don't do much. Their true power lies in the fact that they can be
 * treated like objects, and passed to other methods. In fact that is one of the key building blocks
 * of building Intelligent Agents which in tern are the foundation of artificial intelligence. In
 * the above program, we could have easily created the delegate to match the static <code>main
 * </code> method by substituting the delegate creation call with this: <code>
 * MethodDelegate.createStatic(getClass(), "main", MainDelegate.class)</code>.
 *
 * <p>Another key use for Delegates is to register event listeners. It is much easier to have all
 * the code for your events separated out into methods instead of individual classes. One of the
 * ways Java gets around that is to create anonymous classes. They are particularly troublesome
 * because many Debuggers do not know what to do with them. Anonymous classes tend to duplicate alot
 * of code as well. We can use any interface with one declared method to forward events to any
 * method that matches the signature (although the method name can be different).
 *
 * <h3>Equality</h3>
 *
 * The criteria that we use to test if two delegates are equal are:
 *
 * <ul>
 *   <li>They both refer to the same instance. That is, the <code>instance</code> parameter passed
 *       to the newDelegate method was the same for both. The instances are compared with the
 *       identity equality operator, <code>==</code>.
 *   <li>They refer to the same method as resolved by <code>Method.equals</code>.
 * </ul>
 *
 * @version $Id: MethodDelegate.java,v 1.25 2006/03/05 02:43:19 herbyderby Exp $
 */
public abstract class MethodDelegate {
  private static final MethodDelegateKey KEY_FACTORY =
      (MethodDelegateKey) KeyFactory.create(MethodDelegateKey.class, KeyFactory.CLASS_BY_NAME);

  protected Object target;
  protected String eqMethod;

  interface MethodDelegateKey {
    Object newInstance(Class delegateClass, String methodName, Class iface);
  }

  public static MethodDelegate createStatic(Class targetClass, String methodName, Class iface) {
    Generator gen = new Generator();
    gen.setTargetClass(targetClass);
    gen.setMethodName(methodName);
    gen.setInterface(iface);
    return gen.create();
  }

  public static MethodDelegate create(Object target, String methodName, Class iface) {
    Generator gen = new Generator();
    gen.setTarget(target);
    gen.setMethodName(methodName);
    gen.setInterface(iface);
    return gen.create();
  }

  public boolean equals(Object obj) {
    MethodDelegate other = (MethodDelegate) obj;
    return target == other.target && eqMethod.equals(other.eqMethod);
  }

  public int hashCode() {
    return target.hashCode() ^ eqMethod.hashCode();
  }

  public Object getTarget() {
    return target;
  }

  public abstract MethodDelegate newInstance(Object target);

  public static class Generator extends AbstractClassGenerator {
    private static final Source SOURCE = new Source(MethodDelegate.class.getName());
    private static final Type METHOD_DELEGATE =
        TypeUtils.parseType("net.sf.cglib.reflect.MethodDelegate");
    private static final Signature NEW_INSTANCE =
        new Signature("newInstance", METHOD_DELEGATE, new Type[] {Constants.TYPE_OBJECT});

    private Object target;
    private Class targetClass;
    private String methodName;
    private Class iface;

    public Generator() {
      super(SOURCE);
    }

    public void setTarget(Object target) {
      this.target = target;
      this.targetClass = target.getClass();
    }

    public void setTargetClass(Class targetClass) {
      this.targetClass = targetClass;
    }

    public void setMethodName(String methodName) {
      this.methodName = methodName;
    }

    public void setInterface(Class iface) {
      this.iface = iface;
    }

    protected ClassLoader getDefaultClassLoader() {
      return targetClass.getClassLoader();
    }

    protected ProtectionDomain getProtectionDomain() {
      return ReflectUtils.getProtectionDomain(targetClass);
    }

    public MethodDelegate create() {
      setNamePrefix(targetClass.getName());
      Object key = KEY_FACTORY.newInstance(targetClass, methodName, iface);
      return (MethodDelegate) super.create(key);
    }

    protected Object firstInstance(Class type) {
      return ((MethodDelegate) ReflectUtils.newInstance(type)).newInstance(target);
    }

    protected Object nextInstance(Object instance) {
      return ((MethodDelegate) instance).newInstance(target);
    }

    public void generateClass(ClassVisitor v) throws NoSuchMethodException {
      Method proxy = ReflectUtils.findInterfaceMethod(iface);
      final Method method = targetClass.getMethod(methodName, proxy.getParameterTypes());
      if (!proxy.getReturnType().isAssignableFrom(method.getReturnType())) {
        throw new IllegalArgumentException("incompatible return types");
      }

      MethodInfo methodInfo = ReflectUtils.getMethodInfo(method);

      boolean isStatic = TypeUtils.isStatic(methodInfo.getModifiers());
      if ((target == null) ^ isStatic) {
        throw new IllegalArgumentException(
            "Static method " + (isStatic ? "not " : "") + "expected");
      }

      ClassEmitter ce = new ClassEmitter(v);
      CodeEmitter e;
      ce.begin_class(
          Constants.V1_2,
          Constants.ACC_PUBLIC,
          getClassName(),
          METHOD_DELEGATE,
          new Type[] {Type.getType(iface)},
          Constants.SOURCE_FILE);
      ce.declare_field(Constants.PRIVATE_FINAL_STATIC, "eqMethod", Constants.TYPE_STRING, null);
      EmitUtils.null_constructor(ce);

      // generate proxied method
      MethodInfo proxied = ReflectUtils.getMethodInfo(iface.getDeclaredMethods()[0]);
      int modifiers = Constants.ACC_PUBLIC;
      if ((proxied.getModifiers() & Constants.ACC_VARARGS) == Constants.ACC_VARARGS) {
        modifiers |= Constants.ACC_VARARGS;
      }
      e = EmitUtils.begin_method(ce, proxied, modifiers);
      e.load_this();
      e.super_getfield("target", Constants.TYPE_OBJECT);
      e.checkcast(methodInfo.getClassInfo().getType());
      e.load_args();
      e.invoke(methodInfo);
      e.return_value();
      e.end_method();

      // newInstance
      e = ce.begin_method(Constants.ACC_PUBLIC, NEW_INSTANCE, null);
      e.new_instance_this();
      e.dup();
      e.dup2();
      e.invoke_constructor_this();
      e.getfield("eqMethod");
      e.super_putfield("eqMethod", Constants.TYPE_STRING);
      e.load_arg(0);
      e.super_putfield("target", Constants.TYPE_OBJECT);
      e.return_value();
      e.end_method();

      // static initializer
      e = ce.begin_static();
      e.push(methodInfo.getSignature().toString());
      e.putfield("eqMethod");
      e.return_value();
      e.end_method();

      ce.end_class();
    }
  }
}