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