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.StringUtils.*; 016import static org.apache.juneau.reflect.ReflectFlags.*; 017import static org.apache.juneau.internal.CollectionUtils.*; 018 019import java.lang.annotation.*; 020import java.lang.reflect.*; 021import java.util.*; 022import java.util.concurrent.*; 023import java.util.function.*; 024 025import org.apache.juneau.*; 026import org.apache.juneau.annotation.*; 027import org.apache.juneau.internal.*; 028import org.apache.juneau.utils.*; 029 030/** 031 * Lightweight utility class for introspecting information about a class. 032 * 033 * <p> 034 * Provides various convenience methods for introspecting fields/methods/annotations 035 * that aren't provided by the standard Java reflection APIs. 036 * 037 * <p> 038 * Objects are designed to be lightweight to create and threadsafe. 039 * 040 * <h5 class='figure'> 041 * <p class='bpcode w800'> 042 * <jc>// Wrap our class inside a ClassInfo.</jc> 043 * ClassInfo ci = ClassInfo.<jsm>of</jsm>(MyClass.<jk>class</jk>); 044 * 045 * <jc>// Get all methods in parent-to-child order, sorted alphabetically per class.</jc> 046 * <jk>for</jk> (MethodInfo mi : ci.getAllMethodInfos(<jk>true</jk>, <jk>true</jk>)) { 047 * <jc>// Do something with it.</jc> 048 * } 049 * 050 * <jc>// Get all class-level annotations in parent-to-child order.</jc> 051 * <jk>for</jk> (MyAnnotation a : ci.getAnnotations(MyAnnotation.<jk>class</jk>, <jk>true</jk>)) { 052 * // Do something with it. 053 * } 054 * </p> 055 */ 056@BeanIgnore 057public final class ClassInfo { 058 059 private final Type t; 060 final Class<?> c; 061 private final boolean isParameterizedType; 062 private List<ClassInfo> interfaces, declaredInterfaces, parents, allParents; 063 private List<MethodInfo> publicMethods, declaredMethods, allMethods, allMethodsParentFirst; 064 private List<ConstructorInfo> publicConstructors, declaredConstructors; 065 private List<FieldInfo> publicFields, declaredFields, allFields, allFieldsParentFirst; 066 private Map<Class<?>,Optional<Annotation>> annotationMap, declaredAnnotationMap; 067 private int dim = -1; 068 private ClassInfo componentType; 069 070 //----------------------------------------------------------------------------------------------------------------- 071 // Instantiation. 072 //----------------------------------------------------------------------------------------------------------------- 073 074 /** 075 * Constructor. 076 * 077 * @param c The class type. 078 * @param t The generic type (if parameterized type). 079 */ 080 protected ClassInfo(Class<?> c, Type t) { 081 this.t = t; 082 this.c = c; 083 this.isParameterizedType = t == null ? false : (t instanceof ParameterizedType); 084 } 085 086 /** 087 * Returns a class info wrapper around the specified class type. 088 * 089 * @param t The class type. 090 * @return The constructed class info, or <jk>null</jk> if the type was <jk>null</jk>. 091 */ 092 public static ClassInfo of(Type t) { 093 if (t == null) 094 return null; 095 return new ClassInfo(ClassUtils.toClass(t), t); 096 } 097 098 /** 099 * Returns a class info wrapper around the specified class type. 100 * 101 * @param c The class type. 102 * @return The constructed class info, or <jk>null</jk> if the type was <jk>null</jk>. 103 */ 104 public static ClassInfo of(Class<?> c) { 105 if (c == null) 106 return null; 107 return new ClassInfo(c, c); 108 } 109 110 /** 111 * Returns a class info wrapper around the specified class type. 112 * 113 * @param c The class type. 114 * @param t The generic type (if parameterized type). 115 * @return The constructed class info, or <jk>null</jk> if the type was <jk>null</jk>. 116 */ 117 public static ClassInfo of(Class<?> c, Type t) { 118 return new ClassInfo(c, t); 119 } 120 121 /** 122 * Same as using the constructor, but operates on an object instance. 123 * 124 * @param o The class instance. 125 * @return The constructed class info. 126 */ 127 public static ClassInfo of(Object o) { 128 if (o == null) 129 return null; 130 return new ClassInfo(o.getClass(), o.getClass()); 131 } 132 133 /** 134 * Returns the wrapped class as a {@link Type}. 135 * 136 * @return The wrapped class as a {@link Type}. 137 */ 138 public Type innerType() { 139 return t; 140 } 141 142 /** 143 * Returns the wrapped class as a {@link Class}. 144 * 145 * @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}). 146 */ 147 @SuppressWarnings("unchecked") 148 public <T> Class<T> inner() { 149 return (Class<T>)c; 150 } 151 152 /** 153 * If this class is a parameterized {@link Value} type, returns the parameterized type. 154 * 155 * @return The parameterized type, or this object if this class is not a parameterized {@link Value} type. 156 */ 157 public ClassInfo resolved() { 158 if (Value.isType(t)) 159 return of(Value.getParameterType(t)); 160 return this; 161 } 162 163 //----------------------------------------------------------------------------------------------------------------- 164 // Parent classes and interfaces. 165 //----------------------------------------------------------------------------------------------------------------- 166 167 /** 168 * Returns the parent class. 169 * 170 * @return 171 * The parent class, or <jk>null</jk> if the class has no parent. 172 */ 173 public ClassInfo getParent() { 174 return c == null ? null : of(c.getSuperclass()); 175 } 176 177 /** 178 * Returns a list of interfaces declared on this class. 179 * 180 * <p> 181 * Does not include interfaces declared on parent classes. 182 * 183 * @return 184 * An unmodifiable list of interfaces declared on this class. 185 * <br>Results are in the same order as {@link Class#getInterfaces()}. 186 */ 187 public List<ClassInfo> getDeclaredInterfaces() { 188 if (declaredInterfaces == null) { 189 Class<?>[] ii = c == null ? new Class[0] : c.getInterfaces(); 190 List<ClassInfo> l = new ArrayList<>(ii.length); 191 for (Class<?> i : ii) 192 l.add(of(i)); 193 declaredInterfaces = unmodifiableList(l); 194 } 195 return declaredInterfaces; 196 } 197 198 /** 199 * Returns a list of interfaces defined on this class and superclasses. 200 * 201 * @return 202 * An unmodifiable list of interfaces defined on this class and superclasses. 203 * <br>Results are in child-to-parent order. 204 */ 205 public List<ClassInfo> getInterfaces() { 206 if (interfaces == null) { 207 Set<ClassInfo> s = new LinkedHashSet<>(); 208 for (ClassInfo ci : getParents()) 209 for (ClassInfo ci2 : ci.getDeclaredInterfaces()) { 210 s.add(ci2); 211 for (ClassInfo ci3 : ci2.getInterfaces()) 212 s.add(ci3); 213 } 214 interfaces = unmodifiableList(new ArrayList<>(s)); 215 } 216 return interfaces; 217 } 218 219 /** 220 * Returns a list of interfaces defined on this class and superclasses. 221 * 222 * @return 223 * An unmodifiable list of interfaces defined on this class and superclasses. 224 * <br>Results are in parent-to-child order. 225 */ 226 public Iterable<ClassInfo> getInterfacesParentFirst() { 227 return iterable(getInterfaces(), true); 228 } 229 230 /** 231 * Returns a list including this class and all parent classes. 232 * 233 * <p> 234 * Does not include interfaces. 235 * 236 * @return An unmodifiable list including this class and all parent classes. 237 * <br>Results are in child-to-parent order. 238 */ 239 public List<ClassInfo> getParents() { 240 if (parents == null) { 241 List<ClassInfo> l = new ArrayList<>(); 242 Class<?> pc = c; 243 while (pc != null && pc != Object.class) { 244 l.add(of(pc)); 245 pc = pc.getSuperclass(); 246 } 247 parents = Collections.unmodifiableList(l); 248 } 249 return parents; 250 } 251 252 /** 253 * Returns a list including this class and all parent classes. 254 * 255 * <p> 256 * Does not include interfaces. 257 * 258 * @return An unmodifiable list including this class and all parent classes. 259 * <br>Results are in parent-to-child order. 260 */ 261 public Iterable<ClassInfo> getParentsParentFirst() { 262 return iterable(getParents(), true); 263 } 264 265 /** 266 * Returns a list including this class and all parent classes and interfaces. 267 * 268 * @return An unmodifiable list including this class and all parent classes. 269 * <br>Results are ordered child-to-parent order with classes listed before interfaces. 270 */ 271 public List<ClassInfo> getAllParents() { 272 if (allParents == null) { 273 List<ClassInfo> l = new ArrayList<>(); 274 l.addAll(getParents()); 275 l.addAll(getInterfaces()); 276 allParents = Collections.unmodifiableList(l); 277 } 278 return allParents; 279 } 280 281 /** 282 * Returns a list including this class and all parent classes and interfaces. 283 * 284 * @return An unmodifiable list including this class and all parent classes. 285 * <br>Results are ordered parent-to-child order with interfaces listed before classes. 286 */ 287 public Iterable<ClassInfo> getAllParentsParentFirst() { 288 return iterable(getAllParents(), true); 289 } 290 291 //----------------------------------------------------------------------------------------------------------------- 292 // Methods 293 //----------------------------------------------------------------------------------------------------------------- 294 295 /** 296 * Returns all public methods on this class. 297 * 298 * <p> 299 * Methods defined on the {@link Object} class are excluded from the results. 300 * 301 * @return 302 * All public methods on this class. 303 * <br>Results are ordered alphabetically. 304 */ 305 public List<MethodInfo> getPublicMethods() { 306 if (publicMethods == null) { 307 Method[] mm = c == null ? new Method[0] : c.getMethods(); 308 List<MethodInfo> l = new ArrayList<>(mm.length); 309 for (Method m : mm) 310 if (m.getDeclaringClass() != Object.class) 311 l.add(MethodInfo.of(this, m)); 312 l.sort(null); 313 publicMethods = Collections.unmodifiableList(l); 314 } 315 return publicMethods; 316 } 317 318 /** 319 * Returns the public method with the specified method name and argument types. 320 * 321 * @param name The method name (e.g. <js>"toString"</js>). 322 * @param args The exact argument types. 323 * @return 324 * The public method with the specified method name and argument types, or <jk>null</jk> if not found. 325 */ 326 public MethodInfo getPublicMethod(String name, Class<?>...args) { 327 for (MethodInfo mi : getPublicMethods()) 328 if (mi.hasName(name) && mi.hasParamTypes(args)) 329 return mi; 330 return null; 331 } 332 333 /** 334 * Returns the method with the specified method name and argument types. 335 * 336 * @param name The method name (e.g. <js>"toString"</js>). 337 * @param args The exact argument types. 338 * @return 339 * The method with the specified method name and argument types, or <jk>null</jk> if not found. 340 */ 341 public MethodInfo getMethod(String name, Class<?>...args) { 342 for (MethodInfo mi : getAllMethods()) 343 if (mi.hasName(name) && mi.hasParamTypes(args)) 344 return mi; 345 return null; 346 } 347 348 /** 349 * Returns all methods declared on this class. 350 * 351 * @return 352 * All methods declared on this class. 353 * <br>Results are ordered alphabetically. 354 */ 355 public List<MethodInfo> getDeclaredMethods() { 356 if (declaredMethods == null) { 357 Method[] mm = c == null ? new Method[0] : c.getDeclaredMethods(); 358 List<MethodInfo> l = new ArrayList<>(mm.length); 359 for (Method m : mm) 360 if (! "$jacocoInit".equals(m.getName())) // Jacoco adds its own simulated methods. 361 l.add(MethodInfo.of(this, m)); 362 l.sort(null); 363 declaredMethods = Collections.unmodifiableList(l); 364 } 365 return declaredMethods; 366 } 367 368 /** 369 * Returns all declared methods on this class and all parent classes. 370 * 371 * @return 372 * All declared methods on this class and all parent classes. 373 * <br>Results are ordered child-to-parent, and then alphabetically per class. 374 */ 375 public List<MethodInfo> getAllMethods() { 376 if (allMethods == null) { 377 List<MethodInfo> l = new ArrayList<>(); 378 for (ClassInfo c : getAllParents()) 379 c.appendDeclaredMethods(l); 380 allMethods = Collections.unmodifiableList(l); 381 } 382 return allMethods; 383 } 384 385 /** 386 * Returns all declared methods on this class and all parent classes. 387 * 388 * 389 * @return 390 * All declared methods on this class and all parent classes. 391 * <br>Results are ordered parent-to-child, and then alphabetically per class. 392 */ 393 public List<MethodInfo> getAllMethodsParentFirst() { 394 if (allMethodsParentFirst == null) { 395 List<MethodInfo> l = new ArrayList<>(); 396 for (ClassInfo c : getAllParentsParentFirst()) 397 c.appendDeclaredMethods(l); 398 allMethodsParentFirst = Collections.unmodifiableList(l); 399 } 400 return allMethodsParentFirst; 401 } 402 403 private List<MethodInfo> appendDeclaredMethods(List<MethodInfo> l) { 404 l.addAll(getDeclaredMethods()); 405 return l; 406 } 407 408 //----------------------------------------------------------------------------------------------------------------- 409 // Special methods 410 //----------------------------------------------------------------------------------------------------------------- 411 412 /** 413 * Find the public static creator method on this class. 414 * 415 * <p> 416 * Looks for the following method names: 417 * <ul> 418 * <li><c>create</c> 419 * <li><c>from</c> 420 * <li><c>fromValue</c> 421 * <li><c>parse</c> 422 * <li><c>valueOf</c> 423 * <li><c>fromX</c> 424 * <li><c>forX</c> 425 * <li><c>parseX</c> 426 * </ul> 427 * 428 * @param ic The argument type. 429 * @param additionalNames Additional method names to check for. 430 * @return The static method, or <jk>null</jk> if it couldn't be found. 431 */ 432 public MethodInfo getStaticCreateMethod(Class<?> ic, String...additionalNames) { 433 if (c != null) { 434 for (MethodInfo m : getPublicMethods()) { 435 if (m.isAll(STATIC, PUBLIC, NOT_DEPRECATED) && m.hasReturnType(c) && m.hasParamTypes(ic)) { 436 String n = m.getSimpleName(), cn = ic.getSimpleName(); 437 if ( 438 isOneOf(n, "create","from","fromValue","parse","valueOf") 439 || isOneOf(n, additionalNames) 440 || (n.startsWith("from") && n.substring(4).equals(cn)) 441 || (n.startsWith("for") && n.substring(3).equals(cn)) 442 || (n.startsWith("parse") && n.substring(5).equals(cn)) 443 ) { 444 return m; 445 } 446 } 447 } 448 } 449 return null; 450 } 451 452 /** 453 * Find the public static method with the specified name and args. 454 * 455 * @param name The method name. 456 * @param rt The method return type. 457 * @param args The method arguments 458 * @return The method, or <jk>null</jk> if it couldn't be found. 459 */ 460 public MethodInfo getStaticPublicMethod(String name, Class<?> rt, Class<?>...args) { 461 if (c != null) 462 for (MethodInfo m : getPublicMethods()) 463 if (m.isAll(STATIC, PUBLIC, NOT_DEPRECATED) && name.equals(m.getSimpleName()) && m.hasReturnType(rt) && m.hasParamTypes(args)) 464 return m; 465 return null; 466 } 467 468 /** 469 * Find the public static method with the specified name and args. 470 * 471 * @param name The method name. 472 * @param rt The method return type. 473 * @param args The method arguments 474 * @return The method, or <jk>null</jk> if it couldn't be found. 475 */ 476 public Method getStaticPublicMethodInner(String name, Class<?> rt, Class<?>...args) { 477 MethodInfo mi = getStaticPublicMethod(name, rt, args); 478 return mi == null ? null : mi.inner(); 479 } 480 481 /** 482 * Returns the <c>public static Builder create()</c> method on this class. 483 * 484 * @return The <c>public static Builder create()</c> method on this class, or <jk>null</jk> if it doesn't exist. 485 */ 486 public MethodInfo getBuilderCreateMethod() { 487 for (MethodInfo m : getDeclaredMethods()) 488 if (m.isAll(PUBLIC, STATIC) && m.hasName("create") && (!m.hasReturnType(void.class))) 489 return m; 490 return null; 491 } 492 493 /** 494 * Returns the <c>T build()</c> method on this class. 495 * 496 * @return The <c>T build()</c> method on this class, or <jk>null</jk> if it doesn't exist. 497 */ 498 public MethodInfo getBuilderBuildMethod() { 499 for (MethodInfo m : getDeclaredMethods()) 500 if (m.isAll(NOT_STATIC) && m.hasName("build") && (!m.hasParams()) && (!m.hasReturnType(void.class))) 501 return m; 502 return null; 503 } 504 505 //----------------------------------------------------------------------------------------------------------------- 506 // Constructors 507 //----------------------------------------------------------------------------------------------------------------- 508 509 /** 510 * Returns all the public constructors defined on this class. 511 * 512 * @return All public constructors defined on this class. 513 */ 514 public List<ConstructorInfo> getPublicConstructors() { 515 if (publicConstructors == null) { 516 Constructor<?>[] cc = c == null ? new Constructor[0] : c.getConstructors(); 517 List<ConstructorInfo> l = new ArrayList<>(cc.length); 518 for (Constructor<?> ccc : cc) 519 l.add(ConstructorInfo.of(this, ccc)); 520 l.sort(null); 521 publicConstructors = Collections.unmodifiableList(l); 522 } 523 return publicConstructors; 524 } 525 526 /** 527 * Returns the public constructor with the specified argument types. 528 * 529 * @param args The exact argument types. 530 * @return 531 * The public constructor with the specified argument types, or <jk>null</jk> if not found. 532 */ 533 public ConstructorInfo getPublicConstructor(Class<?>...args) { 534 for (ConstructorInfo ci : getPublicConstructors()) 535 if (ci.hasParamTypes(args)) 536 return ci; 537 return null; 538 } 539 540 /** 541 * Returns the declared constructor with the specified argument types. 542 * 543 * @param args The exact argument types. 544 * @return 545 * The declared constructor with the specified argument types, or <jk>null</jk> if not found. 546 */ 547 public ConstructorInfo getDeclaredConstructor(Class<?>...args) { 548 for (ConstructorInfo ci : getDeclaredConstructors()) 549 if (ci.hasParamTypes(args)) 550 return ci; 551 return null; 552 } 553 554 /** 555 * Same as {@link #getPublicConstructor(Class...)} but allows for inexact arg type matching. 556 * 557 * <p> 558 * For example, the method <c>foo(CharSequence)</c> will be matched by <code>getAvailablePublicConstructor(String.<jk>class</jk>)</code> 559 * 560 * @param args The exact argument types. 561 * @return 562 * The public constructor with the specified argument types, or <jk>null</jk> if not found. 563 */ 564 public ConstructorInfo getAvailablePublicConstructor(Class<?>...args) { 565 return getConstructor(Visibility.PUBLIC, false, args); 566 } 567 568 /** 569 * Returns all the constructors defined on this class. 570 * 571 * @return All constructors defined on this class. 572 */ 573 public List<ConstructorInfo> getDeclaredConstructors() { 574 if (declaredConstructors == null) { 575 Constructor<?>[] cc = c == null ? new Constructor[0] : c.getDeclaredConstructors(); 576 List<ConstructorInfo> l = new ArrayList<>(cc.length); 577 for (Constructor<?> ccc : cc) 578 l.add(ConstructorInfo.of(this, ccc)); 579 l.sort(null); 580 declaredConstructors = Collections.unmodifiableList(l); 581 } 582 return declaredConstructors; 583 } 584 585 /** 586 * Finds the public constructor that can take in the specified arguments. 587 * 588 * @param args The arguments we want to pass into the constructor. 589 * @return 590 * The constructor, or <jk>null</jk> if a public constructor could not be found that takes in the specified 591 * arguments. 592 */ 593 public ConstructorInfo getPublicConstructor(Object...args) { 594 return getPublicConstructor(ClassUtils.getClasses(args)); 595 } 596 597 /** 598 * Finds the public constructor that can take in the specified arguments using fuzzy-arg matching. 599 * 600 * @param args The arguments we want to pass into the constructor. 601 * @return 602 * The constructor, or <jk>null</jk> if a public constructor could not be found that takes in the specified 603 * arguments. 604 */ 605 public ConstructorInfo getPublicConstructorFuzzy(Object...args) { 606 return getConstructor(Visibility.PUBLIC, true, ClassUtils.getClasses(args)); 607 } 608 609 /** 610 * Finds a constructor with the specified parameters without throwing an exception. 611 * 612 * @param vis The minimum visibility. 613 * @param argTypes 614 * The argument types in the constructor. 615 * Can be subtypes of the actual constructor argument types. 616 * @return The matching constructor, or <jk>null</jk> if constructor could not be found. 617 */ 618 public ConstructorInfo getConstructor(Visibility vis, Class<?>...argTypes) { 619 return getConstructor(vis, false, argTypes); 620 } 621 622 private ConstructorInfo getConstructor(Visibility vis, boolean fuzzyArgs, Class<?>...argTypes) { 623 if (fuzzyArgs) { 624 int bestCount = -1; 625 ConstructorInfo bestMatch = null; 626 for (ConstructorInfo n : getDeclaredConstructors()) { 627 if (vis.isVisible(n.inner())) { 628 int m = ClassUtils.fuzzyArgsMatch(n.getParamTypes(), argTypes); 629 if (m > bestCount) { 630 bestCount = m; 631 bestMatch = n; 632 } 633 } 634 } 635 return bestMatch; 636 } 637 638 boolean isMemberClass = isNonStaticMemberClass(); 639 for (ConstructorInfo n : getDeclaredConstructors()) { 640 List<ClassInfo> paramTypes = n.getParamTypes(); 641 if (isMemberClass) 642 paramTypes = paramTypes.subList(1, paramTypes.size()); 643 if (ClassUtils.argsMatch(paramTypes, argTypes) && vis.isVisible(n.inner())) 644 return n; 645 } 646 647 return null; 648 } 649 650 //----------------------------------------------------------------------------------------------------------------- 651 // Special constructors 652 //----------------------------------------------------------------------------------------------------------------- 653 654 /** 655 * Locates the no-arg constructor for this class. 656 * 657 * <p> 658 * Constructor must match the visibility requirements specified by parameter 'v'. 659 * If class is abstract, always returns <jk>null</jk>. 660 * Note that this also returns the 1-arg constructor for non-static member classes. 661 * 662 * @param v The minimum visibility. 663 * @return The constructor, or <jk>null</jk> if no no-arg constructor exists with the required visibility. 664 */ 665 public ConstructorInfo getNoArgConstructor(Visibility v) { 666 if (isAbstract()) 667 return null; 668 boolean isMemberClass = isNonStaticMemberClass(); 669 for (ConstructorInfo cc : getDeclaredConstructors()) 670 if (cc.hasNumParams(isMemberClass ? 1 : 0) && cc.isVisible(v)) 671 return cc.makeAccessible(v); 672 return null; 673 } 674 675 //----------------------------------------------------------------------------------------------------------------- 676 // Fields 677 //----------------------------------------------------------------------------------------------------------------- 678 679 /** 680 * Returns all public fields on this class. 681 * 682 * <p> 683 * Hidden fields are excluded from the results. 684 * 685 * @return 686 * All public fields on this class. 687 * <br>Results are in alphabetical order. 688 */ 689 public List<FieldInfo> getPublicFields() { 690 if (publicFields == null) { 691 Map<String,FieldInfo> m = new LinkedHashMap<>(); 692 for (ClassInfo c : getParents()) 693 c.appendDeclaredPublicFields(m); 694 List<FieldInfo> l = new ArrayList<>(m.values()); 695 l.sort(null); 696 publicFields = Collections.unmodifiableList(l); 697 } 698 return publicFields; 699 } 700 701 /** 702 * Returns all declared fields on this class. 703 * 704 * @return 705 * All declared fields on this class. 706 * <br>Results are in alphabetical order. 707 */ 708 public List<FieldInfo> getDeclaredFields() { 709 if (declaredFields == null) { 710 Field[] ff = c == null ? new Field[0] : c.getDeclaredFields(); 711 List<FieldInfo> l = new ArrayList<>(ff.length); 712 for (Field f : ff) 713 if (! "$jacocoData".equals(f.getName())) 714 l.add(FieldInfo.of(this, f)); 715 l.sort(null); 716 declaredFields = Collections.unmodifiableList(l); 717 } 718 return declaredFields; 719 } 720 721 /** 722 * Returns all declared fields on this class and all parent classes. 723 * 724 * @return 725 * All declared fields on this class. 726 * <br>Results are ordered child-to-parent, and then alphabetical per class. 727 */ 728 public List<FieldInfo> getAllFields() { 729 if (allFields == null) { 730 List<FieldInfo> l = new ArrayList<>(); 731 for (ClassInfo c : getAllParents()) 732 c.appendDeclaredFields(l); 733 allFields = Collections.unmodifiableList(l); 734 } 735 return allFields; 736 } 737 738 /** 739 * Returns all declared fields on this class and all parent classes. 740 * 741 * @return 742 * All declared fields on this class. 743 * <br>Results are ordered parent-to-child, and then alphabetical per class. 744 */ 745 public List<FieldInfo> getAllFieldsParentFirst() { 746 if (allFieldsParentFirst == null) { 747 List<FieldInfo> l = new ArrayList<>(); 748 for (ClassInfo c : getAllParentsParentFirst()) 749 c.appendDeclaredFields(l); 750 allFieldsParentFirst = Collections.unmodifiableList(l); 751 } 752 return allFieldsParentFirst; 753 } 754 755 private List<FieldInfo> appendDeclaredFields(List<FieldInfo> l) { 756 l.addAll(getDeclaredFields()); 757 return l; 758 } 759 760 private Map<String,FieldInfo> appendDeclaredPublicFields(Map<String,FieldInfo> m) { 761 for (FieldInfo f : getDeclaredFields()) { 762 String fn = f.getName(); 763 if (f.isPublic() && ! (m.containsKey(fn) || "$jacocoData".equals(fn))) 764 m.put(f.getName(), f); 765 } 766 return m; 767 } 768 769 /** 770 * Returns the public field with the specified name. 771 * 772 * @param name The field name. 773 * @return The public field, or <jk>null</jk> if not found. 774 */ 775 public FieldInfo getPublicField(String name) { 776 for (FieldInfo f : getPublicFields()) 777 if (f.getName().equals(name)) 778 return f; 779 return null; 780 } 781 782 /** 783 * Returns the declared field with the specified name. 784 * 785 * @param name The field name. 786 * @return The declared field, or <jk>null</jk> if not found. 787 */ 788 public FieldInfo getDeclaredField(String name) { 789 for (FieldInfo f : getDeclaredFields()) 790 if (f.getName().equals(name)) 791 return f; 792 return null; 793 } 794 795 /** 796 * Returns the static public field with the specified name. 797 * 798 * @param name The field name. 799 * @return The public field, or <jk>null</jk> if not found. 800 */ 801 public FieldInfo getStaticPublicField(String name) { 802 for (FieldInfo f : getPublicFields()) 803 if (f.isStatic() && f.getName().equals(name)) 804 return f; 805 return null; 806 } 807 808 /** 809 * Returns the static public field with the specified name. 810 * 811 * @param name The field name. 812 * @return The public field, or <jk>null</jk> if not found. 813 */ 814 public Field getStaticPublicFieldInner(String name) { 815 for (FieldInfo f : getPublicFields()) 816 if (f.isStatic() && f.getName().equals(name)) 817 return f.inner(); 818 return null; 819 } 820 821 //----------------------------------------------------------------------------------------------------------------- 822 // Annotations 823 //----------------------------------------------------------------------------------------------------------------- 824 825 /** 826 * Finds the annotation of the specified type defined on this class or parent class/interface. 827 * 828 * <p> 829 * If the annotation cannot be found on the immediate class, searches methods with the same 830 * signature on the parent classes or interfaces. 831 * <br>The search is performed in child-to-parent order. 832 * 833 * @param a 834 * The annotation to search for. 835 * @return 836 * The annotation if found, or <jk>null</jk> if not. 837 */ 838 @SuppressWarnings("unchecked") 839 public <T extends Annotation> T getAnnotation(Class<T> a) { 840 if (a == null) 841 return null; 842 Optional<Annotation> o = annotationMap().get(a); 843 if (o == null) { 844 o = Optional.ofNullable(findAnnotation(a)); 845 annotationMap().put(a, o); 846 } 847 return o.isPresent() ? (T)o.get() : null; 848 } 849 850 /** 851 * Returns <jk>true</jk> if this class has the specified annotation. 852 * 853 * @param a 854 * The annotation to search for. 855 * @return 856 * The <jk>true</jk> if annotation if found. 857 */ 858 public boolean hasAnnotation(Class<? extends Annotation> a) { 859 return getAnnotation(a) != null; 860 } 861 862 /** 863 * Returns the specified annotation only if it's been declared on this class. 864 * 865 * <p> 866 * More efficient than calling {@link Class#getAnnotation(Class)} since it doesn't recursively look for the class 867 * up the parent chain. 868 * 869 * @param <T> The annotation class type. 870 * @param a The annotation class. 871 * @return The annotation, or <jk>null</jk> if not found. 872 */ 873 @SuppressWarnings("unchecked") 874 public <T extends Annotation> T getDeclaredAnnotation(Class<T> a) { 875 if (a == null) 876 return null; 877 Optional<Annotation> o = declaredAnnotationMap().get(a); 878 if (o == null) { 879 o = Optional.ofNullable(findDeclaredAnnotation(a)); 880 declaredAnnotationMap().put(a, o); 881 } 882 return o.isPresent() ? (T)o.get() : null; 883 } 884 885 /** 886 * Returns the specified annotation only if it's been declared on the package of this class. 887 * 888 * @param <T> The annotation class type. 889 * @param a The annotation class. 890 * @return The annotation, or <jk>null</jk> if not found. 891 */ 892 public <T extends Annotation> T getPackageAnnotation(Class<T> a) { 893 Package p = c == null ? null : c.getPackage(); 894 return (p == null ? null : p.getAnnotation(a)); 895 } 896 897 /** 898 * Same as {@link #getDeclaredAnnotation(Class)} but returns the annotation wrapped in a {@link AnnotationInfo}. 899 * 900 * @param a The annotation to search for. 901 * @return The annotation if found, or <jk>null</jk> if not. 902 */ 903 public <T extends Annotation> AnnotationInfo<T> getDeclaredAnnotationInfo(Class<T> a) { 904 T ca = getDeclaredAnnotation(a); 905 return ca == null ? null : AnnotationInfo.of(this, ca); 906 } 907 908 /** 909 * Same as {@link #getPackageAnnotation(Class)} but returns the annotation wrapped in a {@link AnnotationInfo}. 910 * 911 * @param a The annotation to search for. 912 * @return The annotation if found, or <jk>null</jk> if not. 913 */ 914 public <T extends Annotation> AnnotationInfo<T> getPackageAnnotationInfo(Class<T> a) { 915 T ca = getPackageAnnotation(a); 916 return ca == null ? null : AnnotationInfo.of(getPackage(), ca); 917 } 918 919 /** 920 * Returns all annotations of the specified type defined on the specified class or parent classes/interfaces. 921 * 922 * @param a 923 * The annotation to search for. 924 * @return 925 * A list of all matching annotations found in child-to-parent order, or an empty list if none found. 926 */ 927 public <T extends Annotation> List<T> getAnnotations(Class<T> a) { 928 return appendAnnotations(new ArrayList<>(), a); 929 } 930 931 /** 932 * Identical to {@link #getAnnotations(Class)} but optionally returns the list in reverse (parent-to-child) order. 933 * 934 * @param a 935 * The annotation to search for. 936 * @return 937 * A list of all matching annotations found or an empty list if none found. 938 */ 939 public <T extends Annotation> List<T> getAnnotationsParentFirst(Class<T> a) { 940 return appendAnnotationsParentFirst(new ArrayList<>(), a); 941 } 942 943 /** 944 * Same as getAnnotations(Class) except returns the annotations with the accompanying class. 945 * 946 * <p> 947 * Results are ordered child-to-parent. 948 * 949 * @param <T> The annotation class type. 950 * @param a The annotation class type. 951 * @return The found matches, or an empty list if annotation was not found. 952 */ 953 public <T extends Annotation> List<AnnotationInfo<T>> getAnnotationInfos(Class<T> a) { 954 return appendAnnotationInfos(new ArrayList<>(), a); 955 } 956 957 /** 958 * Same as getAnnotations(Class) except returns the annotations with the accompanying class. 959 * 960 * <p> 961 * Results are ordered parent-to-child. 962 * 963 * @param <T> The annotation class type. 964 * @param a The annotation class type. 965 * @return The found matches, or an empty list if annotation was not found. 966 */ 967 public <T extends Annotation> List<AnnotationInfo<T>> getAnnotationInfosParentFirst(Class<T> a) { 968 return appendAnnotationInfosParentFirst(new ArrayList<>(), a); 969 } 970 971 /** 972 * Constructs an {@link AnnotationList} of all annotations found on this class. 973 * 974 * <p> 975 * Annotations are appended in the following orders: 976 * <ol> 977 * <li>On this class. 978 * <li>On parent classes ordered child-to-parent. 979 * <li>On interfaces ordered child-to-parent. 980 * <li>On the package of this class. 981 * </ol> 982 * 983 * @param filter 984 * Optional filter to apply to limit which annotations are added to the list. 985 * <br>Can be <jk>null</jk> for no filtering. 986 * @return A new {@link AnnotationList} object on every call. 987 */ 988 public AnnotationList getAnnotationList(Predicate<AnnotationInfo<?>> filter) { 989 return appendAnnotationList(new AnnotationList(filter)); 990 } 991 992 /** 993 * Constructs an {@link AnnotationList} of all annotations found on this class. 994 * 995 * <p> 996 * Annotations are appended in the following orders: 997 * <ol> 998 * <li>On the package of this class. 999 * <li>On interfaces ordered parent-to-child. 1000 * <li>On parent classes ordered parent-to-child. 1001 * <li>On this class. 1002 * </ol> 1003 * 1004 * @param filter 1005 * Optional filter to apply to limit which annotations are added to the list. 1006 * <br>Can be <jk>null</jk> for no filtering. 1007 * @return A new {@link AnnotationList} object on every call. 1008 */ 1009 public AnnotationList getAnnotationListParentFirst(Predicate<AnnotationInfo<?>> filter) { 1010 return appendAnnotationListParentFirst(new AnnotationList(filter)); 1011 } 1012 1013 /** 1014 * Finds and appends the specified annotation on the specified class and superclasses/interfaces to the specified 1015 * list. 1016 * 1017 * <p> 1018 * Annotations are appended in the following orders: 1019 * <ol> 1020 * <li>On this class. 1021 * <li>On parent classes ordered child-to-parent. 1022 * <li>On interfaces ordered child-to-parent. 1023 * <li>On the package of this class. 1024 * </ol> 1025 * 1026 * @param l The list of annotations. 1027 * @param a The annotation to search for. 1028 * @return The same list. 1029 */ 1030 public <T extends Annotation> List<T> appendAnnotations(List<T> l, Class<T> a) { 1031 for (ClassInfo ci : getParents()) 1032 addIfNotNull(l, ci.getDeclaredAnnotation(a)); 1033 for (ClassInfo ci : getInterfaces()) 1034 addIfNotNull(l, ci.getDeclaredAnnotation(a)); 1035 addIfNotNull(l, getPackageAnnotation(a)); 1036 return l; 1037 } 1038 1039 /** 1040 * Finds and appends the specified annotation on the specified class and superclasses/interfaces to the specified 1041 * list. 1042 * 1043 * <p> 1044 * Annotations are appended in the following orders: 1045 * <ol> 1046 * <li>On the package of this class. 1047 * <li>On interfaces ordered child-to-parent. 1048 * <li>On parent classes ordered child-to-parent. 1049 * <li>On this class. 1050 * </ol> 1051 * 1052 * @param l The list of annotations. 1053 * @param a The annotation to search for. 1054 * @return The same list. 1055 */ 1056 public <T extends Annotation> List<T> appendAnnotationsParentFirst(List<T> l, Class<T> a) { 1057 addIfNotNull(l, getPackageAnnotation(a)); 1058 for (ClassInfo ci : getInterfacesParentFirst()) 1059 addIfNotNull(l, ci.getDeclaredAnnotation(a)); 1060 for (ClassInfo ci : getParentsParentFirst()) 1061 addIfNotNull(l, ci.getDeclaredAnnotation(a)); 1062 return l; 1063 } 1064 1065 /** 1066 * Finds and appends the specified annotation on the specified class and superclasses/interfaces to the specified 1067 * list. 1068 * 1069 * <p> 1070 * Annotations are appended 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 l The list of annotations. 1079 * @param a The annotation to search for. 1080 * @return The same list. 1081 */ 1082 public <T extends Annotation> List<AnnotationInfo<T>> appendAnnotationInfos(List<AnnotationInfo<T>> l, Class<T> a) { 1083 for (ClassInfo ci : getParents()) 1084 addIfNotNull(l, ci.getDeclaredAnnotationInfo(a)); 1085 for (ClassInfo ci : getInterfaces()) 1086 addIfNotNull(l, ci.getDeclaredAnnotationInfo(a)); 1087 addIfNotNull(l, getPackageAnnotationInfo(a)); 1088 return l; 1089 } 1090 1091 /** 1092 * Finds and appends the specified annotation on the specified class and superclasses/interfaces to the specified 1093 * list. 1094 * 1095 * <p> 1096 * Annotations are appended in the following orders: 1097 * <ol> 1098 * <li>On the package of this class. 1099 * <li>On interfaces ordered child-to-parent. 1100 * <li>On parent classes ordered child-to-parent. 1101 * <li>On this class. 1102 * </ol> 1103 * 1104 * @param l The list of annotations. 1105 * @param a The annotation to search for. 1106 * @return The same list. 1107 */ 1108 public <T extends Annotation> List<AnnotationInfo<T>> appendAnnotationInfosParentFirst(List<AnnotationInfo<T>> l, Class<T> a) { 1109 addIfNotNull(l, getPackageAnnotationInfo(a)); 1110 for (ClassInfo ci : getInterfacesParentFirst()) 1111 addIfNotNull(l, ci.getDeclaredAnnotationInfo(a)); 1112 for (ClassInfo ci : getParentsParentFirst()) 1113 addIfNotNull(l, ci.getDeclaredAnnotationInfo(a)); 1114 return l; 1115 } 1116 1117 AnnotationList appendAnnotationList(AnnotationList m) { 1118 for (ClassInfo ci : getParents()) 1119 for (Annotation a : ci.c.getDeclaredAnnotations()) 1120 m.add(AnnotationInfo.of(ci, a)); 1121 for (ClassInfo ci : getInterfaces()) 1122 for (Annotation a : ci.c.getDeclaredAnnotations()) 1123 m.add(AnnotationInfo.of(ci, a)); 1124 Package p = c.getPackage(); 1125 if (p != null) 1126 for (Annotation a : p.getDeclaredAnnotations()) 1127 m.add(AnnotationInfo.of(p, a)); 1128 return m; 1129 } 1130 1131 AnnotationList appendAnnotationListParentFirst(AnnotationList m) { 1132 Package p = c.getPackage(); 1133 if (p != null) 1134 for (Annotation a : p.getDeclaredAnnotations()) 1135 m.add(AnnotationInfo.of(p, a)); 1136 for (ClassInfo ci : getInterfacesParentFirst()) 1137 for (Annotation a : ci.c.getDeclaredAnnotations()) 1138 m.add(AnnotationInfo.of(ci, a)); 1139 for (ClassInfo ci : getParentsParentFirst()) 1140 for (Annotation a : ci.c.getDeclaredAnnotations()) 1141 m.add(AnnotationInfo.of(ci, a)); 1142 return m; 1143 } 1144 1145 private <T extends Annotation> T findAnnotation(Class<T> a) { 1146 T t2 = getDeclaredAnnotation(a); 1147 if (t2 != null) 1148 return t2; 1149 1150 ClassInfo sci = getParent(); 1151 if (sci != null) { 1152 t2 = sci.getAnnotation(a); 1153 if (t2 != null) 1154 return t2; 1155 } 1156 1157 for (ClassInfo c2 : getInterfaces()) { 1158 t2 = c2.getAnnotation(a); 1159 if (t2 != null) 1160 return t2; 1161 } 1162 1163 return null; 1164 } 1165 1166 @SuppressWarnings("unchecked") 1167 private <T extends Annotation> T findDeclaredAnnotation(Class<T> a) { 1168 for (Annotation a2 : c.getDeclaredAnnotations()) 1169 if (a2.annotationType() == a) 1170 return (T)a2; 1171 return null; 1172 } 1173 1174 private synchronized Map<Class<?>,Optional<Annotation>> annotationMap() { 1175 if (annotationMap == null) 1176 annotationMap = new ConcurrentHashMap<>(); 1177 return annotationMap; 1178 } 1179 1180 private synchronized Map<Class<?>,Optional<Annotation>> declaredAnnotationMap() { 1181 if (declaredAnnotationMap == null) 1182 declaredAnnotationMap = new ConcurrentHashMap<>(); 1183 return declaredAnnotationMap; 1184 } 1185 1186 //----------------------------------------------------------------------------------------------------------------- 1187 // Characteristics 1188 //----------------------------------------------------------------------------------------------------------------- 1189 1190 /** 1191 * Returns <jk>true</jk> if all specified flags are applicable to this class. 1192 * 1193 * @param flags The flags to test for. 1194 * @return <jk>true</jk> if all specified flags are applicable to this class. 1195 */ 1196 public boolean isAll(ReflectFlags...flags) { 1197 for (ReflectFlags f : flags) { 1198 switch (f) { 1199 case DEPRECATED: 1200 if (isNotDeprecated()) 1201 return false; 1202 break; 1203 case NOT_DEPRECATED: 1204 if (isDeprecated()) 1205 return false; 1206 break; 1207 case PUBLIC: 1208 if (isNotPublic()) 1209 return false; 1210 break; 1211 case NOT_PUBLIC: 1212 if (isPublic()) 1213 return false; 1214 break; 1215 case STATIC: 1216 if (isNotStatic()) 1217 return false; 1218 break; 1219 case NOT_STATIC: 1220 if (isStatic()) 1221 return false; 1222 break; 1223 case MEMBER: 1224 if (isNotMemberClass()) 1225 return false; 1226 break; 1227 case NOT_MEMBER: 1228 if (isMemberClass()) 1229 return false; 1230 break; 1231 case ABSTRACT: 1232 if (isNotAbstract()) 1233 return false; 1234 break; 1235 case NOT_ABSTRACT: 1236 if (isAbstract()) 1237 return false; 1238 break; 1239 case INTERFACE: 1240 if (isClass()) 1241 return false; 1242 break; 1243 case CLASS: 1244 if (isInterface()) 1245 return false; 1246 break; 1247 default: 1248 throw new RuntimeException("Invalid flag for class: " + f); 1249 1250 } 1251 } 1252 return true; 1253 } 1254 1255 /** 1256 * Returns <jk>true</jk> if all specified flags are applicable to this class. 1257 * 1258 * @param flags The flags to test for. 1259 * @return <jk>true</jk> if all specified flags are applicable to this class. 1260 */ 1261 public boolean isAny(ReflectFlags...flags) { 1262 for (ReflectFlags f : flags) { 1263 switch (f) { 1264 case DEPRECATED: 1265 if (isDeprecated()) 1266 return true; 1267 break; 1268 case NOT_DEPRECATED: 1269 if (isNotDeprecated()) 1270 return true; 1271 break; 1272 case PUBLIC: 1273 if (isPublic()) 1274 return true; 1275 break; 1276 case NOT_PUBLIC: 1277 if (isNotPublic()) 1278 return true; 1279 break; 1280 case STATIC: 1281 if (isStatic()) 1282 return true; 1283 break; 1284 case NOT_STATIC: 1285 if (isNotStatic()) 1286 return true; 1287 break; 1288 case MEMBER: 1289 if (isMemberClass()) 1290 return true; 1291 break; 1292 case NOT_MEMBER: 1293 if (isNotMemberClass()) 1294 return true; 1295 break; 1296 case ABSTRACT: 1297 if (isAbstract()) 1298 return true; 1299 break; 1300 case NOT_ABSTRACT: 1301 if (isNotAbstract()) 1302 return true; 1303 break; 1304 case INTERFACE: 1305 if (isInterface()) 1306 return true; 1307 break; 1308 case CLASS: 1309 if (isClass()) 1310 return true; 1311 break; 1312 default: 1313 throw new RuntimeException("Invalid flag for class: " + f); 1314 } 1315 } 1316 return false; 1317 } 1318 1319 /** 1320 * Returns <jk>true</jk> if this class has the {@link Deprecated @Deprecated} annotation on it. 1321 * 1322 * @return <jk>true</jk> if this class has the {@link Deprecated @Deprecated} annotation on it. 1323 */ 1324 public boolean isDeprecated() { 1325 return c != null && c.isAnnotationPresent(Deprecated.class); 1326 } 1327 1328 /** 1329 * Returns <jk>true</jk> if this class doesn't have the {@link Deprecated @Deprecated} annotation on it. 1330 * 1331 * @return <jk>true</jk> if this class doesn't have the {@link Deprecated @Deprecated} annotation on it. 1332 */ 1333 public boolean isNotDeprecated() { 1334 return c == null || ! c.isAnnotationPresent(Deprecated.class); 1335 } 1336 1337 /** 1338 * Returns <jk>true</jk> if this class is public. 1339 * 1340 * @return <jk>true</jk> if this class is public. 1341 */ 1342 public boolean isPublic() { 1343 return c != null && Modifier.isPublic(c.getModifiers()); 1344 } 1345 1346 /** 1347 * Returns <jk>true</jk> if this class is not public. 1348 * 1349 * @return <jk>true</jk> if this class is not public. 1350 */ 1351 public boolean isNotPublic() { 1352 return c == null || ! Modifier.isPublic(c.getModifiers()); 1353 } 1354 1355 /** 1356 * Returns <jk>true</jk> if this class is public. 1357 * 1358 * <p> 1359 * Note that interfaces are always reported as static, and the static keyword on a member interface is meaningless. 1360 * 1361 * @return <jk>true</jk> if this class is public. 1362 */ 1363 public boolean isStatic() { 1364 return c != null && Modifier.isStatic(c.getModifiers()); 1365 } 1366 1367 /** 1368 * Returns <jk>true</jk> if this class is not static. 1369 * 1370 * <p> 1371 * Note that interfaces are always reported as static, and the static keyword on a member interface is meaningless. 1372 * 1373 * @return <jk>true</jk> if this class is not static. 1374 */ 1375 public boolean isNotStatic() { 1376 return c == null || ! Modifier.isStatic(c.getModifiers()); 1377 } 1378 1379 /** 1380 * Returns <jk>true</jk> if this class is abstract. 1381 * 1382 * <p> 1383 * Note that interfaces are always reported as abstract. 1384 * 1385 * @return <jk>true</jk> if this class is abstract. 1386 */ 1387 public boolean isAbstract() { 1388 return c != null && Modifier.isAbstract(c.getModifiers()); 1389 } 1390 1391 /** 1392 * Returns <jk>true</jk> if this class is not abstract. 1393 * 1394 * <p> 1395 * Note that interfaces are always reported as abstract. 1396 * 1397 * @return <jk>true</jk> if this class is not abstract. 1398 */ 1399 public boolean isNotAbstract() { 1400 return c == null || ! Modifier.isAbstract(c.getModifiers()); 1401 } 1402 1403 /** 1404 * Returns <jk>true</jk> if this class is a member class. 1405 * 1406 * @return <jk>true</jk> if this class is a member class. 1407 */ 1408 public boolean isMemberClass() { 1409 return c != null && c.isMemberClass(); 1410 } 1411 1412 /** 1413 * Returns <jk>true</jk> if this class is a member class. 1414 * 1415 * @return <jk>true</jk> if this class is a member class. 1416 */ 1417 public boolean isNotMemberClass() { 1418 return c == null || ! c.isMemberClass(); 1419 } 1420 1421 /** 1422 * Returns <jk>true</jk> if this class is a member class and not static. 1423 * 1424 * @return <jk>true</jk> if this class is a member class and not static. 1425 */ 1426 public boolean isNonStaticMemberClass() { 1427 return c != null && c.isMemberClass() && ! isStatic(); 1428 } 1429 1430 /** 1431 * Returns <jk>false</jk> if this class is a member class and not static. 1432 * 1433 * @return <jk>false</jk> if this class is a member class and not static. 1434 */ 1435 public boolean isNotNonStaticMemberClass() { 1436 return ! isNonStaticMemberClass(); 1437 } 1438 1439 /** 1440 * Returns <jk>true</jk> if this class is a local class. 1441 * 1442 * @return <jk>true</jk> if this class is a local class. 1443 */ 1444 public boolean isLocalClass() { 1445 return c != null && c.isLocalClass(); 1446 } 1447 1448 /** 1449 * Returns <jk>true</jk> if this class is a local class. 1450 * 1451 * @return <jk>true</jk> if this class is a local class. 1452 */ 1453 public boolean isNotLocalClass() { 1454 return c == null || ! c.isLocalClass(); 1455 } 1456 1457 /** 1458 * Identifies if the specified visibility matches this constructor. 1459 * 1460 * @param v The visibility to validate against. 1461 * @return <jk>true</jk> if this visibility matches the modifier attribute of this constructor. 1462 */ 1463 public boolean isVisible(Visibility v) { 1464 return c != null && v.isVisible(c); 1465 } 1466 1467 /** 1468 * Returns <jk>true</jk> if this is a primitive class. 1469 * 1470 * @return <jk>true</jk> if this is a primitive class. 1471 */ 1472 public boolean isPrimitive() { 1473 return c != null && c.isPrimitive(); 1474 } 1475 1476 /** 1477 * Returns <jk>true</jk> if this is not a primitive class. 1478 * 1479 * @return <jk>true</jk> if this is not a primitive class. 1480 */ 1481 public boolean isNotPrimitive() { 1482 return c == null || ! c.isPrimitive(); 1483 } 1484 1485 /** 1486 * Returns <jk>true</jk> if this class is an interface. 1487 * 1488 * @return <jk>true</jk> if this class is an interface. 1489 */ 1490 public boolean isInterface() { 1491 return c != null && c.isInterface(); 1492 } 1493 1494 /** 1495 * Returns <jk>true</jk> if this class is not an interface. 1496 * 1497 * @return <jk>true</jk> if this class is not an interface. 1498 */ 1499 public boolean isClass() { 1500 return c != null && ! c.isInterface(); 1501 } 1502 1503 //----------------------------------------------------------------------------------------------------------------- 1504 // Primitive wrappers 1505 //----------------------------------------------------------------------------------------------------------------- 1506 1507 /** 1508 * Returns <jk>true</jk> if the {@link #getPrimitiveWrapper()} method returns a value. 1509 * 1510 * @return <jk>true</jk> if the {@link #getPrimitiveWrapper()} method returns a value. 1511 */ 1512 public boolean hasPrimitiveWrapper() { 1513 return pmap1.containsKey(c); 1514 } 1515 1516 /** 1517 * If this class is a primitive (e.g. <code><jk>int</jk>.<jk>class</jk></code>) returns it's wrapper class 1518 * (e.g. <code>Integer.<jk>class</jk></code>). 1519 * 1520 * @return The wrapper class, or <jk>null</jk> if class is not a primitive. 1521 */ 1522 public Class<?> getPrimitiveWrapper() { 1523 return pmap1.get(c); 1524 } 1525 1526 /** 1527 * If this class is a primitive wrapper (e.g. <code><jk>Integer</jk>.<jk>class</jk></code>) returns it's 1528 * primitive class (e.g. <code>int.<jk>class</jk></code>). 1529 * 1530 * @return The primitive class, or <jk>null</jk> if class is not a primitive wrapper. 1531 */ 1532 public Class<?> getPrimitiveForWrapper() { 1533 return pmap2.get(c); 1534 } 1535 1536 /** 1537 * If this class is a primitive (e.g. <code><jk>int</jk>.<jk>class</jk></code>) returns it's wrapper class 1538 * (e.g. <code>Integer.<jk>class</jk></code>). 1539 * 1540 * @return The wrapper class if it's primitive, or the same class if class is not a primitive. 1541 */ 1542 public Class<?> getWrapperIfPrimitive() { 1543 if (c != null && ! c.isPrimitive()) 1544 return c; 1545 return pmap1.get(c); 1546 } 1547 1548 /** 1549 * Same as {@link #getWrapperIfPrimitive()} but wraps it in a {@link ClassInfo}. 1550 * 1551 * @return The wrapper class if it's primitive, or the same class if class is not a primitive. 1552 */ 1553 public ClassInfo getWrapperInfoIfPrimitive() { 1554 if (c == null || ! c.isPrimitive()) 1555 return this; 1556 return of(pmap1.get(c)); 1557 } 1558 1559 /** 1560 * Returns the default value for this primitive class. 1561 * 1562 * @return The default value, or <jk>null</jk> if this is not a primitive class. 1563 */ 1564 public Object getPrimitiveDefault() { 1565 return primitiveDefaultMap.get(c); 1566 } 1567 1568 private static final Map<Class<?>, Class<?>> 1569 pmap1 = new HashMap<>(), 1570 pmap2 = new HashMap<>(); 1571 static { 1572 pmap1.put(boolean.class, Boolean.class); 1573 pmap1.put(byte.class, Byte.class); 1574 pmap1.put(short.class, Short.class); 1575 pmap1.put(char.class, Character.class); 1576 pmap1.put(int.class, Integer.class); 1577 pmap1.put(long.class, Long.class); 1578 pmap1.put(float.class, Float.class); 1579 pmap1.put(double.class, Double.class); 1580 pmap2.put(Boolean.class, boolean.class); 1581 pmap2.put(Byte.class, byte.class); 1582 pmap2.put(Short.class, short.class); 1583 pmap2.put(Character.class, char.class); 1584 pmap2.put(Integer.class, int.class); 1585 pmap2.put(Long.class, long.class); 1586 pmap2.put(Float.class, float.class); 1587 pmap2.put(Double.class, double.class); 1588 } 1589 1590 private static final Map<Class<?>,Object> primitiveDefaultMap = Collections.unmodifiableMap( 1591 new AMap<Class<?>,Object>() 1592 .append(Boolean.TYPE, false) 1593 .append(Character.TYPE, (char)0) 1594 .append(Short.TYPE, (short)0) 1595 .append(Integer.TYPE, 0) 1596 .append(Long.TYPE, 0l) 1597 .append(Float.TYPE, 0f) 1598 .append(Double.TYPE, 0d) 1599 .append(Byte.TYPE, (byte)0) 1600 .append(Boolean.class, false) 1601 .append(Character.class, (char)0) 1602 .append(Short.class, (short)0) 1603 .append(Integer.class, 0) 1604 .append(Long.class, 0l) 1605 .append(Float.class, 0f) 1606 .append(Double.class, 0d) 1607 .append(Byte.class, (byte)0) 1608 ); 1609 1610 //----------------------------------------------------------------------------------------------------------------- 1611 // Labels 1612 //----------------------------------------------------------------------------------------------------------------- 1613 1614 /** 1615 * Returns the full name of this class. 1616 * 1617 * <h5 class='section'>Examples:</h5> 1618 * <ul> 1619 * <li><js>"com.foo.MyClass"<js> - Normal class 1620 * <li><js>"com.foo.MyClass[][]"<js> - Array. 1621 * <li><js>"com.foo.MyClass$InnerClass"<js> - Inner class. 1622 * <li><js>"com.foo.MyClass$InnerClass[][]"<js> - Inner class array. 1623 * <li><js>"int"<js> - Primitive class. 1624 * <li><js>"int[][]"<js> - Primitive class class. 1625 * <li><js>"java.util.Map<java.lang.String,java.lang.Object>"<js> - Parameterized type. 1626 * <li><js>"java.util.AbstractMap<K,V>"<js> - Parameterized generic type. 1627 * <li><js>"V"<js> - Parameterized generic type argument. 1628 * </ul> 1629 * 1630 * @return The underlying class name. 1631 */ 1632 public String getFullName() { 1633 Class<?> ct = getComponentType().inner(); 1634 int dim = getDimensions(); 1635 if (ct != null && dim == 0 && ! isParameterizedType) 1636 return ct.getName(); 1637 StringBuilder sb = new StringBuilder(128); 1638 appendFullName(sb); 1639 return sb.toString(); 1640 } 1641 1642 /** 1643 * Same as {@link #getFullName()} but appends to an existing string builder. 1644 * 1645 * @param sb The string builder to append to. 1646 * @return The same string builder. 1647 */ 1648 public StringBuilder appendFullName(StringBuilder sb) { 1649 Class<?> ct = getComponentType().inner(); 1650 int dim = getDimensions(); 1651 if (ct != null && dim == 0 && ! isParameterizedType) 1652 return sb.append(ct.getName()); 1653 sb.append(ct != null ? ct.getName() : t.getTypeName()); 1654 if (isParameterizedType) { 1655 ParameterizedType pt = (ParameterizedType)t; 1656 sb.append('<'); 1657 boolean first = true; 1658 for (Type t2 : pt.getActualTypeArguments()) { 1659 if (! first) 1660 sb.append(','); 1661 first = false; 1662 of(t2).appendFullName(sb); 1663 } 1664 sb.append('>'); 1665 } 1666 for (int i = 0; i < dim; i++) 1667 sb.append('[').append(']'); 1668 return sb; 1669 } 1670 1671 /** 1672 * Returns the short name of the underlying class. 1673 * 1674 * <p> 1675 * Similar to {@link #getSimpleName()} but also renders local or member class name prefixes. 1676 * 1677 * @return The short name of the underlying class. 1678 */ 1679 public String getShortName() { 1680 Class<?> ct = getComponentType().inner(); 1681 int dim = getDimensions(); 1682 if (ct != null && dim == 0 && ! (isParameterizedType || isMemberClass() || c.isLocalClass())) 1683 return ct.getSimpleName(); 1684 StringBuilder sb = new StringBuilder(32); 1685 appendShortName(sb); 1686 return sb.toString(); 1687 } 1688 1689 /** 1690 * Same as {@link #getShortName()} but appends to an existing string builder. 1691 * 1692 * @param sb The string builder to append to. 1693 * @return The same string builder. 1694 */ 1695 public StringBuilder appendShortName(StringBuilder sb) { 1696 Class<?> ct = getComponentType().inner(); 1697 int dim = getDimensions(); 1698 if (ct != null) { 1699 if (ct.isLocalClass()) 1700 sb.append(of(ct.getEnclosingClass()).getSimpleName()).append('$').append(ct.getSimpleName()); 1701 else if (ct.isMemberClass()) 1702 sb.append(of(ct.getDeclaringClass()).getSimpleName()).append('$').append(ct.getSimpleName()); 1703 else 1704 sb.append(ct.getSimpleName()); 1705 } else { 1706 sb.append(t.getTypeName()); 1707 } 1708 if (isParameterizedType) { 1709 ParameterizedType pt = (ParameterizedType)t; 1710 sb.append('<'); 1711 boolean first = true; 1712 for (Type t2 : pt.getActualTypeArguments()) { 1713 if (! first) 1714 sb.append(','); 1715 first = false; 1716 of(t2).appendShortName(sb); 1717 } 1718 sb.append('>'); 1719 } 1720 for (int i = 0; i < dim; i++) 1721 sb.append('[').append(']'); 1722 return sb; 1723 } 1724 1725 /** 1726 * Returns the simple name of the underlying class. 1727 * 1728 * <p> 1729 * Returns either {@link Class#getSimpleName()} or {@link Type#getTypeName()} depending on whether 1730 * this is a class or type. 1731 * 1732 * @return The simple name of the underlying class; 1733 */ 1734 public String getSimpleName() { 1735 return c != null ? c.getSimpleName() : t.getTypeName(); 1736 } 1737 1738 /** 1739 * Returns the name of the underlying class. 1740 * 1741 * @return The name of the underlying class. 1742 */ 1743 public String getName() { 1744 return c != null ? c.getName() : t.getTypeName(); 1745 } 1746 1747 /** 1748 * Same as {@link #getSimpleName()} but uses <js>"Array"</j> instead of <js>"[]"</js>. 1749 * 1750 * @return The readable name for this class. 1751 */ 1752 public String getReadableName() { 1753 if (c == null) 1754 return t.getTypeName(); 1755 if (! c.isArray()) 1756 return c.getSimpleName(); 1757 Class<?> c = this.c; 1758 StringBuilder sb = new StringBuilder(); 1759 while (c.isArray()) { 1760 sb.append("Array"); 1761 c = c.getComponentType(); 1762 } 1763 return c.getSimpleName() + sb; 1764 } 1765 1766 //----------------------------------------------------------------------------------------------------------------- 1767 // Hierarchy 1768 //----------------------------------------------------------------------------------------------------------------- 1769 1770 /** 1771 * Returns <jk>true</jk> if this class is a parent or the same as <c>child</c>. 1772 * 1773 * @param child The child class. 1774 * @return <jk>true</jk> if this class is a parent or the same as <c>child</c>. 1775 */ 1776 public boolean isParentOf(Class<?> child) { 1777 return c != null && child != null && c.isAssignableFrom(child); 1778 } 1779 1780 /** 1781 * Returns <jk>true</jk> if this class is a parent or the same as <c>child</c>. 1782 * 1783 * @param child The child class. 1784 * @return <jk>true</jk> if this class is a parent or the same as <c>child</c>. 1785 */ 1786 public boolean isParentOf(Type child) { 1787 if (child instanceof Class) 1788 return isParentOf((Class<?>)child); 1789 return false; 1790 } 1791 1792 /** 1793 * Returns <jk>true</jk> if this class is a child of <c>parent</c>. 1794 * 1795 * @param parent The parent class. 1796 * @return <jk>true</jk> if this class is a parent of <c>child</c>. 1797 */ 1798 public boolean isStrictChildOf(Class<?> parent) { 1799 return c != null && parent != null && parent.isAssignableFrom(c) && ! c.equals(parent); 1800 } 1801 1802 /** 1803 * Returns <jk>true</jk> if this class is a child or the same as <c>parent</c>. 1804 * 1805 * @param parent The parent class. 1806 * @return <jk>true</jk> if this class is a child or the same as <c>parent</c>. 1807 */ 1808 public boolean isChildOf(Class<?> parent) { 1809 return c != null && parent != null && parent.isAssignableFrom(c); 1810 } 1811 1812 /** 1813 * Returns <jk>true</jk> if this class is a child or the same as any of the <c>parents</c>. 1814 * 1815 * @param parents The parents class. 1816 * @return <jk>true</jk> if this class is a child or the same as any of the <c>parents</c>. 1817 */ 1818 public boolean isChildOfAny(Class<?>...parents) { 1819 for (Class<?> p : parents) 1820 if (isChildOf(p)) 1821 return true; 1822 return false; 1823 } 1824 1825 /** 1826 * Returns <jk>true</jk> if this class is a child or the same as <c>parent</c>. 1827 * 1828 * @param parent The parent class. 1829 * @return <jk>true</jk> if this class is a parent or the same as <c>parent</c>. 1830 */ 1831 public boolean isChildOf(Type parent) { 1832 if (parent instanceof Class) 1833 return isChildOf((Class<?>)parent); 1834 return false; 1835 } 1836 1837 /** 1838 * Returns <jk>true</jk> if this class is a child or the same as <c>parent</c>. 1839 * 1840 * @param parent The parent class. 1841 * @return <jk>true</jk> if this class is a parent or the same as <c>parent</c>. 1842 */ 1843 public boolean isChildOf(ClassInfo parent) { 1844 return isChildOf(parent.inner()); 1845 } 1846 1847 /** 1848 * Checks for equality with the specified class. 1849 * 1850 * @param c The class to check equality with. 1851 * @return <jk>true</jk> if the specified class is the same as this one. 1852 */ 1853 public boolean is(Class<?> c) { 1854 return this.c != null && this.c.equals(c); 1855 } 1856 1857 /** 1858 * Checks for equality with the specified class. 1859 * 1860 * @param c The class to check equality with. 1861 * @return <jk>true</jk> if the specified class is the same as this one. 1862 */ 1863 public boolean is(ClassInfo c) { 1864 if (this.c != null) 1865 return this.c.equals(c.inner()); 1866 return t.equals(c.t); 1867 } 1868 1869 /** 1870 * Returns <jk>true</jk> if this class is any of the specified types. 1871 * 1872 * @param types The types to check against. 1873 * @return <jk>true</jk> if this class is any of the specified types. 1874 */ 1875 public boolean isAny(Class<?>...types) { 1876 for (Class<?> cc : types) 1877 if (is(cc)) 1878 return true; 1879 return false; 1880 } 1881 1882 /** 1883 * Returns the package of this class. 1884 * 1885 * @return The package of this class. 1886 */ 1887 public Package getPackage() { 1888 return c == null ? null : c.getPackage(); 1889 } 1890 1891 /** 1892 * Returns <jk>true</jk> if this class is not in the root package. 1893 * 1894 * @return <jk>true</jk> if this class is not in the root package. 1895 */ 1896 public boolean hasPackage() { 1897 return getPackage() != null; 1898 } 1899 1900 /** 1901 * Returns the number of dimensions if this is an array type. 1902 * 1903 * @return The number of dimensions if this is an array type, or <c>0</c> if it is not. 1904 */ 1905 public int getDimensions() { 1906 if (dim == -1) { 1907 int d = 0; 1908 Class<?> ct = c; 1909 while (ct != null && ct.isArray()) { 1910 d++; 1911 ct = ct.getComponentType(); 1912 } 1913 this.dim = d; 1914 this.componentType = ct == c ? this : of(ct); 1915 } 1916 return dim; 1917 } 1918 1919 /** 1920 * Returns the base component type of this class if it's an array. 1921 * 1922 * @return The base component type of this class if it's an array, or this object if it's not. 1923 */ 1924 public ClassInfo getComponentType() { 1925 if (componentType == null) { 1926 if (c == null) 1927 componentType = this; 1928 else 1929 getDimensions(); 1930 } 1931 return componentType; 1932 } 1933 1934 /** 1935 * Returns <jk>true</jk> if this class is an enum. 1936 * 1937 * @return <jk>true</jk> if this class is an enum. 1938 */ 1939 public boolean isEnum() { 1940 return c != null && c.isEnum(); 1941 } 1942 1943 //----------------------------------------------------------------------------------------------------------------- 1944 // Instantiation 1945 //----------------------------------------------------------------------------------------------------------------- 1946 1947 /** 1948 * Shortcut for calling {@link Class#newInstance()} on the underlying class. 1949 * 1950 * @return A new instance of the underlying class 1951 * @throws ExecutableException Exception occurred on invoked constructor/method/field. 1952 */ 1953 public Object newInstance() throws ExecutableException { 1954 if (c == null) 1955 throw new ExecutableException("Type ''{0}'' cannot be instantiated", getFullName()); 1956 try { 1957 return c.newInstance(); 1958 } catch (InstantiationException | IllegalAccessException e) { 1959 throw new ExecutableException(e); 1960 } 1961 } 1962 1963 //----------------------------------------------------------------------------------------------------------------- 1964 // Parameter types 1965 //----------------------------------------------------------------------------------------------------------------- 1966 1967 /** 1968 * Finds the real parameter type of this class. 1969 * 1970 * @param index The zero-based index of the parameter to resolve. 1971 * @param pt The parameterized type class containing the parameterized type to resolve (e.g. <c>HashMap</c>). 1972 * @return The resolved real class. 1973 */ 1974 public Class<?> getParameterType(int index, Class<?> pt) { 1975 if (pt == null) 1976 throw new FormattedIllegalArgumentException("Parameterized type cannot be null"); 1977 1978 // We need to make up a mapping of type names. 1979 Map<Type,Type> typeMap = new HashMap<>(); 1980 Class<?> cc = c; 1981 while (pt != cc.getSuperclass()) { 1982 extractTypes(typeMap, cc); 1983 cc = cc.getSuperclass(); 1984 if (cc == null) 1985 throw new FormattedIllegalArgumentException("Class ''{0}'' is not a subclass of parameterized type ''{1}''", c.getSimpleName(), pt.getSimpleName()); 1986 } 1987 1988 Type gsc = cc.getGenericSuperclass(); 1989 1990 if (! (gsc instanceof ParameterizedType)) 1991 throw new FormattedIllegalArgumentException("Class ''{0}'' is not a parameterized type", pt.getSimpleName()); 1992 1993 ParameterizedType cpt = (ParameterizedType)gsc; 1994 Type[] atArgs = cpt.getActualTypeArguments(); 1995 if (index >= atArgs.length) 1996 throw new FormattedIllegalArgumentException("Invalid type index. index={0}, argsLength={1}", index, atArgs.length); 1997 Type actualType = cpt.getActualTypeArguments()[index]; 1998 1999 if (typeMap.containsKey(actualType)) 2000 actualType = typeMap.get(actualType); 2001 2002 if (actualType instanceof Class) { 2003 return (Class<?>)actualType; 2004 2005 } else if (actualType instanceof GenericArrayType) { 2006 Type gct = ((GenericArrayType)actualType).getGenericComponentType(); 2007 if (gct instanceof ParameterizedType) 2008 return Array.newInstance((Class<?>)((ParameterizedType)gct).getRawType(), 0).getClass(); 2009 } else if (actualType instanceof TypeVariable) { 2010 TypeVariable<?> typeVariable = (TypeVariable<?>)actualType; 2011 List<Class<?>> nestedOuterTypes = new LinkedList<>(); 2012 for (Class<?> ec = cc.getEnclosingClass(); ec != null; ec = ec.getEnclosingClass()) { 2013 Class<?> outerClass = cc.getClass(); 2014 nestedOuterTypes.add(outerClass); 2015 Map<Type,Type> outerTypeMap = new HashMap<>(); 2016 extractTypes(outerTypeMap, outerClass); 2017 for (Map.Entry<Type,Type> entry : outerTypeMap.entrySet()) { 2018 Type key = entry.getKey(), value = entry.getValue(); 2019 if (key instanceof TypeVariable) { 2020 TypeVariable<?> keyType = (TypeVariable<?>)key; 2021 if (keyType.getName().equals(typeVariable.getName()) && isInnerClass(keyType.getGenericDeclaration(), typeVariable.getGenericDeclaration())) { 2022 if (value instanceof Class) 2023 return (Class<?>)value; 2024 typeVariable = (TypeVariable<?>)entry.getValue(); 2025 } 2026 } 2027 } 2028 } 2029 } else if (actualType instanceof ParameterizedType) { 2030 return (Class<?>)((ParameterizedType)actualType).getRawType(); 2031 } 2032 throw new FormattedIllegalArgumentException("Could not resolve variable ''{0}'' to a type.", actualType.getTypeName()); 2033 } 2034 2035 private static boolean isInnerClass(GenericDeclaration od, GenericDeclaration id) { 2036 if (od instanceof Class && id instanceof Class) { 2037 Class<?> oc = (Class<?>)od; 2038 Class<?> ic = (Class<?>)id; 2039 while ((ic = ic.getEnclosingClass()) != null) 2040 if (ic == oc) 2041 return true; 2042 } 2043 return false; 2044 } 2045 2046 private static void extractTypes(Map<Type,Type> typeMap, Class<?> c) { 2047 Type gs = c.getGenericSuperclass(); 2048 if (gs instanceof ParameterizedType) { 2049 ParameterizedType pt = (ParameterizedType)gs; 2050 Type[] typeParameters = ((Class<?>)pt.getRawType()).getTypeParameters(); 2051 Type[] actualTypeArguments = pt.getActualTypeArguments(); 2052 for (int i = 0; i < typeParameters.length; i++) { 2053 if (typeMap.containsKey(actualTypeArguments[i])) 2054 actualTypeArguments[i] = typeMap.get(actualTypeArguments[i]); 2055 typeMap.put(typeParameters[i], actualTypeArguments[i]); 2056 } 2057 } 2058 } 2059 2060 //----------------------------------------------------------------------------------------------------------------- 2061 // Other 2062 //----------------------------------------------------------------------------------------------------------------- 2063 2064 @Override 2065 public String toString() { 2066 return t.toString(); 2067 } 2068 2069 @Override 2070 public int hashCode() { 2071 return t.hashCode(); 2072 } 2073 2074 @Override 2075 public boolean equals(Object o) { 2076 return o == null ? false : ((ClassInfo)o).t.equals(t); 2077 } 2078}