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