1 /* 2 * Javassist, a Java-bytecode translator toolkit. 3 * Copyright (C) 1999-2007 Shigeru Chiba. All Rights Reserved. 4 * 5 * The contents of this file are subject to the Mozilla Public License Version 6 * 1.1 (the "License"); you may not use this file except in compliance with 7 * the License. Alternatively, the contents of this file may be used under 8 * the terms of the GNU Lesser General Public License Version 2.1 or later. 9 * 10 * Software distributed under the License is distributed on an "AS IS" basis, 11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 12 * for the specific language governing rights and limitations under the 13 * License. 14 */ 15 16 package javassist.util.proxy; 17 18 import java.lang.reflect.Method; 19 import java.io.Serializable; 20 21 /** 22 * Runtime support routines that the classes generated by ProxyFactory use. 23 * 24 * @see ProxyFactory 25 */ 26 public class RuntimeSupport { 27 /** 28 * A method handler that only executes a method. 29 */ 30 public static MethodHandler default_interceptor = new DefaultMethodHandler(); 31 32 static class DefaultMethodHandler implements MethodHandler, Serializable { invoke(Object self, Method m, Method proceed, Object[] args)33 public Object invoke(Object self, Method m, 34 Method proceed, Object[] args) 35 throws Exception 36 { 37 return proceed.invoke(self, args); 38 } 39 }; 40 41 /** 42 * Finds two methods specified by the parameters and stores them 43 * into the given array. 44 * 45 * @throws RuntimeException if the methods are not found. 46 * @see javassist.util.proxy.ProxyFactory 47 */ find2Methods(Object self, String superMethod, String thisMethod, int index, String desc, java.lang.reflect.Method[] methods)48 public static void find2Methods(Object self, String superMethod, 49 String thisMethod, int index, 50 String desc, java.lang.reflect.Method[] methods) 51 { 52 synchronized (methods) { 53 if (methods[index] == null) { 54 methods[index + 1] = thisMethod == null ? null 55 : findMethod(self, thisMethod, desc); 56 methods[index] = findSuperMethod(self, superMethod, desc); 57 } 58 } 59 } 60 61 /** 62 * Finds a method with the given name and descriptor. 63 * It searches only the class of self. 64 * 65 * @throws RuntimeException if the method is not found. 66 */ findMethod(Object self, String name, String desc)67 public static Method findMethod(Object self, String name, String desc) { 68 Method m = findMethod2(self.getClass(), name, desc); 69 if (m == null) 70 error(self, name, desc); 71 72 return m; 73 } 74 75 /** 76 * Finds a method that has the given name and descriptor and is declared 77 * in the super class. 78 * 79 * @throws RuntimeException if the method is not found. 80 */ findSuperMethod(Object self, String name, String desc)81 public static Method findSuperMethod(Object self, String name, String desc) { 82 Class clazz = self.getClass(); 83 Method m = findSuperMethod2(clazz.getSuperclass(), name, desc); 84 if (m == null) 85 m = searchInterfaces(clazz, name, desc); 86 87 if (m == null) 88 error(self, name, desc); 89 90 return m; 91 } 92 error(Object self, String name, String desc)93 private static void error(Object self, String name, String desc) { 94 throw new RuntimeException("not found " + name + ":" + desc 95 + " in " + self.getClass().getName()); 96 } 97 findSuperMethod2(Class clazz, String name, String desc)98 private static Method findSuperMethod2(Class clazz, String name, String desc) { 99 Method m = findMethod2(clazz, name, desc); 100 if (m != null) 101 return m; 102 103 Class superClass = clazz.getSuperclass(); 104 if (superClass != null) { 105 m = findSuperMethod2(superClass, name, desc); 106 if (m != null) 107 return m; 108 } 109 110 return searchInterfaces(clazz, name, desc); 111 } 112 searchInterfaces(Class clazz, String name, String desc)113 private static Method searchInterfaces(Class clazz, String name, String desc) { 114 Method m = null; 115 Class[] interfaces = clazz.getInterfaces(); 116 for (int i = 0; i < interfaces.length; i++) { 117 m = findSuperMethod2(interfaces[i], name, desc); 118 if (m != null) 119 return m; 120 } 121 122 return m; 123 } 124 findMethod2(Class clazz, String name, String desc)125 private static Method findMethod2(Class clazz, String name, String desc) { 126 Method[] methods = SecurityActions.getDeclaredMethods(clazz); 127 int n = methods.length; 128 for (int i = 0; i < n; i++) 129 if (methods[i].getName().equals(name) 130 && makeDescriptor(methods[i]).equals(desc)) 131 return methods[i]; 132 133 return null; 134 } 135 136 /** 137 * Makes a descriptor for a given method. 138 */ makeDescriptor(Method m)139 public static String makeDescriptor(Method m) { 140 Class[] params = m.getParameterTypes(); 141 return makeDescriptor(params, m.getReturnType()); 142 } 143 144 /** 145 * Makes a descriptor for a given method. 146 * 147 * @param params parameter types. 148 * @param retType return type. 149 */ makeDescriptor(Class[] params, Class retType)150 public static String makeDescriptor(Class[] params, Class retType) { 151 StringBuffer sbuf = new StringBuffer(); 152 sbuf.append('('); 153 for (int i = 0; i < params.length; i++) 154 makeDesc(sbuf, params[i]); 155 156 sbuf.append(')'); 157 makeDesc(sbuf, retType); 158 return sbuf.toString(); 159 } 160 makeDesc(StringBuffer sbuf, Class type)161 private static void makeDesc(StringBuffer sbuf, Class type) { 162 if (type.isArray()) { 163 sbuf.append('['); 164 makeDesc(sbuf, type.getComponentType()); 165 } 166 else if (type.isPrimitive()) { 167 if (type == Void.TYPE) 168 sbuf.append('V'); 169 else if (type == Integer.TYPE) 170 sbuf.append('I'); 171 else if (type == Byte.TYPE) 172 sbuf.append('B'); 173 else if (type == Long.TYPE) 174 sbuf.append('J'); 175 else if (type == Double.TYPE) 176 sbuf.append('D'); 177 else if (type == Float.TYPE) 178 sbuf.append('F'); 179 else if (type == Character.TYPE) 180 sbuf.append('C'); 181 else if (type == Short.TYPE) 182 sbuf.append('S'); 183 else if (type == Boolean.TYPE) 184 sbuf.append('Z'); 185 else 186 throw new RuntimeException("bad type: " + type.getName()); 187 } 188 else 189 sbuf.append('L').append(type.getName().replace('.', '/')) 190 .append(';'); 191 } 192 193 /** 194 * Converts a proxy object to an object that is writable to an 195 * object stream. This method is called by <code>writeReplace()</code> 196 * in a proxy class. 197 * 198 * @since 3.4 199 */ makeSerializedProxy(Object proxy)200 public static SerializedProxy makeSerializedProxy(Object proxy) 201 throws java.io.InvalidClassException 202 { 203 Class clazz = proxy.getClass(); 204 205 MethodHandler methodHandler = null; 206 if (proxy instanceof ProxyObject) 207 methodHandler = ((ProxyObject)proxy).getHandler(); 208 209 return new SerializedProxy(clazz, ProxyFactory.getFilterSignature(clazz), methodHandler); 210 } 211 } 212