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