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