1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 import java.lang.annotation.Annotation; 18 import java.lang.reflect.InvocationHandler; 19 import java.lang.reflect.InvocationTargetException; 20 import java.lang.reflect.Constructor; 21 import java.lang.reflect.Field; 22 import java.lang.reflect.Method; 23 import java.lang.reflect.Proxy; 24 import java.util.Arrays; 25 26 /** 27 * Do some basic tests. 28 */ 29 public class BasicTest { 30 main(String[] args)31 public static void main(String[] args) { 32 Mix proxyMe = new Mix(); 33 Object proxy = createProxy(proxyMe); 34 35 if (!Proxy.isProxyClass(proxy.getClass())) 36 System.out.println("not a proxy class?"); 37 if (Proxy.getInvocationHandler(proxy) == null) 38 System.out.println("ERROR: Proxy.getInvocationHandler is null"); 39 40 /* take it for a spin; verifies instanceof constraint */ 41 Shapes shapes = (Shapes) proxy; 42 shapes.circle(3); 43 shapes.rectangle(10, 20); 44 shapes.blob(); 45 Quads quads = (Quads) proxy; 46 quads.rectangle(15, 25); 47 quads.trapezoid(6, 81.18, 4); 48 Colors colors = (Colors) proxy; 49 colors.red(1.0f); 50 colors.blue(777); 51 colors.mauve("sorry"); 52 colors.blob(); 53 Trace trace = (Trace) proxy; 54 trace.getTrace(); 55 56 // Test the proxy spec: These Object functions are supposed to be given to the handler. 57 int unusedHashCode = ((Object)trace).hashCode(); 58 boolean unusedEquals = ((Object)trace).equals(trace); 59 String unusedString = ((Object)trace).toString(); 60 61 try { 62 shapes.upChuck(); 63 System.out.println("Didn't get expected exception"); 64 } catch (IndexOutOfBoundsException ioobe) { 65 System.out.println("Got expected ioobe"); 66 } 67 try { 68 shapes.upCheck(); 69 System.out.println("Didn't get expected exception"); 70 } catch (InterruptedException ie) { 71 System.out.println("Got expected ie"); 72 } 73 74 /* 75 * Exercise annotations on Proxy classes. This is mostly to ensure 76 * that annotation calls work correctly on generated classes. 77 */ 78 System.out.println(""); 79 Method[] methods = proxy.getClass().getDeclaredMethods(); 80 Arrays.sort(methods, new MethodComparator()); 81 System.out.println("Proxy interfaces: " + 82 Arrays.deepToString(proxy.getClass().getInterfaces())); 83 System.out.println("Proxy methods: " + 84 Main.replaceProxyClassNamesForOutput(Arrays.deepToString(methods))); 85 Method meth = methods[methods.length -1]; 86 System.out.println("Decl annos: " + Arrays.deepToString(meth.getDeclaredAnnotations())); 87 Annotation[][] paramAnnos = meth.getParameterAnnotations(); 88 System.out.println("Param annos (" + paramAnnos.length + ") : " 89 + Arrays.deepToString(paramAnnos)); 90 System.out.println("Modifiers: " + meth.getModifiers()); 91 } 92 createProxy(Object proxyMe)93 static Object createProxy(Object proxyMe) { 94 /* declare an object that will handle the method calls */ 95 InvocationHandler handler = new MyInvocationHandler(proxyMe); 96 97 /* create the proxy class */ 98 Class<?> proxyClass = Proxy.getProxyClass(Shapes.class.getClassLoader(), 99 Quads.class, Colors.class, Trace.class); 100 Main.registerProxyClassName(proxyClass.getCanonicalName()); 101 102 /* create a proxy object, passing the handler object in */ 103 Object proxy = null; 104 try { 105 Constructor<?> cons = proxyClass.getConstructor(InvocationHandler.class); 106 //System.out.println("Constructor is " + cons); 107 proxy = cons.newInstance(handler); 108 } catch (NoSuchMethodException nsme) { 109 System.out.println("failed: " + nsme); 110 } catch (InstantiationException ie) { 111 System.out.println("failed: " + ie); 112 } catch (IllegalAccessException ie) { 113 System.out.println("failed: " + ie); 114 } catch (InvocationTargetException ite) { 115 System.out.println("failed: " + ite); 116 } 117 118 return proxy; 119 } 120 } 121 122 /* 123 * Some interfaces. 124 */ 125 interface Shapes { circle(int r)126 public void circle(int r); rectangle(int x, int y)127 public int rectangle(int x, int y); 128 blob()129 public String blob(); 130 checkMe()131 public R0base checkMe(); upChuck()132 public void upChuck(); upCheck()133 public void upCheck() throws InterruptedException; 134 } 135 136 interface Quads extends Shapes { rectangle(int x, int y)137 public int rectangle(int x, int y); square(int x, int y)138 public int square(int x, int y); trapezoid(int x, double off, int y)139 public int trapezoid(int x, double off, int y); 140 checkMe()141 public R0a checkMe(); 142 } 143 144 /* 145 * More interfaces. 146 */ 147 interface Colors { red(float howRed)148 public int red(float howRed); green(double howGreen)149 public int green(double howGreen); blue(int howBlue)150 public double blue(int howBlue); mauve(String apology)151 public int mauve(String apology); 152 blob()153 public String blob(); 154 checkMe()155 public R0aa checkMe(); 156 } 157 158 interface Trace { getTrace()159 public void getTrace(); 160 } 161 162 /* 163 * Some return types. 164 */ 165 class R0base { int mBlah; } 166 class R0a extends R0base { int mBlah_a; } 167 class R0aa extends R0a { int mBlah_aa; } 168 169 170 /* 171 * A class that implements them all. 172 */ 173 class Mix implements Quads, Colors { circle(int r)174 public void circle(int r) { 175 System.out.println("--- circle " + r); 176 } rectangle(int x, int y)177 public int rectangle(int x, int y) { 178 System.out.println("--- rectangle " + x + "," + y); 179 return 4; 180 } square(int x, int y)181 public int square(int x, int y) { 182 System.out.println("--- square " + x + "," + y); 183 return 4; 184 } trapezoid(int x, double off, int y)185 public int trapezoid(int x, double off, int y) { 186 System.out.println("--- trap " + x + "," + y + "," + off); 187 return 8; 188 } blob()189 public String blob() { 190 System.out.println("--- blob"); 191 return "mix"; 192 } 193 red(float howRed)194 public int red(float howRed) { 195 System.out.println("--- red " + howRed); 196 return 0; 197 } green(double howGreen)198 public int green(double howGreen) { 199 System.out.println("--- green " + howGreen); 200 return 1; 201 } blue(int howBlue)202 public double blue(int howBlue) { 203 System.out.println("--- blue " + howBlue); 204 return 2.54; 205 } mauve(String apology)206 public int mauve(String apology) { 207 System.out.println("--- mauve " + apology); 208 return 3; 209 } 210 checkMe()211 public R0aa checkMe() { 212 return null; 213 } upChuck()214 public void upChuck() { 215 throw new IndexOutOfBoundsException("upchuck"); 216 } upCheck()217 public void upCheck() throws InterruptedException { 218 throw new InterruptedException("upcheck"); 219 } 220 } 221 222 /* 223 * Invocation handler, defining the implementation of the proxy functions. 224 */ 225 class MyInvocationHandler implements InvocationHandler { 226 Object mObj; 227 MyInvocationHandler(Object obj)228 public MyInvocationHandler(Object obj) { 229 mObj = obj; 230 } 231 232 /* 233 * This is called when anything gets invoked in the proxy object. 234 */ invoke(Object proxy, Method method, Object[] args)235 public Object invoke(Object proxy, Method method, Object[] args) 236 throws Throwable { 237 238 System.out.println("Invoke " + method); 239 240 Object result = null; 241 242 // Trap Object calls. This is important here to avoid a recursive 243 // invocation of toString() in the print statements below. 244 if (method.getDeclaringClass() == java.lang.Object.class) { 245 //System.out.println("!!! object " + method.getName()); 246 if (method.getName().equals("toString")) { 247 return super.toString(); 248 } else if (method.getName().equals("hashCode")) { 249 return Integer.valueOf(super.hashCode()); 250 } else if (method.getName().equals("equals")) { 251 return Boolean.valueOf(super.equals(args[0])); 252 } else { 253 throw new RuntimeException("huh?"); 254 } 255 } 256 257 if (method.getDeclaringClass() == Trace.class) { 258 if (method.getName().equals("getTrace")) { 259 StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); 260 for (int i = 0; i < stackTrace.length; i++) { 261 StackTraceElement ste = stackTrace[i]; 262 if (ste.getMethodName().equals("getTrace")) { 263 String outputClassName = Main.replaceProxyClassNamesForOutput(ste.getClassName()); 264 System.out.println(outputClassName + "." + ste.getMethodName() + " " + 265 ste.getFileName() + ":" + ste.getLineNumber()); 266 } 267 } 268 return null; 269 } 270 } 271 272 if (method.getDeclaringClass() == Trace.class) { 273 if (method.getName().equals("getTrace")) { 274 StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); 275 for (int i = 0; i < stackTrace.length; i++) { 276 StackTraceElement ste = stackTrace[i]; 277 if (ste.getMethodName().equals("getTrace")) { 278 String outputClassName = Main.replaceProxyClassNamesForOutput(ste.getClassName()); 279 System.out.println(outputClassName + "." + ste.getMethodName() + " " + 280 ste.getFileName() + ":" + ste.getLineNumber()); 281 } 282 } 283 return null; 284 } 285 } 286 287 if (args == null || args.length == 0) { 288 System.out.println(" (no args)"); 289 } else { 290 for (int i = 0; i < args.length; i++) 291 System.out.println(" " + i + ": " + args[i]); 292 } 293 294 try { 295 if (true) { 296 result = method.invoke(mObj, args); 297 } else { 298 result = -1; 299 } 300 System.out.println("Success: method " + method.getName() 301 + " res=" + result); 302 } catch (InvocationTargetException ite) { 303 throw ite.getTargetException(); 304 } catch (IllegalAccessException iae) { 305 throw new RuntimeException(iae); 306 } 307 return result; 308 } 309 } 310