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