1 /*
   2  * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.xml.internal.bind.v2.model.nav;
  27 
  28 import java.lang.reflect.Array;
  29 import java.lang.reflect.Field;
  30 import java.lang.reflect.GenericArrayType;
  31 import java.lang.reflect.GenericDeclaration;
  32 import java.lang.reflect.Method;
  33 import java.lang.reflect.Modifier;
  34 import java.lang.reflect.ParameterizedType;
  35 import java.lang.reflect.Type;
  36 import java.lang.reflect.TypeVariable;
  37 import java.lang.reflect.WildcardType;
  38 import java.util.Arrays;
  39 import java.util.Collection;
  40 
  41 import com.sun.xml.internal.bind.v2.runtime.Location;
  42 
  43 /**
  44  * {@link Navigator} implementation for {@code java.lang.reflect}.
  45  *
  46  */
  47 /*package*/final class ReflectionNavigator implements Navigator<Type, Class, Field, Method> {
  48 
  49 //  ----------  Singleton -----------------
  50     private static final ReflectionNavigator INSTANCE = new ReflectionNavigator();
  51 
  52     /*package*/static ReflectionNavigator getInstance() {
  53         return INSTANCE;
  54     }
  55 
  56     private ReflectionNavigator() {
  57     }
  58 //  ---------------------------------------
  59 
  60     public Class getSuperClass(Class clazz) {
  61         if (clazz == Object.class) {
  62             return null;
  63         }
  64         Class sc = clazz.getSuperclass();
  65         if (sc == null) {
  66             sc = Object.class;        // error recovery
  67         }
  68         return sc;
  69     }
  70 
  71     private static final TypeVisitor<Type, Class> baseClassFinder = new TypeVisitor<Type, Class>() {
  72 
  73         public Type onClass(Class c, Class sup) {
  74             // t is a raw type
  75             if (sup == c) {
  76                 return sup;
  77             }
  78 
  79             Type r;
  80 
  81             Type sc = c.getGenericSuperclass();
  82             if (sc != null) {
  83                 r = visit(sc, sup);
  84                 if (r != null) {
  85                     return r;
  86                 }
  87             }
  88 
  89             for (Type i : c.getGenericInterfaces()) {
  90                 r = visit(i, sup);
  91                 if (r != null) {
  92                     return r;
  93                 }
  94             }
  95 
  96             return null;
  97         }
  98 
  99         public Type onParameterizdType(ParameterizedType p, Class sup) {
 100             Class raw = (Class) p.getRawType();
 101             if (raw == sup) {
 102                 // p is of the form sup<...>
 103                 return p;
 104             } else {
 105                 // recursively visit super class/interfaces
 106                 Type r = raw.getGenericSuperclass();
 107                 if (r != null) {
 108                     r = visit(bind(r, raw, p), sup);
 109                 }
 110                 if (r != null) {
 111                     return r;
 112                 }
 113                 for (Type i : raw.getGenericInterfaces()) {
 114                     r = visit(bind(i, raw, p), sup);
 115                     if (r != null) {
 116                         return r;
 117                     }
 118                 }
 119                 return null;
 120             }
 121         }
 122 
 123         public Type onGenericArray(GenericArrayType g, Class sup) {
 124             // not clear what I should do here
 125             return null;
 126         }
 127 
 128         public Type onVariable(TypeVariable v, Class sup) {
 129             return visit(v.getBounds()[0], sup);
 130         }
 131 
 132         public Type onWildcard(WildcardType w, Class sup) {
 133             // not clear what I should do here
 134             return null;
 135         }
 136 
 137         /**
 138          * Replaces the type variables in {@code t} by its actual arguments.
 139          *
 140          * @param decl
 141          *      provides a list of type variables. See {@link GenericDeclaration#getTypeParameters()}
 142          * @param args
 143          *      actual arguments. See {@link ParameterizedType#getActualTypeArguments()}
 144          */
 145         private Type bind(Type t, GenericDeclaration decl, ParameterizedType args) {
 146             return binder.visit(t, new BinderArg(decl, args.getActualTypeArguments()));
 147         }
 148     };
 149 
 150     private static class BinderArg {
 151 
 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                 }
 170             }
 171             return v;   // this is a free variable
 172         }
 173     }
 174     private static final TypeVisitor<Type, BinderArg> binder = new TypeVisitor<Type, BinderArg>() {
 175 
 176         public Type onClass(Class c, BinderArg args) {
 177             return c;
 178         }
 179 
 180         public Type onParameterizdType(ParameterizedType p, BinderArg args) {
 181             Type[] params = p.getActualTypeArguments();
 182 
 183             boolean different = false;
 184             for (int i = 0; i < params.length; i++) {
 185                 Type t = params[i];
 186                 params[i] = visit(t, args);
 187                 different |= t != params[i];
 188             }
 189 
 190             Type newOwner = p.getOwnerType();
 191             if (newOwner != null) {
 192                 newOwner = visit(newOwner, args);
 193             }
 194             different |= p.getOwnerType() != newOwner;
 195 
 196             if (!different) {
 197                 return p;
 198             }
 199 
 200             return new ParameterizedTypeImpl((Class<?>) p.getRawType(), params, newOwner);
 201         }
 202 
 203         public Type onGenericArray(GenericArrayType g, BinderArg types) {
 204             Type c = visit(g.getGenericComponentType(), types);
 205             if (c == g.getGenericComponentType()) {
 206                 return g;
 207             }
 208 
 209             return new GenericArrayTypeImpl(c);
 210         }
 211 
 212         public Type onVariable(TypeVariable v, BinderArg types) {
 213             return types.replace(v);
 214         }
 215 
 216         public Type onWildcard(WildcardType w, BinderArg types) {
 217             // TODO: this is probably still incorrect
 218             // bind( "? extends T" ) with T= "? extends Foo" should be "? extends Foo",
 219             // not "? extends (? extends Foo)"
 220             Type[] lb = w.getLowerBounds();
 221             Type[] ub = w.getUpperBounds();
 222             boolean diff = false;
 223 
 224             for (int i = 0; i < lb.length; i++) {
 225                 Type t = lb[i];
 226                 lb[i] = visit(t, types);
 227                 diff |= (t != lb[i]);
 228             }
 229 
 230             for (int i = 0; i < ub.length; i++) {
 231                 Type t = ub[i];
 232                 ub[i] = visit(t, types);
 233                 diff |= (t != ub[i]);
 234             }
 235 
 236             if (!diff) {
 237                 return w;
 238             }
 239 
 240             return new WildcardTypeImpl(lb, ub);
 241         }
 242     };
 243 
 244     public Type getBaseClass(Type t, Class sup) {
 245         return baseClassFinder.visit(t, sup);
 246     }
 247 
 248     public String getClassName(Class clazz) {
 249         return clazz.getName();
 250     }
 251 
 252     public String getTypeName(Type type) {
 253         if (type instanceof Class) {
 254             Class c = (Class) type;
 255             if (c.isArray()) {
 256                 return getTypeName(c.getComponentType()) + "[]";
 257             }
 258             return c.getName();
 259         }
 260         return type.toString();
 261     }
 262 
 263     public String getClassShortName(Class clazz) {
 264         return clazz.getSimpleName();
 265     }
 266 
 267     public Collection<? extends Field> getDeclaredFields(Class clazz) {
 268         return Arrays.asList(clazz.getDeclaredFields());
 269     }
 270 
 271     public Field getDeclaredField(Class clazz, String fieldName) {
 272         try {
 273             return clazz.getDeclaredField(fieldName);
 274         } catch (NoSuchFieldException e) {
 275             return null;
 276         }
 277     }
 278 
 279     public Collection<? extends Method> getDeclaredMethods(Class clazz) {
 280         return Arrays.asList(clazz.getDeclaredMethods());
 281     }
 282 
 283     public Class getDeclaringClassForField(Field field) {
 284         return field.getDeclaringClass();
 285     }
 286 
 287     public Class getDeclaringClassForMethod(Method method) {
 288         return method.getDeclaringClass();
 289     }
 290 
 291     public Type getFieldType(Field field) {
 292         if (field.getType().isArray()) {
 293             Class c = field.getType().getComponentType();
 294             if (c.isPrimitive()) {
 295                 return Array.newInstance(c, 0).getClass();
 296             }
 297         }
 298         return fix(field.getGenericType());
 299     }
 300 
 301     public String getFieldName(Field field) {
 302         return field.getName();
 303     }
 304 
 305     public String getMethodName(Method method) {
 306         return method.getName();
 307     }
 308 
 309     public Type getReturnType(Method method) {
 310         return fix(method.getGenericReturnType());
 311     }
 312 
 313     public Type[] getMethodParameters(Method method) {
 314         return method.getGenericParameterTypes();
 315     }
 316 
 317     public boolean isStaticMethod(Method method) {
 318         return Modifier.isStatic(method.getModifiers());
 319     }
 320 
 321     public boolean isFinalMethod(Method method) {
 322         return Modifier.isFinal(method.getModifiers());
 323     }
 324 
 325     public boolean isSubClassOf(Type sub, Type sup) {
 326         return erasure(sup).isAssignableFrom(erasure(sub));
 327     }
 328 
 329     public Class ref(Class c) {
 330         return c;
 331     }
 332 
 333     public Class use(Class c) {
 334         return c;
 335     }
 336 
 337     public Class asDecl(Type t) {
 338         return erasure(t);
 339     }
 340 
 341     public Class asDecl(Class c) {
 342         return c;
 343     }
 344     /**
 345      * Implements the logic for {@link #erasure(Type)}.
 346      */
 347     private static final TypeVisitor<Class, Void> eraser = new TypeVisitor<Class, Void>() {
 348 
 349         public Class onClass(Class c, Void v) {
 350             return c;
 351         }
 352 
 353         public Class onParameterizdType(ParameterizedType p, Void v) {
 354             // TODO: why getRawType returns Type? not Class?
 355             return visit(p.getRawType(), null);
 356         }
 357 
 358         public Class onGenericArray(GenericArrayType g, Void v) {
 359             return Array.newInstance(
 360                     visit(g.getGenericComponentType(), null),
 361                     0).getClass();
 362         }
 363 
 364         public Class onVariable(TypeVariable tv, Void v) {
 365             return visit(tv.getBounds()[0], null);
 366         }
 367 
 368         public Class onWildcard(WildcardType w, Void v) {
 369             return visit(w.getUpperBounds()[0], null);
 370         }
 371     };
 372 
 373     /**
 374      * Returns the runtime representation of the given type.
 375      *
 376      * This corresponds to the notion of the erasure in JSR-14.
 377      *
 378      * <p>
 379      * Because of the difference in the way Annotation Processing and the Java reflection
 380      * treats primitive type and array type, we can't define this method
 381      * on {@link Navigator}.
 382      *
 383      * <p>
 384      * It made me realize how difficult it is to define the common navigation
 385      * layer for two different underlying reflection library. The other way
 386      * is to throw away the entire parameterization and go to the wrapper approach.
 387      */
 388     public <T> Class<T> erasure(Type t) {
 389         return eraser.visit(t, null);
 390     }
 391 
 392     public boolean isAbstract(Class clazz) {
 393         return Modifier.isAbstract(clazz.getModifiers());
 394     }
 395 
 396     public boolean isFinal(Class clazz) {
 397         return Modifier.isFinal(clazz.getModifiers());
 398     }
 399 
 400     /**
 401      * Returns the {@link Type} object that represents {@code clazz&lt;T1,T2,T3>}.
 402      */
 403     public Type createParameterizedType(Class rawType, Type... arguments) {
 404         return new ParameterizedTypeImpl(rawType, arguments, null);
 405     }
 406 
 407     public boolean isArray(Type t) {
 408         if (t instanceof Class) {
 409             Class c = (Class) t;
 410             return c.isArray();
 411         }
 412         if (t instanceof GenericArrayType) {
 413             return true;
 414         }
 415         return false;
 416     }
 417 
 418     public boolean isArrayButNotByteArray(Type t) {
 419         if (t instanceof Class) {
 420             Class c = (Class) t;
 421             return c.isArray() && c != byte[].class;
 422         }
 423         if (t instanceof GenericArrayType) {
 424             t = ((GenericArrayType) t).getGenericComponentType();
 425             return t != Byte.TYPE;
 426         }
 427         return false;
 428     }
 429 
 430     public Type getComponentType(Type t) {
 431         if (t instanceof Class) {
 432             Class c = (Class) t;
 433             return c.getComponentType();
 434         }
 435         if (t instanceof GenericArrayType) {
 436             return ((GenericArrayType) t).getGenericComponentType();
 437         }
 438 
 439         throw new IllegalArgumentException();
 440     }
 441 
 442     public Type getTypeArgument(Type type, int i) {
 443         if (type instanceof ParameterizedType) {
 444             ParameterizedType p = (ParameterizedType) type;
 445             return fix(p.getActualTypeArguments()[i]);
 446         } else {
 447             throw new IllegalArgumentException();
 448         }
 449     }
 450 
 451     public boolean isParameterizedType(Type type) {
 452         return type instanceof ParameterizedType;
 453     }
 454 
 455     public boolean isPrimitive(Type type) {
 456         if (type instanceof Class) {
 457             Class c = (Class) type;
 458             return c.isPrimitive();
 459         }
 460         return false;
 461     }
 462 
 463     public Type getPrimitive(Class primitiveType) {
 464         assert primitiveType.isPrimitive();
 465         return primitiveType;
 466     }
 467 
 468     public Location getClassLocation(final Class clazz) {
 469         return new Location() {
 470 
 471             @Override
 472             public String toString() {
 473                 return clazz.getName();
 474             }
 475         };
 476     }
 477 
 478     public Location getFieldLocation(final Field field) {
 479         return new Location() {
 480 
 481             @Override
 482             public String toString() {
 483                 return field.toString();
 484             }
 485         };
 486     }
 487 
 488     public Location getMethodLocation(final Method method) {
 489         return new Location() {
 490 
 491             @Override
 492             public String toString() {
 493                 return method.toString();
 494             }
 495         };
 496     }
 497 
 498     public boolean hasDefaultConstructor(Class c) {
 499         try {
 500             c.getDeclaredConstructor();
 501             return true;
 502         } catch (NoSuchMethodException e) {
 503             return false; // todo: do this WITHOUT exception throw
 504         }
 505     }
 506 
 507     public boolean isStaticField(Field field) {
 508         return Modifier.isStatic(field.getModifiers());
 509     }
 510 
 511     public boolean isPublicMethod(Method method) {
 512         return Modifier.isPublic(method.getModifiers());
 513     }
 514 
 515     public boolean isPublicField(Field field) {
 516         return Modifier.isPublic(field.getModifiers());
 517     }
 518 
 519     public boolean isEnum(Class c) {
 520         return Enum.class.isAssignableFrom(c);
 521     }
 522 
 523     public Field[] getEnumConstants(Class clazz) {
 524         try {
 525             Object[] values = clazz.getEnumConstants();
 526             Field[] fields = new Field[values.length];
 527             for (int i = 0; i < values.length; i++) {
 528                 fields[i] = clazz.getField(((Enum) values[i]).name());
 529             }
 530             return fields;
 531         } catch (NoSuchFieldException e) {
 532             // impossible
 533             throw new NoSuchFieldError(e.getMessage());
 534         }
 535     }
 536 
 537     public Type getVoidType() {
 538         return Void.class;
 539     }
 540 
 541     public String getPackageName(Class clazz) {
 542         String name = clazz.getName();
 543         int idx = name.lastIndexOf('.');
 544         if (idx < 0) {
 545             return "";
 546         } else {
 547             return name.substring(0, idx);
 548         }
 549     }
 550 
 551     @Override
 552     public Class loadObjectFactory(Class referencePoint, String pkg) {
 553         ClassLoader cl= SecureLoader.getClassClassLoader(referencePoint);
 554         if (cl == null)
 555             cl = SecureLoader.getSystemClassLoader();
 556 
 557         try {
 558             return cl.loadClass(pkg + ".ObjectFactory");
 559         } catch (ClassNotFoundException e) {
 560             return null;
 561         }
 562     }
 563 
 564     public boolean isBridgeMethod(Method method) {
 565         return method.isBridge();
 566     }
 567 
 568     public boolean isOverriding(Method method, Class base) {
 569         // this isn't actually correct,
 570         // as the JLS considers
 571         // class Derived extends Base<Integer> {
 572         //   Integer getX() { ... }
 573         // }
 574         // class Base<T> {
 575         //   T getX() { ... }
 576         // }
 577         // to be overrided. Handling this correctly needs a careful implementation
 578 
 579         String name = method.getName();
 580         Class[] params = method.getParameterTypes();
 581 
 582         while (base != null) {
 583             try {
 584                 if (base.getDeclaredMethod(name, params) != null) {
 585                     return true;
 586                 }
 587             } catch (NoSuchMethodException e) {
 588                 // recursively go into the base class
 589             }
 590 
 591             base = base.getSuperclass();
 592         }
 593 
 594         return false;
 595     }
 596 
 597     public boolean isInterface(Class clazz) {
 598         return clazz.isInterface();
 599     }
 600 
 601     public boolean isTransient(Field f) {
 602         return Modifier.isTransient(f.getModifiers());
 603     }
 604 
 605     public boolean isInnerClass(Class clazz) {
 606         return clazz.getEnclosingClass() != null && !Modifier.isStatic(clazz.getModifiers());
 607     }
 608 
 609     @Override
 610     public boolean isSameType(Type t1, Type t2) {
 611         return t1.equals(t2);
 612     }
 613 
 614     /**
 615      * JDK 5.0 has a bug of creating {@link GenericArrayType} where it shouldn't.
 616      * fix that manually to work around the problem.
 617      *
 618      * See bug 6202725.
 619      */
 620     private Type fix(Type t) {
 621         if (!(t instanceof GenericArrayType)) {
 622             return t;
 623         }
 624 
 625         GenericArrayType gat = (GenericArrayType) t;
 626         if (gat.getGenericComponentType() instanceof Class) {
 627             Class c = (Class) gat.getGenericComponentType();
 628             return Array.newInstance(c, 0).getClass();
 629         }
 630 
 631         return t;
 632     }
 633 }