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<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 }