001: /*
002: * Copyright 2003,2004 The Apache Software Foundation
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package net.sf.cglib.core;
017:
018: import java.beans.*;
019: import java.lang.reflect.*;
020: import java.security.AccessController;
021: import java.security.PrivilegedAction;
022: import java.security.ProtectionDomain;
023: import java.util.*;
024: import org.objectweb.asm.Attribute;
025: import org.objectweb.asm.Type;
026:
027: /**
028: * @version $Id: ReflectUtils.java,v 1.29 2006/02/28 00:30:51 herbyderby Exp $
029: */
030: public class ReflectUtils {
031: private ReflectUtils() {
032: }
033:
034: private static final Map primitives = new HashMap(8);
035: private static final Map transforms = new HashMap(8);
036: private static final ClassLoader defaultLoader = ReflectUtils.class
037: .getClassLoader();
038: private static Method DEFINE_CLASS;
039: private static final ProtectionDomain PROTECTION_DOMAIN;
040:
041: static {
042: PROTECTION_DOMAIN = (ProtectionDomain) AccessController
043: .doPrivileged(new PrivilegedAction() {
044: public Object run() {
045: return ReflectUtils.class.getProtectionDomain();
046: }
047: });
048:
049: AccessController.doPrivileged(new PrivilegedAction() {
050: public Object run() {
051: try {
052: Class loader = Class
053: .forName("java.lang.ClassLoader"); // JVM crash w/o this
054: DEFINE_CLASS = loader.getDeclaredMethod(
055: "defineClass", new Class[] { String.class,
056: byte[].class, Integer.TYPE,
057: Integer.TYPE,
058: ProtectionDomain.class });
059: DEFINE_CLASS.setAccessible(true);
060: } catch (ClassNotFoundException e) {
061: throw new CodeGenerationException(e);
062: } catch (NoSuchMethodException e) {
063: throw new CodeGenerationException(e);
064: }
065: return null;
066: }
067: });
068: }
069:
070: private static final String[] CGLIB_PACKAGES = { "java.lang", };
071:
072: static {
073: primitives.put("byte", Byte.TYPE);
074: primitives.put("char", Character.TYPE);
075: primitives.put("double", Double.TYPE);
076: primitives.put("float", Float.TYPE);
077: primitives.put("int", Integer.TYPE);
078: primitives.put("long", Long.TYPE);
079: primitives.put("short", Short.TYPE);
080: primitives.put("boolean", Boolean.TYPE);
081:
082: transforms.put("byte", "B");
083: transforms.put("char", "C");
084: transforms.put("double", "D");
085: transforms.put("float", "F");
086: transforms.put("int", "I");
087: transforms.put("long", "J");
088: transforms.put("short", "S");
089: transforms.put("boolean", "Z");
090: }
091:
092: public static Type[] getExceptionTypes(Member member) {
093: if (member instanceof Method) {
094: return TypeUtils.getTypes(((Method) member)
095: .getExceptionTypes());
096: } else if (member instanceof Constructor) {
097: return TypeUtils.getTypes(((Constructor) member)
098: .getExceptionTypes());
099: } else {
100: throw new IllegalArgumentException(
101: "Cannot get exception types of a field");
102: }
103: }
104:
105: public static Signature getSignature(Member member) {
106: if (member instanceof Method) {
107: return new Signature(member.getName(), Type
108: .getMethodDescriptor((Method) member));
109: } else if (member instanceof Constructor) {
110: Type[] types = TypeUtils.getTypes(((Constructor) member)
111: .getParameterTypes());
112: return new Signature(Constants.CONSTRUCTOR_NAME, Type
113: .getMethodDescriptor(Type.VOID_TYPE, types));
114:
115: } else {
116: throw new IllegalArgumentException(
117: "Cannot get signature of a field");
118: }
119: }
120:
121: public static Constructor findConstructor(String desc) {
122: return findConstructor(desc, defaultLoader);
123: }
124:
125: public static Constructor findConstructor(String desc,
126: ClassLoader loader) {
127: try {
128: int lparen = desc.indexOf('(');
129: String className = desc.substring(0, lparen).trim();
130: return getClass(className, loader).getConstructor(
131: parseTypes(desc, loader));
132: } catch (ClassNotFoundException e) {
133: throw new CodeGenerationException(e);
134: } catch (NoSuchMethodException e) {
135: throw new CodeGenerationException(e);
136: }
137: }
138:
139: public static Method findMethod(String desc) {
140: return findMethod(desc, defaultLoader);
141: }
142:
143: public static Method findMethod(String desc, ClassLoader loader) {
144: try {
145: int lparen = desc.indexOf('(');
146: int dot = desc.lastIndexOf('.', lparen);
147: String className = desc.substring(0, dot).trim();
148: String methodName = desc.substring(dot + 1, lparen).trim();
149: return getClass(className, loader).getDeclaredMethod(
150: methodName, parseTypes(desc, loader));
151: } catch (ClassNotFoundException e) {
152: throw new CodeGenerationException(e);
153: } catch (NoSuchMethodException e) {
154: throw new CodeGenerationException(e);
155: }
156: }
157:
158: private static Class[] parseTypes(String desc, ClassLoader loader)
159: throws ClassNotFoundException {
160: int lparen = desc.indexOf('(');
161: int rparen = desc.indexOf(')', lparen);
162: List params = new ArrayList();
163: int start = lparen + 1;
164: for (;;) {
165: int comma = desc.indexOf(',', start);
166: if (comma < 0) {
167: break;
168: }
169: params.add(desc.substring(start, comma).trim());
170: start = comma + 1;
171: }
172: if (start < rparen) {
173: params.add(desc.substring(start, rparen).trim());
174: }
175: Class[] types = new Class[params.size()];
176: for (int i = 0; i < types.length; i++) {
177: types[i] = getClass((String) params.get(i), loader);
178: }
179: return types;
180: }
181:
182: private static Class getClass(String className, ClassLoader loader)
183: throws ClassNotFoundException {
184: return getClass(className, loader, CGLIB_PACKAGES);
185: }
186:
187: private static Class getClass(String className, ClassLoader loader,
188: String[] packages) throws ClassNotFoundException {
189: String save = className;
190: int dimensions = 0;
191: int index = 0;
192: while ((index = className.indexOf("[]", index) + 1) > 0) {
193: dimensions++;
194: }
195: StringBuffer brackets = new StringBuffer(className.length()
196: - dimensions);
197: for (int i = 0; i < dimensions; i++) {
198: brackets.append('[');
199: }
200: className = className.substring(0, className.length() - 2
201: * dimensions);
202:
203: String prefix = (dimensions > 0) ? brackets + "L" : "";
204: String suffix = (dimensions > 0) ? ";" : "";
205: try {
206: return Class.forName(prefix + className + suffix, false,
207: loader);
208: } catch (ClassNotFoundException ignore) {
209: }
210: for (int i = 0; i < packages.length; i++) {
211: try {
212: return Class.forName(prefix + packages[i] + '.'
213: + className + suffix, false, loader);
214: } catch (ClassNotFoundException ignore) {
215: }
216: }
217: if (dimensions == 0) {
218: Class c = (Class) primitives.get(className);
219: if (c != null) {
220: return c;
221: }
222: } else {
223: String transform = (String) transforms.get(className);
224: if (transform != null) {
225: try {
226: return Class.forName(brackets + transform, false,
227: loader);
228: } catch (ClassNotFoundException ignore) {
229: }
230: }
231: }
232: throw new ClassNotFoundException(save);
233: }
234:
235: public static Object newInstance(Class type) {
236: return newInstance(type, Constants.EMPTY_CLASS_ARRAY, null);
237: }
238:
239: public static Object newInstance(Class type,
240: Class[] parameterTypes, Object[] args) {
241: return newInstance(getConstructor(type, parameterTypes), args);
242: }
243:
244: public static Object newInstance(final Constructor cstruct,
245: final Object[] args) {
246:
247: boolean flag = cstruct.isAccessible();
248: try {
249: cstruct.setAccessible(true);
250: Object result = cstruct.newInstance(args);
251: return result;
252: } catch (InstantiationException e) {
253: throw new CodeGenerationException(e);
254: } catch (IllegalAccessException e) {
255: throw new CodeGenerationException(e);
256: } catch (InvocationTargetException e) {
257: throw new CodeGenerationException(e.getTargetException());
258: } finally {
259: cstruct.setAccessible(flag);
260: }
261:
262: }
263:
264: public static Constructor getConstructor(Class type,
265: Class[] parameterTypes) {
266: try {
267: Constructor constructor = type
268: .getDeclaredConstructor(parameterTypes);
269: constructor.setAccessible(true);
270: return constructor;
271: } catch (NoSuchMethodException e) {
272: throw new CodeGenerationException(e);
273: }
274: }
275:
276: public static String[] getNames(Class[] classes) {
277: if (classes == null)
278: return null;
279: String[] names = new String[classes.length];
280: for (int i = 0; i < names.length; i++) {
281: names[i] = classes[i].getName();
282: }
283: return names;
284: }
285:
286: public static Class[] getClasses(Object[] objects) {
287: Class[] classes = new Class[objects.length];
288: for (int i = 0; i < objects.length; i++) {
289: classes[i] = objects[i].getClass();
290: }
291: return classes;
292: }
293:
294: public static Method findNewInstance(Class iface) {
295: Method m = findInterfaceMethod(iface);
296: if (!m.getName().equals("newInstance")) {
297: throw new IllegalArgumentException(iface
298: + " missing newInstance method");
299: }
300: return m;
301: }
302:
303: public static Method[] getPropertyMethods(
304: PropertyDescriptor[] properties, boolean read, boolean write) {
305: Set methods = new HashSet();
306: for (int i = 0; i < properties.length; i++) {
307: PropertyDescriptor pd = properties[i];
308: if (read) {
309: methods.add(pd.getReadMethod());
310: }
311: if (write) {
312: methods.add(pd.getWriteMethod());
313: }
314: }
315: methods.remove(null);
316: return (Method[]) methods.toArray(new Method[methods.size()]);
317: }
318:
319: public static PropertyDescriptor[] getBeanProperties(Class type) {
320: return getPropertiesHelper(type, true, true);
321: }
322:
323: public static PropertyDescriptor[] getBeanGetters(Class type) {
324: return getPropertiesHelper(type, true, false);
325: }
326:
327: public static PropertyDescriptor[] getBeanSetters(Class type) {
328: return getPropertiesHelper(type, false, true);
329: }
330:
331: private static PropertyDescriptor[] getPropertiesHelper(Class type,
332: boolean read, boolean write) {
333: try {
334: BeanInfo info = Introspector
335: .getBeanInfo(type, Object.class);
336: PropertyDescriptor[] all = info.getPropertyDescriptors();
337: if (read && write) {
338: return all;
339: }
340: List properties = new ArrayList(all.length);
341: for (int i = 0; i < all.length; i++) {
342: PropertyDescriptor pd = all[i];
343: if ((read && pd.getReadMethod() != null)
344: || (write && pd.getWriteMethod() != null)) {
345: properties.add(pd);
346: }
347: }
348: return (PropertyDescriptor[]) properties
349: .toArray(new PropertyDescriptor[properties.size()]);
350: } catch (IntrospectionException e) {
351: throw new CodeGenerationException(e);
352: }
353: }
354:
355: public static Method findDeclaredMethod(final Class type,
356: final String methodName, final Class[] parameterTypes)
357: throws NoSuchMethodException {
358:
359: Class cl = type;
360: while (cl != null) {
361: try {
362: return cl.getDeclaredMethod(methodName, parameterTypes);
363: } catch (NoSuchMethodException e) {
364: cl = cl.getSuperclass();
365: }
366: }
367: throw new NoSuchMethodException(methodName);
368:
369: }
370:
371: public static List addAllMethods(final Class type, final List list) {
372:
373: list.addAll(java.util.Arrays.asList(type.getDeclaredMethods()));
374: Class super class = type.getSuperclass();
375: if (super class != null) {
376: addAllMethods(super class, list);
377: }
378: Class[] interfaces = type.getInterfaces();
379: for (int i = 0; i < interfaces.length; i++) {
380: addAllMethods(interfaces[i], list);
381: }
382:
383: return list;
384: }
385:
386: public static List addAllInterfaces(Class type, List list) {
387: Class super class = type.getSuperclass();
388: if (super class != null) {
389: list.addAll(Arrays.asList(type.getInterfaces()));
390: addAllInterfaces(super class, list);
391: }
392: return list;
393: }
394:
395: public static Method findInterfaceMethod(Class iface) {
396: if (!iface.isInterface()) {
397: throw new IllegalArgumentException(iface
398: + " is not an interface");
399: }
400: Method[] methods = iface.getDeclaredMethods();
401: if (methods.length != 1) {
402: throw new IllegalArgumentException(
403: "expecting exactly 1 method in " + iface);
404: }
405: return methods[0];
406: }
407:
408: public static Class defineClass(String className, byte[] b,
409: ClassLoader loader) throws Exception {
410: Object[] args = new Object[] { className, b, new Integer(0),
411: new Integer(b.length), PROTECTION_DOMAIN };
412: return (Class) DEFINE_CLASS.invoke(loader, args);
413: }
414:
415: public static int findPackageProtected(Class[] classes) {
416: for (int i = 0; i < classes.length; i++) {
417: if (!Modifier.isPublic(classes[i].getModifiers())) {
418: return i;
419: }
420: }
421: return 0;
422: }
423:
424: public static MethodInfo getMethodInfo(final Member member,
425: final int modifiers) {
426: final Signature sig = getSignature(member);
427: return new MethodInfo() {
428: private ClassInfo ci;
429:
430: public ClassInfo getClassInfo() {
431: if (ci == null)
432: ci = ReflectUtils.getClassInfo(member
433: .getDeclaringClass());
434: return ci;
435: }
436:
437: public int getModifiers() {
438: return modifiers;
439: }
440:
441: public Signature getSignature() {
442: return sig;
443: }
444:
445: public Type[] getExceptionTypes() {
446: return ReflectUtils.getExceptionTypes(member);
447: }
448:
449: public Attribute getAttribute() {
450: return null;
451: }
452: };
453: }
454:
455: public static MethodInfo getMethodInfo(Member member) {
456: return getMethodInfo(member, member.getModifiers());
457: }
458:
459: public static ClassInfo getClassInfo(final Class clazz) {
460: final Type type = Type.getType(clazz);
461: final Type sc = (clazz.getSuperclass() == null) ? null : Type
462: .getType(clazz.getSuperclass());
463: return new ClassInfo() {
464: public Type getType() {
465: return type;
466: }
467:
468: public Type getSuperType() {
469: return sc;
470: }
471:
472: public Type[] getInterfaces() {
473: return TypeUtils.getTypes(clazz.getInterfaces());
474: }
475:
476: public int getModifiers() {
477: return clazz.getModifiers();
478: }
479: };
480: }
481:
482: // used by MethodInterceptorGenerated generated code
483: public static Method[] findMethods(String[] namesAndDescriptors,
484: Method[] methods) {
485: Map map = new HashMap();
486: for (int i = 0; i < methods.length; i++) {
487: Method method = methods[i];
488: map
489: .put(method.getName()
490: + Type.getMethodDescriptor(method), method);
491: }
492: Method[] result = new Method[namesAndDescriptors.length / 2];
493: for (int i = 0; i < result.length; i++) {
494: result[i] = (Method) map.get(namesAndDescriptors[i * 2]
495: + namesAndDescriptors[i * 2 + 1]);
496: if (result[i] == null) {
497: // TODO: error?
498: }
499: }
500: return result;
501: }
502: }
|