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