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