• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2003,2004 The Apache Software Foundation
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 package org.mockito.cglib.core;
17 
18 import java.beans.*;
19 import java.lang.reflect.*;
20 import java.security.AccessController;
21 import java.security.PrivilegedAction;
22 import java.security.ProtectionDomain;
23 import java.util.*;
24 
25 import org.mockito.asm.Attribute;
26 import org.mockito.asm.Type;
27 
28 /**
29  * @version $Id: ReflectUtils.java,v 1.29 2006/02/28 00:30:51 herbyderby Exp $
30  */
31 public class ReflectUtils {
ReflectUtils()32     private ReflectUtils() { }
33 
34     private static final Map primitives = new HashMap(8);
35     private static final Map transforms = new HashMap(8);
36     private static final ClassLoader defaultLoader = ReflectUtils.class.getClassLoader();
37     private static Method DEFINE_CLASS;
38     private static final ProtectionDomain PROTECTION_DOMAIN;
39 
40     static {
41         PROTECTION_DOMAIN = (ProtectionDomain)AccessController.doPrivileged(new PrivilegedAction() {
42             public Object run() {
43                 return ReflectUtils.class.getProtectionDomain();
44             }
45         });
46 
AccessController.doPrivileged(new PrivilegedAction() { public Object run() { try { Class loader = Class.forName("java.lang.ClassLoader"); DEFINE_CLASS = loader.getDeclaredMethod("defineClass", new Class[]{ String.class, byte[].class, Integer.TYPE, Integer.TYPE, ProtectionDomain.class }); DEFINE_CLASS.setAccessible(true); } catch (ClassNotFoundException e) { throw new CodeGenerationException(e); } catch (NoSuchMethodException e) { throw new CodeGenerationException(e); } return null; } })47         AccessController.doPrivileged(new PrivilegedAction() {
48             public Object run() {
49                 try {
50                     Class loader = Class.forName("java.lang.ClassLoader"); // JVM crash w/o this
51                     DEFINE_CLASS = loader.getDeclaredMethod("defineClass",
52                                                             new Class[]{ String.class,
53                                                                          byte[].class,
54                                                                          Integer.TYPE,
55                                                                          Integer.TYPE,
56                                                                          ProtectionDomain.class });
57                     DEFINE_CLASS.setAccessible(true);
58                 } catch (ClassNotFoundException e) {
59                     throw new CodeGenerationException(e);
60                 } catch (NoSuchMethodException e) {
61                     throw new CodeGenerationException(e);
62                 }
63                 return null;
64             }
65         });
66     }
67 
68     private static final String[] CGLIB_PACKAGES = {
69         "java.lang",
70     };
71 
72     static {
73         primitives.put("byte", Byte.TYPE);
74         primitives.put("char", Character.TYPE);
75         primitives.put("double", Double.TYPE);
76         primitives.put("float", Float.TYPE);
77         primitives.put("int", Integer.TYPE);
78         primitives.put("long", Long.TYPE);
79         primitives.put("short", Short.TYPE);
80         primitives.put("boolean", Boolean.TYPE);
81 
82         transforms.put("byte", "B");
83         transforms.put("char", "C");
84         transforms.put("double", "D");
85         transforms.put("float", "F");
86         transforms.put("int", "I");
87         transforms.put("long", "J");
88         transforms.put("short", "S");
89         transforms.put("boolean", "Z");
90     }
91 
getExceptionTypes(Member member)92     public static Type[] getExceptionTypes(Member member) {
93         if (member instanceof Method) {
94             return TypeUtils.getTypes(((Method)member).getExceptionTypes());
95         } else if (member instanceof Constructor) {
96             return TypeUtils.getTypes(((Constructor)member).getExceptionTypes());
97         } else {
98             throw new IllegalArgumentException("Cannot get exception types of a field");
99         }
100     }
101 
getSignature(Member member)102     public static Signature getSignature(Member member) {
103         if (member instanceof Method) {
104             return new Signature(member.getName(), Type.getMethodDescriptor((Method)member));
105         } else if (member instanceof Constructor) {
106             Type[] types = TypeUtils.getTypes(((Constructor)member).getParameterTypes());
107             return new Signature(Constants.CONSTRUCTOR_NAME,
108                                  Type.getMethodDescriptor(Type.VOID_TYPE, types));
109 
110         } else {
111             throw new IllegalArgumentException("Cannot get signature of a field");
112         }
113     }
114 
findConstructor(String desc)115     public static Constructor findConstructor(String desc) {
116         return findConstructor(desc, defaultLoader);
117     }
118 
findConstructor(String desc, ClassLoader loader)119     public static Constructor findConstructor(String desc, ClassLoader loader) {
120         try {
121             int lparen = desc.indexOf('(');
122             String className = desc.substring(0, lparen).trim();
123             return getClass(className, loader).getConstructor(parseTypes(desc, loader));
124         } catch (ClassNotFoundException e) {
125             throw new CodeGenerationException(e);
126         } catch (NoSuchMethodException e) {
127             throw new CodeGenerationException(e);
128         }
129     }
130 
findMethod(String desc)131     public static Method findMethod(String desc) {
132         return findMethod(desc, defaultLoader);
133     }
134 
findMethod(String desc, ClassLoader loader)135     public static Method findMethod(String desc, ClassLoader loader) {
136         try {
137             int lparen = desc.indexOf('(');
138             int dot = desc.lastIndexOf('.', lparen);
139             String className = desc.substring(0, dot).trim();
140             String methodName = desc.substring(dot + 1, lparen).trim();
141             return getClass(className, loader).getDeclaredMethod(methodName, parseTypes(desc, loader));
142         } catch (ClassNotFoundException e) {
143             throw new CodeGenerationException(e);
144         } catch (NoSuchMethodException e) {
145             throw new CodeGenerationException(e);
146         }
147     }
148 
parseTypes(String desc, ClassLoader loader)149     private static Class[] parseTypes(String desc, ClassLoader loader) throws ClassNotFoundException {
150         int lparen = desc.indexOf('(');
151         int rparen = desc.indexOf(')', lparen);
152         List params = new ArrayList();
153         int start = lparen + 1;
154         for (;;) {
155             int comma = desc.indexOf(',', start);
156             if (comma < 0) {
157                 break;
158             }
159             params.add(desc.substring(start, comma).trim());
160             start = comma + 1;
161         }
162         if (start < rparen) {
163             params.add(desc.substring(start, rparen).trim());
164         }
165         Class[] types = new Class[params.size()];
166         for (int i = 0; i < types.length; i++) {
167             types[i] = getClass((String)params.get(i), loader);
168         }
169         return types;
170     }
171 
getClass(String className, ClassLoader loader)172     private static Class getClass(String className, ClassLoader loader) throws ClassNotFoundException {
173         return getClass(className, loader, CGLIB_PACKAGES);
174     }
175 
getClass(String className, ClassLoader loader, String[] packages)176     private static Class getClass(String className, ClassLoader loader, String[] packages) throws ClassNotFoundException {
177         String save = className;
178         int dimensions = 0;
179         int index = 0;
180         while ((index = className.indexOf("[]", index) + 1) > 0) {
181             dimensions++;
182         }
183         StringBuffer brackets = new StringBuffer(className.length() - dimensions);
184         for (int i = 0; i < dimensions; i++) {
185             brackets.append('[');
186         }
187         className = className.substring(0, className.length() - 2 * dimensions);
188 
189         String prefix = (dimensions > 0) ? brackets + "L" : "";
190         String suffix = (dimensions > 0) ? ";" : "";
191         try {
192             return Class.forName(prefix + className + suffix, false, loader);
193         } catch (ClassNotFoundException ignore) { }
194         for (int i = 0; i < packages.length; i++) {
195             try {
196                 return Class.forName(prefix + packages[i] + '.' + className + suffix, false, loader);
197             } catch (ClassNotFoundException ignore) { }
198         }
199         if (dimensions == 0) {
200             Class c = (Class)primitives.get(className);
201             if (c != null) {
202                 return c;
203             }
204         } else {
205             String transform = (String)transforms.get(className);
206             if (transform != null) {
207                 try {
208                     return Class.forName(brackets + transform, false, loader);
209                 } catch (ClassNotFoundException ignore) { }
210             }
211         }
212         throw new ClassNotFoundException(save);
213     }
214 
215 
newInstance(Class type)216     public static Object newInstance(Class type) {
217         return newInstance(type, Constants.EMPTY_CLASS_ARRAY, null);
218     }
219 
newInstance(Class type, Class[] parameterTypes, Object[] args)220     public static Object newInstance(Class type, Class[] parameterTypes, Object[] args) {
221         return newInstance(getConstructor(type, parameterTypes), args);
222     }
223 
newInstance(final Constructor cstruct, final Object[] args)224     public static Object newInstance(final Constructor cstruct, final Object[] args) {
225 
226         boolean flag = cstruct.isAccessible();
227         try {
228             cstruct.setAccessible(true);
229             Object result = cstruct.newInstance(args);
230             return result;
231         } catch (InstantiationException e) {
232             throw new CodeGenerationException(e);
233         } catch (IllegalAccessException e) {
234             throw new CodeGenerationException(e);
235         } catch (InvocationTargetException e) {
236             throw new CodeGenerationException(e.getTargetException());
237         } finally {
238             cstruct.setAccessible(flag);
239         }
240 
241     }
242 
getConstructor(Class type, Class[] parameterTypes)243     public static Constructor getConstructor(Class type, Class[] parameterTypes) {
244         try {
245             Constructor constructor = type.getDeclaredConstructor(parameterTypes);
246             constructor.setAccessible(true);
247             return constructor;
248         } catch (NoSuchMethodException e) {
249             throw new CodeGenerationException(e);
250         }
251     }
252 
getNames(Class[] classes)253     public static String[] getNames(Class[] classes)
254     {
255         if (classes == null)
256             return null;
257         String[] names = new String[classes.length];
258         for (int i = 0; i < names.length; i++) {
259             names[i] = classes[i].getName();
260         }
261         return names;
262     }
263 
getClasses(Object[] objects)264     public static Class[] getClasses(Object[] objects) {
265         Class[] classes = new Class[objects.length];
266         for (int i = 0; i < objects.length; i++) {
267             classes[i] = objects[i].getClass();
268         }
269         return classes;
270     }
271 
findNewInstance(Class iface)272     public static Method findNewInstance(Class iface) {
273         Method m = findInterfaceMethod(iface);
274         if (!m.getName().equals("newInstance")) {
275             throw new IllegalArgumentException(iface + " missing newInstance method");
276         }
277         return m;
278     }
279 
getPropertyMethods(PropertyDescriptor[] properties, boolean read, boolean write)280     public static Method[] getPropertyMethods(PropertyDescriptor[] properties, boolean read, boolean write) {
281         Set methods = new HashSet();
282         for (int i = 0; i < properties.length; i++) {
283             PropertyDescriptor pd = properties[i];
284             if (read) {
285                 methods.add(pd.getReadMethod());
286             }
287             if (write) {
288                 methods.add(pd.getWriteMethod());
289             }
290         }
291         methods.remove(null);
292         return (Method[])methods.toArray(new Method[methods.size()]);
293     }
294 
getBeanProperties(Class type)295     public static PropertyDescriptor[] getBeanProperties(Class type) {
296         return getPropertiesHelper(type, true, true);
297     }
298 
getBeanGetters(Class type)299     public static PropertyDescriptor[] getBeanGetters(Class type) {
300         return getPropertiesHelper(type, true, false);
301     }
302 
getBeanSetters(Class type)303     public static PropertyDescriptor[] getBeanSetters(Class type) {
304         return getPropertiesHelper(type, false, true);
305     }
306 
getPropertiesHelper(Class type, boolean read, boolean write)307     private static PropertyDescriptor[] getPropertiesHelper(Class type, boolean read, boolean write) {
308         try {
309             BeanInfo info = Introspector.getBeanInfo(type, Object.class);
310             PropertyDescriptor[] all = info.getPropertyDescriptors();
311             if (read && write) {
312                 return all;
313             }
314             List properties = new ArrayList(all.length);
315             for (int i = 0; i < all.length; i++) {
316                 PropertyDescriptor pd = all[i];
317                 if ((read && pd.getReadMethod() != null) ||
318                     (write && pd.getWriteMethod() != null)) {
319                     properties.add(pd);
320                 }
321             }
322             return (PropertyDescriptor[])properties.toArray(new PropertyDescriptor[properties.size()]);
323         } catch (IntrospectionException e) {
324             throw new CodeGenerationException(e);
325         }
326     }
327 
328 
329 
findDeclaredMethod(final Class type, final String methodName, final Class[] parameterTypes)330     public static Method findDeclaredMethod(final Class type,
331                                             final String methodName, final Class[] parameterTypes)
332     throws NoSuchMethodException {
333 
334         Class cl = type;
335         while (cl != null) {
336             try {
337                 return cl.getDeclaredMethod(methodName, parameterTypes);
338             } catch (NoSuchMethodException e) {
339                 cl = cl.getSuperclass();
340             }
341         }
342         throw new NoSuchMethodException(methodName);
343 
344     }
345 
addAllMethods(final Class type, final List list)346     public static List addAllMethods(final Class type, final List list) {
347 
348 
349         list.addAll(java.util.Arrays.asList(type.getDeclaredMethods()));
350         Class superclass = type.getSuperclass();
351         if (superclass != null) {
352             addAllMethods(superclass, list);
353         }
354         Class[] interfaces = type.getInterfaces();
355         for (int i = 0; i < interfaces.length; i++) {
356             addAllMethods(interfaces[i], list);
357         }
358 
359         return list;
360     }
361 
addAllInterfaces(Class type, List list)362     public static List addAllInterfaces(Class type, List list) {
363         Class superclass = type.getSuperclass();
364         if (superclass != null) {
365             list.addAll(Arrays.asList(type.getInterfaces()));
366             addAllInterfaces(superclass, list);
367         }
368         return list;
369     }
370 
371 
findInterfaceMethod(Class iface)372     public static Method findInterfaceMethod(Class iface) {
373         if (!iface.isInterface()) {
374             throw new IllegalArgumentException(iface + " is not an interface");
375         }
376         Method[] methods = iface.getDeclaredMethods();
377         if (methods.length != 1) {
378             throw new IllegalArgumentException("expecting exactly 1 method in " + iface);
379         }
380         return methods[0];
381     }
382 
defineClass(String className, byte[] b, ClassLoader loader)383     public static Class defineClass(String className, byte[] b, ClassLoader loader) throws Exception {
384         Object[] args = new Object[]{className, b, new Integer(0), new Integer(b.length), PROTECTION_DOMAIN };
385         return (Class)DEFINE_CLASS.invoke(loader, args);
386     }
387 
findPackageProtected(Class[] classes)388     public static int findPackageProtected(Class[] classes) {
389         for (int i = 0; i < classes.length; i++) {
390             if (!Modifier.isPublic(classes[i].getModifiers())) {
391                 return i;
392             }
393         }
394         return 0;
395     }
396 
getMethodInfo(final Member member, final int modifiers)397     public static MethodInfo getMethodInfo(final Member member, final int modifiers) {
398         final Signature sig = getSignature(member);
399         return new MethodInfo() {
400             private ClassInfo ci;
401             public ClassInfo getClassInfo() {
402                 if (ci == null)
403                     ci = ReflectUtils.getClassInfo(member.getDeclaringClass());
404                 return ci;
405             }
406             public int getModifiers() {
407                 return modifiers;
408             }
409             public Signature getSignature() {
410                 return sig;
411             }
412             public Type[] getExceptionTypes() {
413                 return ReflectUtils.getExceptionTypes(member);
414             }
415             public Attribute getAttribute() {
416                 return null;
417             }
418         };
419     }
420 
getMethodInfo(Member member)421     public static MethodInfo getMethodInfo(Member member) {
422         return getMethodInfo(member, member.getModifiers());
423     }
424 
getClassInfo(final Class clazz)425     public static ClassInfo getClassInfo(final Class clazz) {
426         final Type type = Type.getType(clazz);
427         final Type sc = (clazz.getSuperclass() == null) ? null : Type.getType(clazz.getSuperclass());
428         return new ClassInfo() {
429             public Type getType() {
430                 return type;
431             }
432             public Type getSuperType() {
433                 return sc;
434             }
435             public Type[] getInterfaces() {
436                 return TypeUtils.getTypes(clazz.getInterfaces());
437             }
438             public int getModifiers() {
439                 return clazz.getModifiers();
440             }
441         };
442     }
443 
444     // used by MethodInterceptorGenerated generated code
445     public static Method[] findMethods(String[] namesAndDescriptors, Method[] methods)
446     {
447         Map map = new HashMap();
448         for (int i = 0; i < methods.length; i++) {
449             Method method = methods[i];
450             map.put(method.getName() + Type.getMethodDescriptor(method), method);
451         }
452         Method[] result = new Method[namesAndDescriptors.length / 2];
453         for (int i = 0; i < result.length; i++) {
454             result[i] = (Method)map.get(namesAndDescriptors[i * 2] + namesAndDescriptors[i * 2 + 1]);
455             if (result[i] == null) {
456                 // TODO: error?
457             }
458         }
459         return result;
460     }
461 }
462