/* * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import java.lang.annotation.Annotation; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.Arrays; import java.util.Comparator; /** * Do some basic tests. */ public class BasicTest { public static void main(String[] args) { Mix proxyMe = new Mix(); Object proxy = createProxy(proxyMe); if (!Proxy.isProxyClass(proxy.getClass())) System.err.println("not a proxy class?"); if (Proxy.getInvocationHandler(proxy) == null) System.err.println("ERROR: Proxy.getInvocationHandler is null"); /* take it for a spin; verifies instanceof constraint */ Shapes shapes = (Shapes) proxy; shapes.circle(3); shapes.rectangle(10, 20); shapes.blob(); Quads quads = (Quads) proxy; quads.rectangle(15, 25); quads.trapezoid(6, 81.18, 4); Colors colors = (Colors) proxy; colors.red(1.0f); colors.blue(777); colors.mauve("sorry"); colors.blob(); Trace trace = (Trace) proxy; trace.getTrace(); try { shapes.upChuck(); System.out.println("Didn't get expected exception"); } catch (IndexOutOfBoundsException ioobe) { System.out.println("Got expected ioobe"); } try { shapes.upCheck(); System.out.println("Didn't get expected exception"); } catch (InterruptedException ie) { System.out.println("Got expected ie"); } /* * Exercise annotations on Proxy classes. This is mostly to ensure * that annotation calls work correctly on generated classes. */ System.out.println(""); Method[] methods = proxy.getClass().getDeclaredMethods(); Arrays.sort(methods, new Comparator<Method>() { public int compare(Method o1, Method o2) { int result = o1.getName().compareTo(o2.getName()); if (result != 0) { return result; } return o1.getReturnType().getName().compareTo(o2.getReturnType().getName()); } }); System.out.println("Proxy interfaces: " + Arrays.deepToString(proxy.getClass().getInterfaces())); System.out.println("Proxy methods: " + Arrays.deepToString(methods)); Method meth = methods[methods.length -1]; System.out.println("Decl annos: " + Arrays.deepToString(meth.getDeclaredAnnotations())); Annotation[][] paramAnnos = meth.getParameterAnnotations(); System.out.println("Param annos (" + paramAnnos.length + ") : " + Arrays.deepToString(paramAnnos)); System.out.println("Modifiers: " + meth.getModifiers()); } static Object createProxy(Object proxyMe) { /* declare an object that will handle the method calls */ InvocationHandler handler = new MyInvocationHandler(proxyMe); /* create the proxy class */ Class proxyClass = Proxy.getProxyClass(Shapes.class.getClassLoader(), new Class[] { Quads.class, Colors.class, Trace.class }); /* create a proxy object, passing the handler object in */ Object proxy = null; try { Constructor<Class> cons; cons = proxyClass.getConstructor( new Class[] { InvocationHandler.class }); //System.out.println("Constructor is " + cons); proxy = cons.newInstance(new Object[] { handler }); } catch (NoSuchMethodException nsme) { System.err.println("failed: " + nsme); } catch (InstantiationException ie) { System.err.println("failed: " + ie); } catch (IllegalAccessException ie) { System.err.println("failed: " + ie); } catch (InvocationTargetException ite) { System.err.println("failed: " + ite); } return proxy; } } /* * Some interfaces. */ interface Shapes { public void circle(int r); public int rectangle(int x, int y); public String blob(); public R0base checkMe(); public void upChuck(); public void upCheck() throws InterruptedException; } interface Quads extends Shapes { public int rectangle(int x, int y); public int square(int x, int y); public int trapezoid(int x, double off, int y); public R0a checkMe(); } /* * More interfaces. */ interface Colors { public int red(float howRed); public int green(double howGreen); public double blue(int howBlue); public int mauve(String apology); public String blob(); public R0aa checkMe(); } interface Trace { public void getTrace(); } /* * Some return types. */ class R0base { int mBlah; } class R0a extends R0base { int mBlah_a; } class R0aa extends R0a { int mBlah_aa; } /* * A class that implements them all. */ class Mix implements Quads, Colors { public void circle(int r) { System.out.println("--- circle " + r); } public int rectangle(int x, int y) { System.out.println("--- rectangle " + x + "," + y); return 4; } public int square(int x, int y) { System.out.println("--- square " + x + "," + y); return 4; } public int trapezoid(int x, double off, int y) { System.out.println("--- trap " + x + "," + y + "," + off); return 8; } public String blob() { System.out.println("--- blob"); return "mix"; } public int red(float howRed) { System.out.println("--- red " + howRed); return 0; } public int green(double howGreen) { System.out.println("--- green " + howGreen); return 1; } public double blue(int howBlue) { System.out.println("--- blue " + howBlue); return 2.54; } public int mauve(String apology) { System.out.println("--- mauve " + apology); return 3; } public R0aa checkMe() { return null; } public void upChuck() { throw new IndexOutOfBoundsException("upchuck"); } public void upCheck() throws InterruptedException { throw new InterruptedException("upcheck"); } } /* * Invocation handler, defining the implementation of the proxy functions. */ class MyInvocationHandler implements InvocationHandler { Object mObj; public MyInvocationHandler(Object obj) { mObj = obj; } /* * This is called when anything gets invoked in the proxy object. */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = null; // Trap Object calls. This is important here to avoid a recursive // invocation of toString() in the print statements below. if (method.getDeclaringClass() == java.lang.Object.class) { //System.out.println("!!! object " + method.getName()); if (method.getName().equals("toString")) { return super.toString(); } else if (method.getName().equals("hashCode")) { return Integer.valueOf(super.hashCode()); } else if (method.getName().equals("equals")) { return Boolean.valueOf(super.equals(args[0])); } else { throw new RuntimeException("huh?"); } } if (method.getDeclaringClass() == Trace.class) { if (method.getName().equals("getTrace")) { StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); for (int i = 0; i < stackTrace.length; i++) { StackTraceElement ste = stackTrace[i]; if (ste.getMethodName().equals("getTrace")) { System.out.println(ste.getClassName() + "." + ste.getMethodName() + " " + ste.getFileName() + ":" + ste.getLineNumber()); } } return null; } } if (method.getDeclaringClass() == Trace.class) { if (method.getName().equals("getTrace")) { StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); for (int i = 0; i < stackTrace.length; i++) { StackTraceElement ste = stackTrace[i]; if (ste.getMethodName().equals("getTrace")) { System.out.println(ste.getClassName() + "." + ste.getMethodName() + " " + ste.getFileName() + ":" + ste.getLineNumber()); } } return null; } } System.out.println("Invoke " + method); if (args == null || args.length == 0) { System.out.println(" (no args)"); } else { for (int i = 0; i < args.length; i++) System.out.println(" " + i + ": " + args[i]); } try { if (true) { result = method.invoke(mObj, args); } else { result = -1; } System.out.println("Success: method " + method.getName() + " res=" + result); } catch (InvocationTargetException ite) { throw ite.getTargetException(); } catch (IllegalAccessException iae) { throw new RuntimeException(iae); } return result; } }