001 package org.codehaus.groovy.runtime; 002 003 import java.lang.reflect.InvocationHandler; 004 import java.lang.reflect.InvocationTargetException; 005 import java.lang.reflect.Method; 006 007 /** 008 * This class is a general adapter to map a call to an Java interface 009 * to a given delegate. 010 * <p> 011 * @author Ben Yu 012 * @author <a href="mailto:blackdrag@gmx.org">Jochen Theodorou</a> 013 */ 014 public abstract class ConversionHandler implements InvocationHandler { 015 private Object delegate; 016 017 /** 018 * Creates a ConversionHandler with an deleagte. 019 * @param delegate the delegate 020 * @throws IllegalArgumentException if the given delegate is null 021 */ 022 public ConversionHandler(Object delegate) { 023 if (delegate==null) throw new IllegalArgumentException("delegate must not be null"); 024 this.delegate = delegate; 025 } 026 027 /** 028 * gets the delegate. 029 * @return the delegate 030 */ 031 public Object getDelegate(){ 032 return delegate; 033 } 034 035 /** 036 * This method is a default implementation for the invoke method 037 * given in Invocationhandler. Any call to an method with an 038 * declaring class that is not Object is redirected to invokeCustom. 039 * Methods like tostring, equals and hashcode are called on the class 040 * itself instead of the delegate. It is better to overwrite the 041 * invokeCustom method where the Object related methods are filtered out. 042 * 043 * @see #invokeCustom(Object, Method, Object[]) 044 * @see InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[]) 045 * 046 * @param proxy the proxy 047 * @param method the method 048 * @param args the arguments 049 * @return the result of the invocation by method or delegate 050 * @throws Throwable any exception caused by the delegate or the method 051 */ 052 public Object invoke(Object proxy, Method method, Object[] args) 053 throws Throwable { 054 if(!isObjectMethod(method)){ 055 return invokeCustom(proxy,method,args); 056 } 057 try { 058 return method.invoke(this, args); 059 } catch (InvocationTargetException ite) { 060 throw ite.getTargetException(); 061 } 062 } 063 064 /** 065 * This method is called for all Methods not defined on Object. 066 * The delegate should be called here. 067 * 068 * @param proxy the proxy 069 * @param method the method 070 * @param args the arguments 071 * @return the result of the invocation of the delegate 072 * @throws Throwable any exception causes by the delegate 073 * @see #invoke(Object, Method, Object[]) 074 * @see InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[]) 075 * 076 */ 077 public abstract Object invokeCustom(Object proxy, Method method, Object[] args) throws Throwable; 078 079 /** 080 * Indicates whether some other object is "equal to" this one. 081 * The delegate is used if the class of the parameter and the 082 * current class are equal. In other cases the method will return 083 * false. The exact class is here used, if inheritance is needed, 084 * this method must be overwritten. 085 * 086 * @see java.lang.Object#equals(java.lang.Object) 087 */ 088 public boolean equals(Object obj) { 089 if (obj!=null && obj.getClass()==this.getClass()){ 090 return (((ConversionHandler)obj).getDelegate()).equals(obj); 091 } else { 092 return false; 093 } 094 } 095 096 /** 097 * Returns a hash code value for the delegate. 098 * @see java.lang.Object#hashCode() 099 */ 100 public int hashCode() { 101 return delegate.hashCode(); 102 } 103 104 /** 105 * Returns a String version of the delegate. 106 * @see java.lang.Object#toString() 107 */ 108 public String toString() { 109 return delegate.toString(); 110 } 111 112 private static boolean isObjectMethod(Method mtd){ 113 return mtd.getDeclaringClass().equals(Object.class); 114 } 115 }