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&lt;java.lang.String,java.lang.Object&gt;"<js> - Parameterized type.
1626    *    <li><js>"java.util.AbstractMap&lt;K,V&gt;"<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}