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;
014
015import static org.apache.juneau.ClassMeta.ClassCategory.*;
016import static org.apache.juneau.internal.ClassUtils.*;
017import static org.apache.juneau.reflect.ReflectFlags.*;
018
019import java.io.*;
020import java.lang.annotation.*;
021import java.lang.reflect.*;
022import java.lang.reflect.Proxy;
023import java.net.*;
024import java.net.URI;
025import java.util.*;
026import java.util.Date;
027import java.util.concurrent.*;
028import java.util.concurrent.locks.*;
029
030import org.apache.juneau.annotation.*;
031import org.apache.juneau.http.*;
032import org.apache.juneau.internal.*;
033import org.apache.juneau.json.*;
034import org.apache.juneau.reflect.*;
035import org.apache.juneau.transform.*;
036import org.apache.juneau.utils.*;
037
038/**
039 * A wrapper class around the {@link Class} object that provides cached information about that class.
040 *
041 * <p>
042 * Instances of this class can be created through the {@link BeanContext#getClassMeta(Class)} method.
043 *
044 * <p>
045 * The {@link BeanContext} class will cache and reuse instances of this class except for the following class types:
046 * <ul>
047 *    <li>Arrays
048 *    <li>Maps with non-Object key/values.
049 *    <li>Collections with non-Object key/values.
050 * </ul>
051 *
052 * <p>
053 * This class is tied to the {@link BeanContext} class because it's that class that makes the determination of what is
054 * a bean.
055 *
056 * @param <T> The class type of the wrapped class.
057 */
058@Bean(properties="innerClass,classCategory,elementType,keyType,valueType,notABeanReason,initException,beanMeta")
059public final class ClassMeta<T> implements Type {
060
061   /** Class categories. */
062   enum ClassCategory {
063      MAP, COLLECTION, CLASS, METHOD, NUMBER, DECIMAL, BOOLEAN, CHAR, DATE, ARRAY, ENUM, OTHER, CHARSEQ, STR, OBJ, URI, BEANMAP, READER, INPUTSTREAM, VOID, ARGS
064   }
065
066   final Class<T> innerClass;                              // The class being wrapped.
067   final ClassInfo info;
068
069   private final Class<? extends T> implClass;             // The implementation class to use if this is an interface.
070   private final ClassCategory cc;                         // The class category.
071   private final Method fromStringMethod;                  // The static valueOf(String) or fromString(String) or forString(String) method (if it has one).
072   private final ConstructorInfo
073      noArgConstructor,                                    // The no-arg constructor for this class (if it has one).
074      stringConstructor;                                   // The X(String) constructor (if it has one).
075   private final Method
076      exampleMethod;                                       // The example() or @Example-annotated method (if it has one).
077   private final Field
078      exampleField;                                        // The @Example-annotated field (if it has one).
079   private final Setter
080      namePropertyMethod,                                  // The method to set the name on an object (if it has one).
081      parentPropertyMethod;                                // The method to set the parent on an object (if it has one).
082   private final boolean
083      isDelegate,                                          // True if this class extends Delegate.
084      isAbstract,                                          // True if this class is abstract.
085      isMemberClass;                                       // True if this is a non-static member class.
086   private final Object primitiveDefault;                  // Default value for primitive type classes.
087   private final Map<String,Method>
088      publicMethods;                                       // All public methods, including static methods.
089   private final PojoSwap<?,?>[] childPojoSwaps;           // Any PojoSwaps where the normal type is a subclass of this class.
090   private final ConcurrentHashMap<Class<?>,PojoSwap<?,?>>
091      childSwapMap,                                        // Maps normal subclasses to PojoSwaps.
092      childUnswapMap;                                      // Maps swap subclasses to PojoSwaps.
093   private final PojoSwap<T,?>[] pojoSwaps;                // The object POJO swaps associated with this bean (if it has any).
094   private final BeanFilter beanFilter;                    // The bean filter associated with this bean (if it has one).
095   private final BuilderSwap<T,?> builderSwap;             // The builder swap associated with this bean (if it has one).
096   private final MetadataMap extMeta;                      // Extended metadata
097   private final BeanContext beanContext;                  // The bean context that created this object.
098   private final ClassMeta<?>
099      elementType,                                         // If ARRAY or COLLECTION, the element class type.
100      keyType,                                             // If MAP, the key class type.
101      valueType;                                           // If MAP, the value class type.
102   private final BeanMeta<T> beanMeta;                     // The bean meta for this bean class (if it's a bean).
103   private final String
104      typePropertyName,                                    // The property name of the _type property for this class and subclasses.
105      notABeanReason,                                      // If this isn't a bean, the reason why.
106      dictionaryName;                                      // The dictionary name of this class if it has one.
107   private final Throwable initException;                  // Any exceptions thrown in the init() method.
108   private final InvocationHandler invocationHandler;      // The invocation handler for this class (if it has one).
109   private final BeanRegistry beanRegistry;                // The bean registry of this class meta (if it has one).
110   private final ClassMeta<?>[] args;                      // Arg types if this is an array of args.
111   private final Object example;                          // Example object.
112   private final Map<Class<?>,Mutater<?,T>> fromMutaters = new ConcurrentHashMap<>();
113   private final Map<Class<?>,Mutater<T,?>> toMutaters = new ConcurrentHashMap<>();
114   private final Mutater<String,T> stringMutater;
115
116   private ReadWriteLock lock = new ReentrantReadWriteLock(false);
117   private Lock rLock = lock.readLock(), wLock = lock.writeLock();
118
119   /**
120    * Construct a new {@code ClassMeta} based on the specified {@link Class}.
121    *
122    * @param innerClass The class being wrapped.
123    * @param beanContext The bean context that created this object.
124    * @param implClass
125    *    For interfaces and abstract classes, this represents the "real" class to instantiate.
126    *    Can be <jk>null</jk>.
127    * @param beanFilter
128    *    The {@link BeanFilter} programmatically associated with this class.
129    *    Can be <jk>null</jk>.
130    * @param pojoSwap
131    *    The {@link PojoSwap} programmatically associated with this class.
132    *    Can be <jk>null</jk>.
133    * @param childPojoSwap
134    *    The child {@link PojoSwap PojoSwaps} programmatically associated with this class.
135    *    These are the <c>PojoSwaps</c> that have normal classes that are subclasses of this class.
136    *    Can be <jk>null</jk>.
137    * @param delayedInit
138    *    Don't call init() in constructor.
139    *    Used for delayed initialization when the possibility of class reference loops exist.
140    */
141   @SuppressWarnings({ "rawtypes", "unchecked" })
142   ClassMeta(Class<T> innerClass, BeanContext beanContext, Class<? extends T> implClass, BeanFilter beanFilter, PojoSwap<T,?>[] pojoSwaps, PojoSwap<?,?>[] childPojoSwaps, Object example) {
143      this.innerClass = innerClass;
144      this.info = getClassInfo(innerClass);
145      this.beanContext = beanContext;
146      this.extMeta = new MetadataMap();
147      String notABeanReason = null;
148
149      wLock.lock();
150      try {
151         // We always immediately add this class meta to the bean context cache so that we can resolve recursive references.
152         if (beanContext != null && beanContext.cmCache != null)
153            beanContext.cmCache.put(innerClass, this);
154
155         ClassMetaBuilder<T> builder = new ClassMetaBuilder(innerClass, beanContext, implClass, beanFilter, pojoSwaps, childPojoSwaps, example);
156
157         this.cc = builder.cc;
158         this.isDelegate = builder.isDelegate;
159         this.fromStringMethod = builder.fromStringMethod;
160         this.parentPropertyMethod = builder.parentPropertyMethod;
161         this.namePropertyMethod = builder.namePropertyMethod;
162         this.noArgConstructor = builder.noArgConstructor;
163         this.stringConstructor = builder.stringConstructor;
164         this.primitiveDefault = builder.primitiveDefault;
165         this.publicMethods = builder.publicMethods;
166         this.beanFilter = beanFilter;
167         this.pojoSwaps = builder.pojoSwaps.isEmpty() ? null : builder.pojoSwaps.toArray(new PojoSwap[builder.pojoSwaps.size()]);
168         this.builderSwap = builder.builderSwap;
169         this.keyType = builder.keyType;
170         this.valueType = builder.valueType;
171         this.elementType = builder.elementType;
172         notABeanReason = builder.notABeanReason;
173         this.beanMeta = builder.beanMeta;
174         this.initException = builder.initException;
175         this.typePropertyName = builder.typePropertyName;
176         this.dictionaryName = builder.dictionaryName;
177         this.invocationHandler = builder.invocationHandler;
178         this.beanRegistry = builder.beanRegistry;
179         this.isMemberClass = builder.isMemberClass;
180         this.isAbstract = builder.isAbstract;
181         this.implClass = builder.implClass;
182         this.childUnswapMap = builder.childUnswapMap;
183         this.childSwapMap = builder.childSwapMap;
184         this.childPojoSwaps = builder.childPojoSwaps;
185         this.exampleMethod = builder.exampleMethod;
186         this.exampleField = builder.exampleField;
187         this.example = builder.example;
188         this.args = null;
189         this.stringMutater = builder.stringMutater;
190      } catch (ClassMetaRuntimeException e) {
191         notABeanReason = e.getMessage();
192         throw e;
193      } finally {
194         this.notABeanReason = notABeanReason;
195         wLock.unlock();
196      }
197   }
198
199   /**
200    * Causes thread to wait until constructor has exited.
201    */
202   final void waitForInit() {
203      rLock.lock();
204      rLock.unlock();
205   }
206
207   /**
208    * Copy constructor.
209    *
210    * <p>
211    * Used for creating Map and Collection class metas that shouldn't be cached.
212    */
213   ClassMeta(ClassMeta<T> mainType, ClassMeta<?> keyType, ClassMeta<?> valueType, ClassMeta<?> elementType) {
214      this.innerClass = mainType.innerClass;
215      this.info = mainType.info;
216      this.implClass = mainType.implClass;
217      this.childPojoSwaps = mainType.childPojoSwaps;
218      this.childSwapMap = mainType.childSwapMap;
219      this.childUnswapMap = mainType.childUnswapMap;
220      this.cc = mainType.cc;
221      this.fromStringMethod = mainType.fromStringMethod;
222      this.noArgConstructor = mainType.noArgConstructor;
223      this.stringConstructor = mainType.stringConstructor;
224      this.namePropertyMethod = mainType.namePropertyMethod;
225      this.parentPropertyMethod = mainType.parentPropertyMethod;
226      this.isDelegate = mainType.isDelegate;
227      this.isAbstract = mainType.isAbstract;
228      this.isMemberClass = mainType.isMemberClass;
229      this.primitiveDefault = mainType.primitiveDefault;
230      this.publicMethods = mainType.publicMethods;
231      this.beanContext = mainType.beanContext;
232      this.elementType = elementType;
233      this.keyType = keyType;
234      this.valueType = valueType;
235      this.invocationHandler = mainType.invocationHandler;
236      this.beanMeta = mainType.beanMeta;
237      this.typePropertyName = mainType.typePropertyName;
238      this.dictionaryName = mainType.dictionaryName;
239      this.notABeanReason = mainType.notABeanReason;
240      this.pojoSwaps = mainType.pojoSwaps;
241      this.builderSwap = mainType.builderSwap;
242      this.beanFilter = mainType.beanFilter;
243      this.extMeta = mainType.extMeta;
244      this.initException = mainType.initException;
245      this.beanRegistry = mainType.beanRegistry;
246      this.exampleMethod = mainType.exampleMethod;
247      this.exampleField = mainType.exampleField;
248      this.example = mainType.example;
249      this.args = null;
250      this.stringMutater = mainType.stringMutater;
251   }
252
253   /**
254    * Constructor for args-arrays.
255    */
256   @SuppressWarnings("unchecked")
257   ClassMeta(ClassMeta<?>[] args) {
258      this.innerClass = (Class<T>) Object[].class;
259      this.info = getClassInfo(innerClass);
260      this.extMeta = new MetadataMap();
261      this.args = args;
262      this.implClass = null;
263      this.childPojoSwaps = null;
264      this.childSwapMap = null;
265      this.childUnswapMap = null;
266      this.cc = ARGS;
267      this.fromStringMethod = null;
268      this.noArgConstructor = null;
269      this.stringConstructor = null;
270      this.namePropertyMethod = null;
271      this.parentPropertyMethod = null;
272      this.isDelegate = false;
273      this.isAbstract = false;
274      this.isMemberClass = false;
275      this.primitiveDefault = null;
276      this.publicMethods = null;
277      this.beanContext = null;
278      this.elementType = null;
279      this.keyType = null;
280      this.valueType = null;
281      this.invocationHandler = null;
282      this.beanMeta = null;
283      this.typePropertyName = null;
284      this.dictionaryName = null;
285      this.notABeanReason = null;
286      this.pojoSwaps = null;
287      this.builderSwap = null;
288      this.beanFilter = null;
289      this.initException = null;
290      this.beanRegistry = null;
291      this.exampleMethod = null;
292      this.exampleField = null;
293      this.example = null;
294      this.stringMutater = null;
295   }
296
297   @SuppressWarnings({"unchecked","rawtypes","hiding"})
298   private final class ClassMetaBuilder<T> {
299      Class<T> innerClass;
300      ClassInfo ci;
301      Class<? extends T> implClass;
302      BeanContext beanContext;
303      ClassCategory cc = ClassCategory.OTHER;
304      boolean
305         isDelegate = false,
306         isMemberClass = false,
307         isAbstract = false;
308      Method
309         fromStringMethod = null;
310      Setter
311         parentPropertyMethod = null,
312         namePropertyMethod = null;
313      ConstructorInfo
314         noArgConstructor = null,
315         stringConstructor = null;
316      Object primitiveDefault = null;
317      Map<String,Method>
318         publicMethods = new LinkedHashMap<>();
319      ClassMeta<?>
320         keyType = null,
321         valueType = null,
322         elementType = null;
323      String
324         typePropertyName = null,
325         notABeanReason = null,
326         dictionaryName = null;
327      Throwable initException = null;
328      BeanMeta beanMeta = null;
329      List<PojoSwap> pojoSwaps = new ArrayList<>();
330      BuilderSwap builderSwap;
331      InvocationHandler invocationHandler = null;
332      BeanRegistry beanRegistry = null;
333      PojoSwap<?,?>[] childPojoSwaps;
334      ConcurrentHashMap<Class<?>,PojoSwap<?,?>>
335         childSwapMap,
336         childUnswapMap;
337      Method exampleMethod;
338      Field exampleField;
339      Object example;
340      Mutater<String,T> stringMutater;
341
342      ClassMetaBuilder(Class<T> innerClass, BeanContext beanContext, Class<? extends T> implClass, BeanFilter beanFilter, PojoSwap<T,?>[] pojoSwaps, PojoSwap<?,?>[] childPojoSwaps, Object example) {
343         this.innerClass = innerClass;
344         this.beanContext = beanContext;
345
346         this.implClass = implClass;
347         ClassInfo ici = getClassInfo(implClass);
348         this.childPojoSwaps = childPojoSwaps;
349         if (childPojoSwaps == null) {
350            this.childSwapMap = null;
351            this.childUnswapMap = null;
352         } else {
353            this.childSwapMap = new ConcurrentHashMap<>();
354            this.childUnswapMap = new ConcurrentHashMap<>();
355         }
356
357         Class<T> c = innerClass;
358         ci = getClassInfo(c);
359
360         if (c.isPrimitive()) {
361            if (c == Boolean.TYPE)
362               cc = BOOLEAN;
363            else if (c == Byte.TYPE || c == Short.TYPE || c == Integer.TYPE || c == Long.TYPE || c == Float.TYPE || c == Double.TYPE) {
364               if (c == Float.TYPE || c == Double.TYPE)
365                  cc = DECIMAL;
366               else
367                  cc = NUMBER;
368            }
369            else if (c == Character.TYPE)
370               cc = CHAR;
371            else if (c == void.class || c == Void.class)
372               cc = VOID;
373         } else {
374            if (ci.isChildOf(Delegate.class))
375               isDelegate = true;
376
377            if (c == Object.class)
378               cc = OBJ;
379            else if (c.isEnum())
380               cc = ENUM;
381            else if (c.equals(Class.class))
382               cc = ClassCategory.CLASS;
383            else if (ci.isChildOf(Method.class))
384               cc = METHOD;
385            else if (ci.isChildOf(CharSequence.class)) {
386               if (c.equals(String.class))
387                  cc = STR;
388               else
389                  cc = CHARSEQ;
390            }
391            else if (ci.isChildOf(Number.class)) {
392               if (ci.isChildOfAny(Float.class, Double.class))
393                  cc = DECIMAL;
394               else
395                  cc = NUMBER;
396            }
397            else if (ci.isChildOf(Collection.class))
398               cc = COLLECTION;
399            else if (ci.isChildOf(Map.class)) {
400               if (ci.isChildOf(BeanMap.class))
401                  cc = BEANMAP;
402               else
403                  cc = MAP;
404            }
405            else if (c == Character.class)
406               cc = CHAR;
407            else if (c == Boolean.class)
408               cc = BOOLEAN;
409            else if (ci.isChildOfAny(Date.class, Calendar.class))
410               cc = DATE;
411            else if (c.isArray())
412               cc = ARRAY;
413            else if (ci.isChildOfAny(URL.class, URI.class) || c.isAnnotationPresent(org.apache.juneau.annotation.URI.class))
414               cc = URI;
415            else if (ci.isChildOf(Reader.class))
416               cc = READER;
417            else if (ci.isChildOf(InputStream.class))
418               cc = INPUTSTREAM;
419         }
420
421         isMemberClass = ci.isMemberClass() && ci.isNotStatic();
422
423         // Find static fromString(String) or equivalent method.
424         // fromString() must be checked before valueOf() so that Enum classes can create their own
425         //    specialized fromString() methods to override the behavior of Enum.valueOf(String).
426         // valueOf() is used by enums.
427         // parse() is used by the java logging Level class.
428         // forName() is used by Class and Charset
429         for (String methodName : new String[]{"fromString","fromValue","valueOf","parse","parseString","forName","forString"}) {
430            if (fromStringMethod == null) {
431               for (MethodInfo m : ci.getPublicMethods()) {
432                  if (m.isAll(STATIC, PUBLIC, NOT_DEPRECATED) && m.hasName(methodName) && m.hasReturnType(c) && m.hasParamTypes(String.class)) {
433                     fromStringMethod = m.inner();
434                     break;
435                  }
436               }
437            }
438         }
439
440         // Find example() method if present.
441         for (MethodInfo m : ci.getPublicMethods()) {
442            if (m.isAll(PUBLIC, NOT_DEPRECATED, STATIC) && m.hasName("example") && m.hasFuzzyParamTypes(BeanSession.class)) {
443               exampleMethod = m.inner();
444               break;
445            }
446         }
447
448         for (FieldInfo f : ci.getAllFieldsParentFirst()) {
449            if (f.hasAnnotation(ParentProperty.class)) {
450               if (f.isStatic())
451                  throw new ClassMetaRuntimeException("@ParentProperty used on invalid field ''{0}''.  Must be static.", f);
452               f.setAccessible();
453               parentPropertyMethod = new Setter.FieldSetter(f.inner());
454            }
455            if (f.hasAnnotation(NameProperty.class)) {
456               if (f.isStatic())
457                  throw new ClassMetaRuntimeException("@NameProperty used on invalid field ''{0}''.  Must be static.", f);
458               f.setAccessible();
459               namePropertyMethod = new Setter.FieldSetter(f.inner());
460            }
461         }
462
463         for (FieldInfo f : ci.getDeclaredFields()) {
464            if (f.hasAnnotation(Example.class)) {
465               if (! (f.isStatic() && ci.isParentOf(f.getType().inner())))
466                  throw new ClassMetaRuntimeException("@Example used on invalid field ''{0}''.  Must be static and an instance of the type.", f);
467               f.setAccessible();
468               exampleField = f.inner();
469            }
470         }
471
472         // Find @NameProperty and @ParentProperty methods if present.
473         for (MethodInfo m : ci.getAllMethodsParentFirst()) {
474            if (m.hasAnnotation(ParentProperty.class)) {
475               if (m.isStatic() || ! m.hasNumParams(1))
476                  throw new ClassMetaRuntimeException("@ParentProperty used on invalid method ''{0}''.  Must not be static and have one argument.", m);
477               m.setAccessible();
478               parentPropertyMethod = new Setter.MethodSetter(m.inner());
479            }
480            if (m.hasAnnotation(NameProperty.class)) {
481               if (m.isStatic() || ! m.hasNumParams(1))
482                  throw new ClassMetaRuntimeException("@NameProperty used on invalid method ''{0}''.  Must not be static and have one argument.", m);
483               m.setAccessible();
484               namePropertyMethod = new Setter.MethodSetter(m.inner());
485            }
486         }
487
488         for (MethodInfo m : ci.getDeclaredMethods()) {
489            if (m.hasAnnotation(Example.class)) {
490               if (! (m.isStatic() && m.hasFuzzyParamTypes(BeanSession.class) && ci.isParentOf(m.getReturnType().inner())))
491                  throw new ClassMetaRuntimeException("@Example used on invalid method ''{0}''.  Must be static and return an instance of the declaring class.", m);
492               m.setAccessible();
493               exampleMethod = m.inner();
494            }
495         }
496
497         // Note:  Primitive types are normally abstract.
498         isAbstract = ci.isAbstract() && ci.isNotPrimitive();
499
500         // Find constructor(String) method if present.
501         for (ConstructorInfo cs : ci.getPublicConstructors()) {
502            if (cs.isPublic() && cs.isNotDeprecated()) {
503               List<ClassInfo> pt = cs.getParamTypes();
504               if (pt.size() == (isMemberClass ? 1 : 0) && c != Object.class && ! isAbstract) {
505                  noArgConstructor = cs;
506               } else if (pt.size() == (isMemberClass ? 2 : 1)) {
507                  ClassInfo arg = pt.get(isMemberClass ? 1 : 0);
508                  if (arg.is(String.class))
509                     stringConstructor = cs;
510               }
511            }
512         }
513
514         primitiveDefault = ci.getPrimitiveDefault();
515
516         for (MethodInfo m : ci.getPublicMethods())
517            if (m.isAll(PUBLIC, NOT_DEPRECATED))
518               publicMethods.put(m.getSignature(), m.inner());
519
520         if (innerClass != Object.class) {
521            ClassInfo x = implClass == null ? ci : ici;
522            noArgConstructor = x.getPublicConstructor();
523         }
524
525         if (beanFilter == null)
526            beanFilter = findBeanFilter();
527
528         if (pojoSwaps != null)
529            this.pojoSwaps.addAll(Arrays.asList(pojoSwaps));
530
531         if (beanContext != null)
532            this.builderSwap = BuilderSwap.findSwapFromPojoClass(c, beanContext.getBeanConstructorVisibility(), beanContext.getBeanMethodVisibility());
533
534         findPojoSwaps(this.pojoSwaps);
535
536         try {
537
538            // If this is an array, get the element type.
539            if (cc == ARRAY)
540               elementType = findClassMeta(innerClass.getComponentType());
541
542            // If this is a MAP, see if it's parameterized (e.g. AddressBook extends HashMap<String,Person>)
543            else if (cc == MAP) {
544               ClassMeta[] parameters = findParameters();
545               if (parameters != null && parameters.length == 2) {
546                  keyType = parameters[0];
547                  valueType = parameters[1];
548               } else {
549                  keyType = findClassMeta(Object.class);
550                  valueType = findClassMeta(Object.class);
551               }
552            }
553
554            // If this is a COLLECTION, see if it's parameterized (e.g. AddressBook extends LinkedList<Person>)
555            else if (cc == COLLECTION) {
556               ClassMeta[] parameters = findParameters();
557               if (parameters != null && parameters.length == 1) {
558                  elementType = parameters[0];
559               } else {
560                  elementType = findClassMeta(Object.class);
561               }
562            }
563
564            // If the category is unknown, see if it's a bean.
565            // Note that this needs to be done after all other initialization has been done.
566            else if (cc == OTHER) {
567
568               BeanMeta newMeta = null;
569               try {
570                  newMeta = new BeanMeta(ClassMeta.this, beanContext, beanFilter, null);
571                  notABeanReason = newMeta.notABeanReason;
572
573                  // Always get these even if it's not a bean:
574                  beanRegistry = newMeta.beanRegistry;
575                  typePropertyName = newMeta.typePropertyName;
576
577               } catch (RuntimeException e) {
578                  notABeanReason = e.getMessage();
579                  throw e;
580               }
581               if (notABeanReason == null)
582                  beanMeta = newMeta;
583            }
584
585         } catch (NoClassDefFoundError e) {
586            initException = e;
587         } catch (RuntimeException e) {
588            initException = e;
589            throw e;
590         }
591
592         if (beanMeta != null)
593            dictionaryName = beanMeta.getDictionaryName();
594
595         if (beanMeta != null && beanContext != null && beanContext.isUseInterfaceProxies() && innerClass.isInterface())
596            invocationHandler = new BeanProxyInvocationHandler<T>(beanMeta);
597
598         Bean b = c.getAnnotation(Bean.class);
599         if (b != null) {
600            if (b.beanDictionary().length != 0)
601               beanRegistry = new BeanRegistry(beanContext, null, b.beanDictionary());
602
603            // This could be a non-bean POJO with a type name.
604            if (dictionaryName == null && ! b.typeName().isEmpty())
605               dictionaryName = b.typeName();
606         }
607
608         Example e = c.getAnnotation(Example.class);
609
610         if (example == null && e != null && ! e.value().isEmpty())
611            example = e.value();
612
613         if (example == null) {
614            switch(cc) {
615               case BOOLEAN:
616                  example = true;
617                  break;
618               case CHAR:
619                  example = 'a';
620                  break;
621               case CHARSEQ:
622               case STR:
623                  example = "foo";
624                  break;
625               case DECIMAL:
626                  if (isFloat())
627                     example = new Float(1f);
628                  else if (isDouble())
629                     example = new Double(1d);
630                  break;
631               case ENUM:
632                  Iterator<? extends Enum> i = EnumSet.allOf((Class<? extends Enum>)c).iterator();
633                  if (i.hasNext())
634                     example = i.next();
635                  break;
636               case NUMBER:
637                  if (isShort())
638                     example = new Short((short)1);
639                  else if (isInteger())
640                     example = new Integer(1);
641                  else if (isLong())
642                     example = new Long(1l);
643                  break;
644               case URI:
645               case ARGS:
646               case ARRAY:
647               case BEANMAP:
648               case CLASS:
649               case COLLECTION:
650               case DATE:
651               case INPUTSTREAM:
652               case MAP:
653               case METHOD:
654               case OBJ:
655               case OTHER:
656               case READER:
657               case VOID:
658                  break;
659            }
660         }
661
662         this.example = example;
663
664         this.stringMutater = Mutaters.get(String.class, c);
665      }
666
667      private BeanFilter findBeanFilter() {
668         try {
669            List<Bean> ba = info.getAnnotations(Bean.class);
670            if (! ba.isEmpty())
671               return new AnnotationBeanFilterBuilder(innerClass, ba).build();
672         } catch (Exception e) {
673            throw new RuntimeException(e);
674         }
675         return null;
676      }
677
678      private void findPojoSwaps(List<PojoSwap> l) {
679         Swap swap = innerClass.getAnnotation(Swap.class);
680         if (swap != null)
681            l.add(createPojoSwap(swap));
682         Swaps swaps = innerClass.getAnnotation(Swaps.class);
683         if (swaps != null)
684            for (Swap s : swaps.value())
685               l.add(createPojoSwap(s));
686
687         PojoSwap defaultSwap = DefaultSwaps.find(ci);
688         if (defaultSwap == null)
689            defaultSwap = AutoObjectSwap.find(ci);
690         if (defaultSwap == null)
691            defaultSwap = AutoNumberSwap.find(ci);
692         if (defaultSwap == null)
693            defaultSwap = AutoMapSwap.find(ci);
694         if (defaultSwap == null)
695            defaultSwap = AutoListSwap.find(ci);
696         if (defaultSwap != null)
697            l.add(defaultSwap);
698      }
699
700      private PojoSwap<T,?> createPojoSwap(Swap s) {
701         Class<?> c = s.value();
702         if (c == Null.class)
703            c = s.impl();
704         ClassInfo ci = getClassInfo(c);
705
706         if (ci.isChildOf(PojoSwap.class)) {
707            PojoSwap ps = castOrCreate(PojoSwap.class, c);
708            if (s.mediaTypes().length > 0)
709               ps.forMediaTypes(MediaType.forStrings(s.mediaTypes()));
710            if (! s.template().isEmpty())
711               ps.withTemplate(s.template());
712            return ps;
713         }
714
715         if (ci.isChildOf(Surrogate.class)) {
716            List<SurrogateSwap<?,?>> l = SurrogateSwap.findPojoSwaps(c);
717            if (! l.isEmpty())
718               return (PojoSwap<T,?>)l.iterator().next();
719         }
720
721         throw new ClassMetaRuntimeException("Invalid swap class ''{0}'' specified.  Must extend from PojoSwap or Surrogate.", c);
722      }
723
724      private ClassMeta<?> findClassMeta(Class<?> c) {
725         return beanContext.getClassMeta(c, false);
726      }
727
728      private ClassMeta<?>[] findParameters() {
729         return beanContext.findParameters(innerClass, innerClass);
730      }
731   }
732
733   /**
734    * Returns the {@link ClassInfo} wrapper for the underlying class.
735    *
736    * @return The {@link ClassInfo} wrapper for the underlying class, never <jk>null</jk>.
737    */
738   public ClassInfo getInfo() {
739      return info;
740   }
741
742   /**
743    * Returns the type property name associated with this class and subclasses.
744    *
745    * <p>
746    * If <jk>null</jk>, <js>"_type"</js> should be assumed.
747    *
748    * @return
749    *    The type property name associated with this bean class, or <jk>null</jk> if there is no explicit type
750    *    property name defined or this isn't a bean.
751    */
752   public String getBeanTypePropertyName() {
753      return typePropertyName;
754   }
755
756   /**
757    * Returns the bean dictionary name associated with this class.
758    *
759    * <p>
760    * The lexical name is defined by {@link Bean#typeName() @Bean(typeName)}.
761    *
762    * @return
763    *    The type name associated with this bean class, or <jk>null</jk> if there is no type name defined or this
764    *    isn't a bean.
765    */
766   public String getDictionaryName() {
767      return dictionaryName;
768   }
769
770   /**
771    * Returns the bean registry for this class.
772    *
773    * <p>
774    * This bean registry contains names specified in the {@link Bean#beanDictionary() @Bean(beanDictionary)} annotation
775    * defined on the class, regardless of whether the class is an actual bean.
776    * This allows interfaces to define subclasses with type names.
777    *
778    * @return The bean registry for this class, or <jk>null</jk> if no bean registry is associated with it.
779    */
780   public BeanRegistry getBeanRegistry() {
781      return beanRegistry;
782   }
783
784   /**
785    * Returns the category of this class.
786    *
787    * @return The category of this class.
788    */
789   public ClassCategory getClassCategory() {
790      return cc;
791   }
792
793   /**
794    * Returns <jk>true</jk> if this class is a superclass of or the same as the specified class.
795    *
796    * @param c The comparison class.
797    * @return <jk>true</jk> if this class is a superclass of or the same as the specified class.
798    */
799   public boolean isAssignableFrom(Class<?> c) {
800      return info.isChildOf(c);
801   }
802
803   /**
804    * Returns <jk>true</jk> if this class is a subclass of or the same as the specified class.
805    *
806    * @param c The comparison class.
807    * @return <jk>true</jk> if this class is a subclass of or the same as the specified class.
808    */
809   public boolean isInstanceOf(Class<?> c) {
810      return info.isParentOf(c);
811   }
812
813   /**
814    * Returns <jk>true</jk> if this class or any child classes has a {@link PojoSwap} associated with it.
815    *
816    * <p>
817    * Used when transforming bean properties to prevent having to look up transforms if we know for certain that no
818    * transforms are associated with a bean property.
819    *
820    * @return <jk>true</jk> if this class or any child classes has a {@link PojoSwap} associated with it.
821    */
822   protected boolean hasChildPojoSwaps() {
823      return childPojoSwaps != null;
824   }
825
826   /**
827    * Returns the {@link PojoSwap} where the specified class is the same/subclass of the normal class of one of the
828    * child POJO swaps associated with this class.
829    *
830    * @param normalClass The normal class being resolved.
831    * @return The resolved {@link PojoSwap} or <jk>null</jk> if none were found.
832    */
833   protected PojoSwap<?,?> getChildPojoSwapForSwap(Class<?> normalClass) {
834      if (childSwapMap != null) {
835         PojoSwap<?,?> s = childSwapMap.get(normalClass);
836         if (s == null) {
837            for (PojoSwap<?,?> f : childPojoSwaps)
838               if (s == null && f.getNormalClass().isParentOf(normalClass))
839                  s = f;
840            if (s == null)
841               s = PojoSwap.NULL;
842            PojoSwap<?,?> s2 = childSwapMap.putIfAbsent(normalClass, s);
843            if (s2 != null)
844               s = s2;
845         }
846         if (s == PojoSwap.NULL)
847            return null;
848         return s;
849      }
850      return null;
851   }
852
853   /**
854    * Returns the {@link PojoSwap} where the specified class is the same/subclass of the swap class of one of the child
855    * POJO swaps associated with this class.
856    *
857    * @param swapClass The swap class being resolved.
858    * @return The resolved {@link PojoSwap} or <jk>null</jk> if none were found.
859    */
860   protected PojoSwap<?,?> getChildPojoSwapForUnswap(Class<?> swapClass) {
861      if (childUnswapMap != null) {
862         PojoSwap<?,?> s = childUnswapMap.get(swapClass);
863         if (s == null) {
864            for (PojoSwap<?,?> f : childPojoSwaps)
865               if (s == null && f.getSwapClass().isParentOf(swapClass))
866                  s = f;
867            if (s == null)
868               s = PojoSwap.NULL;
869            PojoSwap<?,?> s2 = childUnswapMap.putIfAbsent(swapClass, s);
870            if (s2 != null)
871               s = s2;
872         }
873         if (s == PojoSwap.NULL)
874            return null;
875         return s;
876      }
877      return null;
878   }
879
880   /**
881    * Locates the no-arg constructor for the specified class.
882    *
883    * <p>
884    * Constructor must match the visibility requirements specified by parameter 'v'.
885    * If class is abstract, always returns <jk>null</jk>.
886    * Note that this also returns the 1-arg constructor for non-static member classes.
887    *
888    * @param c The class from which to locate the no-arg constructor.
889    * @param v The minimum visibility.
890    * @return The constructor, or <jk>null</jk> if no no-arg constructor exists with the required visibility.
891    */
892   @SuppressWarnings({"unchecked"})
893   protected static <T> Constructor<? extends T> findNoArgConstructor(Class<?> c, Visibility v) {
894      ClassInfo ci = getClassInfo(c);
895      if (ci.isAbstract())
896         return null;
897      boolean isMemberClass = ci.isMemberClass() && ci.isNotStatic();
898      for (ConstructorInfo cc : ci.getPublicConstructors()) {
899         if (cc.hasNumParams(isMemberClass ? 1 : 0) && cc.isVisible(v) && cc.isNotDeprecated())
900            return (Constructor<? extends T>) v.transform(cc.inner());
901      }
902      return null;
903   }
904
905   /**
906    * Returns the {@link Class} object that this class type wraps.
907    *
908    * @return The wrapped class object.
909    */
910   public Class<T> getInnerClass() {
911      return innerClass;
912   }
913
914   /**
915    * Returns the serialized (swapped) form of this class if there is an {@link PojoSwap} associated with it.
916    *
917    * @param session
918    *    The bean session.
919    *    <br>Required because the swap used may depend on the media type being serialized or parsed.
920    * @return The serialized class type, or this object if no swap is associated with the class.
921    */
922   @BeanIgnore
923   public ClassMeta<?> getSerializedClassMeta(BeanSession session) {
924      PojoSwap<T,?> ps = getPojoSwap(session);
925      return (ps == null ? this : ps.getSwapClassMeta(session));
926   }
927
928   /**
929    * Returns the example of this class.
930    *
931    * @param session
932    *    The bean session.
933    *    <br>Required because the example method may take it in as a parameter.
934    * @return The serialized class type, or this object if no swap is associated with the class.
935    */
936   @SuppressWarnings({"unchecked","rawtypes"})
937   @BeanIgnore
938   public T getExample(BeanSession session) {
939      try {
940         if (example != null) {
941            if (isInstance(example))
942               return (T)example;
943            if (example instanceof String) {
944               if (isCharSequence())
945                  return (T)example;
946               String s = example.toString();
947               if (isMapOrBean() && StringUtils.isObjectMap(s, false))
948                  return JsonParser.DEFAULT.parse(s, this);
949               if (isCollectionOrArray() && StringUtils.isObjectList(s, false))
950                  return JsonParser.DEFAULT.parse(s, this);
951            }
952            if (example instanceof Map && isMapOrBean()) {
953               return JsonParser.DEFAULT.parse(SimpleJsonSerializer.DEFAULT_READABLE.toString(example), this);
954            }
955            if (example instanceof Collection && isCollectionOrArray()) {
956               return JsonParser.DEFAULT.parse(SimpleJsonSerializer.DEFAULT_READABLE.serialize(example), this);
957            }
958         }
959         if (exampleMethod != null)
960            return (T)getMethodInfo(exampleMethod).invokeFuzzy(null, session);
961         if (exampleField != null)
962            return (T)exampleField.get(null);
963
964         if (isCollection()) {
965            Object etExample = getElementType().getExample(session);
966            if (etExample != null) {
967               if (canCreateNewInstance()) {
968                  Collection c = (Collection)newInstance();
969                  c.add(etExample);
970                  return (T)c;
971               }
972               return (T)Collections.singleton(etExample);
973            }
974         } else if (isArray()) {
975            Object etExample = getElementType().getExample(session);
976            if (etExample != null) {
977               Object o = Array.newInstance(getElementType().innerClass, 1);
978               Array.set(o, 0, etExample);
979               return (T)o;
980            }
981         } else if (isMap()) {
982            Object vtExample = getValueType().getExample(session);
983            Object ktExample = getKeyType().getExample(session);
984            if (ktExample != null && vtExample != null) {
985               if (canCreateNewInstance()) {
986                  Map m = (Map)newInstance();
987                  m.put(ktExample, vtExample);
988                  return (T)m;
989               }
990               return (T)Collections.singletonMap(ktExample, vtExample);
991            }
992         }
993
994         return null;
995      } catch (Exception e) {
996         throw new ClassMetaRuntimeException(e);
997      }
998   }
999
1000   /**
1001    * For array and {@code Collection} types, returns the class type of the components of the array or
1002    * {@code Collection}.
1003    *
1004    * @return The element class type, or <jk>null</jk> if this class is not an array or Collection.
1005    */
1006   public ClassMeta<?> getElementType() {
1007      return elementType;
1008   }
1009
1010   /**
1011    * For {@code Map} types, returns the class type of the keys of the {@code Map}.
1012    *
1013    * @return The key class type, or <jk>null</jk> if this class is not a Map.
1014    */
1015   public ClassMeta<?> getKeyType() {
1016      return keyType;
1017   }
1018
1019   /**
1020    * For {@code Map} types, returns the class type of the values of the {@code Map}.
1021    *
1022    * @return The value class type, or <jk>null</jk> if this class is not a Map.
1023    */
1024   public ClassMeta<?> getValueType() {
1025      return valueType;
1026   }
1027
1028   /**
1029    * Returns <jk>true</jk> if this class implements {@link Delegate}, meaning it's a representation of some other
1030    * object.
1031    *
1032    * @return <jk>true</jk> if this class implements {@link Delegate}.
1033    */
1034   public boolean isDelegate() {
1035      return isDelegate;
1036   }
1037
1038   /**
1039    * Returns <jk>true</jk> if this class is a subclass of {@link Map}.
1040    *
1041    * @return <jk>true</jk> if this class is a subclass of {@link Map}.
1042    */
1043   public boolean isMap() {
1044      return cc == MAP || cc == BEANMAP;
1045   }
1046
1047   /**
1048    * Returns <jk>true</jk> if this class is a subclass of {@link Map} or it's a bean.
1049    *
1050    * @return <jk>true</jk> if this class is a subclass of {@link Map} or it's a bean.
1051    */
1052   public boolean isMapOrBean() {
1053      return cc == MAP || cc == BEANMAP || beanMeta != null;
1054   }
1055
1056   /**
1057    * Returns <jk>true</jk> if this class is a subclass of {@link BeanMap}.
1058    *
1059    * @return <jk>true</jk> if this class is a subclass of {@link BeanMap}.
1060    */
1061   public boolean isBeanMap() {
1062      return cc == BEANMAP;
1063   }
1064
1065   /**
1066    * Returns <jk>true</jk> if this class is a subclass of {@link Collection}.
1067    *
1068    * @return <jk>true</jk> if this class is a subclass of {@link Collection}.
1069    */
1070   public boolean isCollection() {
1071      return cc == COLLECTION;
1072   }
1073
1074   /**
1075    * Returns <jk>true</jk> if this class is a subclass of {@link Collection} or is an array.
1076    *
1077    * @return <jk>true</jk> if this class is a subclass of {@link Collection} or is an array.
1078    */
1079   public boolean isCollectionOrArray() {
1080      return cc == COLLECTION || cc == ARRAY;
1081   }
1082
1083
1084   /**
1085    * Returns <jk>true</jk> if this class extends from {@link Set}.
1086    *
1087    * @return <jk>true</jk> if this class extends from {@link Set}.
1088    */
1089   public boolean isSet() {
1090      return cc == COLLECTION && info.isChildOf(Set.class);
1091   }
1092
1093   /**
1094    * Returns <jk>true</jk> if this class extends from {@link List}.
1095    *
1096    * @return <jk>true</jk> if this class extends from {@link List}.
1097    */
1098   public boolean isList() {
1099      return cc == COLLECTION && info.isChildOf(List.class);
1100   }
1101
1102   /**
1103    * Returns <jk>true</jk> if this class is <code><jk>byte</jk>[]</code>.
1104    *
1105    * @return <jk>true</jk> if this class is <code><jk>byte</jk>[]</code>.
1106    */
1107   public boolean isByteArray() {
1108      return cc == ARRAY && this.innerClass == byte[].class;
1109   }
1110
1111   /**
1112    * Returns <jk>true</jk> if this class is {@link Class}.
1113    *
1114    * @return <jk>true</jk> if this class is {@link Class}.
1115    */
1116   public boolean isClass() {
1117      return cc == ClassCategory.CLASS;
1118   }
1119
1120   /**
1121    * Returns <jk>true</jk> if this class is {@link Method}.
1122    *
1123    * @return <jk>true</jk> if this class is {@link Method}.
1124    */
1125   public boolean isMethod() {
1126      return cc == METHOD;
1127   }
1128
1129   /**
1130    * Returns <jk>true</jk> if this class is an {@link Enum}.
1131    *
1132    * @return <jk>true</jk> if this class is an {@link Enum}.
1133    */
1134   public boolean isEnum() {
1135      return cc == ENUM;
1136   }
1137
1138   /**
1139    * Returns <jk>true</jk> if this class is an array.
1140    *
1141    * @return <jk>true</jk> if this class is an array.
1142    */
1143   public boolean isArray() {
1144      return cc == ARRAY;
1145   }
1146
1147   /**
1148    * Returns <jk>true</jk> if this class is a bean.
1149    *
1150    * @return <jk>true</jk> if this class is a bean.
1151    */
1152   public boolean isBean() {
1153      return beanMeta != null;
1154   }
1155
1156   /**
1157    * Returns <jk>true</jk> if this class is {@link Object}.
1158    *
1159    * @return <jk>true</jk> if this class is {@link Object}.
1160    */
1161   public boolean isObject() {
1162      return cc == OBJ;
1163   }
1164
1165   /**
1166    * Returns <jk>true</jk> if this class is not {@link Object}.
1167    *
1168    * @return <jk>true</jk> if this class is not {@link Object}.
1169    */
1170   public boolean isNotObject() {
1171      return cc != OBJ;
1172   }
1173
1174   /**
1175    * Returns <jk>true</jk> if this class is a subclass of {@link Number}.
1176    *
1177    * @return <jk>true</jk> if this class is a subclass of {@link Number}.
1178    */
1179   public boolean isNumber() {
1180      return cc == NUMBER || cc == DECIMAL;
1181   }
1182
1183   /**
1184    * Returns <jk>true</jk> if this class is a subclass of {@link Float} or {@link Double}.
1185    *
1186    * @return <jk>true</jk> if this class is a subclass of {@link Float} or {@link Double}.
1187    */
1188   public boolean isDecimal() {
1189      return cc == DECIMAL;
1190   }
1191
1192   /**
1193    * Returns <jk>true</jk> if this class is either {@link Float} or <jk>float</jk>.
1194    *
1195    * @return <jk>true</jk> if this class is either {@link Float} or <jk>float</jk>.
1196    */
1197   public boolean isFloat() {
1198      return innerClass == Float.class || innerClass == float.class;
1199   }
1200
1201   /**
1202    * Returns <jk>true</jk> if this class is either {@link Double} or <jk>double</jk>.
1203    *
1204    * @return <jk>true</jk> if this class is either {@link Double} or <jk>double</jk>.
1205    */
1206   public boolean isDouble() {
1207      return innerClass == Double.class || innerClass == double.class;
1208   }
1209
1210   /**
1211    * Returns <jk>true</jk> if this class is either {@link Short} or <jk>short</jk>.
1212    *
1213    * @return <jk>true</jk> if this class is either {@link Short} or <jk>short</jk>.
1214    */
1215   public boolean isShort() {
1216      return innerClass == Short.class || innerClass == short.class;
1217   }
1218
1219   /**
1220    * Returns <jk>true</jk> if this class is either {@link Integer} or <jk>int</jk>.
1221    *
1222    * @return <jk>true</jk> if this class is either {@link Integer} or <jk>int</jk>.
1223    */
1224   public boolean isInteger() {
1225      return innerClass == Integer.class || innerClass == int.class;
1226   }
1227
1228   /**
1229    * Returns <jk>true</jk> if this class is either {@link Long} or <jk>long</jk>.
1230    *
1231    * @return <jk>true</jk> if this class is either {@link Long} or <jk>long</jk>.
1232    */
1233   public boolean isLong() {
1234      return innerClass == Long.class || innerClass == long.class;
1235   }
1236
1237   /**
1238    * Returns <jk>true</jk> if this metadata represents the specified type.
1239    *
1240    * @param c The class to test against.
1241    * @return <jk>true</jk> if this metadata represents the specified type.
1242    */
1243   public boolean isType(Class<?> c) {
1244      return info.isChildOf(c);
1245   }
1246
1247   /**
1248    * Returns <jk>true</jk> if this class is a {@link Boolean}.
1249    *
1250    * @return <jk>true</jk> if this class is a {@link Boolean}.
1251    */
1252   public boolean isBoolean() {
1253      return cc == BOOLEAN;
1254   }
1255
1256   /**
1257    * Returns <jk>true</jk> if this class is a subclass of {@link CharSequence}.
1258    *
1259    * @return <jk>true</jk> if this class is a subclass of {@link CharSequence}.
1260    */
1261   public boolean isCharSequence() {
1262      return cc == STR || cc == CHARSEQ;
1263   }
1264
1265   /**
1266    * Returns <jk>true</jk> if this class is a {@link String}.
1267    *
1268    * @return <jk>true</jk> if this class is a {@link String}.
1269    */
1270   public boolean isString() {
1271      return cc == STR;
1272   }
1273
1274   /**
1275    * Returns <jk>true</jk> if this class is a {@link Character}.
1276    *
1277    * @return <jk>true</jk> if this class is a {@link Character}.
1278    */
1279   public boolean isChar() {
1280      return cc == CHAR;
1281   }
1282
1283   /**
1284    * Returns <jk>true</jk> if this class is a primitive.
1285    *
1286    * @return <jk>true</jk> if this class is a primitive.
1287    */
1288   public boolean isPrimitive() {
1289      return innerClass.isPrimitive();
1290   }
1291
1292   /**
1293    * Returns <jk>true</jk> if this class is a {@link Date} or {@link Calendar}.
1294    *
1295    * @return <jk>true</jk> if this class is a {@link Date} or {@link Calendar}.
1296    */
1297   public boolean isDateOrCalendar() {
1298      return cc == DATE;
1299   }
1300
1301   /**
1302    * Returns <jk>true</jk> if this class is a {@link Date}.
1303    *
1304    * @return <jk>true</jk> if this class is a {@link Date}.
1305    */
1306   public boolean isDate() {
1307      return cc == DATE && info.isChildOf(Date.class);
1308   }
1309
1310   /**
1311    * Returns <jk>true</jk> if this class is a {@link Calendar}.
1312    *
1313    * @return <jk>true</jk> if this class is a {@link Calendar}.
1314    */
1315   public boolean isCalendar() {
1316      return cc == DATE && info.isChildOf(Calendar.class);
1317   }
1318
1319   /**
1320    * Returns <jk>true</jk> if this class is a {@link URI} or {@link URL}.
1321    *
1322    * @return <jk>true</jk> if this class is a {@link URI} or {@link URL}.
1323    */
1324   public boolean isUri() {
1325      return cc == URI;
1326   }
1327
1328   /**
1329    * Returns <jk>true</jk> if this class is a {@link Reader}.
1330    *
1331    * @return <jk>true</jk> if this class is a {@link Reader}.
1332    */
1333   public boolean isReader() {
1334      return cc == READER;
1335   }
1336
1337   /**
1338    * Returns <jk>true</jk> if this class is an {@link InputStream}.
1339    *
1340    * @return <jk>true</jk> if this class is an {@link InputStream}.
1341    */
1342   public boolean isInputStream() {
1343      return cc == INPUTSTREAM;
1344   }
1345
1346   /**
1347    * Returns <jk>true</jk> if this class is {@link Void} or <jk>void</jk>.
1348    *
1349    * @return <jk>true</jk> if this class is {@link Void} or <jk>void</jk>.
1350    */
1351   public boolean isVoid() {
1352      return cc == VOID;
1353   }
1354
1355   /**
1356    * Returns <jk>true</jk> if this metadata represents an array of argument types.
1357    *
1358    * @return <jk>true</jk> if this metadata represents an array of argument types.
1359    */
1360   public boolean isArgs() {
1361      return cc == ARGS;
1362   }
1363
1364   /**
1365    * Returns the argument types of this meta.
1366    *
1367    * @return The argument types of this meta, or <jk>null</jk> if this isn't an array of argument types.
1368    */
1369   public ClassMeta<?>[] getArgs() {
1370      return args;
1371   }
1372
1373   /**
1374    * Returns the argument metadata at the specified index if this is an args metadata object.
1375    *
1376    * @param index The argument index.
1377    * @return The The argument metadata.  Never <jk>null</jk>.
1378    * @throws BeanRuntimeException If this metadata object is not a list of arguments, or the index is out of range.
1379    */
1380   public ClassMeta<?> getArg(int index) {
1381      if (args != null && index >= 0 && index < args.length)
1382         return args[index];
1383      throw new BeanRuntimeException("Invalid argument index specified:  {0}.  Only {1} arguments are defined.", index, args == null ? 0 : args.length);
1384   }
1385
1386   /**
1387    * Returns <jk>true</jk> if instance of this object can be <jk>null</jk>.
1388    *
1389    * <p>
1390    * Objects can be <jk>null</jk>, but primitives cannot, except for chars which can be represented by
1391    * <code>(<jk>char</jk>)0</code>.
1392    *
1393    * @return <jk>true</jk> if instance of this class can be null.
1394    */
1395   public boolean isNullable() {
1396      if (innerClass.isPrimitive())
1397         return cc == CHAR;
1398      return true;
1399   }
1400
1401   /**
1402    * Returns <jk>true</jk> if this class is abstract.
1403    *
1404    * @return <jk>true</jk> if this class is abstract.
1405    */
1406   public boolean isAbstract() {
1407      return isAbstract;
1408   }
1409
1410   /**
1411    * Returns <jk>true</jk> if this class is an inner class.
1412    *
1413    * @return <jk>true</jk> if this class is an inner class.
1414    */
1415   public boolean isMemberClass() {
1416      return isMemberClass;
1417   }
1418
1419   /**
1420    * All public methods on this class including static methods.
1421    *
1422    * <p>
1423    * Keys are method signatures.
1424    *
1425    * @return The public methods on this class.
1426    */
1427   public Map<String,Method> getPublicMethods() {
1428      return publicMethods;
1429   }
1430
1431   /**
1432    * Returns the {@link PojoSwap} associated with this class that's the best match for the specified session.
1433    *
1434    * @param session
1435    *    The current bean session.
1436    *    <br>If multiple swaps are associated with a class, only the first one with a matching media type will
1437    *    be returned.
1438    * @return
1439    *    The {@link PojoSwap} associated with this class, or <jk>null</jk> if there are no POJO swaps associated with
1440    *    this class.
1441    */
1442   public PojoSwap<T,?> getPojoSwap(BeanSession session) {
1443      if (pojoSwaps != null) {
1444         int matchQuant = 0, matchIndex = -1;
1445
1446         for (int i = 0; i < pojoSwaps.length; i++) {
1447            int q = pojoSwaps[i].match(session);
1448            if (q > matchQuant) {
1449               matchQuant = q;
1450               matchIndex = i;
1451            }
1452         }
1453
1454         if (matchIndex > -1)
1455            return pojoSwaps[matchIndex];
1456      }
1457      return null;
1458   }
1459
1460   /**
1461    * Returns the builder swap associated with this class.
1462    *
1463    * @param session The current bean session.
1464    * @return The builder swap associated with this class, or <jk>null</jk> if it doesn't exist.
1465    */
1466   public BuilderSwap<T,?> getBuilderSwap(BeanSession session) {
1467      return builderSwap;
1468   }
1469
1470   /**
1471    * Returns the {@link BeanMeta} associated with this class.
1472    *
1473    * @return
1474    *    The {@link BeanMeta} associated with this class, or <jk>null</jk> if there is no bean meta associated with
1475    *    this class.
1476    */
1477   public BeanMeta<T> getBeanMeta() {
1478      return beanMeta;
1479   }
1480
1481   /**
1482    * Returns the no-arg constructor for this class.
1483    *
1484    * @return The no-arg constructor for this class, or <jk>null</jk> if it does not exist.
1485    */
1486   public ConstructorInfo getConstructor() {
1487      return noArgConstructor;
1488   }
1489
1490   /**
1491    * Returns the language-specified extended metadata on this class.
1492    *
1493    * @param c The name of the metadata class to create.
1494    * @return Extended metadata on this class.  Never <jk>null</jk>.
1495    */
1496   public <M extends ClassMetaExtended> M getExtendedMeta(Class<M> c) {
1497      return extMeta.get(c, this);
1498   }
1499
1500   /**
1501    * Returns the interface proxy invocation handler for this class.
1502    *
1503    * @return The interface proxy invocation handler, or <jk>null</jk> if it does not exist.
1504    */
1505   public InvocationHandler getProxyInvocationHandler() {
1506      return invocationHandler;
1507   }
1508
1509   /**
1510    * Returns <jk>true</jk> if this class has a no-arg constructor or invocation handler.
1511    *
1512    * @return <jk>true</jk> if a new instance of this class can be constructed.
1513    */
1514   public boolean canCreateNewInstance() {
1515      if (isMemberClass)
1516         return false;
1517      if (noArgConstructor != null)
1518         return true;
1519      if (getProxyInvocationHandler() != null)
1520         return true;
1521      if (isArray() && elementType.canCreateNewInstance())
1522         return true;
1523      return false;
1524   }
1525
1526   /**
1527    * Returns <jk>true</jk> if this class has a no-arg constructor or invocation handler.
1528    * Returns <jk>false</jk> if this is a non-static member class and the outer object does not match the class type of
1529    * the defining class.
1530    *
1531    * @param outer
1532    *    The outer class object for non-static member classes.  Can be <jk>null</jk> for non-member or static classes.
1533    * @return
1534    *    <jk>true</jk> if a new instance of this class can be created within the context of the specified outer object.
1535    */
1536   public boolean canCreateNewInstance(Object outer) {
1537      if (isMemberClass)
1538         return outer != null && noArgConstructor != null && noArgConstructor.hasParamTypes(outer.getClass());
1539      return canCreateNewInstance();
1540   }
1541
1542   /**
1543    * Returns <jk>true</jk> if this class can be instantiated as a bean.
1544    * Returns <jk>false</jk> if this is a non-static member class and the outer object does not match the class type of
1545    * the defining class.
1546    *
1547    * @param outer
1548    *    The outer class object for non-static member classes.  Can be <jk>null</jk> for non-member or static classes.
1549    * @return
1550    *    <jk>true</jk> if a new instance of this bean can be created within the context of the specified outer object.
1551    */
1552   public boolean canCreateNewBean(Object outer) {
1553      if (beanMeta == null)
1554         return false;
1555      if (beanMeta.constructor == null)
1556         return false;
1557      if (isMemberClass)
1558         return outer != null && beanMeta.constructor.hasParamTypes(outer.getClass());
1559      return true;
1560   }
1561
1562   /**
1563    * Returns <jk>true</jk> if this class can call the {@link #newInstanceFromString(Object, String)} method.
1564    *
1565    * @param outer
1566    *    The outer class object for non-static member classes.
1567    *    Can be <jk>null</jk> for non-member or static classes.
1568    * @return <jk>true</jk> if this class has a no-arg constructor or invocation handler.
1569    */
1570   public boolean canCreateNewInstanceFromString(Object outer) {
1571      if (fromStringMethod != null)
1572         return true;
1573      if (stringConstructor != null) {
1574         if (isMemberClass)
1575            return outer != null && stringConstructor.hasParamTypes(outer.getClass(), String.class);
1576         return true;
1577      }
1578      return false;
1579   }
1580
1581   /**
1582    * Returns the method or field annotated with {@link NameProperty @NameProperty}.
1583    *
1584    * @return
1585    *    The method or field  annotated with {@link NameProperty @NameProperty} or <jk>null</jk> if method does not
1586    *    exist.
1587    */
1588   public Setter getNameProperty() {
1589      return namePropertyMethod;
1590   }
1591
1592   /**
1593    * Returns the method or field annotated with {@link ParentProperty @ParentProperty}.
1594    *
1595    * @return
1596    *    The method or field annotated with {@link ParentProperty @ParentProperty} or <jk>null</jk> if method does not
1597    *    exist.
1598    */
1599   public Setter getParentProperty() {
1600      return parentPropertyMethod;
1601   }
1602
1603   /**
1604    * Returns the reason why this class is not a bean, or <jk>null</jk> if it is a bean.
1605    *
1606    * @return The reason why this class is not a bean, or <jk>null</jk> if it is a bean.
1607    */
1608   public synchronized String getNotABeanReason() {
1609      return notABeanReason;
1610   }
1611
1612   /**
1613    * Returns any exception that was throw in the <c>init()</c> method.
1614    *
1615    * @return The cached exception.
1616    */
1617   public Throwable getInitException() {
1618      return initException;
1619   }
1620
1621   /**
1622    * Returns the {@link BeanContext} that created this object.
1623    *
1624    * @return The bean context.
1625    */
1626   public BeanContext getBeanContext() {
1627      return beanContext;
1628   }
1629
1630   /**
1631    * Returns the default value for primitives such as <jk>int</jk> or <jk>Integer</jk>.
1632    *
1633    * @return The default value, or <jk>null</jk> if this class type is not a primitive.
1634    */
1635   @SuppressWarnings("unchecked")
1636   public T getPrimitiveDefault() {
1637      return (T)primitiveDefault;
1638   }
1639
1640   /**
1641    * Converts the specified object to a string.
1642    *
1643    * @param t The object to convert.
1644    * @return The object converted to a string, or <jk>null</jk> if the object was null.
1645    */
1646   public String toString(Object t) {
1647      if (t == null)
1648         return null;
1649      if (isEnum() && beanContext.isUseEnumNames())
1650         return ((Enum<?>)t).name();
1651      return t.toString();
1652   }
1653
1654   /**
1655    * Create a new instance of the main class of this declared type from a <c>String</c> input.
1656    *
1657    * <p>
1658    * In order to use this method, the class must have one of the following methods:
1659    * <ul>
1660    *    <li><code><jk>public static</jk> T valueOf(String in);</code>
1661    *    <li><code><jk>public static</jk> T fromString(String in);</code>
1662    *    <li><code><jk>public</jk> T(String in);</code>
1663    * </ul>
1664    *
1665    * @param outer
1666    *    The outer class object for non-static member classes.  Can be <jk>null</jk> for non-member or static classes.
1667    * @param arg The input argument value.
1668    * @return A new instance of the object, or <jk>null</jk> if there is no string constructor on the object.
1669    * @throws ExecutableException Exception occurred on invoked constructor/method/field.
1670    */
1671   @SuppressWarnings({ "unchecked", "rawtypes" })
1672   public T newInstanceFromString(Object outer, String arg) throws ExecutableException {
1673
1674      if (isEnum() && beanContext.isUseEnumNames() && fromStringMethod != null)
1675         return (T)Enum.valueOf((Class<? extends Enum>)this.innerClass, arg);
1676
1677      Method m = fromStringMethod;
1678      if (m != null) {
1679         try {
1680            return (T)m.invoke(null, arg);
1681         } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
1682            throw new ExecutableException(e);
1683         }
1684      }
1685      ConstructorInfo c = stringConstructor;
1686      if (c != null) {
1687         if (isMemberClass)
1688            return c.<T>invoke(outer, arg);
1689         return c.<T>invoke(arg);
1690      }
1691      throw new InstantiationError("No string constructor or valueOf(String) method found for class '"+getInnerClass().getName()+"'");
1692   }
1693
1694   /**
1695    * Create a new instance of the main class of this declared type.
1696    *
1697    * @return A new instance of the object, or <jk>null</jk> if there is no no-arg constructor on the object.
1698    * @throws ExecutableException Exception occurred on invoked constructor/method/field.
1699    */
1700   @SuppressWarnings("unchecked")
1701   public T newInstance() throws ExecutableException {
1702      if (isArray())
1703         return (T)Array.newInstance(getInnerClass().getComponentType(), 0);
1704      ConstructorInfo c = getConstructor();
1705      if (c != null)
1706         return c.<T>invoke((Object[])null);
1707      InvocationHandler h = getProxyInvocationHandler();
1708      if (h != null)
1709         return (T)Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[] { getInnerClass(), java.io.Serializable.class }, h);
1710      if (isArray())
1711         return (T)Array.newInstance(this.elementType.innerClass,0);
1712      return null;
1713   }
1714
1715   /**
1716    * Same as {@link #newInstance()} except for instantiating non-static member classes.
1717    *
1718    * @param outer
1719    *    The instance of the owning object of the member class instance.
1720    *    Can be <jk>null</jk> if instantiating a non-member or static class.
1721    * @return A new instance of the object, or <jk>null</jk> if there is no no-arg constructor on the object.
1722    * @throws ExecutableException Exception occurred on invoked constructor/method/field.
1723    */
1724   public T newInstance(Object outer) throws ExecutableException {
1725      if (isMemberClass)
1726         return noArgConstructor.<T>invoke(outer);
1727      return newInstance();
1728   }
1729
1730   /**
1731    * Checks to see if the specified class type is the same as this one.
1732    *
1733    * @param t The specified class type.
1734    * @return <jk>true</jk> if the specified class type is the same as the class for this type.
1735    */
1736   @Override /* Object */
1737   public boolean equals(Object t) {
1738      if (t == null || ! (t instanceof ClassMeta))
1739         return false;
1740      ClassMeta<?> t2 = (ClassMeta<?>)t;
1741      return t2.getInnerClass() == this.getInnerClass();
1742   }
1743
1744   /**
1745    * Similar to {@link #equals(Object)} except primitive and Object types that are similar are considered the same.
1746    * (e.g. <jk>boolean</jk> == <c>Boolean</c>).
1747    *
1748    * @param cm The class meta to compare to.
1749    * @return <jk>true</jk> if the specified class-meta is equivalent to this one.
1750    */
1751   public boolean same(ClassMeta<?> cm) {
1752      if (equals(cm))
1753         return true;
1754      return (isPrimitive() && cc == cm.cc);
1755   }
1756
1757   @Override /* Object */
1758   public String toString() {
1759      return toString(false);
1760   }
1761
1762   /**
1763    * Same as {@link #toString()} except use simple class names.
1764    *
1765    * @param simple Print simple class names only (no package).
1766    * @return A new string.
1767    */
1768   public String toString(boolean simple) {
1769      return toString(new StringBuilder(), simple).toString();
1770   }
1771
1772   /**
1773    * Appends this object as a readable string to the specified string builder.
1774    *
1775    * @param sb The string builder to append this object to.
1776    * @param simple Print simple class names only (no package).
1777    * @return The same string builder passed in (for method chaining).
1778    */
1779   protected StringBuilder toString(StringBuilder sb, boolean simple) {
1780      String n = innerClass.getName();
1781      if (simple) {
1782         int i = n.lastIndexOf('.');
1783         n = n.substring(i == -1 ? 0 : i+1).replace('$', '.');
1784      }
1785      if (cc == ARRAY)
1786         return elementType.toString(sb, simple).append('[').append(']');
1787      if (cc == MAP)
1788         return sb.append(n).append(keyType.isObject() && valueType.isObject() ? "" : "<"+keyType.toString(simple)+","+valueType.toString(simple)+">");
1789      if (cc == BEANMAP)
1790         return sb.append(BeanMap.class.getName()).append('<').append(n).append('>');
1791      if (cc == COLLECTION)
1792         return sb.append(n).append(elementType.isObject() ? "" : "<"+elementType.toString(simple)+">");
1793      return sb.append(n);
1794   }
1795
1796   /**
1797    * Returns <jk>true</jk> if the specified object is an instance of this class.
1798    *
1799    * <p>
1800    * This is a simple comparison on the base class itself and not on any generic parameters.
1801    *
1802    * @param o The object to check.
1803    * @return <jk>true</jk> if the specified object is an instance of this class.
1804    */
1805   public boolean isInstance(Object o) {
1806      if (o != null)
1807         return info.isParentOf(o.getClass()) || (isPrimitive() && info.getPrimitiveWrapper() == o.getClass());
1808      return false;
1809   }
1810
1811   /**
1812    * Returns a readable name for this class (e.g. <js>"java.lang.String"</js>, <js>"boolean[]"</js>).
1813    *
1814    * @return The readable name for this class.
1815    */
1816   public String getFullName() {
1817      return info.getFullName();
1818   }
1819
1820   /**
1821    * Shortcut for calling {@link Class#getName()} on the inner class of this metadata.
1822    *
1823    * @return The  name of the inner class.
1824    */
1825   public String getName() {
1826      return innerClass.getName();
1827   }
1828
1829   /**
1830    * Shortcut for calling {@link Class#getSimpleName()} on the inner class of this metadata.
1831    *
1832    * @return The simple name of the inner class.
1833    */
1834   public String getSimpleName() {
1835      return innerClass.getSimpleName();
1836   }
1837
1838   @Override /* Object */
1839   public int hashCode() {
1840      return super.hashCode();
1841   }
1842
1843   /**
1844    * Returns <jk>true</jk> if this class has a transform associated with it that allows it to be created from a Reader.
1845    *
1846    * @return <jk>true</jk> if this class has a transform associated with it that allows it to be created from a Reader.
1847    */
1848   public boolean hasReaderMutater() {
1849      return hasMutaterFrom(Reader.class);
1850   }
1851
1852   /**
1853    * Returns the transform for this class for creating instances from a Reader.
1854    *
1855    * @return The transform, or <jk>null</jk> if no such transform exists.
1856    */
1857   public Mutater<Reader,T> getReaderMutater() {
1858      return getFromMutater(Reader.class);
1859   }
1860
1861   /**
1862    * Returns <jk>true</jk> if this class has a transform associated with it that allows it to be created from an InputStream.
1863    *
1864    * @return <jk>true</jk> if this class has a transform associated with it that allows it to be created from an InputStream.
1865    */
1866   public boolean hasInputStreamMutater() {
1867      return hasMutaterFrom(InputStream.class);
1868   }
1869
1870   /**
1871    * Returns the transform for this class for creating instances from an InputStream.
1872    *
1873    * @return The transform, or <jk>null</jk> if no such transform exists.
1874    */
1875   public Mutater<InputStream,T> getInputStreamMutater() {
1876      return getFromMutater(InputStream.class);
1877   }
1878
1879   /**
1880    * Returns <jk>true</jk> if this class has a transform associated with it that allows it to be created from a String.
1881    *
1882    * @return <jk>true</jk> if this class has a transform associated with it that allows it to be created from a String.
1883    */
1884   public boolean hasStringMutater() {
1885      return stringMutater != null;
1886   }
1887
1888   /**
1889    * Returns the transform for this class for creating instances from a String.
1890    *
1891    * @return The transform, or <jk>null</jk> if no such transform exists.
1892    */
1893   public Mutater<String,T> getStringMutater() {
1894      return stringMutater;
1895   }
1896
1897   /**
1898    * Returns <jk>true</jk> if this class can be instantiated from the specified type.
1899    *
1900    * @param c The class type to convert from.
1901    * @return <jk>true</jk> if this class can be instantiated from the specified type.
1902    */
1903   public boolean hasMutaterFrom(Class<?> c) {
1904      return getFromMutater(c) != null;
1905   }
1906
1907   /**
1908    * Returns <jk>true</jk> if this class can be instantiated from the specified type.
1909    *
1910    * @param c The class type to convert from.
1911    * @return <jk>true</jk> if this class can be instantiated from the specified type.
1912    */
1913   public boolean hasMutaterFrom(ClassMeta<?> c) {
1914      return getFromMutater(c.getInnerClass()) != null;
1915   }
1916
1917   /**
1918    * Returns <jk>true</jk> if this class can be transformed to the specified type.
1919    *
1920    * @param c The class type to convert from.
1921    * @return <jk>true</jk> if this class can be transformed to the specified type.
1922    */
1923   public boolean hasMutaterTo(Class<?> c) {
1924      return getToMutater(c) != null;
1925   }
1926
1927   /**
1928    * Returns <jk>true</jk> if this class can be transformed to the specified type.
1929    *
1930    * @param c The class type to convert from.
1931    * @return <jk>true</jk> if this class can be transformed to the specified type.
1932    */
1933   public boolean hasMutaterTo(ClassMeta<?> c) {
1934      return getToMutater(c.getInnerClass()) != null;
1935   }
1936
1937   /**
1938    * Transforms the specified object into an instance of this class.
1939    *
1940    * @param o The object to transform.
1941    * @return The transformed object.
1942    */
1943   @SuppressWarnings({"unchecked","rawtypes"})
1944   public T mutateFrom(Object o) {
1945      Mutater t = getFromMutater(o.getClass());
1946      return (T)(t == null ? null : t.mutate(o));
1947   }
1948
1949   /**
1950    * Transforms the specified object into an instance of this class.
1951    *
1952    * @param o The object to transform.
1953    * @param c The class
1954    * @return The transformed object.
1955    */
1956   @SuppressWarnings({"unchecked","rawtypes"})
1957   public <O> O mutateTo(Object o, Class<O> c) {
1958      Mutater t = getToMutater(c);
1959      return (O)(t == null ? null : t.mutate(o));
1960   }
1961
1962   /**
1963    * Transforms the specified object into an instance of this class.
1964    *
1965    * @param o The object to transform.
1966    * @param c The class
1967    * @return The transformed object.
1968    */
1969   public <O> O mutateTo(Object o, ClassMeta<O> c) {
1970      return mutateTo(o, c.getInnerClass());
1971   }
1972
1973   /**
1974    * Returns the transform for this class for creating instances from other object types.
1975    *
1976    * @param c The transform-from class.
1977    * @return The transform, or <jk>null</jk> if no such transform exists.
1978    */
1979   @SuppressWarnings({ "rawtypes", "unchecked" })
1980   public <I> Mutater<I,T> getFromMutater(Class<I> c) {
1981      Mutater t = fromMutaters.get(c);
1982      if (t == Mutaters.NULL)
1983         return null;
1984      if (t == null) {
1985         t = Mutaters.get(c, innerClass);
1986         if (t == null)
1987            t = Mutaters.NULL;
1988         fromMutaters.put(c, t);
1989      }
1990      return t == Mutaters.NULL ? null : t;
1991   }
1992
1993   /**
1994    * Returns the transform for this class for creating instances from other object types.
1995    *
1996    * @param c The transform-from class.
1997    * @return The transform, or <jk>null</jk> if no such transform exists.
1998    */
1999   @SuppressWarnings({ "rawtypes", "unchecked" })
2000   public <O> Mutater<T,O> getToMutater(Class<O> c) {
2001      Mutater t = toMutaters.get(c);
2002      if (t == Mutaters.NULL)
2003         return null;
2004      if (t == null) {
2005         t = Mutaters.get(innerClass, c);
2006         if (t == null)
2007            t = Mutaters.NULL;
2008         toMutaters.put(c, t);
2009      }
2010      return t == Mutaters.NULL ? null : t;
2011   }
2012
2013   /**
2014    * Shortcut for calling <code>getInnerClass().getAnnotation(a) != <jk>null</jk></code>.
2015    *
2016    * @param a The annotation to check for.
2017    * @return <jk>true</jk> if the inner class has the annotation.
2018    */
2019   public boolean hasAnnotation(Class<? extends Annotation> a) {
2020      return getAnnotation(a) != null;
2021   }
2022
2023   /**
2024    * Shortcut for calling <c>getInnerClass().getAnnotation(a)</c>.
2025    *
2026    * @param a The annotation to retrieve.
2027    * @return The specified annotation, or <jk>null</jk> if the class does not have the specified annotation.
2028    */
2029   public <A extends Annotation> A getAnnotation(Class<A> a) {
2030      return this.innerClass.getAnnotation(a);
2031   }
2032}