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