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