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