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