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