001// *************************************************************************************************************************** 002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * 003// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * 004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * 005// * with the License. You may obtain a copy of the License at * 006// * * 007// * http://www.apache.org/licenses/LICENSE-2.0 * 008// * * 009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * 010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * 011// * specific language governing permissions and limitations under the License. * 012// *************************************************************************************************************************** 013package org.apache.juneau.reflect; 014 015import static org.apache.juneau.internal.ObjectUtils.*; 016import static org.apache.juneau.common.internal.ArgUtils.*; 017import static org.apache.juneau.common.internal.StringUtils.*; 018import static org.apache.juneau.common.internal.ThrowableUtils.*; 019import static org.apache.juneau.internal.CollectionUtils.*; 020import static org.apache.juneau.internal.ConsumerUtils.*; 021 022import java.lang.annotation.*; 023import java.lang.reflect.*; 024import java.util.*; 025import java.util.concurrent.*; 026import java.util.function.*; 027 028import org.apache.juneau.*; 029import org.apache.juneau.internal.*; 030 031/** 032 * Lightweight utility class for introspecting information about a class. 033 * 034 * <p> 035 * Provides various convenience methods for introspecting fields/methods/annotations 036 * that aren't provided by the standard Java reflection APIs. 037 * 038 * <p> 039 * Objects are designed to be lightweight to create and threadsafe. 040 * 041 * <h5 class='figure'>Example:</h5> 042 * <p class='bjava'> 043 * <jc>// Wrap our class inside a ClassInfo.</jc> 044 * ClassInfo <jv>classInfo</jv> = ClassInfo.<jsm>of</jsm>(MyClass.<jk>class</jk>); 045 * 046 * <jc>// Get all methods in parent-to-child order, sorted alphabetically per class.</jc> 047 * <jk>for</jk> (MethodInfo <jv>methodInfo</jv> : <jv>classInfo</jv>.getAllMethods()) { 048 * <jc>// Do something with it.</jc> 049 * } 050 * 051 * <jc>// Get all class-level annotations in parent-to-child order.</jc> 052 * <jk>for</jk> (MyAnnotation <jv>annotation</jv> : <jv>classInfo</jv>.getAnnotations(MyAnnotation.<jk>class</jk>)) { 053 * <jc>// Do something with it.</jc> 054 * } 055 * </p> 056 * 057 * <h5 class='section'>See Also:</h5><ul> 058 * </ul> 059 */ 060public final class ClassInfo { 061 062 //----------------------------------------------------------------------------------------------------------------- 063 // Static 064 //----------------------------------------------------------------------------------------------------------------- 065 066 private static final Map<Class<?>,ClassInfo> CACHE = new ConcurrentHashMap<>(); 067 068 /** Reusable ClassInfo for Object class. */ 069 public static final ClassInfo OBJECT = ClassInfo.of(Object.class); 070 071 /** 072 * Returns a class info wrapper around the specified class type. 073 * 074 * @param t The class type. 075 * @return The constructed class info, or <jk>null</jk> if the type was <jk>null</jk>. 076 */ 077 public static ClassInfo of(Type t) { 078 if (t == null) 079 return null; 080 if (t instanceof Class) 081 return of((Class<?>)t); 082 return new ClassInfo(ClassUtils.toClass(t), t); 083 } 084 085 /** 086 * Returns a class info wrapper around the specified class type. 087 * 088 * @param c The class type. 089 * @return The constructed class info, or <jk>null</jk> if the type was <jk>null</jk>. 090 */ 091 public static ClassInfo of(Class<?> c) { 092 if (c == null) 093 return null; 094 ClassInfo ci = CACHE.get(c); 095 if (ci == null) { 096 ci = new ClassInfo(c, c); 097 CACHE.put(c, ci); 098 } 099 return ci; 100 } 101 102 /** 103 * Returns a class info wrapper around the specified class type. 104 * 105 * @param c The class type. 106 * @param t The generic type (if parameterized type). 107 * @return The constructed class info, or <jk>null</jk> if the type was <jk>null</jk>. 108 */ 109 public static ClassInfo of(Class<?> c, Type t) { 110 if (c == t) 111 return of(c); 112 return new ClassInfo(c, t); 113 } 114 115 /** 116 * Same as using the constructor, but operates on an object instance. 117 * 118 * @param o The class instance. 119 * @return The constructed class info, or <jk>null</jk> if the object was <jk>null</jk>. 120 */ 121 public static ClassInfo of(Object o) { 122 return of(o == null ? null : o instanceof Class ? (Class<?>)o : o.getClass()); 123 } 124 125 /** 126 * Same as {@link #of(Object)} but attempts to deproxify the object if it's wrapped in a CGLIB proxy. 127 * 128 * @param o The class instance. 129 * @return The constructed class info, or <jk>null</jk> if the object was <jk>null</jk>. 130 */ 131 public static ClassInfo ofProxy(Object o) { 132 if (o == null) 133 return null; 134 Class<?> c = getProxyFor(o); 135 return c == null ? ClassInfo.of(o) : ClassInfo.of(c); 136 } 137 138 /** 139 * When this metadata is against a CGLIB proxy, this method finds the underlying "real" class. 140 * 141 * @param o The class instance. 142 * @return The non-proxy class, or <jk>null</jk> if it's not a CGLIB proxy. 143 */ 144 private static Class<?> getProxyFor(Object o) { 145 Class<?> c = o.getClass(); 146 String s = c.getName(); 147 if (s.indexOf('$') == -1 || ! s.contains("$$EnhancerBySpringCGLIB$$")) 148 return null; 149 Value<Class<?>> v = Value.empty(); 150 ClassInfo.of(c).forEachPublicMethod( 151 m -> m.hasName("getTargetClass") && m.hasNoParams() && m.hasReturnType(Class.class), 152 m -> safeRun(() -> v.set(m.invoke(o))) 153 ); 154 return v.orElse(null); 155 } 156 157 //----------------------------------------------------------------------------------------------------------------- 158 // Instance 159 //----------------------------------------------------------------------------------------------------------------- 160 161 private final Type t; 162 final Class<?> c; 163 private final boolean isParameterizedType; 164 private volatile Boolean isRepeatedAnnotation; 165 private volatile ClassInfo[] interfaces, declaredInterfaces, parents, allParents; 166 private volatile MethodInfo[] publicMethods, declaredMethods, allMethods, allMethodsParentFirst; 167 private volatile MethodInfo repeatedAnnotationMethod; 168 private volatile ConstructorInfo[] publicConstructors, declaredConstructors; 169 private volatile FieldInfo[] publicFields, declaredFields, allFields; 170 private volatile Annotation[] declaredAnnotations; 171 private int dim = -1; 172 private ClassInfo componentType; 173 174 private final ConcurrentHashMap<Method,MethodInfo> methods = new ConcurrentHashMap<>(); 175 private final ConcurrentHashMap<Field,FieldInfo> fields = new ConcurrentHashMap<>(); 176 private final ConcurrentHashMap<Constructor<?>,ConstructorInfo> constructors = new ConcurrentHashMap<>(); 177 178 /** 179 * Constructor. 180 * 181 * @param c The class type. 182 * @param t The generic type (if parameterized type). 183 */ 184 protected ClassInfo(Class<?> c, Type t) { 185 this.t = t; 186 this.c = c; 187 this.isParameterizedType = t == null ? false : (t instanceof ParameterizedType); 188 } 189 190 /** 191 * Returns the wrapped class as a {@link Type}. 192 * 193 * @return The wrapped class as a {@link Type}. 194 */ 195 public Type innerType() { 196 return t; 197 } 198 199 /** 200 * Returns the wrapped class as a {@link Class}. 201 * 202 * @param <T> The inner class type. 203 * @return The wrapped class as a {@link Class}, or <jk>null</jk> if it's not a class (e.g. it's a {@link ParameterizedType}). 204 */ 205 @SuppressWarnings("unchecked") 206 public <T> Class<T> inner() { 207 return (Class<T>)c; 208 } 209 210 /** 211 * Unwrap this class if it's a parameterized type of the specified type such as {@link Value} or {@link Optional}. 212 * 213 * @param wrapperTypes The parameterized types to unwrap if this class is one of those types. 214 * @return The class info on the unwrapped type, or just this type if this isn't one of the specified types. 215 */ 216 public ClassInfo unwrap(Class<?>...wrapperTypes) { 217 for (Class<?> wt : wrapperTypes) { 218 if (isParameterizedTypeOf(wt)) { 219 Type t = getFirstParameterType(wt); 220 if (t != null) 221 return of(t).unwrap(wrapperTypes); // Recursively do it again. 222 } 223 } 224 return this; 225 } 226 227 private boolean isParameterizedTypeOf(Class<?> c) { 228 return 229 (t instanceof ParameterizedType && ((ParameterizedType)t).getRawType() == c) 230 || (t instanceof Class && c.isAssignableFrom((Class<?>)t)); 231 } 232 233 private Type getFirstParameterType(Class<?> parameterizedType) { 234 if (t instanceof ParameterizedType) { 235 ParameterizedType pt = (ParameterizedType)t; 236 Type[] ta = pt.getActualTypeArguments(); 237 if (ta.length > 0) 238 return ta[0]; 239 } else if (t instanceof Class) /* Class that extends Optional<T> */ { 240 Class<?> c = (Class<?>)t; 241 if (c != parameterizedType && parameterizedType.isAssignableFrom(c)) 242 return ClassInfo.of(c).getParameterType(0, parameterizedType); 243 } 244 return null; 245 } 246 247 MethodInfo getMethodInfo(Method x) { 248 MethodInfo i = methods.get(x); 249 if (i == null) { 250 i = new MethodInfo(this, x); 251 methods.put(x, i); 252 } 253 return i; 254 } 255 256 FieldInfo getFieldInfo(Field x) { 257 FieldInfo i = fields.get(x); 258 if (i == null) { 259 i = new FieldInfo(this, x); 260 fields.put(x, i); 261 } 262 return i; 263 } 264 265 ConstructorInfo getConstructorInfo(Constructor<?> x) { 266 ConstructorInfo i = constructors.get(x); 267 if (i == null) { 268 i = new ConstructorInfo(this, x); 269 constructors.put(x, i); 270 } 271 return i; 272 } 273 274 //----------------------------------------------------------------------------------------------------------------- 275 // Parent classes and interfaces. 276 //----------------------------------------------------------------------------------------------------------------- 277 278 /** 279 * Returns the parent class. 280 * 281 * @return 282 * The parent class, or <jk>null</jk> if the class has no parent. 283 */ 284 public ClassInfo getSuperclass() { 285 return c == null ? null : of(c.getSuperclass()); 286 } 287 288 /** 289 * Returns a list of interfaces declared on this class. 290 * 291 * <p> 292 * Does not include interfaces declared on parent classes. 293 * 294 * <p> 295 * Results are in the same order as Class.getInterfaces(). 296 * 297 * @return 298 * An unmodifiable list of interfaces declared on this class. 299 * <br>Results are in the same order as {@link Class#getInterfaces()}. 300 */ 301 public List<ClassInfo> getDeclaredInterfaces() { 302 return ulist(_getDeclaredInterfaces()); 303 } 304 305 /** 306 * Returns a list of interfaces defined on this class and superclasses. 307 * 308 * <p> 309 * Results are in child-to-parent order. 310 * 311 * @return 312 * An unmodifiable list of interfaces defined on this class and superclasses. 313 * <br>Results are in child-to-parent order. 314 */ 315 public List<ClassInfo> getInterfaces() { 316 return ulist(_getInterfaces()); 317 } 318 319 /** 320 * Returns a list including this class and all parent classes. 321 * 322 * <p> 323 * Does not include interfaces. 324 * 325 * <p> 326 * Results are in child-to-parent order. 327 * 328 * @return An unmodifiable list including this class and all parent classes. 329 * <br>Results are in child-to-parent order. 330 */ 331 public List<ClassInfo> getParents() { 332 return ulist(_getParents()); 333 } 334 335 /** 336 * Returns a list including this class and all parent classes and interfaces. 337 * 338 * <p> 339 * Results are classes-before-interfaces, then child-to-parent order. 340 * 341 * @return An unmodifiable list including this class and all parent classes. 342 * <br>Results are ordered child-to-parent order with classes listed before interfaces. 343 */ 344 public List<ClassInfo> getAllParents() { 345 return ulist(_getAllParents()); 346 } 347 348 /** 349 * Returns the first matching parent class or interface. 350 * 351 * <p> 352 * Results are classes-before-interfaces, then child-to-parent order. 353 * 354 * @param filter A predicate to apply to the entries to determine if value should be used. Can be <jk>null</jk>. 355 * @return The parent class or interface that matches the specified predicate. 356 */ 357 public ClassInfo getAnyParent(Predicate<ClassInfo> filter) { 358 for (ClassInfo ci : _getAllParents()) 359 if (test(filter, ci)) 360 return ci; 361 return null; 362 } 363 364 /** Results are in child-to-parent order. */ 365 ClassInfo[] _getInterfaces() { 366 if (interfaces == null) { 367 synchronized(this) { 368 Set<ClassInfo> s = set(); 369 for (ClassInfo ci : _getParents()) 370 for (ClassInfo ci2 : ci._getDeclaredInterfaces()) { 371 s.add(ci2); 372 for (ClassInfo ci3 : ci2._getInterfaces()) 373 s.add(ci3); 374 } 375 interfaces = s.toArray(new ClassInfo[s.size()]); 376 } 377 } 378 return interfaces; 379 } 380 381 /** Results are in the same order as Class.getInterfaces(). */ 382 ClassInfo[] _getDeclaredInterfaces() { 383 if (declaredInterfaces == null) { 384 synchronized(this) { 385 Class<?>[] ii = c == null ? new Class[0] : c.getInterfaces(); 386 ClassInfo[] l = new ClassInfo[ii.length]; 387 for (int i = 0; i < ii.length; i++) 388 l[i] = of(ii[i]); 389 declaredInterfaces = l; 390 } 391 } 392 return declaredInterfaces; 393 } 394 395 /** Results are in child-to-parent order. */ 396 ClassInfo[] _getParents() { 397 if (parents == null) { 398 synchronized(this) { 399 List<ClassInfo> l = list(); 400 Class<?> pc = c; 401 while (pc != null && pc != Object.class) { 402 l.add(of(pc)); 403 pc = pc.getSuperclass(); 404 } 405 parents = l.toArray(new ClassInfo[l.size()]); 406 } 407 } 408 return parents; 409 } 410 411 /** Results are classes-before-interfaces, then child-to-parent order. */ 412 ClassInfo[] _getAllParents() { 413 if (allParents == null) { 414 synchronized(this) { 415 ClassInfo[] a1 = _getParents(), a2 = _getInterfaces(); 416 ClassInfo[] l = new ClassInfo[a1.length + a2.length]; 417 for (int i = 0; i < a1.length; i++) 418 l[i] = a1[i]; 419 for (int i = 0; i < a2.length; i++) 420 l[i+a1.length] = a2[i]; 421 allParents = l; 422 } 423 } 424 return allParents; 425 } 426 427 //----------------------------------------------------------------------------------------------------------------- 428 // Methods 429 //----------------------------------------------------------------------------------------------------------------- 430 431 /** 432 * Returns all public methods on this class. 433 * 434 * <p> 435 * Methods defined on the {@link Object} class are excluded from the results. 436 * 437 * @return 438 * All public methods on this class. 439 * <br>Results are ordered alphabetically. 440 */ 441 public List<MethodInfo> getPublicMethods() { 442 return ulist(_getPublicMethods()); 443 } 444 445 /** 446 * Performs an action on all matching public methods on this class. 447 * 448 * @param filter A predicate to apply to the entries to determine if action should be performed. Can be <jk>null</jk>. 449 * @param action An action to perform on the entry. 450 * @return This object. 451 */ 452 public final ClassInfo forEachPublicMethod(Predicate<MethodInfo> filter, Consumer<MethodInfo> action) { 453 for (MethodInfo mi : _getPublicMethods()) 454 consume(filter, action, mi); 455 return this; 456 } 457 458 /** 459 * Returns the first matching public method on this class. 460 * 461 * @param filter A predicate to apply to the entries to determine if value should be used. Can be <jk>null</jk>. 462 * @return The first matching method, or <jk>null</jk> if no methods matched. 463 */ 464 public final MethodInfo getPublicMethod(Predicate<MethodInfo> filter) { 465 for (MethodInfo mi : _getPublicMethods()) 466 if (test(filter, mi)) 467 return mi; 468 return null; 469 } 470 471 /** 472 * Returns all methods declared on this class. 473 * 474 * @return 475 * All methods declared on this class. 476 * <br>Results are ordered alphabetically. 477 * <br>List is unmodifiable. 478 */ 479 public List<MethodInfo> getDeclaredMethods() { 480 return ulist(_getDeclaredMethods()); 481 } 482 483 /** 484 * Performs an action on all matching declared methods on this class. 485 * 486 * @param filter A predicate to apply to the entries to determine if action should be performed. Can be <jk>null</jk>. 487 * @param action An action to perform on the entry. 488 * @return This object. 489 */ 490 public final ClassInfo forEachDeclaredMethod(Predicate<MethodInfo> filter, Consumer<MethodInfo> action) { 491 for (MethodInfo mi : _getDeclaredMethods()) 492 consume(filter, action, mi); 493 return this; 494 } 495 496 /** 497 * Returns the first matching declared method on this class. 498 * 499 * @param filter A predicate to apply to the entries to determine if value should be used. Can be <jk>null</jk>. 500 * @return The first matching method, or <jk>null</jk> if no methods matched. 501 */ 502 public MethodInfo getDeclaredMethod(Predicate<MethodInfo> filter) { 503 for (MethodInfo mi : _getDeclaredMethods()) 504 if (test(filter, mi)) 505 return mi; 506 return null; 507 } 508 509 /** 510 * Returns all declared methods on this class and all parent classes. 511 * 512 * @return 513 * All declared methods on this class and all parent classes. 514 * <br>Results are ordered child-to-parent, and then alphabetically per class. 515 * <br>List is unmodifiable. 516 */ 517 public List<MethodInfo> getMethods() { 518 return ulist(_getAllMethods()); 519 } 520 521 /** 522 * Performs an action on all matching methods on this class. 523 * 524 * @param filter A predicate to apply to the entries to determine if action should be performed. Can be <jk>null</jk>. 525 * @param action An action to perform on the entry. 526 * @return This object. 527 */ 528 public final ClassInfo forEachMethod(Predicate<MethodInfo> filter, Consumer<MethodInfo> action) { 529 for (MethodInfo mi : _getAllMethods()) 530 consume(filter, action, mi); 531 return this; 532 } 533 534 /** 535 * Returns the first matching method on this class. 536 * 537 * @param filter A predicate to apply to the entries to determine if value should be used. Can be <jk>null</jk>. 538 * @return The first matching method, or <jk>null</jk> if no methods matched. 539 */ 540 public MethodInfo getMethod(Predicate<MethodInfo> filter) { 541 for (MethodInfo mi : _getAllMethods()) 542 if (test(filter, mi)) 543 return mi; 544 return null; 545 } 546 547 /** 548 * Returns all declared methods on this class and all parent classes. 549 * 550 * @return 551 * All declared methods on this class and all parent classes. 552 * <br>Results are ordered parent-to-child, and then alphabetically per class. 553 * <br>List is unmodifiable. 554 */ 555 public List<MethodInfo> getAllMethodsParentFirst() { 556 return ulist(_getAllMethodsParentFirst()); 557 } 558 559 /** 560 * Performs an action on all matching declared methods on this class and all parent classes. 561 * 562 * @param filter A predicate to apply to the entries to determine if action should be performed. Can be <jk>null</jk>. 563 * @param action An action to perform on the entry. 564 * @return This object. 565 */ 566 public final ClassInfo forEachAllMethodParentFirst(Predicate<MethodInfo> filter, Consumer<MethodInfo> action) { 567 for (MethodInfo mi : _getAllMethodsParentFirst()) 568 consume(filter, action, mi); 569 return this; 570 } 571 572 MethodInfo[] _getPublicMethods() { 573 if (publicMethods == null) { 574 synchronized(this) { 575 Method[] mm = c == null ? new Method[0] : c.getMethods(); 576 List<MethodInfo> l = list(mm.length); 577 for (Method m : mm) 578 if (m.getDeclaringClass() != Object.class) 579 l.add(getMethodInfo(m)); 580 l.sort(null); 581 publicMethods = l.toArray(new MethodInfo[l.size()]); 582 } 583 } 584 return publicMethods; 585 } 586 587 MethodInfo[] _getDeclaredMethods() { 588 if (declaredMethods == null) { 589 synchronized(this) { 590 Method[] mm = c == null ? new Method[0] : c.getDeclaredMethods(); 591 List<MethodInfo> l = list(mm.length); 592 for (Method m : mm) 593 if (! "$jacocoInit".equals(m.getName())) // Jacoco adds its own simulated methods. 594 l.add(getMethodInfo(m)); 595 l.sort(null); 596 declaredMethods = l.toArray(new MethodInfo[l.size()]); 597 } 598 } 599 return declaredMethods; 600 } 601 602 MethodInfo[] _getAllMethods() { 603 if (allMethods == null) { 604 synchronized(this) { 605 List<MethodInfo> l = list(); 606 for (ClassInfo c : _getAllParents()) 607 c._appendDeclaredMethods(l); 608 allMethods = l.toArray(new MethodInfo[l.size()]); 609 } 610 } 611 return allMethods; 612 } 613 614 MethodInfo[] _getAllMethodsParentFirst() { 615 if (allMethodsParentFirst == null) { 616 synchronized(this) { 617 List<MethodInfo> l = list(); 618 ClassInfo[] parents = _getAllParents(); 619 for (int i = parents.length-1; i >=0; i--) 620 parents[i]._appendDeclaredMethods(l); 621 allMethodsParentFirst = l.toArray(new MethodInfo[l.size()]); 622 } 623 } 624 return allMethodsParentFirst; 625 } 626 627 private synchronized List<MethodInfo> _appendDeclaredMethods(List<MethodInfo> l) { 628 for (MethodInfo mi : _getDeclaredMethods()) 629 l.add(mi); 630 return l; 631 } 632 633 //----------------------------------------------------------------------------------------------------------------- 634 // Constructors 635 //----------------------------------------------------------------------------------------------------------------- 636 637 /** 638 * Returns all the public constructors defined on this class. 639 * 640 * @return All public constructors defined on this class. 641 */ 642 public List<ConstructorInfo> getPublicConstructors() { 643 return ulist(_getPublicConstructors()); 644 } 645 646 /** 647 * Performs an action on all matching public constructors on this class. 648 * 649 * @param filter A predicate to apply to the entries to determine if action should be performed. Can be <jk>null</jk>. 650 * @param action An action to perform on the entry. 651 * @return This object. 652 */ 653 public final ClassInfo forEachPublicConstructor(Predicate<ConstructorInfo> filter, Consumer<ConstructorInfo> action) { 654 for (ConstructorInfo mi : _getPublicConstructors()) 655 consume(filter, action, mi); 656 return this; 657 } 658 659 /** 660 * Returns the first matching public constructor on this class. 661 * 662 * @param filter A predicate to apply to the entries to determine if value should be used. Can be <jk>null</jk>. 663 * @return The public constructor that matches the specified predicate. 664 */ 665 public ConstructorInfo getPublicConstructor(Predicate<ConstructorInfo> filter) { 666 for (ConstructorInfo ci : _getPublicConstructors()) 667 if (test(filter, ci)) 668 return ci; 669 return null; 670 } 671 672 /** 673 * Returns all the constructors defined on this class. 674 * 675 * @return 676 * All constructors defined on this class. 677 * <br>List is unmodifiable. 678 */ 679 public List<ConstructorInfo> getDeclaredConstructors() { 680 return ulist(_getDeclaredConstructors()); 681 } 682 683 /** 684 * Performs an action on all matching declared constructors on this class. 685 * 686 * @param filter A predicate to apply to the entries to determine if action should be performed. Can be <jk>null</jk>. 687 * @param action An action to perform on the entry. 688 * @return This object. 689 */ 690 public final ClassInfo forEachDeclaredConstructor(Predicate<ConstructorInfo> filter, Consumer<ConstructorInfo> action) { 691 for (ConstructorInfo mi : _getDeclaredConstructors()) 692 consume(filter, action, mi); 693 return this; 694 } 695 696 /** 697 * Returns the first matching declared constructor on this class. 698 * 699 * @param filter A predicate to apply to the entries to determine if value should be used. Can be <jk>null</jk>. 700 * @return The declared constructor that matches the specified predicate. 701 */ 702 public ConstructorInfo getDeclaredConstructor(Predicate<ConstructorInfo> filter) { 703 for (ConstructorInfo ci : _getDeclaredConstructors()) 704 if (test(filter, ci)) 705 return ci; 706 return null; 707 } 708 709 ConstructorInfo[] _getPublicConstructors() { 710 if (publicConstructors == null) { 711 synchronized(this) { 712 Constructor<?>[] cc = c == null ? new Constructor[0] : c.getConstructors(); 713 List<ConstructorInfo> l = list(cc.length); 714 for (Constructor<?> ccc : cc) 715 l.add(getConstructorInfo(ccc)); 716 l.sort(null); 717 publicConstructors = l.toArray(new ConstructorInfo[l.size()]); 718 } 719 } 720 return publicConstructors; 721 } 722 723 ConstructorInfo[] _getDeclaredConstructors() { 724 if (declaredConstructors == null) { 725 synchronized(this) { 726 Constructor<?>[] cc = c == null ? new Constructor[0] : c.getDeclaredConstructors(); 727 List<ConstructorInfo> l = list(cc.length); 728 for (Constructor<?> ccc : cc) 729 l.add(getConstructorInfo(ccc)); 730 l.sort(null); 731 declaredConstructors = l.toArray(new ConstructorInfo[l.size()]); 732 } 733 } 734 return declaredConstructors; 735 } 736 737 //----------------------------------------------------------------------------------------------------------------- 738 // Special constructors 739 //----------------------------------------------------------------------------------------------------------------- 740 741 /** 742 * Locates the no-arg constructor for this class. 743 * 744 * <p> 745 * Constructor must match the visibility requirements specified by parameter 'v'. 746 * If class is abstract, always returns <jk>null</jk>. 747 * Note that this also returns the 1-arg constructor for non-static member classes. 748 * 749 * @param v The minimum visibility. 750 * @return The constructor, or <jk>null</jk> if no no-arg constructor exists with the required visibility. 751 */ 752 public ConstructorInfo getNoArgConstructor(Visibility v) { 753 if (isAbstract()) 754 return null; 755 boolean isMemberClass = isNonStaticMemberClass(); 756 for (ConstructorInfo cc : _getDeclaredConstructors()) 757 if (cc.hasNumParams(isMemberClass ? 1 : 0) && cc.isVisible(v)) 758 return cc.accessible(v); 759 return null; 760 } 761 762 //----------------------------------------------------------------------------------------------------------------- 763 // Fields 764 //----------------------------------------------------------------------------------------------------------------- 765 766 /** 767 * Returns all public fields on this class. 768 * 769 * <p> 770 * Hidden fields are excluded from the results. 771 * 772 * @return 773 * All public fields on this class. 774 * <br>Results are in alphabetical order. 775 * <br>List is unmodifiable. 776 */ 777 public List<FieldInfo> getPublicFields() { 778 return ulist(_getPublicFields()); 779 } 780 781 /** 782 * Performs an action on all matching public fields on this class. 783 * 784 * @param filter A predicate to apply to the entries to determine if action should be performed. Can be <jk>null</jk>. 785 * @param action An action to perform on the entry. 786 * @return This object. 787 */ 788 public final ClassInfo forEachPublicField(Predicate<FieldInfo> filter, Consumer<FieldInfo> action) { 789 for (FieldInfo mi : _getPublicFields()) 790 consume(filter, action, mi); 791 return this; 792 } 793 794 /** 795 * Returns the first matching public field on this class. 796 * 797 * @param filter A predicate to apply to the entries to determine if value should be used. Can be <jk>null</jk>. 798 * @return The public field, or <jk>null</jk> if not found. 799 */ 800 public FieldInfo getPublicField(Predicate<FieldInfo> filter) { 801 for (FieldInfo f : _getPublicFields()) 802 if (test(filter, f)) 803 return f; 804 return null; 805 } 806 807 /** 808 * Returns all declared fields on this class. 809 * 810 * @return 811 * All declared fields on this class. 812 * <br>Results are in alphabetical order. 813 * <br>List is unmodifiable. 814 */ 815 public List<FieldInfo> getDeclaredFields() { 816 return ulist(_getDeclaredFields()); 817 } 818 819 /** 820 * Performs an action on all matching declared fields on this class. 821 * 822 * @param filter A predicate to apply to the entries to determine if action should be performed. Can be <jk>null</jk>. 823 * @param action An action to perform on the entry. 824 * @return This object. 825 */ 826 public ClassInfo forEachDeclaredField(Predicate<FieldInfo> filter, Consumer<FieldInfo> action) { 827 for (FieldInfo fi : _getDeclaredFields()) 828 consume(filter, action, fi); 829 return this; 830 } 831 832 /** 833 * Returns the first matching declared field on this class. 834 * 835 * @param filter A predicate to apply to the entries to determine if value should be used. Can be <jk>null</jk>. 836 * @return The declared field, or <jk>null</jk> if not found. 837 */ 838 public FieldInfo getDeclaredField(Predicate<FieldInfo> filter) { 839 for (FieldInfo f : _getDeclaredFields()) 840 if (test(filter, f)) 841 return f; 842 return null; 843 } 844 845 /** 846 * Returns all fields on this class and all parent classes. 847 * 848 * <p> 849 * Results are ordered parent-to-child, and then alphabetical per class. 850 * 851 * @return 852 * All declared fields on this class. 853 * <br>List is unmodifiable. 854 */ 855 public List<FieldInfo> getAllFields() { 856 return ulist(_getAllFields()); 857 } 858 859 /** 860 * Performs an action on all matching fields on this class and all parent classes. 861 * 862 * <p> 863 * Results are ordered parent-to-child, and then alphabetical per class. 864 * 865 * @param filter A predicate to apply to the entries to determine if action should be performed. Can be <jk>null</jk>. 866 * @param action An action to perform on the entry. 867 * @return This object. 868 */ 869 public ClassInfo forEachAllField(Predicate<FieldInfo> filter, Consumer<FieldInfo> action) { 870 for (FieldInfo fi : _getAllFields()) 871 consume(filter, action, fi); 872 return this; 873 } 874 875 FieldInfo[] _getPublicFields() { 876 if (publicFields == null) { 877 synchronized(this) { 878 Map<String,FieldInfo> m = map(); 879 for (ClassInfo c : _getParents()) { 880 for (FieldInfo f : c._getDeclaredFields()) { 881 String fn = f.getName(); 882 if (f.isPublic() && ! (m.containsKey(fn) || "$jacocoData".equals(fn))) 883 m.put(f.getName(), f); 884 } 885 } 886 List<FieldInfo> l = listFrom(m.values()); 887 l.sort(null); 888 publicFields = l.toArray(new FieldInfo[l.size()]); 889 } 890 } 891 return publicFields; 892 } 893 894 FieldInfo[] _getDeclaredFields() { 895 if (declaredFields == null) { 896 synchronized(this) { 897 Field[] ff = c == null ? new Field[0] : c.getDeclaredFields(); 898 List<FieldInfo> l = list(ff.length); 899 for (Field f : ff) 900 if (! "$jacocoData".equals(f.getName())) 901 l.add(getFieldInfo(f)); 902 l.sort(null); 903 declaredFields = l.toArray(new FieldInfo[l.size()]); 904 } 905 } 906 return declaredFields; 907 } 908 909 FieldInfo[] _getAllFields() { 910 if (allFields == null) { 911 synchronized(this) { 912 List<FieldInfo> l = list(); 913 ClassInfo[] parents = _getAllParents(); 914 for (int i = parents.length-1; i >=0; i--) 915 for (FieldInfo f : parents[i]._getDeclaredFields()) 916 l.add(f); 917 allFields = l.toArray(new FieldInfo[l.size()]); 918 } 919 } 920 return allFields; 921 } 922 923 //----------------------------------------------------------------------------------------------------------------- 924 // Annotations 925 //----------------------------------------------------------------------------------------------------------------- 926 927 /** 928 * Returns all annotations of the specified type defined on the specified class or parent classes/interfaces in parent-to-child order. 929 * 930 * @param <A> The annotation type to look for. 931 * @param type The annotation type to look for. 932 * @return The matching annotations. 933 */ 934 public <A extends Annotation> List<A> getAnnotations(Class<A> type) { 935 return getAnnotations(null, type); 936 } 937 938 /** 939 * Returns all annotations of the specified type defined on this or parent classes/interfaces. 940 * 941 * <p> 942 * Returns the list in reverse (parent-to-child) order. 943 * 944 * @param <A> The annotation type to look for. 945 * @param annotationProvider The annotation provider. 946 * @param type The annotation type to look for. 947 * @return The matching annotations. 948 */ 949 public <A extends Annotation> List<A> getAnnotations(AnnotationProvider annotationProvider, Class<A> type) { 950 List<A> l = list(); 951 forEachAnnotation(annotationProvider, type, x-> true, x -> l.add(x)); 952 return l; 953 } 954 955 /** 956 * Performs an action on all matching annotations on this class and superclasses/interfaces. 957 * 958 * @param <A> The annotation type to look for. 959 * @param type The annotation to look for. 960 * @param filter A predicate to apply to the entries to determine if action should be performed. Can be <jk>null</jk>. 961 * @param action An action to perform on the entry. 962 * @return This object. 963 */ 964 public <A extends Annotation> ClassInfo forEachAnnotation(Class<A> type, Predicate<A> filter, Consumer<A> action) { 965 return forEachAnnotation(null, type, filter, action); 966 } 967 968 /** 969 * Performs an action on all matching annotations on this class and superclasses/interfaces. 970 * 971 * <p> 972 * Annotations are appended in the following orders: 973 * <ol> 974 * <li>On the package of this class. 975 * <li>On interfaces ordered parent-to-child. 976 * <li>On parent classes ordered parent-to-child. 977 * <li>On this class. 978 * </ol> 979 * 980 * @param <A> The annotation type to look for. 981 * @param annotationProvider The annotation provider. 982 * @param type The annotation to look for. 983 * @param filter A predicate to apply to the entries to determine if action should be performed. Can be <jk>null</jk>. 984 * @param action An action to perform on the entry. 985 * @return This object. 986 */ 987 public <A extends Annotation> ClassInfo forEachAnnotation(AnnotationProvider annotationProvider, Class<A> type, Predicate<A> filter, Consumer<A> action) { 988 if (annotationProvider == null) 989 annotationProvider = AnnotationProvider.DEFAULT; 990 A t2 = getPackageAnnotation(type); 991 if (t2 != null) 992 consume(filter, action, t2); 993 ClassInfo[] interfaces = _getInterfaces(); 994 for (int i = interfaces.length-1; i >= 0; i--) 995 annotationProvider.forEachDeclaredAnnotation(type, interfaces[i].inner(), filter, action); 996 ClassInfo[] parents = _getParents(); 997 for (int i = parents.length-1; i >= 0; i--) 998 annotationProvider.forEachDeclaredAnnotation(type, parents[i].inner(), filter, action); 999 return this; 1000 } 1001 1002 /** 1003 * Returns the first matching annotation on this class and superclasses/interfaces. 1004 * 1005 * <p> 1006 * Annotations are searched in the following orders: 1007 * <ol> 1008 * <li>On the package of this class. 1009 * <li>On interfaces ordered parent-to-child. 1010 * <li>On parent classes ordered parent-to-child. 1011 * <li>On this class. 1012 * </ol> 1013 * 1014 * @param <A> The annotation type to look for. 1015 * @param type The annotation to look for. 1016 * @param filter A predicate to apply to the entries to determine if annotation should be returned. Can be <jk>null</jk>. 1017 * @return This object. 1018 */ 1019 public <A extends Annotation> A firstAnnotation(Class<A> type, Predicate<A> filter) { 1020 return firstAnnotation(null, type, filter); 1021 } 1022 1023 /** 1024 * Returns the first matching annotation on this class and superclasses/interfaces. 1025 * 1026 * <p> 1027 * Annotations are searched in the following orders: 1028 * <ol> 1029 * <li>On the package of this class. 1030 * <li>On interfaces ordered parent-to-child. 1031 * <li>On parent classes ordered parent-to-child. 1032 * <li>On this class. 1033 * </ol> 1034 * 1035 * @param <A> The annotation type to look for. 1036 * @param annotationProvider The annotation provider. 1037 * @param type The annotation to look for. 1038 * @param filter A predicate to apply to the entries to determine if annotation should be returned. Can be <jk>null</jk>. 1039 * @return This object. 1040 */ 1041 public <A extends Annotation> A firstAnnotation(AnnotationProvider annotationProvider, Class<A> type, Predicate<A> filter) { 1042 if (annotationProvider == null) 1043 annotationProvider = AnnotationProvider.DEFAULT; 1044 A x = null; 1045 x = getPackageAnnotation(type); 1046 if (x != null && test(filter, x)) 1047 return x; 1048 ClassInfo[] interfaces = _getInterfaces(); 1049 for (int i = interfaces.length-1; i >= 0; i--) { 1050 x = annotationProvider.firstAnnotation(type, interfaces[i].inner(), filter); 1051 if (x != null) 1052 return x; 1053 } 1054 ClassInfo[] parents = _getParents(); 1055 for (int i = parents.length-1; i >= 0; i--) { 1056 x = annotationProvider.firstAnnotation(type, parents[i].inner(), filter); 1057 if (x != null) 1058 return x; 1059 } 1060 return null; 1061 } 1062 1063 /** 1064 * Returns the last matching annotation on this class and superclasses/interfaces. 1065 * 1066 * <p> 1067 * Annotations are searched in the following orders: 1068 * <ol> 1069 * <li>On this class. 1070 * <li>On parent classes ordered child-to-parent. 1071 * <li>On interfaces ordered child-to-parent. 1072 * <li>On the package of this class. 1073 * </ol> 1074 * 1075 * @param <A> The annotation type to look for. 1076 * @param type The annotation to look for. 1077 * @param filter A predicate to apply to the entries to determine if annotation should be returned. Can be <jk>null</jk>. 1078 * @return This object. 1079 */ 1080 public <A extends Annotation> A lastAnnotation(Class<A> type, Predicate<A> filter) { 1081 return lastAnnotation(null, type, filter); 1082 } 1083 1084 /** 1085 * Returns the last matching annotation on this class and superclasses/interfaces. 1086 * 1087 * <p> 1088 * Annotations are searched in the following orders: 1089 * <ol> 1090 * <li>On this class. 1091 * <li>On parent classes ordered child-to-parent. 1092 * <li>On interfaces ordered child-to-parent. 1093 * <li>On the package of this class. 1094 * </ol> 1095 * 1096 * @param <A> The annotation type to look for. 1097 * @param annotationProvider The annotation provider. 1098 * @param type The annotation to look for. 1099 * @param filter A predicate to apply to the entries to determine if annotation should be returned. Can be <jk>null</jk>. 1100 * @return This object. 1101 */ 1102 public <A extends Annotation> A lastAnnotation(AnnotationProvider annotationProvider, Class<A> type, Predicate<A> filter) { 1103 if (annotationProvider == null) 1104 annotationProvider = AnnotationProvider.DEFAULT; 1105 A x = null; 1106 ClassInfo[] parents = _getParents(); 1107 for (int i = 0; i < parents.length; i++) { 1108 x = annotationProvider.lastAnnotation(type, parents[i].inner(), filter); 1109 if (x != null) 1110 return x; 1111 } 1112 ClassInfo[] interfaces = _getInterfaces(); 1113 for (int i = 0; i < interfaces.length; i++) { 1114 x = annotationProvider.lastAnnotation(type, interfaces[i].inner(), filter); 1115 if (x != null) 1116 return x; 1117 } 1118 x = getPackageAnnotation(type); 1119 if (x != null && test(filter, x)) 1120 return x; 1121 return null; 1122 } 1123 1124 /** 1125 * Finds the annotation of the specified type defined on this class or parent class/interface. 1126 * 1127 * <p> 1128 * If the annotation cannot be found on the immediate class, searches methods with the same 1129 * signature on the parent classes or interfaces. 1130 * <br>The search is performed in child-to-parent order. 1131 * 1132 * @param <A> The annotation type to look for. 1133 * @param type The annotation to look for. 1134 * @return The annotation if found, or <jk>null</jk> if not. 1135 */ 1136 public <A extends Annotation> A getAnnotation(Class<A> type) { 1137 return getAnnotation(null, type); 1138 } 1139 1140 /** 1141 * Finds the annotation of the specified type defined on this class or parent class/interface. 1142 * 1143 * <p> 1144 * If the annotation cannot be found on the immediate class, searches methods with the same signature on the parent classes or interfaces. <br> 1145 * The search is performed in child-to-parent order. 1146 * 1147 * @param <A> The annotation type to look for. 1148 * @param annotationProvider The annotation provider. 1149 * @param type The annotation to look for. 1150 * @return The annotation if found, or <jk>null</jk> if not. 1151 */ 1152 public <A extends Annotation> A getAnnotation(AnnotationProvider annotationProvider, Class<A> type) { 1153 return findAnnotation(annotationProvider, type); 1154 } 1155 1156 /** 1157 * Returns <jk>true</jk> if this class has the specified annotation. 1158 * 1159 * @param <A> The annotation type to look for. 1160 * @param type The annotation to look for. 1161 * @return The <jk>true</jk> if annotation if found. 1162 */ 1163 public <A extends Annotation> boolean hasAnnotation(Class<A> type) { 1164 return hasAnnotation(null, type); 1165 } 1166 1167 /** 1168 * Returns <jk>true</jk> if this class doesn't have the specified annotation. 1169 * 1170 * @param <A> The annotation type to look for. 1171 * @param type The annotation to look for. 1172 * @return The <jk>true</jk> if annotation if not found. 1173 */ 1174 public <A extends Annotation> boolean hasNoAnnotation(Class<A> type) { 1175 return ! hasAnnotation(type); 1176 } 1177 1178 /** 1179 * Returns <jk>true</jk> if this class has the specified annotation. 1180 * 1181 * @param <A> The annotation type to look for. 1182 * @param annotationProvider The annotation provider. 1183 * @param type The annotation to look for. 1184 * @return The <jk>true</jk> if annotation if found. 1185 */ 1186 public <A extends Annotation> boolean hasAnnotation(AnnotationProvider annotationProvider, Class<A> type) { 1187 if (annotationProvider == null) 1188 annotationProvider = AnnotationProvider.DEFAULT; 1189 return annotationProvider.firstAnnotation(type, c, x -> true) != null; 1190 } 1191 1192 /** 1193 * Returns the specified annotation only if it's been declared on the package of this class. 1194 * 1195 * @param <A> The annotation type to look for. 1196 * @param type The annotation class. 1197 * @return The annotation, or <jk>null</jk> if not found. 1198 */ 1199 public <A extends Annotation> A getPackageAnnotation(Class<A> type) { 1200 Package p = c == null ? null : c.getPackage(); 1201 return (p == null ? null : p.getAnnotation(type)); 1202 } 1203 1204 /** 1205 * Returns the first matching annotation of the specified type defined on the specified class or parent classes/interfaces in parent-to-child order. 1206 * 1207 * @param <A> The annotation type to look for. 1208 * @param type The annotation to look for. 1209 * @param filter A predicate to apply to the entries to determine if value should be used. Can be <jk>null</jk>. 1210 * @return This object. 1211 */ 1212 public <A extends Annotation> A getAnnotation(Class<A> type, Predicate<A> filter) { 1213 return getAnnotation(null, type, filter); 1214 } 1215 1216 /** 1217 * Constructs an {@link AnnotationList} of all annotations found on this class. 1218 * 1219 * <p> 1220 * Annotations are appended in the following orders: 1221 * <ol> 1222 * <li>On the package of this class. 1223 * <li>On interfaces ordered parent-to-child. 1224 * <li>On parent classes ordered parent-to-child. 1225 * <li>On this class. 1226 * </ol> 1227 * 1228 * @return A new {@link AnnotationList} object on every call. 1229 */ 1230 public AnnotationList getAnnotationList() { 1231 return getAnnotationList(x -> true); 1232 } 1233 1234 /** 1235 * Constructs an {@link AnnotationList} of all matching annotations on this class. 1236 * 1237 * <p> 1238 * Annotations are appended in the following orders: 1239 * <ol> 1240 * <li>On the package of this class. 1241 * <li>On interfaces ordered parent-to-child. 1242 * <li>On parent classes ordered parent-to-child. 1243 * <li>On this class. 1244 * </ol> 1245 * 1246 * @param filter A predicate to apply to the entries to determine if value should be used. Can be <jk>null</jk>. 1247 * @return A new {@link AnnotationList} object on every call. 1248 */ 1249 public AnnotationList getAnnotationList(Predicate<AnnotationInfo<?>> filter) { 1250 AnnotationList l = new AnnotationList(); 1251 forEachAnnotationInfo(filter, x -> l.add(x)); 1252 return l; 1253 } 1254 1255 /* 1256 * If the annotation is an array of other annotations, returns the inner annotations. 1257 * 1258 * @param a The annotation to split if repeated. 1259 * @return The nested annotations, or a singleton array of the same annotation if it's not repeated. 1260 */ 1261 private static Annotation[] splitRepeated(Annotation a) { 1262 try { 1263 ClassInfo ci = ClassInfo.of(a.annotationType()); 1264 MethodInfo mi = ci.getRepeatedAnnotationMethod(); 1265 if (mi != null) 1266 return mi.invoke(a); 1267 } catch (Exception e) { 1268 e.printStackTrace(); 1269 } 1270 return new Annotation[]{a}; 1271 } 1272 1273 private <A extends Annotation> A findAnnotation(AnnotationProvider ap, Class<A> a) { 1274 if (a == null) 1275 return null; 1276 if (ap == null) 1277 ap = AnnotationProvider.DEFAULT; 1278 A t = ap.firstDeclaredAnnotation(a, c, x -> true); 1279 if (t != null) 1280 return t; 1281 ClassInfo sci = getSuperclass(); 1282 if (sci != null) { 1283 t = sci.getAnnotation(ap, a); 1284 if (t != null) 1285 return t; 1286 } 1287 for (ClassInfo c2 : _getInterfaces()) { 1288 t = c2.getAnnotation(ap, a); 1289 if (t != null) 1290 return t; 1291 } 1292 return null; 1293 } 1294 1295 private <A extends Annotation> A getAnnotation(AnnotationProvider ap, Class<A> a, Predicate<A> filter) { 1296 if (ap == null) 1297 ap = AnnotationProvider.DEFAULT; 1298 A t2 = getPackageAnnotation(a); 1299 if (t2 != null && filter.test(t2)) 1300 return t2; 1301 ClassInfo[] interfaces = _getInterfaces(); 1302 for (int i = interfaces.length-1; i >= 0; i--) { 1303 A o = ap.firstDeclaredAnnotation(a, interfaces[i].inner(), filter); 1304 if (o != null) 1305 return o; 1306 } 1307 ClassInfo[] parents = _getParents(); 1308 for (int i = parents.length-1; i >= 0; i--) { 1309 A o = ap.firstDeclaredAnnotation(a, parents[i].inner(), filter); 1310 if (o != null) 1311 return o; 1312 } 1313 return null; 1314 } 1315 1316 /** 1317 * Performs an action on all matching annotations on this class/parents/package. 1318 * 1319 * <p> 1320 * Annotations are consumed in the following order: 1321 * <ol> 1322 * <li>On the package of this class. 1323 * <li>On interfaces ordered parent-to-child. 1324 * <li>On parent classes ordered parent-to-child. 1325 * <li>On this class. 1326 * </ol> 1327 * 1328 * @param filter A predicate to apply to the entries to determine if action should be performed. Can be <jk>null</jk>. 1329 * @param action An action to perform on the entry. 1330 * @return This object. 1331 */ 1332 public ClassInfo forEachAnnotationInfo(Predicate<AnnotationInfo<?>> filter, Consumer<AnnotationInfo<?>> action) { 1333 Package p = c.getPackage(); 1334 if (p != null) 1335 for (Annotation a : p.getDeclaredAnnotations()) 1336 for (Annotation a2 : splitRepeated(a)) 1337 AnnotationInfo.of(p, a2).accept(filter, action); 1338 ClassInfo[] interfaces = _getInterfaces(); 1339 for (int i = interfaces.length-1; i >= 0; i--) 1340 for (Annotation a : interfaces[i].c.getDeclaredAnnotations()) 1341 for (Annotation a2 : splitRepeated(a)) 1342 AnnotationInfo.of(interfaces[i], a2).accept(filter, action); 1343 ClassInfo[] parents = _getParents(); 1344 for (int i = parents.length-1; i >= 0; i--) 1345 for (Annotation a : parents[i].c.getDeclaredAnnotations()) 1346 for (Annotation a2 : splitRepeated(a)) 1347 AnnotationInfo.of(parents[i], a2).accept(filter, action); 1348 return this; 1349 } 1350 1351 Annotation[] _getDeclaredAnnotations() { 1352 if (declaredAnnotations == null) { 1353 synchronized(this) { 1354 declaredAnnotations = c.getDeclaredAnnotations(); 1355 } 1356 } 1357 return declaredAnnotations; 1358 } 1359 1360 //----------------------------------------------------------------------------------------------------------------- 1361 // Characteristics 1362 //----------------------------------------------------------------------------------------------------------------- 1363 1364 /** 1365 * Returns <jk>true</jk> if all specified flags are applicable to this class. 1366 * 1367 * @param flags The flags to test for. 1368 * @return <jk>true</jk> if all specified flags are applicable to this class. 1369 */ 1370 public boolean isAll(ReflectFlags...flags) { 1371 for (ReflectFlags f : flags) { 1372 switch (f) { 1373 case DEPRECATED: 1374 if (isNotDeprecated()) 1375 return false; 1376 break; 1377 case NOT_DEPRECATED: 1378 if (isDeprecated()) 1379 return false; 1380 break; 1381 case PUBLIC: 1382 if (isNotPublic()) 1383 return false; 1384 break; 1385 case NOT_PUBLIC: 1386 if (isPublic()) 1387 return false; 1388 break; 1389 case STATIC: 1390 if (isNotStatic()) 1391 return false; 1392 break; 1393 case NOT_STATIC: 1394 if (isStatic()) 1395 return false; 1396 break; 1397 case MEMBER: 1398 if (isNotMemberClass()) 1399 return false; 1400 break; 1401 case NOT_MEMBER: 1402 if (isMemberClass()) 1403 return false; 1404 break; 1405 case ABSTRACT: 1406 if (isNotAbstract()) 1407 return false; 1408 break; 1409 case NOT_ABSTRACT: 1410 if (isAbstract()) 1411 return false; 1412 break; 1413 case INTERFACE: 1414 if (isClass()) 1415 return false; 1416 break; 1417 case CLASS: 1418 if (isInterface()) 1419 return false; 1420 break; 1421 default: 1422 throw new BasicRuntimeException("Invalid flag for class: {0}", f); 1423 1424 } 1425 } 1426 return true; 1427 } 1428 1429 /** 1430 * Returns <jk>true</jk> if all specified flags are applicable to this class. 1431 * 1432 * @param flags The flags to test for. 1433 * @return <jk>true</jk> if all specified flags are applicable to this class. 1434 */ 1435 public boolean isAny(ReflectFlags...flags) { 1436 for (ReflectFlags f : flags) { 1437 switch (f) { 1438 case DEPRECATED: 1439 if (isDeprecated()) 1440 return true; 1441 break; 1442 case NOT_DEPRECATED: 1443 if (isNotDeprecated()) 1444 return true; 1445 break; 1446 case PUBLIC: 1447 if (isPublic()) 1448 return true; 1449 break; 1450 case NOT_PUBLIC: 1451 if (isNotPublic()) 1452 return true; 1453 break; 1454 case STATIC: 1455 if (isStatic()) 1456 return true; 1457 break; 1458 case NOT_STATIC: 1459 if (isNotStatic()) 1460 return true; 1461 break; 1462 case MEMBER: 1463 if (isMemberClass()) 1464 return true; 1465 break; 1466 case NOT_MEMBER: 1467 if (isNotMemberClass()) 1468 return true; 1469 break; 1470 case ABSTRACT: 1471 if (isAbstract()) 1472 return true; 1473 break; 1474 case NOT_ABSTRACT: 1475 if (isNotAbstract()) 1476 return true; 1477 break; 1478 case INTERFACE: 1479 if (isInterface()) 1480 return true; 1481 break; 1482 case CLASS: 1483 if (isClass()) 1484 return true; 1485 break; 1486 default: 1487 throw new BasicRuntimeException("Invalid flag for class: {0}", f); 1488 } 1489 } 1490 return false; 1491 } 1492 1493 /** 1494 * Returns <jk>true</jk> if this class has the {@link Deprecated @Deprecated} annotation on it. 1495 * 1496 * @return <jk>true</jk> if this class has the {@link Deprecated @Deprecated} annotation on it. 1497 */ 1498 public boolean isDeprecated() { 1499 return c != null && c.isAnnotationPresent(Deprecated.class); 1500 } 1501 1502 /** 1503 * Returns <jk>true</jk> if this class doesn't have the {@link Deprecated @Deprecated} annotation on it. 1504 * 1505 * @return <jk>true</jk> if this class doesn't have the {@link Deprecated @Deprecated} annotation on it. 1506 */ 1507 public boolean isNotDeprecated() { 1508 return c == null || ! c.isAnnotationPresent(Deprecated.class); 1509 } 1510 1511 /** 1512 * Returns <jk>true</jk> if this class is public. 1513 * 1514 * @return <jk>true</jk> if this class is public. 1515 */ 1516 public boolean isPublic() { 1517 return c != null && Modifier.isPublic(c.getModifiers()); 1518 } 1519 1520 /** 1521 * Returns <jk>true</jk> if this class is not public. 1522 * 1523 * @return <jk>true</jk> if this class is not public. 1524 */ 1525 public boolean isNotPublic() { 1526 return c == null || ! Modifier.isPublic(c.getModifiers()); 1527 } 1528 1529 /** 1530 * Returns <jk>true</jk> if this class is public. 1531 * 1532 * <p> 1533 * Note that interfaces are always reported as static, and the static keyword on a member interface is meaningless. 1534 * 1535 * @return <jk>true</jk> if this class is public. 1536 */ 1537 public boolean isStatic() { 1538 return c != null && Modifier.isStatic(c.getModifiers()); 1539 } 1540 1541 /** 1542 * Returns <jk>true</jk> if this class is not static. 1543 * 1544 * <p> 1545 * Note that interfaces are always reported as static, and the static keyword on a member interface is meaningless. 1546 * 1547 * @return <jk>true</jk> if this class is not static. 1548 */ 1549 public boolean isNotStatic() { 1550 return c == null || ! Modifier.isStatic(c.getModifiers()); 1551 } 1552 1553 /** 1554 * Returns <jk>true</jk> if this class is abstract. 1555 * 1556 * <p> 1557 * Note that interfaces are always reported as abstract. 1558 * 1559 * @return <jk>true</jk> if this class is abstract. 1560 */ 1561 public boolean isAbstract() { 1562 return c != null && Modifier.isAbstract(c.getModifiers()); 1563 } 1564 1565 /** 1566 * Returns <jk>true</jk> if this class is not abstract. 1567 * 1568 * <p> 1569 * Note that interfaces are always reported as abstract. 1570 * 1571 * @return <jk>true</jk> if this class is not abstract. 1572 */ 1573 public boolean isNotAbstract() { 1574 return c == null || ! Modifier.isAbstract(c.getModifiers()); 1575 } 1576 1577 /** 1578 * Returns <jk>true</jk> if this class is a member class. 1579 * 1580 * @return <jk>true</jk> if this class is a member class. 1581 */ 1582 public boolean isMemberClass() { 1583 return c != null && c.isMemberClass(); 1584 } 1585 1586 /** 1587 * Returns <jk>true</jk> if this class is a member class. 1588 * 1589 * @return <jk>true</jk> if this class is a member class. 1590 */ 1591 public boolean isNotMemberClass() { 1592 return c == null || ! c.isMemberClass(); 1593 } 1594 1595 /** 1596 * Returns <jk>true</jk> if this class is a member class and not static. 1597 * 1598 * @return <jk>true</jk> if this class is a member class and not static. 1599 */ 1600 public boolean isNonStaticMemberClass() { 1601 return c != null && c.isMemberClass() && ! isStatic(); 1602 } 1603 1604 /** 1605 * Returns <jk>false</jk> if this class is a member class and not static. 1606 * 1607 * @return <jk>false</jk> if this class is a member class and not static. 1608 */ 1609 public boolean isNotNonStaticMemberClass() { 1610 return ! isNonStaticMemberClass(); 1611 } 1612 1613 /** 1614 * Returns <jk>true</jk> if this class is a local class. 1615 * 1616 * @return <jk>true</jk> if this class is a local class. 1617 */ 1618 public boolean isLocalClass() { 1619 return c != null && c.isLocalClass(); 1620 } 1621 1622 /** 1623 * Returns <jk>true</jk> if this class is a local class. 1624 * 1625 * @return <jk>true</jk> if this class is a local class. 1626 */ 1627 public boolean isNotLocalClass() { 1628 return c == null || ! c.isLocalClass(); 1629 } 1630 1631 /** 1632 * Identifies if the specified visibility matches this constructor. 1633 * 1634 * @param v The visibility to validate against. 1635 * @return <jk>true</jk> if this visibility matches the modifier attribute of this constructor. 1636 */ 1637 public boolean isVisible(Visibility v) { 1638 return c != null && v.isVisible(c); 1639 } 1640 1641 /** 1642 * Returns <jk>true</jk> if this is a primitive class. 1643 * 1644 * @return <jk>true</jk> if this is a primitive class. 1645 */ 1646 public boolean isPrimitive() { 1647 return c != null && c.isPrimitive(); 1648 } 1649 1650 /** 1651 * Returns <jk>true</jk> if this is not a primitive class. 1652 * 1653 * @return <jk>true</jk> if this is not a primitive class. 1654 */ 1655 public boolean isNotPrimitive() { 1656 return c == null || ! c.isPrimitive(); 1657 } 1658 1659 /** 1660 * Returns <jk>true</jk> if this class is an interface. 1661 * 1662 * @return <jk>true</jk> if this class is an interface. 1663 */ 1664 public boolean isInterface() { 1665 return c != null && c.isInterface(); 1666 } 1667 1668 /** 1669 * Returns <jk>true</jk> if this class is not an interface. 1670 * 1671 * @return <jk>true</jk> if this class is not an interface. 1672 */ 1673 public boolean isClass() { 1674 return c != null && ! c.isInterface(); 1675 } 1676 1677 /** 1678 * Returns <jk>true</jk> if this class is a {@link RuntimeException}. 1679 * 1680 * @return <jk>true</jk> if this class is a {@link RuntimeException}. 1681 */ 1682 public boolean isRuntimeException() { 1683 return isChildOf(RuntimeException.class); 1684 } 1685 1686 //----------------------------------------------------------------------------------------------------------------- 1687 // Primitive wrappers 1688 //----------------------------------------------------------------------------------------------------------------- 1689 1690 /** 1691 * Returns <jk>true</jk> if the {@link #getPrimitiveWrapper()} method returns a value. 1692 * 1693 * @return <jk>true</jk> if the {@link #getPrimitiveWrapper()} method returns a value. 1694 */ 1695 public boolean hasPrimitiveWrapper() { 1696 return pmap1.containsKey(c); 1697 } 1698 1699 /** 1700 * If this class is a primitive (e.g. <code><jk>int</jk>.<jk>class</jk></code>) returns it's wrapper class 1701 * (e.g. <code>Integer.<jk>class</jk></code>). 1702 * 1703 * @return The wrapper class, or <jk>null</jk> if class is not a primitive. 1704 */ 1705 public Class<?> getPrimitiveWrapper() { 1706 return pmap1.get(c); 1707 } 1708 1709 /** 1710 * If this class is a primitive wrapper (e.g. <code><jk>Integer</jk>.<jk>class</jk></code>) returns it's 1711 * primitive class (e.g. <code>int.<jk>class</jk></code>). 1712 * 1713 * @return The primitive class, or <jk>null</jk> if class is not a primitive wrapper. 1714 */ 1715 public Class<?> getPrimitiveForWrapper() { 1716 return pmap2.get(c); 1717 } 1718 1719 /** 1720 * If this class is a primitive (e.g. <code><jk>int</jk>.<jk>class</jk></code>) returns it's wrapper class 1721 * (e.g. <code>Integer.<jk>class</jk></code>). 1722 * 1723 * @return The wrapper class if it's primitive, or the same class if class is not a primitive. 1724 */ 1725 public Class<?> getWrapperIfPrimitive() { 1726 if (c != null && ! c.isPrimitive()) 1727 return c; 1728 return pmap1.get(c); 1729 } 1730 1731 /** 1732 * Same as {@link #getWrapperIfPrimitive()} but wraps it in a {@link ClassInfo}. 1733 * 1734 * @return The wrapper class if it's primitive, or the same class if class is not a primitive. 1735 */ 1736 public ClassInfo getWrapperInfoIfPrimitive() { 1737 if (c == null || ! c.isPrimitive()) 1738 return this; 1739 return of(pmap1.get(c)); 1740 } 1741 1742 /** 1743 * Returns the default value for this primitive class. 1744 * 1745 * @return The default value, or <jk>null</jk> if this is not a primitive class. 1746 */ 1747 public Object getPrimitiveDefault() { 1748 return primitiveDefaultMap.get(c); 1749 } 1750 1751 private static final Map<Class<?>, Class<?>> 1752 pmap1 = new HashMap<>(), 1753 pmap2 = new HashMap<>(); 1754 static { 1755 pmap1.put(boolean.class, Boolean.class); 1756 pmap1.put(byte.class, Byte.class); 1757 pmap1.put(short.class, Short.class); 1758 pmap1.put(char.class, Character.class); 1759 pmap1.put(int.class, Integer.class); 1760 pmap1.put(long.class, Long.class); 1761 pmap1.put(float.class, Float.class); 1762 pmap1.put(double.class, Double.class); 1763 pmap2.put(Boolean.class, boolean.class); 1764 pmap2.put(Byte.class, byte.class); 1765 pmap2.put(Short.class, short.class); 1766 pmap2.put(Character.class, char.class); 1767 pmap2.put(Integer.class, int.class); 1768 pmap2.put(Long.class, long.class); 1769 pmap2.put(Float.class, float.class); 1770 pmap2.put(Double.class, double.class); 1771 } 1772 1773 @SuppressWarnings("rawtypes") 1774 private static final Map<Class,Object> primitiveDefaultMap = 1775 mapBuilder(Class.class,Object.class).unmodifiable() 1776 .add(Boolean.TYPE, false) 1777 .add(Character.TYPE, (char)0) 1778 .add(Short.TYPE, (short)0) 1779 .add(Integer.TYPE, 0) 1780 .add(Long.TYPE, 0l) 1781 .add(Float.TYPE, 0f) 1782 .add(Double.TYPE, 0d) 1783 .add(Byte.TYPE, (byte)0) 1784 .add(Boolean.class, false) 1785 .add(Character.class, (char)0) 1786 .add(Short.class, (short)0) 1787 .add(Integer.class, 0) 1788 .add(Long.class, 0l) 1789 .add(Float.class, 0f) 1790 .add(Double.class, 0d) 1791 .add(Byte.class, (byte)0) 1792 .build(); 1793 1794 //----------------------------------------------------------------------------------------------------------------- 1795 // Labels 1796 //----------------------------------------------------------------------------------------------------------------- 1797 1798 /** 1799 * Returns the full name of this class. 1800 * 1801 * <h5 class='section'>Examples:</h5> 1802 * <ul> 1803 * <li><js>"com.foo.MyClass"</js> - Normal class 1804 * <li><js>"com.foo.MyClass[][]"</js> - Array. 1805 * <li><js>"com.foo.MyClass$InnerClass"</js> - Inner class. 1806 * <li><js>"com.foo.MyClass$InnerClass[][]"</js> - Inner class array. 1807 * <li><js>"int"</js> - Primitive class. 1808 * <li><js>"int[][]"</js> - Primitive class class. 1809 * <li><js>"java.util.Map<java.lang.String,java.lang.Object>"</js> - Parameterized type. 1810 * <li><js>"java.util.AbstractMap<K,V>"</js> - Parameterized generic type. 1811 * <li><js>"V"</js> - Parameterized generic type argument. 1812 * </ul> 1813 * 1814 * @return The underlying class name. 1815 */ 1816 public String getFullName() { 1817 Class<?> ct = getComponentType().inner(); 1818 int dim = getDimensions(); 1819 if (ct != null && dim == 0 && ! isParameterizedType) 1820 return ct.getName(); 1821 StringBuilder sb = new StringBuilder(128); 1822 appendFullName(sb); 1823 return sb.toString(); 1824 } 1825 1826 /** 1827 * Returns all possible names for this class. 1828 * 1829 * @return 1830 * An array consisting of: 1831 * <ul> 1832 * <li>{@link #getFullName()} 1833 * <li>{@link Class#getName()} - Note that this might be a dup. 1834 * <li>{@link #getShortName()} 1835 * <li>{@link #getSimpleName()} 1836 * </ul> 1837 */ 1838 public String[] getNames() { 1839 return new String[]{ getFullName(), c.getName(), getShortName(), getSimpleName() }; 1840 } 1841 1842 /** 1843 * Same as {@link #getFullName()} but appends to an existing string builder. 1844 * 1845 * @param sb The string builder to append to. 1846 * @return The same string builder. 1847 */ 1848 public StringBuilder appendFullName(StringBuilder sb) { 1849 Class<?> ct = getComponentType().inner(); 1850 int dim = getDimensions(); 1851 if (ct != null && dim == 0 && ! isParameterizedType) 1852 return sb.append(ct.getName()); 1853 sb.append(ct != null ? ct.getName() : t.getTypeName()); 1854 if (isParameterizedType) { 1855 ParameterizedType pt = (ParameterizedType)t; 1856 sb.append('<'); 1857 boolean first = true; 1858 for (Type t2 : pt.getActualTypeArguments()) { 1859 if (! first) 1860 sb.append(','); 1861 first = false; 1862 of(t2).appendFullName(sb); 1863 } 1864 sb.append('>'); 1865 } 1866 for (int i = 0; i < dim; i++) 1867 sb.append('[').append(']'); 1868 return sb; 1869 } 1870 1871 /** 1872 * Returns the short name of the underlying class. 1873 * 1874 * <p> 1875 * Similar to {@link #getSimpleName()} but also renders local or member class name prefixes. 1876 * 1877 * @return The short name of the underlying class. 1878 */ 1879 public String getShortName() { 1880 Class<?> ct = getComponentType().inner(); 1881 int dim = getDimensions(); 1882 if (ct != null && dim == 0 && ! (isParameterizedType || isMemberClass() || c.isLocalClass())) 1883 return ct.getSimpleName(); 1884 StringBuilder sb = new StringBuilder(32); 1885 appendShortName(sb); 1886 return sb.toString(); 1887 } 1888 1889 /** 1890 * Same as {@link #getShortName()} but appends to an existing string builder. 1891 * 1892 * @param sb The string builder to append to. 1893 * @return The same string builder. 1894 */ 1895 public StringBuilder appendShortName(StringBuilder sb) { 1896 Class<?> ct = getComponentType().inner(); 1897 int dim = getDimensions(); 1898 if (ct != null) { 1899 if (ct.isLocalClass()) 1900 sb.append(of(ct.getEnclosingClass()).getSimpleName()).append('$').append(ct.getSimpleName()); 1901 else if (ct.isMemberClass()) 1902 sb.append(of(ct.getDeclaringClass()).getSimpleName()).append('$').append(ct.getSimpleName()); 1903 else 1904 sb.append(ct.getSimpleName()); 1905 } else { 1906 sb.append(t.getTypeName()); 1907 } 1908 if (isParameterizedType) { 1909 ParameterizedType pt = (ParameterizedType)t; 1910 sb.append('<'); 1911 boolean first = true; 1912 for (Type t2 : pt.getActualTypeArguments()) { 1913 if (! first) 1914 sb.append(','); 1915 first = false; 1916 of(t2).appendShortName(sb); 1917 } 1918 sb.append('>'); 1919 } 1920 for (int i = 0; i < dim; i++) 1921 sb.append('[').append(']'); 1922 return sb; 1923 } 1924 1925 /** 1926 * Returns the simple name of the underlying class. 1927 * 1928 * <p> 1929 * Returns either {@link Class#getSimpleName()} or {@link Type#getTypeName()} depending on whether 1930 * this is a class or type. 1931 * 1932 * @return The simple name of the underlying class; 1933 */ 1934 public String getSimpleName() { 1935 return c != null ? c.getSimpleName() : t.getTypeName(); 1936 } 1937 1938 /** 1939 * Returns the name of the underlying class. 1940 * 1941 * @return The name of the underlying class. 1942 */ 1943 public String getName() { 1944 return c != null ? c.getName() : t.getTypeName(); 1945 } 1946 1947 /** 1948 * Same as {@link #getSimpleName()} but uses <js>"Array"</js> instead of <js>"[]"</js>. 1949 * 1950 * @return The readable name for this class. 1951 */ 1952 public String getReadableName() { 1953 if (c == null) 1954 return t.getTypeName(); 1955 if (! c.isArray()) 1956 return c.getSimpleName(); 1957 Class<?> c = this.c; 1958 StringBuilder sb = new StringBuilder(); 1959 while (c.isArray()) { 1960 sb.append("Array"); 1961 c = c.getComponentType(); 1962 } 1963 return c.getSimpleName() + sb; 1964 } 1965 1966 //----------------------------------------------------------------------------------------------------------------- 1967 // Hierarchy 1968 //----------------------------------------------------------------------------------------------------------------- 1969 1970 /** 1971 * Returns <jk>true</jk> if this class is a parent or the same as <c>child</c>. 1972 * 1973 * @param child The child class. 1974 * @return <jk>true</jk> if this class is a parent or the same as <c>child</c>. 1975 */ 1976 public boolean isParentOf(Class<?> child) { 1977 return c != null && child != null && c.isAssignableFrom(child); 1978 } 1979 1980 /** 1981 * Returns <jk>true</jk> if this class is a parent or the same as <c>child</c>. 1982 * 1983 * <p> 1984 * Primitive classes are converted to wrapper classes and compared. 1985 * 1986 * <h5 class='section'>Examples:</h5> 1987 * <p class='bjava'> 1988 * ClassInfo.<jsm>of</jsm>(String.<jk>class</jk>).isParentOfFuzzyPrimitives(String.<jk>class</jk>); <jc>// true</jc> 1989 * ClassInfo.<jsm>of</jsm>(CharSequence.<jk>class</jk>).isParentOfFuzzyPrimitives(String.<jk>class</jk>); <jc>// true</jc> 1990 * ClassInfo.<jsm>of</jsm>(String.<jk>class</jk>).isParentOfFuzzyPrimitives(CharSequence.<jk>class</jk>); <jc>// false</jc> 1991 * ClassInfo.<jsm>of</jsm>(<jk>int</jk>.<jk>class</jk>).isParentOfFuzzyPrimitives(Integer.<jk>class</jk>); <jc>// true</jc> 1992 * ClassInfo.<jsm>of</jsm>(Integer.<jk>class</jk>).isParentOfFuzzyPrimitives(<jk>int</jk>.<jk>class</jk>); <jc>// true</jc> 1993 * ClassInfo.<jsm>of</jsm>(Number.<jk>class</jk>).isParentOfFuzzyPrimitives(<jk>int</jk>.<jk>class</jk>); <jc>// true</jc> 1994 * ClassInfo.<jsm>of</jsm>(<jk>int</jk>.<jk>class</jk>).isParentOfFuzzyPrimitives(Number.<jk>class</jk>); <jc>// false</jc> 1995 * ClassInfo.<jsm>of</jsm>(<jk>int</jk>.<jk>class</jk>).isParentOfFuzzyPrimitives(<jk>long</jk>.<jk>class</jk>); <jc>// false</jc> 1996 * </p> 1997 * 1998 * @param child The child class. 1999 * @return <jk>true</jk> if this class is a parent or the same as <c>child</c>. 2000 */ 2001 public boolean isParentOfFuzzyPrimitives(Class<?> child) { 2002 if (c == null || child == null) 2003 return false; 2004 if (c.isAssignableFrom(child)) 2005 return true; 2006 if (this.isPrimitive() || child.isPrimitive()) { 2007 return this.getWrapperIfPrimitive().isAssignableFrom(of(child).getWrapperIfPrimitive()); 2008 } 2009 return false; 2010 } 2011 2012 /** 2013 * Returns <jk>true</jk> if this type can be used as a parameter for the specified object. 2014 * 2015 * @param child The argument to check. 2016 * @return <jk>true</jk> if this type can be used as a parameter for the specified object. 2017 */ 2018 public boolean canAcceptArg(Object child) { 2019 if (c == null || child == null) 2020 return false; 2021 if (c.isInstance(child)) 2022 return true; 2023 if (this.isPrimitive() || child.getClass().isPrimitive()) { 2024 return this.getWrapperIfPrimitive().isAssignableFrom(of(child).getWrapperIfPrimitive()); 2025 } 2026 return false; 2027 } 2028 2029 /** 2030 * Same as {@link #isParentOfFuzzyPrimitives(Class)} but takes in a {@link ClassInfo}. 2031 * 2032 * @param child The child class. 2033 * @return <jk>true</jk> if this class is a parent or the same as <c>child</c>. 2034 */ 2035 public boolean isParentOfFuzzyPrimitives(ClassInfo child) { 2036 if (c == null || child == null) 2037 return false; 2038 if (c.isAssignableFrom(child.inner())) 2039 return true; 2040 if (this.isPrimitive() || child.isPrimitive()) { 2041 return this.getWrapperIfPrimitive().isAssignableFrom(child.getWrapperIfPrimitive()); 2042 } 2043 return false; 2044 } 2045 2046 /** 2047 * Returns <jk>true</jk> if this class is a parent or the same as <c>child</c>. 2048 * 2049 * @param child The child class. 2050 * @return <jk>true</jk> if this class is a parent or the same as <c>child</c>. 2051 */ 2052 public boolean isParentOf(Type child) { 2053 if (child instanceof Class) 2054 return isParentOf((Class<?>)child); 2055 return false; 2056 } 2057 2058 /** 2059 * Returns <jk>true</jk> if this class is a parent or the same as <c>child</c>. 2060 * 2061 * @param child The child class. 2062 * @return <jk>true</jk> if this class is a parent or the same as <c>child</c>. 2063 */ 2064 public boolean isParentOfFuzzyPrimitives(Type child) { 2065 if (child instanceof Class) 2066 return isParentOfFuzzyPrimitives((Class<?>)child); 2067 return false; 2068 } 2069 2070 /** 2071 * Returns <jk>true</jk> if this class is a child of <c>parent</c>. 2072 * 2073 * @param parent The parent class. 2074 * @return <jk>true</jk> if this class is a parent of <c>child</c>. 2075 */ 2076 public boolean isStrictChildOf(Class<?> parent) { 2077 return c != null && parent != null && parent.isAssignableFrom(c) && ! c.equals(parent); 2078 } 2079 2080 /** 2081 * Returns <jk>true</jk> if this class is a child or the same as <c>parent</c>. 2082 * 2083 * @param parent The parent class. 2084 * @return <jk>true</jk> if this class is a child or the same as <c>parent</c>. 2085 */ 2086 public boolean isChildOf(Class<?> parent) { 2087 return c != null && parent != null && parent.isAssignableFrom(c); 2088 } 2089 2090 /** 2091 * Returns <jk>true</jk> if this class is a child or the same as any of the <c>parents</c>. 2092 * 2093 * @param parents The parents class. 2094 * @return <jk>true</jk> if this class is a child or the same as any of the <c>parents</c>. 2095 */ 2096 public boolean isChildOfAny(Class<?>...parents) { 2097 for (Class<?> p : parents) 2098 if (isChildOf(p)) 2099 return true; 2100 return false; 2101 } 2102 2103 /** 2104 * Returns <jk>true</jk> if this class is a child or the same as <c>parent</c>. 2105 * 2106 * @param parent The parent class. 2107 * @return <jk>true</jk> if this class is a parent or the same as <c>parent</c>. 2108 */ 2109 public boolean isChildOf(Type parent) { 2110 if (parent instanceof Class) 2111 return isChildOf((Class<?>)parent); 2112 return false; 2113 } 2114 2115 /** 2116 * Returns <jk>true</jk> if this class is a child or the same as <c>parent</c>. 2117 * 2118 * @param parent The parent class. 2119 * @return <jk>true</jk> if this class is a parent or the same as <c>parent</c>. 2120 */ 2121 public boolean isChildOf(ClassInfo parent) { 2122 return isChildOf(parent.inner()); 2123 } 2124 2125 /** 2126 * Checks for equality with the specified class. 2127 * 2128 * @param c The class to check equality with. 2129 * @return <jk>true</jk> if the specified class is the same as this one. 2130 */ 2131 public boolean is(Class<?> c) { 2132 return this.c != null && this.c.equals(c); 2133 } 2134 2135 /** 2136 * Checks for equality with the specified class. 2137 * 2138 * @param c The class to check equality with. 2139 * @return <jk>true</jk> if the specified class is the same as this one. 2140 */ 2141 public boolean is(ClassInfo c) { 2142 if (this.c != null) 2143 return this.c.equals(c.inner()); 2144 return t.equals(c.t); 2145 } 2146 2147 /** 2148 * Returns <jk>true</jk> if the specified value is an instance of this class. 2149 * 2150 * @param value The value to check. 2151 * @return <jk>true</jk> if the specified value is an instance of this class. 2152 */ 2153 public boolean isInstance(Object value) { 2154 if (this.c != null) 2155 return c.isInstance(value); 2156 return false; 2157 } 2158 2159 /** 2160 * Returns <jk>true</jk> if this class is any of the specified types. 2161 * 2162 * @param types The types to check against. 2163 * @return <jk>true</jk> if this class is any of the specified types. 2164 */ 2165 public boolean isAny(Class<?>...types) { 2166 for (Class<?> cc : types) 2167 if (is(cc)) 2168 return true; 2169 return false; 2170 } 2171 2172 /** 2173 * Returns <jk>true</jk> if all specified flags are applicable to this field. 2174 * 2175 * @param flags The flags to test for. 2176 * @return <jk>true</jk> if all specified flags are applicable to this field. 2177 */ 2178 public boolean is(ReflectFlags...flags) { 2179 return isAll(flags); 2180 } 2181 2182 /** 2183 * Returns the package of this class. 2184 * 2185 * @return The package of this class. 2186 */ 2187 public Package getPackage() { 2188 return c == null ? null : c.getPackage(); 2189 } 2190 2191 /** 2192 * Returns <jk>true</jk> if this class is not in the root package. 2193 * 2194 * @return <jk>true</jk> if this class is not in the root package. 2195 */ 2196 public boolean hasPackage() { 2197 return getPackage() != null; 2198 } 2199 2200 /** 2201 * Returns the number of dimensions if this is an array type. 2202 * 2203 * @return The number of dimensions if this is an array type, or <c>0</c> if it is not. 2204 */ 2205 public int getDimensions() { 2206 if (dim == -1) { 2207 int d = 0; 2208 Class<?> ct = c; 2209 while (ct != null && ct.isArray()) { 2210 d++; 2211 ct = ct.getComponentType(); 2212 } 2213 this.dim = d; 2214 this.componentType = ct == c ? this : of(ct); 2215 } 2216 return dim; 2217 } 2218 2219 /** 2220 * Returns the base component type of this class if it's an array. 2221 * 2222 * @return The base component type of this class if it's an array, or this object if it's not. 2223 */ 2224 public ClassInfo getComponentType() { 2225 if (componentType == null) { 2226 if (c == null) 2227 componentType = this; 2228 else 2229 getDimensions(); 2230 } 2231 return componentType; 2232 } 2233 2234 /** 2235 * Returns <jk>true</jk> if this class is an enum. 2236 * 2237 * @return <jk>true</jk> if this class is an enum. 2238 */ 2239 public boolean isEnum() { 2240 return c != null && c.isEnum(); 2241 } 2242 2243 /** 2244 * Returns <jk>true</jk> if this is a repeated annotation class. 2245 * 2246 * <p> 2247 * A repeated annotation has a single <code>value()</code> method that returns an array 2248 * of annotations who themselves are marked with the {@link Repeatable @Repeatable} annotation 2249 * of this class. 2250 * 2251 * @return <jk>true</jk> if this is a repeated annotation class. 2252 */ 2253 public boolean isRepeatedAnnotation() { 2254 if (isRepeatedAnnotation == null) { 2255 synchronized(this) { 2256 boolean b = false; 2257 repeatedAnnotationMethod = getPublicMethod(x -> x.hasName("value")); 2258 if (repeatedAnnotationMethod != null) { 2259 ClassInfo rt = repeatedAnnotationMethod.getReturnType(); 2260 if (rt.isArray()) { 2261 ClassInfo rct = rt.getComponentType(); 2262 if (rct.hasAnnotation(Repeatable.class)) { 2263 Repeatable r = rct.getAnnotation(Repeatable.class); 2264 b = r.value().equals(c); 2265 } 2266 } 2267 } 2268 isRepeatedAnnotation = b; 2269 } 2270 } 2271 return isRepeatedAnnotation; 2272 } 2273 2274 /** 2275 * Returns the repeated annotation method on this class. 2276 * 2277 * <p> 2278 * The repeated annotation method is the <code>value()</code> method that returns an array 2279 * of annotations who themselves are marked with the {@link Repeatable @Repeatable} annotation 2280 * of this class. 2281 * 2282 * @return The repeated annotation method on this class, or <jk>null</jk> if it doesn't exist. 2283 */ 2284 public MethodInfo getRepeatedAnnotationMethod() { 2285 if (isRepeatedAnnotation()) { 2286 if (repeatedAnnotationMethod == null) { 2287 synchronized(this) { 2288 repeatedAnnotationMethod = getPublicMethod(x -> x.hasName("value")); 2289 } 2290 } 2291 return repeatedAnnotationMethod; 2292 } 2293 return null; 2294 } 2295 2296 /** 2297 * Returns <jk>true</jk> if this class is an array. 2298 * 2299 * @return <jk>true</jk> if this class is an array. 2300 */ 2301 public boolean isArray() { 2302 return c != null && c.isArray(); 2303 } 2304 2305 /** 2306 * Returns <jk>true</jk> if this class is an annotation. 2307 * 2308 * @return <jk>true</jk> if this class is an annotation. 2309 */ 2310 public boolean isAnnotation() { 2311 return c != null && c.isAnnotation(); 2312 } 2313 2314 /** 2315 * Returns <jk>true</jk> if this class is a {@link Collection} or an array. 2316 * 2317 * @return <jk>true</jk> if this class is a {@link Collection} or an array. 2318 */ 2319 public boolean isCollectionOrArray() { 2320 return c != null && (Collection.class.isAssignableFrom(c) || c.isArray()); 2321 } 2322 2323 //----------------------------------------------------------------------------------------------------------------- 2324 // Instantiation 2325 //----------------------------------------------------------------------------------------------------------------- 2326 2327 /** 2328 * Shortcut for calling <c>Class.getDeclaredConstructor().newInstance()</c> on the underlying class. 2329 * 2330 * @return A new instance of the underlying class 2331 * @throws ExecutableException Exception occurred on invoked constructor/method/field. 2332 */ 2333 public Object newInstance() throws ExecutableException { 2334 if (c == null) 2335 throw new ExecutableException("Type ''{0}'' cannot be instantiated", getFullName()); 2336 try { 2337 return c.getDeclaredConstructor().newInstance(); 2338 } catch (InvocationTargetException | NoSuchMethodException | InstantiationException | IllegalAccessException e) { 2339 throw new ExecutableException(e); 2340 } 2341 } 2342 2343 //----------------------------------------------------------------------------------------------------------------- 2344 // Parameter types 2345 //----------------------------------------------------------------------------------------------------------------- 2346 2347 /** 2348 * Finds the real parameter type of this class. 2349 * 2350 * @param index The zero-based index of the parameter to resolve. 2351 * @param pt The parameterized type class containing the parameterized type to resolve (e.g. <c>HashMap</c>). 2352 * @return The resolved real class. 2353 */ 2354 @SuppressWarnings("null") 2355 public Class<?> getParameterType(int index, Class<?> pt) { 2356 assertArgNotNull("pt", pt); 2357 2358 // We need to make up a mapping of type names. 2359 Map<Type,Type> typeMap = new HashMap<>(); 2360 Class<?> cc = c; 2361 while (pt != cc.getSuperclass()) { 2362 extractTypes(typeMap, cc); 2363 cc = cc.getSuperclass(); 2364 assertArg(cc != null, "Class ''{0}'' is not a subclass of parameterized type ''{1}''", c.getSimpleName(), pt.getSimpleName()); 2365 } 2366 2367 Type gsc = cc.getGenericSuperclass(); 2368 2369 assertArg(gsc instanceof ParameterizedType, "Class ''{0}'' is not a parameterized type", pt.getSimpleName()); 2370 2371 ParameterizedType cpt = (ParameterizedType)gsc; 2372 Type[] atArgs = cpt.getActualTypeArguments(); 2373 assertArg(index < atArgs.length, "Invalid type index. index={0}, argsLength={1}", index, atArgs.length); 2374 Type actualType = cpt.getActualTypeArguments()[index]; 2375 2376 if (typeMap.containsKey(actualType)) 2377 actualType = typeMap.get(actualType); 2378 2379 if (actualType instanceof Class) { 2380 return (Class<?>)actualType; 2381 2382 } else if (actualType instanceof GenericArrayType) { 2383 Type gct = ((GenericArrayType)actualType).getGenericComponentType(); 2384 if (gct instanceof ParameterizedType) 2385 return Array.newInstance((Class<?>)((ParameterizedType)gct).getRawType(), 0).getClass(); 2386 } else if (actualType instanceof TypeVariable) { 2387 TypeVariable<?> typeVariable = (TypeVariable<?>)actualType; 2388 List<Class<?>> nestedOuterTypes = new LinkedList<>(); 2389 for (Class<?> ec = cc.getEnclosingClass(); ec != null; ec = ec.getEnclosingClass()) { 2390 Class<?> outerClass = cc.getClass(); 2391 nestedOuterTypes.add(outerClass); 2392 Map<Type,Type> outerTypeMap = new HashMap<>(); 2393 extractTypes(outerTypeMap, outerClass); 2394 for (Map.Entry<Type,Type> entry : outerTypeMap.entrySet()) { 2395 Type key = entry.getKey(), value = entry.getValue(); 2396 if (key instanceof TypeVariable) { 2397 TypeVariable<?> keyType = (TypeVariable<?>)key; 2398 if (keyType.getName().equals(typeVariable.getName()) && isInnerClass(keyType.getGenericDeclaration(), typeVariable.getGenericDeclaration())) { 2399 if (value instanceof Class) 2400 return (Class<?>)value; 2401 typeVariable = (TypeVariable<?>)entry.getValue(); 2402 } 2403 } 2404 } 2405 } 2406 } else if (actualType instanceof ParameterizedType) { 2407 return (Class<?>)((ParameterizedType)actualType).getRawType(); 2408 } 2409 throw new IllegalArgumentException("Could not resolve variable '"+actualType.getTypeName()+"' to a type."); 2410 } 2411 2412 private static boolean isInnerClass(GenericDeclaration od, GenericDeclaration id) { 2413 if (od instanceof Class && id instanceof Class) { 2414 Class<?> oc = (Class<?>)od; 2415 Class<?> ic = (Class<?>)id; 2416 while ((ic = ic.getEnclosingClass()) != null) 2417 if (ic == oc) 2418 return true; 2419 } 2420 return false; 2421 } 2422 2423 private static void extractTypes(Map<Type,Type> typeMap, Class<?> c) { 2424 Type gs = c.getGenericSuperclass(); 2425 if (gs instanceof ParameterizedType) { 2426 ParameterizedType pt = (ParameterizedType)gs; 2427 Type[] typeParameters = ((Class<?>)pt.getRawType()).getTypeParameters(); 2428 Type[] actualTypeArguments = pt.getActualTypeArguments(); 2429 for (int i = 0; i < typeParameters.length; i++) { 2430 if (typeMap.containsKey(actualTypeArguments[i])) 2431 actualTypeArguments[i] = typeMap.get(actualTypeArguments[i]); 2432 typeMap.put(typeParameters[i], actualTypeArguments[i]); 2433 } 2434 } 2435 } 2436 2437 //----------------------------------------------------------------------------------------------------------------- 2438 // Other methods 2439 //----------------------------------------------------------------------------------------------------------------- 2440 2441 /** 2442 * Returns <jk>true</jk> if this object passes the specified predicate test. 2443 * 2444 * @param test The test to perform. 2445 * @return <jk>true</jk> if this object passes the specified predicate test. 2446 */ 2447 public boolean matches(Predicate<ClassInfo> test) { 2448 return test(test, this); 2449 } 2450 2451 /** 2452 * Performs an action on this object if the specified predicate test passes. 2453 * 2454 * @param test A test to apply to determine if action should be executed. Can be <jk>null</jk>. 2455 * @param action An action to perform on this object. 2456 * @return This object. 2457 */ 2458 public ClassInfo accept(Predicate<ClassInfo> test, Consumer<ClassInfo> action) { 2459 if (matches(test)) 2460 action.accept(this); 2461 return this; 2462 } 2463 2464 @Override 2465 public String toString() { 2466 return t.toString(); 2467 } 2468 2469 @Override 2470 public int hashCode() { 2471 return t.hashCode(); 2472 } 2473 2474 @Override 2475 public boolean equals(Object o) { 2476 return (o instanceof ClassInfo) && eq(this, (ClassInfo)o, (x,y)->eq(x.t, y.t)); 2477 } 2478}