001: /*
002: * Copyright 2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package com.sun.xml.internal.bind.v2.model.nav;
027:
028: import java.lang.reflect.Array;
029: import java.lang.reflect.Field;
030: import java.lang.reflect.GenericArrayType;
031: import java.lang.reflect.GenericDeclaration;
032: import java.lang.reflect.Method;
033: import java.lang.reflect.Modifier;
034: import java.lang.reflect.ParameterizedType;
035: import java.lang.reflect.Type;
036: import java.lang.reflect.TypeVariable;
037: import java.lang.reflect.WildcardType;
038: import java.util.Arrays;
039: import java.util.Collection;
040:
041: import com.sun.xml.internal.bind.v2.runtime.Location;
042:
043: /**
044: * {@link Navigator} implementation for {@code java.lang.reflect}.
045: *
046: */
047: public final class ReflectionNavigator implements
048: Navigator<Type, Class, Field, Method> {
049: /**
050: * Singleton.
051: *
052: * Use {@link Navigator#REFLECTION}
053: */
054: ReflectionNavigator() {
055: }
056:
057: public Class getSuperClass(Class clazz) {
058: return clazz.getSuperclass();
059: }
060:
061: private static final TypeVisitor<Type, Class> baseClassFinder = new TypeVisitor<Type, Class>() {
062: public Type onClass(Class c, Class sup) {
063: // t is a raw type
064: if (sup == c)
065: return sup;
066:
067: Type r;
068:
069: Type sc = c.getGenericSuperclass();
070: if (sc != null) {
071: r = visit(sc, sup);
072: if (r != null)
073: return r;
074: }
075:
076: for (Type i : c.getGenericInterfaces()) {
077: r = visit(i, sup);
078: if (r != null)
079: return r;
080: }
081:
082: return null;
083: }
084:
085: public Type onParameterizdType(ParameterizedType p, Class sup) {
086: Class raw = (Class) p.getRawType();
087: if (raw == sup) {
088: // p is of the form sup<...>
089: return p;
090: } else {
091: // recursively visit super class/interfaces
092: Type r = raw.getGenericSuperclass();
093: if (r != null)
094: r = visit(bind(r, raw, p), sup);
095: if (r != null)
096: return r;
097: for (Type i : raw.getGenericInterfaces()) {
098: r = visit(bind(i, raw, p), sup);
099: if (r != null)
100: return r;
101: }
102: return null;
103: }
104: }
105:
106: public Type onGenericArray(GenericArrayType g, Class sup) {
107: // not clear what I should do here
108: return null;
109: }
110:
111: public Type onVariable(TypeVariable v, Class sup) {
112: return visit(v.getBounds()[0], sup);
113: }
114:
115: public Type onWildcard(WildcardType w, Class sup) {
116: // not clear what I should do here
117: return null;
118: }
119:
120: /**
121: * Replaces the type variables in {@code t} by its actual arguments.
122: *
123: * @param decl
124: * provides a list of type variables. See {@link GenericDeclaration#getTypeParameters()}
125: * @param args
126: * actual arguments. See {@link ParameterizedType#getActualTypeArguments()}
127: */
128: private Type bind(Type t, GenericDeclaration decl,
129: ParameterizedType args) {
130: return binder.visit(t, new BinderArg(decl, args
131: .getActualTypeArguments()));
132: }
133: };
134:
135: private static class BinderArg {
136: final TypeVariable[] params;
137: final Type[] args;
138:
139: BinderArg(TypeVariable[] params, Type[] args) {
140: this .params = params;
141: this .args = args;
142: assert params.length == args.length;
143: }
144:
145: public BinderArg(GenericDeclaration decl, Type[] args) {
146: this (decl.getTypeParameters(), args);
147: }
148:
149: Type replace(TypeVariable v) {
150: for (int i = 0; i < params.length; i++)
151: if (params[i] == v)
152: return args[i];
153: return v; // this is a free variable
154: }
155: }
156:
157: private static final TypeVisitor<Type, BinderArg> binder = new TypeVisitor<Type, BinderArg>() {
158: public Type onClass(Class c, BinderArg args) {
159: return c;
160: }
161:
162: public Type onParameterizdType(ParameterizedType p,
163: BinderArg args) {
164: Type[] params = p.getActualTypeArguments();
165:
166: boolean different = false;
167: for (int i = 0; i < params.length; i++) {
168: Type t = params[i];
169: params[i] = visit(t, args);
170: different |= t != params[i];
171: }
172:
173: Type newOwner = p.getOwnerType();
174: if (newOwner != null)
175: newOwner = visit(newOwner, args);
176: different |= p.getOwnerType() != newOwner;
177:
178: if (!different)
179: return p;
180:
181: return new ParameterizedTypeImpl((Class<?>) p.getRawType(),
182: params, newOwner);
183: }
184:
185: public Type onGenericArray(GenericArrayType g, BinderArg types) {
186: Type c = visit(g.getGenericComponentType(), types);
187: if (c == g.getGenericComponentType())
188: return g;
189:
190: return new GenericArrayTypeImpl(c);
191: }
192:
193: public Type onVariable(TypeVariable v, BinderArg types) {
194: return types.replace(v);
195: }
196:
197: public Type onWildcard(WildcardType w, BinderArg types) {
198: // TODO: this is probably still incorrect
199: // bind( "? extends T" ) with T= "? extends Foo" should be "? extends Foo",
200: // not "? extends (? extends Foo)"
201: Type[] lb = w.getLowerBounds();
202: Type[] ub = w.getUpperBounds();
203: boolean diff = false;
204:
205: for (int i = 0; i < lb.length; i++) {
206: Type t = lb[i];
207: lb[i] = visit(t, types);
208: diff |= (t != lb[i]);
209: }
210:
211: for (int i = 0; i < ub.length; i++) {
212: Type t = ub[i];
213: ub[i] = visit(t, types);
214: diff |= (t != ub[i]);
215: }
216:
217: if (!diff)
218: return w;
219:
220: return new WildcardTypeImpl(lb, ub);
221: }
222: };
223:
224: public Type getBaseClass(Type t, Class sup) {
225: return baseClassFinder.visit(t, sup);
226: }
227:
228: public String getClassName(Class clazz) {
229: return clazz.getName();
230: }
231:
232: public String getTypeName(Type type) {
233: if (type instanceof Class) {
234: Class c = (Class) type;
235: if (c.isArray())
236: return getTypeName(c.getComponentType()) + "[]";
237: return c.getName();
238: }
239: return type.toString();
240: }
241:
242: public String getClassShortName(Class clazz) {
243: return clazz.getSimpleName();
244: }
245:
246: public Collection<? extends Field> getDeclaredFields(Class clazz) {
247: return Arrays.asList(clazz.getDeclaredFields());
248: }
249:
250: public Field getDeclaredField(Class clazz, String fieldName) {
251: try {
252: return clazz.getDeclaredField(fieldName);
253: } catch (NoSuchFieldException e) {
254: return null;
255: }
256: }
257:
258: public Collection<? extends Method> getDeclaredMethods(Class clazz) {
259: return Arrays.asList(clazz.getDeclaredMethods());
260: }
261:
262: public Class getDeclaringClassForField(Field field) {
263: return field.getDeclaringClass();
264: }
265:
266: public Class getDeclaringClassForMethod(Method method) {
267: return method.getDeclaringClass();
268: }
269:
270: public Type getFieldType(Field field) {
271: return fix(field.getGenericType());
272: }
273:
274: public String getFieldName(Field field) {
275: return field.getName();
276: }
277:
278: public String getMethodName(Method method) {
279: return method.getName();
280: }
281:
282: public Type getReturnType(Method method) {
283: return fix(method.getGenericReturnType());
284: }
285:
286: public Type[] getMethodParameters(Method method) {
287: return method.getGenericParameterTypes();
288: }
289:
290: public boolean isStaticMethod(Method method) {
291: return Modifier.isStatic(method.getModifiers());
292: }
293:
294: public boolean isSubClassOf(Type sub, Type sup) {
295: return erasure(sup).isAssignableFrom(erasure(sub));
296: }
297:
298: public Class ref(Class c) {
299: return c;
300: }
301:
302: public Class use(Class c) {
303: return c;
304: }
305:
306: public Class asDecl(Type t) {
307: return erasure(t);
308: }
309:
310: public Class asDecl(Class c) {
311: return c;
312: }
313:
314: /**
315: * Implements the logic for {@link #erasure(Type)}.
316: */
317: private static final TypeVisitor<Class, Void> eraser = new TypeVisitor<Class, Void>() {
318: public Class onClass(Class c, Void _) {
319: return c;
320: }
321:
322: public Class onParameterizdType(ParameterizedType p, Void _) {
323: // TODO: why getRawType returns Type? not Class?
324: return visit(p.getRawType(), null);
325: }
326:
327: public Class onGenericArray(GenericArrayType g, Void _) {
328: return Array.newInstance(
329: visit(g.getGenericComponentType(), null), 0)
330: .getClass();
331: }
332:
333: public Class onVariable(TypeVariable v, Void _) {
334: return visit(v.getBounds()[0], null);
335: }
336:
337: public Class onWildcard(WildcardType w, Void _) {
338: return visit(w.getUpperBounds()[0], null);
339: }
340: };
341:
342: /**
343: * Returns the runtime representation of the given type.
344: *
345: * This corresponds to the notion of the erasure in JSR-14.
346: *
347: * <p>
348: * Because of the difference in the way APT and the Java reflection
349: * treats primitive type and array type, we can't define this method
350: * on {@link Navigator}.
351: *
352: * <p>
353: * It made me realize how difficult it is to define the common navigation
354: * layer for two different underlying reflection library. The other way
355: * is to throw away the entire parameterization and go to the wrapper approach.
356: */
357: public <T> Class<T> erasure(Type t) {
358: return eraser.visit(t, null);
359: }
360:
361: public boolean isAbstract(Class clazz) {
362: return Modifier.isAbstract(clazz.getModifiers());
363: }
364:
365: public boolean isFinal(Class clazz) {
366: return Modifier.isFinal(clazz.getModifiers());
367: }
368:
369: /**
370: * Returns the {@link Type} object that represents {@code clazz<T1,T2,T3>}.
371: */
372: public Type createParameterizedType(Class rawType,
373: Type... arguments) {
374: return new ParameterizedTypeImpl(rawType, arguments, null);
375: }
376:
377: public boolean isArray(Type t) {
378: if (t instanceof Class) {
379: Class c = (Class) t;
380: return c.isArray();
381: }
382: if (t instanceof GenericArrayType)
383: return true;
384: return false;
385: }
386:
387: public boolean isArrayButNotByteArray(Type t) {
388: if (t instanceof Class) {
389: Class c = (Class) t;
390: return c.isArray() && c != byte[].class;
391: }
392: if (t instanceof GenericArrayType) {
393: t = ((GenericArrayType) t).getGenericComponentType();
394: return t != Byte.TYPE;
395: }
396: return false;
397: }
398:
399: public Type getComponentType(Type t) {
400: if (t instanceof Class) {
401: Class c = (Class) t;
402: return c.getComponentType();
403: }
404: if (t instanceof GenericArrayType)
405: return ((GenericArrayType) t).getGenericComponentType();
406:
407: throw new IllegalArgumentException();
408: }
409:
410: public Type getTypeArgument(Type type, int i) {
411: if (type instanceof ParameterizedType) {
412: ParameterizedType p = (ParameterizedType) type;
413: return fix(p.getActualTypeArguments()[i]);
414: } else
415: throw new IllegalArgumentException();
416: }
417:
418: public boolean isParameterizedType(Type type) {
419: return type instanceof ParameterizedType;
420: }
421:
422: public boolean isPrimitive(Type type) {
423: if (type instanceof Class) {
424: Class c = (Class) type;
425: return c.isPrimitive();
426: }
427: return false;
428: }
429:
430: public Type getPrimitive(Class primitiveType) {
431: assert primitiveType.isPrimitive();
432: return primitiveType;
433: }
434:
435: public Location getClassLocation(final Class clazz) {
436: return new Location() {
437: public String toString() {
438: return clazz.getName();
439: }
440: };
441: }
442:
443: public Location getFieldLocation(final Field field) {
444: return new Location() {
445: public String toString() {
446: return field.toString();
447: }
448: };
449: }
450:
451: public Location getMethodLocation(final Method method) {
452: return new Location() {
453: public String toString() {
454: return method.toString();
455: }
456: };
457: }
458:
459: public boolean hasDefaultConstructor(Class c) {
460: try {
461: c.getDeclaredConstructor();
462: return true;
463: } catch (NoSuchMethodException e) {
464: return false;
465: }
466: }
467:
468: public boolean isStaticField(Field field) {
469: return Modifier.isStatic(field.getModifiers());
470: }
471:
472: public boolean isPublicMethod(Method method) {
473: return Modifier.isPublic(method.getModifiers());
474: }
475:
476: public boolean isPublicField(Field field) {
477: return Modifier.isPublic(field.getModifiers());
478: }
479:
480: public boolean isEnum(Class c) {
481: return Enum.class.isAssignableFrom(c);
482: }
483:
484: public Field[] getEnumConstants(Class clazz) {
485: try {
486: Object[] values = clazz.getEnumConstants();
487: Field[] fields = new Field[values.length];
488: for (int i = 0; i < values.length; i++) {
489: fields[i] = clazz.getField(((Enum) values[i]).name());
490: }
491: return fields;
492: } catch (NoSuchFieldException e) {
493: // impossible
494: throw new NoSuchFieldError(e.getMessage());
495: }
496: }
497:
498: public Type getVoidType() {
499: return Void.class;
500: }
501:
502: public String getPackageName(Class clazz) {
503: String name = clazz.getName();
504: int idx = name.lastIndexOf('.');
505: if (idx < 0)
506: return "";
507: else
508: return name.substring(0, idx);
509: }
510:
511: public Class findClass(String className, Class referencePoint) {
512: try {
513: ClassLoader cl = referencePoint.getClassLoader();
514: if (cl == null)
515: cl = ClassLoader.getSystemClassLoader();
516: return cl.loadClass(className);
517: } catch (ClassNotFoundException e) {
518: return null;
519: }
520: }
521:
522: public boolean isBridgeMethod(Method method) {
523: return method.isBridge();
524: }
525:
526: public boolean isOverriding(Method method) {
527: // this isn't actually correct,
528: // as the JLS considers
529: // class Derived extends Base<Integer> {
530: // Integer getX() { ... }
531: // }
532: // class Base<T> {
533: // T getX() { ... }
534: // }
535: // to be overrided. Handling this correctly needs a careful implementation
536:
537: Class<?> s = method.getDeclaringClass().getSuperclass();
538: String name = method.getName();
539: Class[] params = method.getParameterTypes();
540:
541: while (s != null) {
542: try {
543: if (s.getDeclaredMethod(name, params) != null)
544: return true;
545: } catch (NoSuchMethodException e) {
546: ; // recursively go into the base class
547: }
548:
549: s = s.getSuperclass();
550: }
551:
552: return false;
553: }
554:
555: public boolean isInterface(Class clazz) {
556: return clazz.isInterface();
557: }
558:
559: public boolean isTransient(Field f) {
560: return Modifier.isTransient(f.getModifiers());
561: }
562:
563: /**
564: * JDK 5.0 has a bug of createing {@link GenericArrayType} where it shouldn't.
565: * fix that manually to work around the problem.
566: *
567: * See bug 6202725.
568: */
569: private Type fix(Type t) {
570: if (!(t instanceof GenericArrayType))
571: return t;
572:
573: GenericArrayType gat = (GenericArrayType) t;
574: if (gat.getGenericComponentType() instanceof Class) {
575: Class c = (Class) gat.getGenericComponentType();
576: return Array.newInstance(c, 0).getClass();
577: }
578:
579: return t;
580: }
581: }
|