001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau;
014
015import static org.apache.juneau.ClassMeta.ClassCategory.*;
016import static org.apache.juneau.internal.ClassUtils.*;
017import static org.apache.juneau.internal.ReflectionUtils.*;
018
019import java.io.*;
020import java.lang.reflect.*;
021import java.lang.reflect.Proxy;
022import java.net.*;
023import java.net.URI;
024import java.util.*;
025import java.util.Date;
026import java.util.concurrent.*;
027import java.util.concurrent.locks.*;
028
029import org.apache.juneau.annotation.*;
030import org.apache.juneau.http.*;
031import org.apache.juneau.internal.*;
032import org.apache.juneau.parser.*;
033import org.apache.juneau.remoteable.*;
034import org.apache.juneau.serializer.*;
035import org.apache.juneau.transform.*;
036import org.apache.juneau.utils.*;
037
038/**
039 * A wrapper class around the {@link Class} object that provides cached information about that class.
040 * 
041 * <p>
042 * Instances of this class can be created through the {@link BeanContext#getClassMeta(Class)} method.
043 * 
044 * <p>
045 * The {@link BeanContext} class will cache and reuse instances of this class except for the following class types:
046 * <ul>
047 *    <li>Arrays
048 *    <li>Maps with non-Object key/values.
049 *    <li>Collections with non-Object key/values.
050 * </ul>
051 * 
052 * <p>
053 * This class is tied to the {@link BeanContext} class because it's that class that makes the determination of what is
054 * a bean.
055 * 
056 * @param <T> The class type of the wrapped class.
057 */
058@Bean(properties="innerClass,classCategory,elementType,keyType,valueType,notABeanReason,initException,beanMeta")
059public final class ClassMeta<T> implements Type {
060
061   /** Class categories. */
062   enum ClassCategory {
063      MAP, COLLECTION, CLASS, METHOD, NUMBER, DECIMAL, BOOLEAN, CHAR, DATE, ARRAY, ENUM, OTHER, CHARSEQ, STR, OBJ, URI, BEANMAP, READER, INPUTSTREAM, VOID, ARGS
064   }
065
066   final Class<T> innerClass;                              // The class being wrapped.
067
068   private final Class<? extends T> implClass;             // The implementation class to use if this is an interface.
069   private final ClassCategory cc;                         // The class category.
070   private final Method fromStringMethod;                  // The static valueOf(String) or fromString(String) or forString(String) method (if it has one).
071   private final Constructor<? extends T>
072      noArgConstructor;                                    // The no-arg constructor for this class (if it has one).
073   private final Constructor<T>
074      stringConstructor,                                   // The X(String) constructor (if it has one).
075      numberConstructor,                                   // The X(Number) constructor (if it has one).
076      swapConstructor;                                     // The X(Swappable) constructor (if it has one).
077   private final Class<?>
078      swapMethodType,                                      // The class type of the object in the number constructor.
079      numberConstructorType;
080   private final Method
081      swapMethod,                                          // The swap() method (if it has one).
082      unswapMethod;                                        // The unswap() method (if it has one).
083   private final Setter
084      namePropertyMethod,                                  // The method to set the name on an object (if it has one).
085      parentPropertyMethod;                                // The method to set the parent on an object (if it has one).
086   private final boolean
087      isDelegate,                                          // True if this class extends Delegate.
088      isAbstract,                                          // True if this class is abstract.
089      isMemberClass;                                       // True if this is a non-static member class.
090   private final Object primitiveDefault;                  // Default value for primitive type classes.
091   private final Map<String,Method>
092      remoteableMethods,                                   // Methods annotated with @RemoteMethod.
093      publicMethods;                                       // All public methods, including static methods.
094   private final PojoSwap<?,?>[] childPojoSwaps;           // Any PojoSwaps where the normal type is a subclass of this class.
095   private final ConcurrentHashMap<Class<?>,PojoSwap<?,?>>
096      childSwapMap,                                        // Maps normal subclasses to PojoSwaps.
097      childUnswapMap;                                      // Maps swap subclasses to PojoSwaps.
098   private final PojoSwap<T,?>[] pojoSwaps;                // The object POJO swaps associated with this bean (if it has any).
099   private final BeanFilter beanFilter;                    // The bean filter associated with this bean (if it has one).
100   private final BuilderSwap<T,?> builderSwap;             // The builder swap associated with this bean (if it has one).
101   private final MetadataMap extMeta;                      // Extended metadata
102   private final BeanContext beanContext;                  // The bean context that created this object.
103   private final ClassMeta<?>
104      elementType,                                         // If ARRAY or COLLECTION, the element class type.
105      keyType,                                             // If MAP, the key class type.
106      valueType;                                           // If MAP, the value class type.
107   private final BeanMeta<T> beanMeta;                     // The bean meta for this bean class (if it's a bean).
108   private final String
109      typePropertyName,                                    // The property name of the _type property for this class and subclasses.
110      notABeanReason,                                      // If this isn't a bean, the reason why.
111      dictionaryName;                                      // The dictionary name of this class if it has one.
112   private final Throwable initException;                  // Any exceptions thrown in the init() method.
113   private final InvocationHandler invocationHandler;      // The invocation handler for this class (if it has one).
114   private final BeanRegistry beanRegistry;                // The bean registry of this class meta (if it has one).
115   private final ClassMeta<?>[] args;                      // Arg types if this is an array of args.
116
117   private ReadWriteLock lock = new ReentrantReadWriteLock(false);
118   private Lock rLock = lock.readLock(), wLock = lock.writeLock();
119
120   /**
121    * Construct a new {@code ClassMeta} based on the specified {@link Class}.
122    * 
123    * @param innerClass The class being wrapped.
124    * @param beanContext The bean context that created this object.
125    * @param implClass
126    *    For interfaces and abstract classes, this represents the "real" class to instantiate.
127    *    Can be <jk>null</jk>.
128    * @param beanFilter
129    *    The {@link BeanFilter} programmatically associated with this class.
130    *    Can be <jk>null</jk>.
131    * @param pojoSwap
132    *    The {@link PojoSwap} programmatically associated with this class.
133    *    Can be <jk>null</jk>.
134    * @param childPojoSwap
135    *    The child {@link PojoSwap PojoSwaps} programmatically associated with this class.
136    *    These are the <code>PojoSwaps</code> that have normal classes that are subclasses of this class.
137    *    Can be <jk>null</jk>.
138    * @param delayedInit
139    *    Don't call init() in constructor.
140    *    Used for delayed initialization when the possibility of class reference loops exist.
141    */
142   @SuppressWarnings({ "rawtypes", "unchecked" })
143   ClassMeta(Class<T> innerClass, BeanContext beanContext, Class<? extends T> implClass, BeanFilter beanFilter, PojoSwap<T,?>[] pojoSwaps, PojoSwap<?,?>[] childPojoSwaps) {
144      this.innerClass = innerClass;
145      this.beanContext = beanContext;
146
147      wLock.lock();
148      try {
149         // We always immediately add this class meta to the bean context cache so that we can resolve recursive references.
150         if (beanContext != null && beanContext.cmCache != null)
151            beanContext.cmCache.put(innerClass, this);
152
153         ClassMetaBuilder<T> builder = new ClassMetaBuilder(innerClass, beanContext, implClass, beanFilter, pojoSwaps, childPojoSwaps);
154
155         this.cc = builder.cc;
156         this.isDelegate = builder.isDelegate;
157         this.fromStringMethod = builder.fromStringMethod;
158         this.swapMethod = builder.swapMethod;
159         this.unswapMethod = builder.unswapMethod;
160         this.swapMethodType = builder.swapMethodType;
161         this.parentPropertyMethod = builder.parentPropertyMethod;
162         this.namePropertyMethod = builder.namePropertyMethod;
163         this.noArgConstructor = builder.noArgConstructor;
164         this.stringConstructor = builder.stringConstructor;
165         this.swapConstructor = builder.swapConstructor;
166         this.numberConstructor = builder.numberConstructor;
167         this.numberConstructorType = builder.numberConstructorType;
168         this.primitiveDefault = builder.primitiveDefault;
169         this.publicMethods = builder.publicMethods;
170         this.remoteableMethods = builder.remoteableMethods;
171         this.beanFilter = beanFilter;
172         this.pojoSwaps = builder.pojoSwaps.isEmpty() ? null : builder.pojoSwaps.toArray(new PojoSwap[builder.pojoSwaps.size()]);
173         this.builderSwap = builder.builderSwap;
174         this.extMeta = new MetadataMap();
175         this.keyType = builder.keyType;
176         this.valueType = builder.valueType;
177         this.elementType = builder.elementType;
178         this.notABeanReason = builder.notABeanReason;
179         this.beanMeta = builder.beanMeta;
180         this.initException = builder.initException;
181         this.typePropertyName = builder.typePropertyName;
182         this.dictionaryName = builder.dictionaryName;
183         this.invocationHandler = builder.invocationHandler;
184         this.beanRegistry = builder.beanRegistry;
185         this.isMemberClass = builder.isMemberClass;
186         this.isAbstract = builder.isAbstract;
187         this.implClass = builder.implClass;
188         this.childUnswapMap = builder.childUnswapMap;
189         this.childSwapMap = builder.childSwapMap;
190         this.childPojoSwaps = builder.childPojoSwaps;
191         this.args = null;
192      } finally {
193         wLock.unlock();
194      }
195   }
196
197   /**
198    * Causes thread to wait until constructor has exited.
199    */
200   final void waitForInit() {
201      rLock.lock();
202      rLock.unlock();
203   }
204
205   /**
206    * Copy constructor.
207    * 
208    * <p>
209    * Used for creating Map and Collection class metas that shouldn't be cached.
210    */
211   ClassMeta(ClassMeta<T> mainType, ClassMeta<?> keyType, ClassMeta<?> valueType, ClassMeta<?> elementType) {
212      this.innerClass = mainType.innerClass;
213      this.implClass = mainType.implClass;
214      this.childPojoSwaps = mainType.childPojoSwaps;
215      this.childSwapMap = mainType.childSwapMap;
216      this.childUnswapMap = mainType.childUnswapMap;
217      this.cc = mainType.cc;
218      this.fromStringMethod = mainType.fromStringMethod;
219      this.noArgConstructor = mainType.noArgConstructor;
220      this.stringConstructor = mainType.stringConstructor;
221      this.numberConstructor = mainType.numberConstructor;
222      this.swapConstructor = mainType.swapConstructor;
223      this.swapMethodType = mainType.swapMethodType;
224      this.numberConstructorType = mainType.numberConstructorType;
225      this.swapMethod = mainType.swapMethod;
226      this.unswapMethod = mainType.unswapMethod;
227      this.namePropertyMethod = mainType.namePropertyMethod;
228      this.parentPropertyMethod = mainType.parentPropertyMethod;
229      this.isDelegate = mainType.isDelegate;
230      this.isAbstract = mainType.isAbstract;
231      this.isMemberClass = mainType.isMemberClass;
232      this.primitiveDefault = mainType.primitiveDefault;
233      this.remoteableMethods = mainType.remoteableMethods;
234      this.publicMethods = mainType.publicMethods;
235      this.beanContext = mainType.beanContext;
236      this.elementType = elementType;
237      this.keyType = keyType;
238      this.valueType = valueType;
239      this.invocationHandler = mainType.invocationHandler;
240      this.beanMeta = mainType.beanMeta;
241      this.typePropertyName = mainType.typePropertyName;
242      this.dictionaryName = mainType.dictionaryName;
243      this.notABeanReason = mainType.notABeanReason;
244      this.pojoSwaps = mainType.pojoSwaps;
245      this.builderSwap = mainType.builderSwap;
246      this.beanFilter = mainType.beanFilter;
247      this.extMeta = mainType.extMeta;
248      this.initException = mainType.initException;
249      this.beanRegistry = mainType.beanRegistry;
250      this.args = null;
251   }
252
253   /**
254    * Constructor for args-arrays.
255    */
256   @SuppressWarnings("unchecked")
257   ClassMeta(ClassMeta<?>[] args) {
258      this.innerClass = (Class<T>) Object[].class;
259      this.args = args;
260      this.implClass = null;
261      this.childPojoSwaps = null;
262      this.childSwapMap = null;
263      this.childUnswapMap = null;
264      this.cc = ARGS;
265      this.fromStringMethod = null;
266      this.noArgConstructor = null;
267      this.stringConstructor = null;
268      this.numberConstructor = null;
269      this.swapConstructor = null;
270      this.swapMethodType = null;
271      this.numberConstructorType = null;
272      this.swapMethod = null;
273      this.unswapMethod = null;
274      this.namePropertyMethod = null;
275      this.parentPropertyMethod = null;
276      this.isDelegate = false;
277      this.isAbstract = false;
278      this.isMemberClass = false;
279      this.primitiveDefault = null;
280      this.remoteableMethods = null;
281      this.publicMethods = null;
282      this.beanContext = null;
283      this.elementType = null;
284      this.keyType = null;
285      this.valueType = null;
286      this.invocationHandler = null;
287      this.beanMeta = null;
288      this.typePropertyName = null;
289      this.dictionaryName = null;
290      this.notABeanReason = null;
291      this.pojoSwaps = null;
292      this.builderSwap = null;
293      this.beanFilter = null;
294      this.extMeta = new MetadataMap();
295      this.initException = null;
296      this.beanRegistry = null;
297   }
298
299   @SuppressWarnings({"unchecked","rawtypes","hiding"})
300   private final class ClassMetaBuilder<T> {
301      Class<T> innerClass;
302      Class<? extends T> implClass;
303      BeanContext beanContext;
304      ClassCategory cc = ClassCategory.OTHER;
305      boolean
306         isDelegate = false,
307         isMemberClass = false,
308         isAbstract = false;
309      Method
310         fromStringMethod = null,
311         swapMethod = null,
312         unswapMethod = null;
313      Setter
314         parentPropertyMethod = null,
315         namePropertyMethod = null;
316      Constructor<T>
317         noArgConstructor = null,
318         stringConstructor = null,
319         swapConstructor = null,
320         numberConstructor = null;
321      Class<?>
322         swapMethodType = null,
323         numberConstructorType = null;
324      Object primitiveDefault = null;
325      Map<String,Method>
326         publicMethods = new LinkedHashMap<>(),
327         remoteableMethods = new LinkedHashMap<>();
328      ClassMeta<?>
329         keyType = null,
330         valueType = null,
331         elementType = null;
332      String
333         typePropertyName = null,
334         notABeanReason = null,
335         dictionaryName = null;
336      Throwable initException = null;
337      BeanMeta beanMeta = null;
338      List<PojoSwap> pojoSwaps = new ArrayList<>();
339      BuilderSwap builderSwap;
340      InvocationHandler invocationHandler = null;
341      BeanRegistry beanRegistry = null;
342      PojoSwap<?,?>[] childPojoSwaps;
343      ConcurrentHashMap<Class<?>,PojoSwap<?,?>>
344         childSwapMap,
345         childUnswapMap;
346
347      ClassMetaBuilder(Class<T> innerClass, BeanContext beanContext, Class<? extends T> implClass, BeanFilter beanFilter, PojoSwap<T,?>[] pojoSwaps, PojoSwap<?,?>[] childPojoSwaps) {
348         this.innerClass = innerClass;
349         this.beanContext = beanContext;
350
351         this.implClass = implClass;
352         this.childPojoSwaps = childPojoSwaps;
353         this.childSwapMap = childPojoSwaps == null ? null : new ConcurrentHashMap<Class<?>,PojoSwap<?,?>>();
354         this.childUnswapMap = childPojoSwaps == null ? null : new ConcurrentHashMap<Class<?>,PojoSwap<?,?>>();
355
356         Class<T> c = innerClass;
357         if (c.isPrimitive()) {
358            if (c == Boolean.TYPE)
359               cc = BOOLEAN;
360            else if (c == Byte.TYPE || c == Short.TYPE || c == Integer.TYPE || c == Long.TYPE || c == Float.TYPE || c == Double.TYPE) {
361               if (c == Float.TYPE || c == Double.TYPE)
362                  cc = DECIMAL;
363               else
364                  cc = NUMBER;
365            }
366            else if (c == Character.TYPE)
367               cc = CHAR;
368            else if (c == void.class || c == Void.class)
369               cc = VOID;
370         } else {
371            if (isParentClass(Delegate.class, c))
372               isDelegate = true;
373
374            if (c == Object.class)
375               cc = OBJ;
376            else if (c.isEnum())
377               cc = ENUM;
378            else if (c.equals(Class.class))
379               cc = CLASS;
380            else if (isParentClass(Method.class, c))
381               cc = METHOD;
382            else if (isParentClass(CharSequence.class, c)) {
383               if (c.equals(String.class))
384                  cc = STR;
385               else
386                  cc = CHARSEQ;
387            }
388            else if (isParentClass(Number.class, c)) {
389               if (isParentClass(Float.class, c) || isParentClass(Double.class, c))
390                  cc = DECIMAL;
391               else
392                  cc = NUMBER;
393            }
394            else if (isParentClass(Collection.class, c))
395               cc = COLLECTION;
396            else if (isParentClass(Map.class, c)) {
397               if (isParentClass(BeanMap.class, c))
398                  cc = BEANMAP;
399               else
400                  cc = MAP;
401            }
402            else if (c == Character.class)
403               cc = CHAR;
404            else if (c == Boolean.class)
405               cc = BOOLEAN;
406            else if (isParentClass(Date.class, c) || isParentClass(Calendar.class, c))
407               cc = DATE;
408            else if (c.isArray())
409               cc = ARRAY;
410            else if (isParentClass(URL.class, c) || isParentClass(URI.class, c) || c.isAnnotationPresent(org.apache.juneau.annotation.URI.class))
411               cc = URI;
412            else if (isParentClass(Reader.class, c))
413               cc = READER;
414            else if (isParentClass(InputStream.class, c))
415               cc = INPUTSTREAM;
416         }
417
418         isMemberClass = c.isMemberClass() && ! isStatic(c);
419
420         // Find static fromString(String) or equivalent method.
421         // fromString() must be checked before valueOf() so that Enum classes can create their own
422         //    specialized fromString() methods to override the behavior of Enum.valueOf(String).
423         // valueOf() is used by enums.
424         // parse() is used by the java logging Level class.
425         // forName() is used by Class and Charset
426         for (String methodName : new String[]{"fromString","fromValue","valueOf","parse","parseString","forName","forString"}) {
427            if (fromStringMethod == null) {
428               for (Method m : c.getMethods()) {
429                  if (isStatic(m) && isPublic(m) && isNotDeprecated(m)) {
430                     String mName = m.getName();
431                     if (mName.equals(methodName) && m.getReturnType() == c) {
432                        Class<?>[] args = m.getParameterTypes();
433                        if (args.length == 1 && args[0] == String.class) {
434                           fromStringMethod = m;
435                           break;
436                        }
437                     }
438                  }
439               }
440            }
441         }
442
443         // Special cases
444         try {
445            if (c == TimeZone.class)
446               fromStringMethod = c.getMethod("getTimeZone", String.class);
447            else if (c == Locale.class)
448               fromStringMethod = LocaleAsString.class.getMethod("fromString", String.class);
449         } catch (NoSuchMethodException e1) {}
450
451         // Find swap() method if present.
452         for (Method m : c.getMethods()) {
453            if (isPublic(m) && isNotDeprecated(m) && ! isStatic(m)) {
454               String mName = m.getName();
455               if (mName.equals("swap")) {
456                  Class<?>[] pt = m.getParameterTypes();
457                  if (pt.length == 1 && pt[0] == BeanSession.class) {
458                     swapMethod = m;
459                     swapMethodType = m.getReturnType();
460                     break;
461                  }
462               }
463            }
464         }
465         // Find unswap() method if present.
466         if (swapMethod != null) {
467            for (Method m : c.getMethods()) {
468               if (isPublic(m) && isNotDeprecated(m) && isStatic(m)) {
469                  String mName = m.getName();
470                  if (mName.equals("unswap")) {
471                     Class<?>[] pt = m.getParameterTypes();
472                     if (pt.length == 2 && pt[0] == BeanSession.class && pt[1] == swapMethodType) {
473                        unswapMethod = m;
474                        break;
475                     }
476                  }
477               }
478            }
479         }
480
481         for (Field f : getAllFields(c, true)) {
482            if (f.isAnnotationPresent(ParentProperty.class)) {
483               f.setAccessible(true);
484               parentPropertyMethod = new Setter.FieldSetter(f);
485            }
486            if (f.isAnnotationPresent(NameProperty.class)) {
487               f.setAccessible(true);
488               namePropertyMethod = new Setter.FieldSetter(f);
489            }
490         }
491
492         // Find @NameProperty and @ParentProperty methods if present.
493         for (Method m : getAllMethods(c, true)) {
494            if (m.isAnnotationPresent(ParentProperty.class) && m.getParameterTypes().length == 1) {
495               m.setAccessible(true);
496               parentPropertyMethod = new Setter.MethodSetter(m);
497            }
498            if (m.isAnnotationPresent(NameProperty.class) && m.getParameterTypes().length == 1) {
499               m.setAccessible(true);
500               namePropertyMethod = new Setter.MethodSetter(m);
501            }
502         }
503
504         // Note:  Primitive types are normally abstract.
505         isAbstract = Modifier.isAbstract(c.getModifiers()) && ! c.isPrimitive();
506
507         // Find constructor(String) method if present.
508         for (Constructor cs : c.getConstructors()) {
509            if (isPublic(cs) && isNotDeprecated(cs)) {
510               Class<?>[] args = cs.getParameterTypes();
511               if (args.length == (isMemberClass ? 1 : 0) && c != Object.class && ! isAbstract) {
512                  noArgConstructor = cs;
513               } else if (args.length == (isMemberClass ? 2 : 1)) {
514                  Class<?> arg = args[(isMemberClass ? 1 : 0)];
515                  if (arg == String.class)
516                     stringConstructor = cs;
517                  else if (swapMethodType != null && swapMethodType.isAssignableFrom(arg))
518                     swapConstructor = cs;
519                  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)))) {
520                     numberConstructor = cs;
521                     numberConstructorType = getWrapperIfPrimitive(arg);
522                  }
523               }
524            }
525         }
526
527         primitiveDefault = ClassUtils.getPrimitiveDefault(c);
528
529         for (Method m : c.getMethods())
530            if (isPublic(m) && isNotDeprecated(m))
531               publicMethods.put(getMethodSignature(m), m);
532
533         Map<Class<?>,Remoteable> remoteableMap = findAnnotationsMap(Remoteable.class, c);
534         if (! remoteableMap.isEmpty()) {
535            Map.Entry<Class<?>,Remoteable> e = remoteableMap.entrySet().iterator().next();  // Grab the first one.
536            Class<?> ic = e.getKey();
537            Remoteable r = e.getValue();
538            String methodPaths = r.methodPaths();
539            String expose = r.expose();
540            for (Method m : "DECLARED".equals(expose) ? ic.getDeclaredMethods() : ic.getMethods()) {
541               if (isPublic(m)) {
542                  RemoteMethod rm = m.getAnnotation(RemoteMethod.class);
543                  if (rm != null || ! "ANNOTATED".equals(expose)) {
544                     String path = "NAME".equals(methodPaths) ? m.getName() : getMethodSignature(m);
545                     remoteableMethods.put(path, m);
546                  }
547               }
548            }
549         }
550
551         if (innerClass != Object.class) {
552            noArgConstructor = (Constructor<T>)findNoArgConstructor(implClass == null ? innerClass : implClass, Visibility.PUBLIC);
553         }
554
555         if (beanFilter == null)
556            beanFilter = findBeanFilter();
557
558         if (swapMethod != null) {
559            final Method fSwapMethod = swapMethod;
560            final Method fUnswapMethod = unswapMethod;
561            final Constructor<T> fSwapConstructor = swapConstructor;
562            this.pojoSwaps.add(
563               new PojoSwap<T,Object>(c, swapMethod.getReturnType()) {
564                  @Override
565                  public Object swap(BeanSession session, Object o) throws SerializeException {
566                     try {
567                        return fSwapMethod.invoke(o, session);
568                     } catch (Exception e) {
569                        throw new SerializeException(e);
570                     }
571                  }
572                  @Override
573                  public T unswap(BeanSession session, Object f, ClassMeta<?> hint) throws ParseException {
574                     try {
575                        if (fUnswapMethod != null)
576                           return (T)fUnswapMethod.invoke(null, session, f);
577                        if (fSwapConstructor != null)
578                           return fSwapConstructor.newInstance(f);
579                        return super.unswap(session, f, hint);
580                     } catch (Exception e) {
581                        throw new ParseException(e);
582                     }
583                  }
584               }
585            );
586         }
587
588         if (pojoSwaps != null)
589            this.pojoSwaps.addAll(Arrays.asList(pojoSwaps));
590         
591         if (beanContext != null)
592            this.builderSwap = BuilderSwap.findSwapFromPojoClass(c, beanContext.beanConstructorVisibility, beanContext.beanMethodVisibility);
593
594         findPojoSwaps(this.pojoSwaps);
595
596         try {
597
598            // If this is an array, get the element type.
599            if (cc == ARRAY)
600               elementType = findClassMeta(innerClass.getComponentType());
601
602            // If this is a MAP, see if it's parameterized (e.g. AddressBook extends HashMap<String,Person>)
603            else if (cc == MAP) {
604               ClassMeta[] parameters = findParameters();
605               if (parameters != null && parameters.length == 2) {
606                  keyType = parameters[0];
607                  valueType = parameters[1];
608               } else {
609                  keyType = findClassMeta(Object.class);
610                  valueType = findClassMeta(Object.class);
611               }
612            }
613
614            // If this is a COLLECTION, see if it's parameterized (e.g. AddressBook extends LinkedList<Person>)
615            else if (cc == COLLECTION) {
616               ClassMeta[] parameters = findParameters();
617               if (parameters != null && parameters.length == 1) {
618                  elementType = parameters[0];
619               } else {
620                  elementType = findClassMeta(Object.class);
621               }
622            }
623
624            // If the category is unknown, see if it's a bean.
625            // Note that this needs to be done after all other initialization has been done.
626            else if (cc == OTHER) {
627
628               BeanMeta newMeta = null;
629               try {
630                  newMeta = new BeanMeta(ClassMeta.this, beanContext, beanFilter, null);
631                  notABeanReason = newMeta.notABeanReason;
632
633                  // Always get these even if it's not a bean:
634                  beanRegistry = newMeta.beanRegistry;
635                  typePropertyName = newMeta.typePropertyName;
636
637               } catch (RuntimeException e) {
638                  notABeanReason = e.getMessage();
639                  throw e;
640               }
641               if (notABeanReason == null)
642                  beanMeta = newMeta;
643            }
644
645         } catch (NoClassDefFoundError e) {
646            initException = e;
647         } catch (RuntimeException e) {
648            initException = e;
649            throw e;
650         }
651
652         if (beanMeta != null)
653            dictionaryName = beanMeta.getDictionaryName();
654
655         if (beanMeta != null && beanContext != null && beanContext.useInterfaceProxies && innerClass.isInterface())
656            invocationHandler = new BeanProxyInvocationHandler<T>(beanMeta);
657
658         Bean b = c.getAnnotation(Bean.class);
659         if (b != null) {
660            if (b.beanDictionary().length != 0)
661               beanRegistry = new BeanRegistry(beanContext, null, b.beanDictionary());
662            
663            // This could be a non-bean POJO with a type name.
664            if (dictionaryName == null && ! b.typeName().isEmpty())
665               dictionaryName = b.typeName();
666         }
667      }
668
669      private BeanFilter findBeanFilter() {
670         try {
671            Map<Class<?>,Bean> ba = findAnnotationsMap(Bean.class, innerClass);
672            if (! ba.isEmpty())
673               return new AnnotationBeanFilterBuilder(innerClass, ba).build();
674         } catch (Exception e) {
675            throw new RuntimeException(e);
676         }
677         return null;
678      }
679
680      private void findPojoSwaps(List<PojoSwap> l) {
681         Swap swap = innerClass.getAnnotation(Swap.class);
682         if (swap != null)
683            l.add(createPojoSwap(swap));
684         Swaps swaps = innerClass.getAnnotation(Swaps.class);
685         if (swaps != null)
686            for (Swap s : swaps.value())
687               l.add(createPojoSwap(s));
688      }
689
690      private PojoSwap<T,?> createPojoSwap(Swap s) {
691         Class<?> c = s.value();
692         if (c == Null.class)
693            c = s.impl();
694
695         if (isParentClass(PojoSwap.class, c)) {
696            PojoSwap ps = beanContext.newInstance(PojoSwap.class, c);
697            if (s.mediaTypes().length > 0)
698               ps.forMediaTypes(MediaType.forStrings(s.mediaTypes()));
699            if (! s.template().isEmpty())
700               ps.withTemplate(s.template());
701            return ps;
702         }
703
704         if (isParentClass(Surrogate.class, c)) {
705            List<SurrogateSwap<?,?>> l = SurrogateSwap.findPojoSwaps(c);
706            if (! l.isEmpty())
707               return (PojoSwap<T,?>)l.iterator().next();
708         }
709
710         throw new FormattedRuntimeException("Invalid swap class ''{0}'' specified.  Must extend from PojoSwap or Surrogate.", c);
711      }
712
713      private ClassMeta<?> findClassMeta(Class<?> c) {
714         return beanContext.getClassMeta(c, false);
715      }
716
717      private ClassMeta<?>[] findParameters() {
718         return beanContext.findParameters(innerClass, innerClass);
719      }
720   }
721
722
723   /**
724    * Returns the type property name associated with this class and subclasses.
725    * 
726    * <p>
727    * If <jk>null</jk>, <js>"_type"</js> should be assumed.
728    * 
729    * @return
730    *    The type property name associated with this bean class, or <jk>null</jk> if there is no explicit type
731    *    property name defined or this isn't a bean.
732    */
733   public String getBeanTypePropertyName() {
734      return typePropertyName;
735   }
736
737   /**
738    * Returns the bean dictionary name associated with this class.
739    * 
740    * <p>
741    * The lexical name is defined by {@link Bean#typeName() @Bean.typeName()}.
742    * 
743    * @return
744    *    The type name associated with this bean class, or <jk>null</jk> if there is no type name defined or this
745    *    isn't a bean.
746    */
747   public String getDictionaryName() {
748      return dictionaryName;
749   }
750
751   /**
752    * Returns the bean registry for this class.
753    * 
754    * <p>
755    * This bean registry contains names specified in the {@link Bean#beanDictionary() @Bean.beanDictionary()} annotation 
756    * defined on the class, regardless of whether the class is an actual bean.
757    * This allows interfaces to define subclasses with type names.
758    * 
759    * @return The bean registry for this class, or <jk>null</jk> if no bean registry is associated with it.
760    */
761   public BeanRegistry getBeanRegistry() {
762      return beanRegistry;
763   }
764
765   /**
766    * Returns the category of this class.
767    * 
768    * @return The category of this class.
769    */
770   public ClassCategory getClassCategory() {
771      return cc;
772   }
773
774   /**
775    * Returns <jk>true</jk> if this class is a superclass of or the same as the specified class.
776    * 
777    * @param c The comparison class.
778    * @return <jk>true</jk> if this class is a superclass of or the same as the specified class.
779    */
780   public boolean isAssignableFrom(Class<?> c) {
781      return isParentClass(innerClass, c);
782   }
783
784   /**
785    * Returns <jk>true</jk> if this class is a subclass of or the same as the specified class.
786    * 
787    * @param c The comparison class.
788    * @return <jk>true</jk> if this class is a subclass of or the same as the specified class.
789    */
790   public boolean isInstanceOf(Class<?> c) {
791      return isParentClass(c, innerClass);
792   }
793
794   /**
795    * Returns <jk>true</jk> if this class or any child classes has a {@link PojoSwap} associated with it.
796    * 
797    * <p>
798    * Used when transforming bean properties to prevent having to look up transforms if we know for certain that no
799    * transforms are associated with a bean property.
800    * 
801    * @return <jk>true</jk> if this class or any child classes has a {@link PojoSwap} associated with it.
802    */
803   protected boolean hasChildPojoSwaps() {
804      return childPojoSwaps != null;
805   }
806
807   /**
808    * Returns the {@link PojoSwap} where the specified class is the same/subclass of the normal class of one of the
809    * child POJO swaps associated with this class.
810    * 
811    * @param normalClass The normal class being resolved.
812    * @return The resolved {@link PojoSwap} or <jk>null</jk> if none were found.
813    */
814   protected PojoSwap<?,?> getChildPojoSwapForSwap(Class<?> normalClass) {
815      if (childSwapMap != null) {
816         PojoSwap<?,?> s = childSwapMap.get(normalClass);
817         if (s == null) {
818            for (PojoSwap<?,?> f : childPojoSwaps)
819               if (s == null && isParentClass(f.getNormalClass(), normalClass))
820                  s = f;
821            if (s == null)
822               s = PojoSwap.NULL;
823            PojoSwap<?,?> s2 = childSwapMap.putIfAbsent(normalClass, s);
824            if (s2 != null)
825               s = s2;
826         }
827         if (s == PojoSwap.NULL)
828            return null;
829         return s;
830      }
831      return null;
832   }
833
834   /**
835    * Returns the {@link PojoSwap} where the specified class is the same/subclass of the swap class of one of the child
836    * POJO swaps associated with this class.
837    * 
838    * @param swapClass The swap class being resolved.
839    * @return The resolved {@link PojoSwap} or <jk>null</jk> if none were found.
840    */
841   protected PojoSwap<?,?> getChildPojoSwapForUnswap(Class<?> swapClass) {
842      if (childUnswapMap != null) {
843         PojoSwap<?,?> s = childUnswapMap.get(swapClass);
844         if (s == null) {
845            for (PojoSwap<?,?> f : childPojoSwaps)
846               if (s == null && isParentClass(f.getSwapClass(), swapClass))
847                  s = f;
848            if (s == null)
849               s = PojoSwap.NULL;
850            PojoSwap<?,?> s2 = childUnswapMap.putIfAbsent(swapClass, s);
851            if (s2 != null)
852               s = s2;
853         }
854         if (s == PojoSwap.NULL)
855            return null;
856         return s;
857      }
858      return null;
859   }
860
861   /**
862    * Locates the no-arg constructor for the specified class.
863    * 
864    * <p>
865    * Constructor must match the visibility requirements specified by parameter 'v'.
866    * If class is abstract, always returns <jk>null</jk>.
867    * Note that this also returns the 1-arg constructor for non-static member classes.
868    * 
869    * @param c The class from which to locate the no-arg constructor.
870    * @param v The minimum visibility.
871    * @return The constructor, or <jk>null</jk> if no no-arg constructor exists with the required visibility.
872    */
873   @SuppressWarnings({"rawtypes","unchecked"})
874   protected static <T> Constructor<? extends T> findNoArgConstructor(Class<?> c, Visibility v) {
875      int mod = c.getModifiers();
876      if (Modifier.isAbstract(mod))
877         return null;
878      boolean isMemberClass = c.isMemberClass() && ! isStatic(c);
879      for (Constructor cc : c.getConstructors()) {
880         mod = cc.getModifiers();
881         if (cc.getParameterTypes().length == (isMemberClass ? 1 : 0) && v.isVisible(mod) && isNotDeprecated(cc))
882            return v.transform(cc);
883      }
884      return null;
885   }
886
887   /**
888    * Returns the {@link Class} object that this class type wraps.
889    * 
890    * @return The wrapped class object.
891    */
892   public Class<T> getInnerClass() {
893      return innerClass;
894   }
895
896   /**
897    * Returns the serialized (swapped) form of this class if there is an {@link PojoSwap} associated with it.
898    * 
899    * @param session
900    *    The bean session.
901    *    <br>Required because the swap used may depend on the media type being serialized or parsed.
902    * @return The serialized class type, or this object if no swap is associated with the class.
903    */
904   @BeanIgnore
905   public ClassMeta<?> getSerializedClassMeta(BeanSession session) {
906      PojoSwap<T,?> ps = getPojoSwap(session);
907      return (ps == null ? this : ps.getSwapClassMeta(session));
908   }
909
910   /**
911    * For array and {@code Collection} types, returns the class type of the components of the array or
912    * {@code Collection}.
913    * 
914    * @return The element class type, or <jk>null</jk> if this class is not an array or Collection.
915    */
916   public ClassMeta<?> getElementType() {
917      return elementType;
918   }
919
920   /**
921    * For {@code Map} types, returns the class type of the keys of the {@code Map}.
922    * 
923    * @return The key class type, or <jk>null</jk> if this class is not a Map.
924    */
925   public ClassMeta<?> getKeyType() {
926      return keyType;
927   }
928
929   /**
930    * For {@code Map} types, returns the class type of the values of the {@code Map}.
931    * 
932    * @return The value class type, or <jk>null</jk> if this class is not a Map.
933    */
934   public ClassMeta<?> getValueType() {
935      return valueType;
936   }
937
938   /**
939    * Returns <jk>true</jk> if this class implements {@link Delegate}, meaning it's a representation of some other
940    * object.
941    * 
942    * @return <jk>true</jk> if this class implements {@link Delegate}.
943    */
944   public boolean isDelegate() {
945      return isDelegate;
946   }
947
948   /**
949    * Returns <jk>true</jk> if this class is a subclass of {@link Map}.
950    * 
951    * @return <jk>true</jk> if this class is a subclass of {@link Map}.
952    */
953   public boolean isMap() {
954      return cc == MAP || cc == BEANMAP;
955   }
956
957   /**
958    * Returns <jk>true</jk> if this class is a subclass of {@link Map} or it's a bean.
959    * 
960    * @return <jk>true</jk> if this class is a subclass of {@link Map} or it's a bean.
961    */
962   public boolean isMapOrBean() {
963      return cc == MAP || cc == BEANMAP || beanMeta != null;
964   }
965
966   /**
967    * Returns <jk>true</jk> if this class is a subclass of {@link BeanMap}.
968    * 
969    * @return <jk>true</jk> if this class is a subclass of {@link BeanMap}.
970    */
971   public boolean isBeanMap() {
972      return cc == BEANMAP;
973   }
974
975   /**
976    * Returns <jk>true</jk> if this class is a subclass of {@link Collection}.
977    * 
978    * @return <jk>true</jk> if this class is a subclass of {@link Collection}.
979    */
980   public boolean isCollection() {
981      return cc == COLLECTION;
982   }
983
984   /**
985    * Returns <jk>true</jk> if this class is a subclass of {@link Collection} or is an array.
986    * 
987    * @return <jk>true</jk> if this class is a subclass of {@link Collection} or is an array.
988    */
989   public boolean isCollectionOrArray() {
990      return cc == COLLECTION || cc == ARRAY;
991   }
992
993   /**
994    * Returns <jk>true</jk> if this class is {@link Class}.
995    * 
996    * @return <jk>true</jk> if this class is {@link Class}.
997    */
998   public boolean isClass() {
999      return cc == CLASS;
1000   }
1001
1002   /**
1003    * Returns <jk>true</jk> if this class is {@link Method}.
1004    * 
1005    * @return <jk>true</jk> if this class is {@link Method}.
1006    */
1007   public boolean isMethod() {
1008      return cc == METHOD;
1009   }
1010
1011   /**
1012    * Returns <jk>true</jk> if this class is an {@link Enum}.
1013    * 
1014    * @return <jk>true</jk> if this class is an {@link Enum}.
1015    */
1016   public boolean isEnum() {
1017      return cc == ENUM;
1018   }
1019
1020   /**
1021    * Returns <jk>true</jk> if this class is an array.
1022    * 
1023    * @return <jk>true</jk> if this class is an array.
1024    */
1025   public boolean isArray() {
1026      return cc == ARRAY;
1027   }
1028
1029   /**
1030    * Returns <jk>true</jk> if this class is a bean.
1031    * 
1032    * @return <jk>true</jk> if this class is a bean.
1033    */
1034   public boolean isBean() {
1035      return beanMeta != null;
1036   }
1037
1038   /**
1039    * Returns <jk>true</jk> if this class is {@link Object}.
1040    * 
1041    * @return <jk>true</jk> if this class is {@link Object}.
1042    */
1043   public boolean isObject() {
1044      return cc == OBJ;
1045   }
1046
1047   /**
1048    * Returns <jk>true</jk> if this class is not {@link Object}.
1049    * 
1050    * @return <jk>true</jk> if this class is not {@link Object}.
1051    */
1052   public boolean isNotObject() {
1053      return cc != OBJ;
1054   }
1055
1056   /**
1057    * Returns <jk>true</jk> if this class is a subclass of {@link Number}.
1058    * 
1059    * @return <jk>true</jk> if this class is a subclass of {@link Number}.
1060    */
1061   public boolean isNumber() {
1062      return cc == NUMBER || cc == DECIMAL;
1063   }
1064
1065   /**
1066    * Returns <jk>true</jk> if this class is a subclass of {@link Float} or {@link Double}.
1067    * 
1068    * @return <jk>true</jk> if this class is a subclass of {@link Float} or {@link Double}.
1069    */
1070   public boolean isDecimal() {
1071      return cc == DECIMAL;
1072   }
1073
1074   /**
1075    * Returns <jk>true</jk> if this class is a {@link Boolean}.
1076    * 
1077    * @return <jk>true</jk> if this class is a {@link Boolean}.
1078    */
1079   public boolean isBoolean() {
1080      return cc == BOOLEAN;
1081   }
1082
1083   /**
1084    * Returns <jk>true</jk> if this class is a subclass of {@link CharSequence}.
1085    * 
1086    * @return <jk>true</jk> if this class is a subclass of {@link CharSequence}.
1087    */
1088   public boolean isCharSequence() {
1089      return cc == STR || cc == CHARSEQ;
1090   }
1091
1092   /**
1093    * Returns <jk>true</jk> if this class is a {@link String}.
1094    * 
1095    * @return <jk>true</jk> if this class is a {@link String}.
1096    */
1097   public boolean isString() {
1098      return cc == STR;
1099   }
1100
1101   /**
1102    * Returns <jk>true</jk> if this class is a {@link Character}.
1103    * 
1104    * @return <jk>true</jk> if this class is a {@link Character}.
1105    */
1106   public boolean isChar() {
1107      return cc == CHAR;
1108   }
1109
1110   /**
1111    * Returns <jk>true</jk> if this class is a primitive.
1112    * 
1113    * @return <jk>true</jk> if this class is a primitive.
1114    */
1115   public boolean isPrimitive() {
1116      return innerClass.isPrimitive();
1117   }
1118
1119   /**
1120    * Returns <jk>true</jk> if this class is a {@link Date} or {@link Calendar}.
1121    * 
1122    * @return <jk>true</jk> if this class is a {@link Date} or {@link Calendar}.
1123    */
1124   public boolean isDate() {
1125      return cc == DATE;
1126   }
1127
1128   /**
1129    * Returns <jk>true</jk> if this class is a {@link URI} or {@link URL}.
1130    * 
1131    * @return <jk>true</jk> if this class is a {@link URI} or {@link URL}.
1132    */
1133   public boolean isUri() {
1134      return cc == URI;
1135   }
1136
1137   /**
1138    * Returns <jk>true</jk> if this class is a {@link Reader}.
1139    * 
1140    * @return <jk>true</jk> if this class is a {@link Reader}.
1141    */
1142   public boolean isReader() {
1143      return cc == READER;
1144   }
1145
1146   /**
1147    * Returns <jk>true</jk> if this class is an {@link InputStream}.
1148    * 
1149    * @return <jk>true</jk> if this class is an {@link InputStream}.
1150    */
1151   public boolean isInputStream() {
1152      return cc == INPUTSTREAM;
1153   }
1154
1155   /**
1156    * Returns <jk>true</jk> if this class is {@link Void} or <jk>void</jk>.
1157    * 
1158    * @return <jk>true</jk> if this class is {@link Void} or <jk>void</jk>.
1159    */
1160   public boolean isVoid() {
1161      return cc == VOID;
1162   }
1163
1164   /**
1165    * Returns <jk>true</jk> if this metadata represents an array of argument types.
1166    * 
1167    * @return <jk>true</jk> if this metadata represents an array of argument types.
1168    */
1169   public boolean isArgs() {
1170      return cc == ARGS;
1171   }
1172
1173   /**
1174    * Returns the argument types of this meta.
1175    * 
1176    * @return The argument types of this meta, or <jk>null</jk> if this isn't an array of argument types.
1177    */
1178   public ClassMeta<?>[] getArgs() {
1179      return args;
1180   }
1181
1182   /**
1183    * Returns the argument metadata at the specified index if this is an args metadata object.
1184    * 
1185    * @param index The argument index.
1186    * @return The The argument metadata.  Never <jk>null</jk>.
1187    * @throws BeanRuntimeException If this metadata object is not a list of arguments, or the index is out of range.
1188    */
1189   public ClassMeta<?> getArg(int index) {
1190      if (args != null && index >= 0 && index < args.length)
1191         return args[index];
1192      throw new BeanRuntimeException("Invalid argument index specified:  {0}.  Only {1} arguments are defined.", index, args == null ? 0 : args.length);
1193   }
1194
1195   /**
1196    * Returns <jk>true</jk> if instance of this object can be <jk>null</jk>.
1197    * 
1198    * <p>
1199    * Objects can be <jk>null</jk>, but primitives cannot, except for chars which can be represented by
1200    * <code>(<jk>char</jk>)0</code>.
1201    * 
1202    * @return <jk>true</jk> if instance of this class can be null.
1203    */
1204   public boolean isNullable() {
1205      if (innerClass.isPrimitive())
1206         return cc == CHAR;
1207      return true;
1208   }
1209
1210   /**
1211    * Returns <jk>true</jk> if this class or one of it's methods are annotated with {@link Remoteable @Remotable}.
1212    * 
1213    * @return <jk>true</jk> if this class is remoteable.
1214    */
1215   public boolean isRemoteable() {
1216      return remoteableMethods != null;
1217   }
1218
1219   /**
1220    * Returns <jk>true</jk> if this class is abstract.
1221    * 
1222    * @return <jk>true</jk> if this class is abstract.
1223    */
1224   public boolean isAbstract() {
1225      return isAbstract;
1226   }
1227
1228   /**
1229    * Returns <jk>true</jk> if this class is an inner class.
1230    * 
1231    * @return <jk>true</jk> if this class is an inner class.
1232    */
1233   public boolean isMemberClass() {
1234      return isMemberClass;
1235   }
1236
1237   /**
1238    * All methods on this class annotated with {@link Remoteable @Remotable}, or all public methods if class is
1239    * annotated.
1240    * 
1241    * <p>
1242    * Keys are method signatures.
1243    * 
1244    * @return All remoteable methods on this class.
1245    */
1246   public Map<String,Method> getRemoteableMethods() {
1247      return remoteableMethods;
1248   }
1249
1250   /**
1251    * All public methods on this class including static methods.
1252    * 
1253    * <p>
1254    * Keys are method signatures.
1255    * 
1256    * @return The public methods on this class.
1257    */
1258   public Map<String,Method> getPublicMethods() {
1259      return publicMethods;
1260   }
1261
1262   /**
1263    * Returns the {@link PojoSwap} associated with this class that's the best match for the specified session.
1264    * 
1265    * @param session
1266    *    The current bean session.
1267    *    <br>If multiple swaps are associated with a class, only the first one with a matching media type will
1268    *    be returned.
1269    * @return
1270    *    The {@link PojoSwap} associated with this class, or <jk>null</jk> if there are no POJO swaps associated with
1271    *    this class.
1272    */
1273   public PojoSwap<T,?> getPojoSwap(BeanSession session) {
1274      if (pojoSwaps != null) {
1275         int matchQuant = 0, matchIndex = -1;
1276
1277         for (int i = 0; i < pojoSwaps.length; i++) {
1278            int q = pojoSwaps[i].match(session);
1279            if (q > matchQuant) {
1280               matchQuant = q;
1281               matchIndex = i;
1282            }
1283         }
1284
1285         if (matchIndex > -1)
1286            return pojoSwaps[matchIndex];
1287      }
1288      return null;
1289   }
1290   
1291   /**
1292    * Returns the builder swap associated with this class.
1293    * 
1294    * @param session The current bean session.
1295    * @return The builder swap associated with this class, or <jk>null</jk> if it doesn't exist.
1296    */
1297   public BuilderSwap<T,?> getBuilderSwap(BeanSession session) {
1298      return builderSwap;
1299   }
1300
1301   /**
1302    * Returns the {@link BeanMeta} associated with this class.
1303    * 
1304    * @return
1305    *    The {@link BeanMeta} associated with this class, or <jk>null</jk> if there is no bean meta associated with
1306    *    this class.
1307    */
1308   public BeanMeta<T> getBeanMeta() {
1309      return beanMeta;
1310   }
1311
1312   /**
1313    * Returns the no-arg constructor for this class.
1314    * 
1315    * @return The no-arg constructor for this class, or <jk>null</jk> if it does not exist.
1316    */
1317   public Constructor<? extends T> getConstructor() {
1318      return noArgConstructor;
1319   }
1320
1321   /**
1322    * Returns the language-specified extended metadata on this class.
1323    * 
1324    * @param c The name of the metadata class to create.
1325    * @return Extended metadata on this class.  Never <jk>null</jk>.
1326    */
1327   public <M extends ClassMetaExtended> M getExtendedMeta(Class<M> c) {
1328      return extMeta.get(c, this);
1329   }
1330
1331   /**
1332    * Returns the interface proxy invocation handler for this class.
1333    * 
1334    * @return The interface proxy invocation handler, or <jk>null</jk> if it does not exist.
1335    */
1336   public InvocationHandler getProxyInvocationHandler() {
1337      return invocationHandler;
1338   }
1339
1340   /**
1341    * Returns <jk>true</jk> if this class has a no-arg constructor or invocation handler.
1342    * 
1343    * @return <jk>true</jk> if a new instance of this class can be constructed.
1344    */
1345   public boolean canCreateNewInstance() {
1346      if (isMemberClass)
1347         return false;
1348      if (noArgConstructor != null)
1349         return true;
1350      if (getProxyInvocationHandler() != null)
1351         return true;
1352      if (isArray() && elementType.canCreateNewInstance())
1353         return true;
1354      return false;
1355   }
1356
1357   /**
1358    * Returns <jk>true</jk> if this class has a no-arg constructor or invocation handler.
1359    * Returns <jk>false</jk> if this is a non-static member class and the outer object does not match the class type of
1360    * the defining class.
1361    * 
1362    * @param outer
1363    *    The outer class object for non-static member classes.  Can be <jk>null</jk> for non-member or static classes.
1364    * @return
1365    *    <jk>true</jk> if a new instance of this class can be created within the context of the specified outer object.
1366    */
1367   public boolean canCreateNewInstance(Object outer) {
1368      if (isMemberClass)
1369         return outer != null && noArgConstructor != null && noArgConstructor.getParameterTypes()[0] == outer.getClass();
1370      return canCreateNewInstance();
1371   }
1372
1373   /**
1374    * Returns <jk>true</jk> if this class can be instantiated as a bean.
1375    * Returns <jk>false</jk> if this is a non-static member class and the outer object does not match the class type of
1376    * the defining class.
1377    * 
1378    * @param outer
1379    *    The outer class object for non-static member classes.  Can be <jk>null</jk> for non-member or static classes.
1380    * @return
1381    *    <jk>true</jk> if a new instance of this bean can be created within the context of the specified outer object.
1382    */
1383   public boolean canCreateNewBean(Object outer) {
1384      if (beanMeta == null)
1385         return false;
1386      if (beanMeta.constructor == null)
1387         return false;
1388      if (isMemberClass)
1389         return outer != null && beanMeta.constructor.getParameterTypes()[0] == outer.getClass();
1390      return true;
1391   }
1392
1393   /**
1394    * Returns <jk>true</jk> if this class can call the {@link #newInstanceFromString(Object, String)} method.
1395    * 
1396    * @param outer
1397    *    The outer class object for non-static member classes.
1398    *    Can be <jk>null</jk> for non-member or static classes.
1399    * @return <jk>true</jk> if this class has a no-arg constructor or invocation handler.
1400    */
1401   public boolean canCreateNewInstanceFromString(Object outer) {
1402      if (fromStringMethod != null)
1403         return true;
1404      if (stringConstructor != null) {
1405         if (isMemberClass)
1406            return outer != null && stringConstructor.getParameterTypes()[0] == outer.getClass();
1407         return true;
1408      }
1409      return false;
1410   }
1411
1412   /**
1413    * Returns <jk>true</jk> if this class can call the {@link #newInstanceFromString(Object, String)} method.
1414    * 
1415    * @param outer
1416    *    The outer class object for non-static member classes.
1417    *    Can be <jk>null</jk> for non-member or static classes.
1418    * @return <jk>true</jk> if this class has a no-arg constructor or invocation handler.
1419    */
1420   public boolean canCreateNewInstanceFromNumber(Object outer) {
1421      if (numberConstructor != null) {
1422         if (isMemberClass)
1423            return outer != null && numberConstructor.getParameterTypes()[0] == outer.getClass();
1424         return true;
1425      }
1426      return false;
1427   }
1428
1429   /**
1430    * Returns the class type of the parameter of the numeric constructor.
1431    * 
1432    * @return The class type of the numeric constructor, or <jk>null</jk> if no such constructor exists.
1433    */
1434   @SuppressWarnings("unchecked")
1435   public Class<? extends Number> getNewInstanceFromNumberClass() {
1436      return (Class<? extends Number>) numberConstructorType;
1437   }
1438
1439   /**
1440    * Returns the method or field annotated with {@link NameProperty @NameProperty}.
1441    * 
1442    * @return
1443    *    The method or field  annotated with {@link NameProperty @NameProperty} or <jk>null</jk> if method does not
1444    *    exist.
1445    */
1446   public Setter getNameProperty() {
1447      return namePropertyMethod;
1448   }
1449
1450   /**
1451    * Returns the method or field annotated with {@link ParentProperty @ParentProperty}.
1452    * 
1453    * @return
1454    *    The method or field annotated with {@link ParentProperty @ParentProperty} or <jk>null</jk> if method does not
1455    *    exist.
1456    */
1457   public Setter getParentProperty() {
1458      return parentPropertyMethod;
1459   }
1460
1461   /**
1462    * Returns the reason why this class is not a bean, or <jk>null</jk> if it is a bean.
1463    * 
1464    * @return The reason why this class is not a bean, or <jk>null</jk> if it is a bean.
1465    */
1466   public synchronized String getNotABeanReason() {
1467      return notABeanReason;
1468   }
1469
1470   /**
1471    * Returns any exception that was throw in the <code>init()</code> method.
1472    * 
1473    * @return The cached exception.
1474    */
1475   public Throwable getInitException() {
1476      return initException;
1477   }
1478
1479   /**
1480    * Returns the {@link BeanContext} that created this object.
1481    * 
1482    * @return The bean context.
1483    */
1484   public BeanContext getBeanContext() {
1485      return beanContext;
1486   }
1487
1488   /**
1489    * Returns the default value for primitives such as <jk>int</jk> or <jk>Integer</jk>.
1490    * 
1491    * @return The default value, or <jk>null</jk> if this class type is not a primitive.
1492    */
1493   @SuppressWarnings("unchecked")
1494   public T getPrimitiveDefault() {
1495      return (T)primitiveDefault;
1496   }
1497
1498   /**
1499    * Create a new instance of the main class of this declared type from a <code>String</code> input.
1500    * 
1501    * <p>
1502    * In order to use this method, the class must have one of the following methods:
1503    * <ul>
1504    *    <li><code><jk>public static</jk> T valueOf(String in);</code>
1505    *    <li><code><jk>public static</jk> T fromString(String in);</code>
1506    *    <li><code><jk>public</jk> T(String in);</code>
1507    * </ul>
1508    * 
1509    * @param outer
1510    *    The outer class object for non-static member classes.  Can be <jk>null</jk> for non-member or static classes.
1511    * @param arg The input argument value.
1512    * @return A new instance of the object, or <jk>null</jk> if there is no string constructor on the object.
1513    * @throws IllegalAccessException
1514    *    If the <code>Constructor</code> object enforces Java language access control and the underlying constructor is
1515    *    inaccessible.
1516    * @throws IllegalArgumentException If the parameter type on the method was invalid.
1517    * @throws InstantiationException
1518    *    If the class that declares the underlying constructor represents an abstract class, or does not have one of
1519    *    the methods described above.
1520    * @throws InvocationTargetException If the underlying constructor throws an exception.
1521    */
1522   @SuppressWarnings("unchecked")
1523   public T newInstanceFromString(Object outer, String arg) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, InstantiationException {
1524      Method m = fromStringMethod;
1525      if (m != null)
1526         return (T)m.invoke(null, arg);
1527      Constructor<T> c = stringConstructor;
1528      if (c != null) {
1529         if (isMemberClass)
1530            return c.newInstance(outer, arg);
1531         return c.newInstance(arg);
1532      }
1533      throw new InstantiationError("No string constructor or valueOf(String) method found for class '"+getInnerClass().getName()+"'");
1534   }
1535
1536   /**
1537    * Create a new instance of the main class of this declared type from a <code>Number</code> input.
1538    * 
1539    * <p>
1540    * In order to use this method, the class must have one of the following methods:
1541    * <ul>
1542    *    <li><code><jk>public</jk> T(Number in);</code>
1543    * </ul>
1544    * 
1545    * @param session The current bean session.
1546    * @param outer
1547    *    The outer class object for non-static member classes.
1548    *    Can be <jk>null</jk> for non-member or static classes.
1549    * @param arg The input argument value.
1550    * @return A new instance of the object, or <jk>null</jk> if there is no numeric constructor on the object.
1551    * @throws IllegalAccessException
1552    *    If the <code>Constructor</code> object enforces Java language access control and the underlying constructor is
1553    *    inaccessible.
1554    * @throws IllegalArgumentException If the parameter type on the method was invalid.
1555    * @throws InstantiationException
1556    *    If the class that declares the underlying constructor represents an abstract class, or does not have one of
1557    *    the methods described above.
1558    * @throws InvocationTargetException If the underlying constructor throws an exception.
1559    */
1560   public T newInstanceFromNumber(BeanSession session, Object outer, Number arg) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, InstantiationException {
1561      Constructor<T> c = numberConstructor;
1562      if (c != null) {
1563         Object arg2 = session.convertToType(arg, numberConstructor.getParameterTypes()[0]);
1564         if (isMemberClass)
1565            return c.newInstance(outer, arg2);
1566         return c.newInstance(arg2);
1567      }
1568      throw new InstantiationError("No string constructor or valueOf(Number) method found for class '"+getInnerClass().getName()+"'");
1569   }
1570
1571   /**
1572    * Create a new instance of the main class of this declared type.
1573    * 
1574    * @return A new instance of the object, or <jk>null</jk> if there is no no-arg constructor on the object.
1575    * @throws IllegalAccessException
1576    *    If the <code>Constructor</code> object enforces Java language access control and the underlying constructor is
1577    *    inaccessible.
1578    * @throws IllegalArgumentException
1579    *    If one of the following occurs:
1580    *    <ul class='spaced-list'>
1581    *       <li>
1582    *          The number of actual and formal parameters differ.
1583    *       <li>
1584    *          An unwrapping conversion for primitive arguments fails.
1585    *       <li>
1586    *          A parameter value cannot be converted to the corresponding formal parameter type by a method invocation
1587    *          conversion.
1588    *       <li>
1589    *          The constructor pertains to an enum type.
1590    *    </ul>
1591    * @throws InstantiationException If the class that declares the underlying constructor represents an abstract class.
1592    * @throws InvocationTargetException If the underlying constructor throws an exception.
1593    */
1594   @SuppressWarnings("unchecked")
1595   public T newInstance() throws IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException {
1596      if (isArray())
1597         return (T)Array.newInstance(getInnerClass().getComponentType(), 0);
1598      Constructor<? extends T> c = getConstructor();
1599      if (c != null)
1600         return c.newInstance((Object[])null);
1601      InvocationHandler h = getProxyInvocationHandler();
1602      if (h != null)
1603         return (T)Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[] { getInnerClass(), java.io.Serializable.class }, h);
1604      if (isArray())
1605         return (T)Array.newInstance(this.elementType.innerClass,0);
1606      return null;
1607   }
1608
1609   /**
1610    * Same as {@link #newInstance()} except for instantiating non-static member classes.
1611    * 
1612    * @param outer
1613    *    The instance of the owning object of the member class instance.
1614    *    Can be <jk>null</jk> if instantiating a non-member or static class.
1615    * @return A new instance of the object, or <jk>null</jk> if there is no no-arg constructor on the object.
1616    * @throws IllegalAccessException
1617    *    If the <code>Constructor</code> object enforces Java language access control and the underlying constructor is
1618    *    inaccessible.
1619    * @throws IllegalArgumentException
1620    *    If one of the following occurs:
1621    *    <ul class='spaced-list'>
1622    *       <li>
1623    *          The number of actual and formal parameters differ.
1624    *       <li>
1625    *          An unwrapping conversion for primitive arguments fails.
1626    *       <li>
1627    *          A parameter value cannot be converted to the corresponding formal parameter type by a method invocation
1628    *          conversion.
1629    *       <li>
1630    *          The constructor pertains to an enum type.
1631    *    </ul>
1632    * @throws InstantiationException If the class that declares the underlying constructor represents an abstract class.
1633    * @throws InvocationTargetException If the underlying constructor throws an exception.
1634    */
1635   public T newInstance(Object outer) throws IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException {
1636      if (isMemberClass)
1637         return noArgConstructor.newInstance(outer);
1638      return newInstance();
1639   }
1640
1641   /**
1642    * Checks to see if the specified class type is the same as this one.
1643    * 
1644    * @param t The specified class type.
1645    * @return <jk>true</jk> if the specified class type is the same as the class for this type.
1646    */
1647   @Override /* Object */
1648   public boolean equals(Object t) {
1649      if (t == null || ! (t instanceof ClassMeta))
1650         return false;
1651      ClassMeta<?> t2 = (ClassMeta<?>)t;
1652      return t2.getInnerClass() == this.getInnerClass();
1653   }
1654
1655   /**
1656    * Similar to {@link #equals(Object)} except primitive and Object types that are similar are considered the same.
1657    * (e.g. <jk>boolean</jk> == <code>Boolean</code>).
1658    * 
1659    * @param cm The class meta to compare to.
1660    * @return <jk>true</jk> if the specified class-meta is equivalent to this one.
1661    */
1662   public boolean same(ClassMeta<?> cm) {
1663      if (equals(cm))
1664         return true;
1665      return (isPrimitive() && cc == cm.cc);
1666   }
1667
1668   @Override /* Object */
1669   public String toString() {
1670      return toString(false);
1671   }
1672
1673   /**
1674    * Same as {@link #toString()} except use simple class names.
1675    * 
1676    * @param simple Print simple class names only (no package).
1677    * @return A new string.
1678    */
1679   public String toString(boolean simple) {
1680      return toString(new StringBuilder(), simple).toString();
1681   }
1682
1683   /**
1684    * Appends this object as a readable string to the specified string builder.
1685    * 
1686    * @param sb The string builder to append this object to.
1687    * @param simple Print simple class names only (no package).
1688    * @return The same string builder passed in (for method chaining).
1689    */
1690   protected StringBuilder toString(StringBuilder sb, boolean simple) {
1691      String n = innerClass.getName();
1692      if (simple) {
1693         int i = n.lastIndexOf('.');
1694         n = n.substring(i == -1 ? 0 : i+1).replace('$', '.');
1695      }
1696      if (cc == ARRAY)
1697         return elementType.toString(sb, simple).append('[').append(']');
1698      if (cc == MAP)
1699         return sb.append(n).append(keyType.isObject() && valueType.isObject() ? "" : "<"+keyType.toString(simple)+","+valueType.toString(simple)+">");
1700      if (cc == BEANMAP)
1701         return sb.append(BeanMap.class.getName()).append('<').append(n).append('>');
1702      if (cc == COLLECTION)
1703         return sb.append(n).append(elementType.isObject() ? "" : "<"+elementType.toString(simple)+">");
1704      if (cc == OTHER && beanMeta == null) {
1705         if (simple)
1706            return sb.append(n);
1707         sb.append("OTHER-").append(n).append(",notABeanReason=").append(notABeanReason);
1708         if (initException != null)
1709            sb.append(",initException=").append(initException);
1710         return sb;
1711      }
1712      return sb.append(n);
1713   }
1714
1715   /**
1716    * Returns <jk>true</jk> if the specified object is an instance of this class.
1717    * 
1718    * <p>
1719    * This is a simple comparison on the base class itself and not on any generic parameters.
1720    * 
1721    * @param o The object to check.
1722    * @return <jk>true</jk> if the specified object is an instance of this class.
1723    */
1724   public boolean isInstance(Object o) {
1725      if (o != null)
1726         return isParentClass(this.innerClass, o.getClass());
1727      return false;
1728   }
1729
1730   /**
1731    * Returns a readable name for this class (e.g. <js>"java.lang.String"</js>, <js>"boolean[]"</js>).
1732    * 
1733    * @return The readable name for this class.
1734    */
1735   public String getReadableName() {
1736      return getReadableClassName(this.innerClass);
1737   }
1738
1739   private static class LocaleAsString {
1740      private static Method forLanguageTagMethod;
1741      static {
1742         try {
1743            forLanguageTagMethod = Locale.class.getMethod("forLanguageTag", String.class);
1744         } catch (NoSuchMethodException e) {}
1745      }
1746
1747      @SuppressWarnings("unused")
1748      public static final Locale fromString(String localeString) {
1749         if (forLanguageTagMethod != null) {
1750            if (localeString.indexOf('_') != -1)
1751               localeString = localeString.replace('_', '-');
1752            try {
1753               return (Locale)forLanguageTagMethod.invoke(null, localeString);
1754            } catch (Exception e) {
1755               throw new BeanRuntimeException(e);
1756            }
1757         }
1758         String[] v = localeString.toString().split("[\\-\\_]");
1759         if (v.length == 1)
1760            return new Locale(v[0]);
1761         else if (v.length == 2)
1762            return new Locale(v[0], v[1]);
1763         else if (v.length == 3)
1764            return new Locale(v[0], v[1], v[2]);
1765         throw new BeanRuntimeException("Could not convert string ''{0}'' to a Locale.", localeString);
1766      }
1767   }
1768
1769   @Override /* Object */
1770   public int hashCode() {
1771      return super.hashCode();
1772   }
1773}