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