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