| /* | |
| * 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; | |
| /** | |
| * 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.out.println("not a proxy class?"); | |
| if (Proxy.getInvocationHandler(proxy) == null) | |
| System.out.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(); | |
| // Test the proxy spec: These Object functions are supposed to be given to the handler. | |
| int unusedHashCode = ((Object)trace).hashCode(); | |
| boolean unusedEquals = ((Object)trace).equals(trace); | |
| String unusedString = ((Object)trace).toString(); | |
| 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 MethodComparator()); | |
| System.out.println("Proxy interfaces: " + | |
| Arrays.deepToString(proxy.getClass().getInterfaces())); | |
| System.out.println("Proxy methods: " + | |
| Main.replaceProxyClassNamesForOutput(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(), | |
| Quads.class, Colors.class, Trace.class); | |
| Main.registerProxyClassName(proxyClass.getCanonicalName()); | |
| /* create a proxy object, passing the handler object in */ | |
| Object proxy = null; | |
| try { | |
| Constructor<?> cons = proxyClass.getConstructor(InvocationHandler.class); | |
| //System.out.println("Constructor is " + cons); | |
| proxy = cons.newInstance(handler); | |
| } catch (NoSuchMethodException nsme) { | |
| System.out.println("failed: " + nsme); | |
| } catch (InstantiationException ie) { | |
| System.out.println("failed: " + ie); | |
| } catch (IllegalAccessException ie) { | |
| System.out.println("failed: " + ie); | |
| } catch (InvocationTargetException ite) { | |
| System.out.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 { | |
| System.out.println("Invoke " + method); | |
| 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")) { | |
| String outputClassName = Main.replaceProxyClassNamesForOutput(ste.getClassName()); | |
| System.out.println(outputClassName + "." + 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")) { | |
| String outputClassName = Main.replaceProxyClassNamesForOutput(ste.getClassName()); | |
| System.out.println(outputClassName + "." + ste.getMethodName() + " " + | |
| ste.getFileName() + ":" + ste.getLineNumber()); | |
| } | |
| } | |
| return null; | |
| } | |
| } | |
| 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; | |
| } | |
| } |