You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@juneau.apache.org by ja...@apache.org on 2016/08/01 00:08:19 UTC

[30/51] [partial] incubator-juneau git commit: Initial Juno contents from IBM JazzHub repo

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/BeanPropertyMeta.java
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/BeanPropertyMeta.java b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/BeanPropertyMeta.java
new file mode 100755
index 0000000..ea9fc3c
--- /dev/null
+++ b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/BeanPropertyMeta.java
@@ -0,0 +1,803 @@
+/*******************************************************************************
+ * Licensed Materials - Property of IBM
+ * (c) Copyright IBM Corporation 2011, 2015. All Rights Reserved.
+ *
+ *  The source code for this program is not published or otherwise
+ *  divested of its trade secrets, irrespective of what has been
+ *  deposited with the U.S. Copyright Office.
+ *******************************************************************************/
+package com.ibm.juno.core;
+
+import static com.ibm.juno.core.Visibility.*;
+import static com.ibm.juno.core.utils.ClassUtils.*;
+import static com.ibm.juno.core.utils.CollectionUtils.*;
+import static com.ibm.juno.core.utils.ReflectionUtils.*;
+
+import java.lang.annotation.*;
+import java.lang.reflect.*;
+import java.net.*;
+import java.util.*;
+
+import com.ibm.juno.core.annotation.*;
+import com.ibm.juno.core.annotation.URI;
+import com.ibm.juno.core.filter.*;
+import com.ibm.juno.core.html.*;
+import com.ibm.juno.core.jena.*;
+import com.ibm.juno.core.parser.*;
+import com.ibm.juno.core.serializer.*;
+import com.ibm.juno.core.utils.*;
+import com.ibm.juno.core.xml.*;
+
+/**
+ * Contains metadata about a bean property.
+ * <p>
+ * 	Contains information such as type of property (e.g. field/getter/setter), class type of property value,
+ * 	and whether any filters are associated with this property.
+ * <p>
+ * 	Developers will typically not need access to this class.  The information provided by it is already
+ * 	exposed through several methods on the {@link BeanMap} API.
+ *
+ * @param <T> The class type of the bean that this metadata applies to.
+ * @author James Bognar (jbognar@us.ibm.com)
+ */
+@SuppressWarnings({ "rawtypes", "unchecked" })
+public class BeanPropertyMeta<T> {
+
+	private Field field;
+	private Method getter, setter;
+	private boolean isConstructorArg, isBeanUri, isUri;
+
+	private final BeanMeta<T> beanMeta;
+
+	private String name;
+	private ClassMeta<?>
+		rawTypeMeta,                           // The real class type of the bean property.
+		typeMeta;                              // The filtered class type of the bean property.
+	private String[] properties;
+	private PojoFilter filter;      // PojoFilter defined only via @BeanProperty annotation.
+
+	/** HTML related metadata on this bean property. */
+	protected HtmlBeanPropertyMeta<T> htmlMeta;
+
+	/** XML related metadata on this bean property. */
+	protected XmlBeanPropertyMeta<T> xmlMeta;
+
+	/** RDF related metadata on this bean property. */
+	protected RdfBeanPropertyMeta<T> rdfMeta;  //
+
+	BeanPropertyMeta(BeanMeta<T> beanMeta, String name) {
+		this.beanMeta = beanMeta;
+		this.name = name;
+	}
+
+	BeanPropertyMeta(BeanMeta<T> beanMeta, String name, ClassMeta<?> rawTypeMeta) {
+		this(beanMeta, name);
+		this.rawTypeMeta = rawTypeMeta;
+	}
+
+	BeanPropertyMeta(BeanMeta<T> beanMeta, String name, Method getter, Method setter) {
+		this(beanMeta, name);
+		setGetter(getter);
+		setSetter(setter);
+	}
+
+	/**
+	 * Returns the name of this bean property.
+	 *
+	 * @return The name of the bean property.
+	 */
+	public String getName() {
+		return name;
+	}
+
+	/**
+	 * Returns the bean meta that this property belongs to.
+	 *
+	 * @return The bean meta that this property belongs to.
+	 */
+	@BeanIgnore
+	public BeanMeta<T> getBeanMeta() {
+		return beanMeta;
+	}
+
+	/**
+	 * Returns the getter method for this property.
+	 *
+	 * @return The getter method for this bean property, or <jk>null</jk> if there is no getter method.
+	 */
+	public Method getGetter() {
+		return getter;
+	}
+
+	/**
+	 * Returns the setter method for this property.
+	 *
+	 * @return The setter method for this bean property, or <jk>null</jk> if there is no setter method.
+	 */
+	public Method getSetter() {
+		return setter;
+	}
+
+	/**
+	 * Returns the field for this property.
+	 *
+	 * @return The field for this bean property, or <jk>null</jk> if there is no field associated with this bean property.
+	 */
+	public Field getField() {
+		return field;
+	}
+
+	/**
+	 * Returns the {@link ClassMeta} of the class of this property.
+	 * <p>
+	 * If this property or the property type class has a {@link PojoFilter} associated with it, this
+	 * 	method returns the filtered class meta.
+	 * This matches the class type that is used by the {@link #get(BeanMap)} and {@link #set(BeanMap, Object)} methods.
+	 *
+	 * @return The {@link ClassMeta} of the class of this property.
+	 */
+	public ClassMeta<?> getClassMeta() {
+		if (typeMeta == null)
+			typeMeta = (filter != null ? filter.getFilteredClassMeta() : rawTypeMeta.getFilteredClassMeta());
+		return typeMeta;
+	}
+
+	/**
+	 * Sets the getter method for this property.
+	 *
+	 * @param getter The getter method to associate with this property.
+	 * @return This object (for method chaining).
+	 */
+	BeanPropertyMeta<T> setGetter(Method getter) {
+		setAccessible(getter);
+		this.getter = getter;
+		return this;
+	}
+
+	/**
+	 * Sets the setter method for this property.
+	 *
+	 * @param setter The setter method to associate with this property.
+	 * @return This object (for method chaining).
+	 */
+	BeanPropertyMeta<T> setSetter(Method setter) {
+		setAccessible(setter);
+		this.setter = setter;
+		return this;
+	}
+
+	/**
+	 * Sets the field for this property.
+	 *
+	 * @param field The field to associate with this property.
+	 * @return This object (for method chaining).
+	 */
+	BeanPropertyMeta<T> setField(Field field) {
+		setAccessible(field);
+		this.field = field;
+		return this;
+	}
+
+	/**
+	 * Marks this property as only settable through a constructor arg.
+	 *
+	 * @return This object (for method chaining).
+	 */
+	BeanPropertyMeta<T> setAsConstructorArg() {
+		this.isConstructorArg = true;
+		return this;
+	}
+
+	/**
+	 * Returns <jk>true</jk> if this bean property is marked with {@link BeanProperty#beanUri()} as <jk>true</jk>.
+	 *
+	 * @return <jk>true</jk> if this bean property is marked with {@link BeanProperty#beanUri()} as <jk>true</jk>.
+	 */
+	public boolean isBeanUri() {
+		return isBeanUri;
+	}
+
+	/**
+	 * Returns <jk>true</jk> if this bean property is a URI.
+	 * <p>
+	 * A bean property can be considered a URI if any of the following are true:
+	 * <ul>
+	 * 	<li>Property class type is {@link URL} or {@link URI}.
+	 * 	<li>Property class type is annotated with {@link com.ibm.juno.core.annotation.URI}.
+	 * 	<li>Property getter, setter, or field is annotated with {@link com.ibm.juno.core.annotation.URI}.
+	 * </ul>
+	 *
+	 * @return <jk>true</jk> if this bean property is a URI.
+	 */
+	public boolean isUri() {
+		return isUri;
+	}
+
+	/**
+	 * Returns the override list of properties defined through a {@link BeanProperty#properties()} annotation
+	 *  on this property.
+	 *
+	 * @return The list of override properties, or <jk>null</jk> if annotation not specified.
+	 */
+	public String[] getProperties() {
+		return properties;
+	}
+
+	/**
+	 * Returns the HTML-related metadata on this bean property.
+	 *
+	 * @return The HTML-related metadata on this bean property.  Never <jk>null</jk>/.
+	 */
+	public HtmlBeanPropertyMeta<T> getHtmlMeta() {
+		return htmlMeta;
+	}
+
+	/**
+	 * Returns the XML-related metadata on this bean property.
+	 *
+	 * @return The XML-related metadata on this bean property.  Never <jk>null</jk>/.
+	 */
+	public XmlBeanPropertyMeta<T> getXmlMeta() {
+		return xmlMeta;
+	}
+
+	/**
+	 * Returns the RDF-related metadata on this bean property.
+	 *
+	 * @return The RDF-related metadata on this bean property.  Never <jk>null</jk>/.
+	 */
+	public RdfBeanPropertyMeta<T> getRdfMeta() {
+		return rdfMeta;
+	}
+
+	boolean validate() throws Exception {
+
+		BeanContext f = beanMeta.ctx;
+		Map<Class<?>,Class<?>[]> typeVarImpls = beanMeta.typeVarImpls;
+
+		if (field == null && getter == null)
+			return false;
+
+		if (field == null && setter == null && f.beansRequireSettersForGetters && ! isConstructorArg)
+			return false;
+
+		if (field != null) {
+			BeanProperty p = field.getAnnotation(BeanProperty.class);
+			rawTypeMeta = f.getClassMeta(p, field.getGenericType(), typeVarImpls);
+			isUri |= (rawTypeMeta.isUri() || field.isAnnotationPresent(com.ibm.juno.core.annotation.URI.class));
+			if (p != null) {
+				filter = getPropertyPojoFilter(p);
+				if (p.properties().length != 0)
+					properties = p.properties();
+				isBeanUri |= p.beanUri();
+			}
+		}
+
+		if (getter != null) {
+			BeanProperty p = getter.getAnnotation(BeanProperty.class);
+			if (rawTypeMeta == null)
+				rawTypeMeta = f.getClassMeta(p, getter.getGenericReturnType(), typeVarImpls);
+			isUri |= (rawTypeMeta.isUri() || getter.isAnnotationPresent(com.ibm.juno.core.annotation.URI.class));
+			if (p != null) {
+				if (filter == null)
+					filter = getPropertyPojoFilter(p);
+				if (properties != null && p.properties().length != 0)
+					properties = p.properties();
+				isBeanUri |= p.beanUri();
+			}
+		}
+
+		if (setter != null) {
+			BeanProperty p = setter.getAnnotation(BeanProperty.class);
+			if (rawTypeMeta == null)
+				rawTypeMeta = f.getClassMeta(p, setter.getGenericParameterTypes()[0], typeVarImpls);
+			isUri |= (rawTypeMeta.isUri() || setter.isAnnotationPresent(com.ibm.juno.core.annotation.URI.class));
+			if (p != null) {
+			if (filter == null)
+				filter = getPropertyPojoFilter(p);
+				if (properties != null && p.properties().length != 0)
+					properties = p.properties();
+				isBeanUri |= p.beanUri();
+			}
+		}
+
+		if (rawTypeMeta == null)
+			return false;
+
+		// Do some annotation validation.
+		Class<?> c = rawTypeMeta.getInnerClass();
+		if (getter != null && ! isParentClass(getter.getReturnType(), c))
+			return false;
+		if (setter != null && ! isParentClass(setter.getParameterTypes()[0], c))
+			return false;
+		if (field != null && ! isParentClass(field.getType(), c))
+			return false;
+
+		htmlMeta = new HtmlBeanPropertyMeta(this);
+		xmlMeta = new XmlBeanPropertyMeta(this);
+		rdfMeta = new RdfBeanPropertyMeta(this);
+
+		return true;
+	}
+
+	private PojoFilter getPropertyPojoFilter(BeanProperty p) throws Exception {
+		Class<? extends PojoFilter> c = p.filter();
+		if (c == PojoFilter.NULL.class)
+			return null;
+		try {
+			PojoFilter f = c.newInstance();
+			f.setBeanContext(this.beanMeta.ctx);
+			return f;
+		} catch (Exception e) {
+			throw new BeanRuntimeException(this.beanMeta.c, "Could not instantiate PojoFilter ''{0}'' for bean property ''{1}''", c.getName(), this.name).initCause(e);
+		}
+	}
+
+	/**
+	 * Equivalent to calling {@link BeanMap#get(Object)}, but is faster since it avoids looking up the property meta.
+	 *
+	 * @param m The bean map to get the filtered value from.
+	 * @return The property value.
+	 */
+	public Object get(BeanMap<T> m) {
+		try {
+			// Read-only beans have their properties stored in a cache until getBean() is called.
+			Object bean = m.bean;
+			if (bean == null)
+				return m.propertyCache.get(name);
+
+			Object o = null;
+
+			if (getter == null && field == null)
+				throw new BeanRuntimeException(beanMeta.c, "Getter or public field not defined on property ''{0}''", name);
+
+			if (getter != null)
+				o = getter.invoke(bean, (Object[])null);
+
+			else if (field != null)
+				o = field.get(bean);
+
+			o = filter(o);
+			if (o == null)
+				return null;
+			if (properties != null) {
+				if (rawTypeMeta.isArray()) {
+					Object[] a = (Object[])o;
+					List l = new ArrayList(a.length);
+					ClassMeta childType = rawTypeMeta.getElementType();
+					for (Object c : a)
+						l.add(applyChildPropertiesFilter(childType, c));
+					return l;
+				} else if (rawTypeMeta.isCollection()) {
+					Collection c = (Collection)o;
+					List l = new ArrayList(c.size());
+					ClassMeta childType = rawTypeMeta.getElementType();
+					for (Object cc : c)
+						l.add(applyChildPropertiesFilter(childType, cc));
+					return l;
+				} else {
+					return applyChildPropertiesFilter(rawTypeMeta, o);
+				}
+			}
+			return o;
+		} catch (SerializeException e) {
+			throw new BeanRuntimeException(e);
+		} catch (Throwable e) {
+			if (beanMeta.ctx.ignoreInvocationExceptionsOnGetters) {
+				if (rawTypeMeta.isPrimitive())
+					return rawTypeMeta.getPrimitiveDefault();
+				return null;
+			}
+			throw new BeanRuntimeException(beanMeta.c, "Exception occurred while getting property ''{0}''", name).initCause(e);
+		}
+	}
+
+	/**
+	 * Equivalent to calling {@link BeanMap#put(Object, Object)}, but is faster since it avoids
+	 * 	looking up the property meta.
+	 *
+	 * @param m The bean map to set the property value on.
+	 * @param value The value to set.
+	 * @return The previous property value.
+	 * @throws BeanRuntimeException If property could not be set.
+	 */
+	public Object set(BeanMap<T> m, Object value) throws BeanRuntimeException {
+		try {
+			// Comvert to raw form.
+			value = unfilter(value);
+			BeanContext bc = this.beanMeta.ctx;
+
+		if (m.bean == null) {
+
+			// If this bean has subtypes, and we haven't set the subtype yet,
+			// store the property in a temporary cache until the bean can be instantiated.
+			if (m.meta.subTypeIdProperty != null && m.propertyCache == null)
+				m.propertyCache = new TreeMap<String,Object>();
+
+			// Read-only beans get their properties stored in a cache.
+			if (m.propertyCache != null)
+				return m.propertyCache.put(name, value);
+
+			throw new BeanRuntimeException("Non-existent bean instance on bean.");
+		}
+
+			boolean isMap = rawTypeMeta.isMap();
+			boolean isCollection = rawTypeMeta.isCollection();
+
+		if (field == null && setter == null && ! (isMap || isCollection)) {
+			if ((value == null && bc.ignoreUnknownNullBeanProperties) || bc.ignorePropertiesWithoutSetters)
+				return null;
+			throw new BeanRuntimeException(beanMeta.c, "Setter or public field not defined on property ''{0}''", name);
+		}
+
+		Object bean = m.getBean(true);  // Don't use getBean() because it triggers array creation!
+
+		try {
+
+			Object r = beanMeta.ctx.beanMapPutReturnsOldValue || isMap || isCollection ? get(m) : null;
+				Class<?> propertyClass = rawTypeMeta.getInnerClass();
+
+			if (value == null && (isMap || isCollection)) {
+				if (setter != null) {
+					setter.invoke(bean, new Object[] { null });
+					return r;
+				} else if (field != null) {
+					field.set(bean, null);
+					return r;
+				}
+				throw new BeanRuntimeException(beanMeta.c, "Cannot set property ''{0}'' to null because no setter or public field is defined", name);
+			}
+
+			if (isMap) {
+
+				if (! (value instanceof Map)) {
+					if (value instanceof CharSequence)
+						value = new ObjectMap((CharSequence)value).setBeanContext(beanMeta.ctx);
+					else
+						throw new BeanRuntimeException(beanMeta.c, "Cannot set property ''{0}'' of type ''{1}'' to object of type ''{2}''", name, propertyClass.getName(), findClassName(value));
+				}
+
+				Map valueMap = (Map)value;
+				Map propMap = (Map)r;
+					ClassMeta<?> valueType = rawTypeMeta.getValueType();
+
+				// If the property type is abstract, then we either need to reuse the existing
+				// map (if it's not null), or try to assign the value directly.
+					if (! rawTypeMeta.canCreateNewInstance()) {
+					if (propMap == null) {
+						if (setter == null && field == null)
+							throw new BeanRuntimeException(beanMeta.c, "Cannot set property ''{0}'' of type ''{1}'' to object of type ''{2}'' because no setter or public field is defined, and the current value is null", name, propertyClass.getName(), findClassName(value));
+
+						if (propertyClass.isInstance(valueMap)) {
+							if (! valueType.isObject()) {
+								for (Map.Entry e : (Set<Map.Entry>)valueMap.entrySet()) {
+									Object v = e.getValue();
+									if (v != null && ! valueType.getInnerClass().isInstance(v))
+										throw new BeanRuntimeException(beanMeta.c, "Cannot set property ''{0}'' of type ''{1}'' to object of type ''{2}'' because the value types in the assigned map do not match the specified ''elementClass'' attribute on the property, and the property value is currently null", name, propertyClass.getName(), findClassName(value));
+								}
+							}
+							if (setter != null)
+								setter.invoke(bean, valueMap);
+							else
+								field.set(bean, valueMap);
+							return r;
+						}
+						throw new BeanRuntimeException(beanMeta.c, "Cannot set property ''{0}'' of type ''{2}'' to object of type ''{2}'' because the assigned map cannot be converted to the specified type because the property type is abstract, and the property value is currently null", name, propertyClass.getName(), findClassName(value));
+					}
+				} else {
+					if (propMap == null) {
+						propMap = (Map)propertyClass.newInstance();
+						if (setter != null)
+							setter.invoke(bean, propMap);
+						else if (field != null)
+							field.set(bean, propMap);
+						else
+							throw new BeanRuntimeException(beanMeta.c, "Cannot set property ''{0}'' of type ''{1}'' to object of type ''{2}'' because no setter or public field is defined on this property, and the existing property value is null", name, propertyClass.getName(), findClassName(value));
+					} else {
+						propMap.clear();
+					}
+				}
+
+				// Set the values.
+				for (Map.Entry e : (Set<Map.Entry>)valueMap.entrySet()) {
+					Object k = e.getKey();
+					Object v = e.getValue();
+					if (! valueType.isObject())
+						v = beanMeta.ctx.convertToType(v, valueType);
+					propMap.put(k, v);
+				}
+
+			} else if (isCollection) {
+
+				if (! (value instanceof Collection)) {
+					if (value instanceof CharSequence)
+						value = new ObjectList((CharSequence)value).setBeanContext(beanMeta.ctx);
+					else
+						throw new BeanRuntimeException(beanMeta.c, "Cannot set property ''{0}'' of type ''{1}'' to object of type ''{2}''", name, propertyClass.getName(), findClassName(value));
+				}
+
+				Collection valueList = (Collection)value;
+				Collection propList = (Collection)r;
+					ClassMeta elementType = rawTypeMeta.getElementType();
+
+				// If the property type is abstract, then we either need to reuse the existing
+				// collection (if it's not null), or try to assign the value directly.
+					if (! rawTypeMeta.canCreateNewInstance()) {
+					if (propList == null) {
+						if (setter == null && field == null)
+							throw new BeanRuntimeException(beanMeta.c, "Cannot set property ''{0}'' of type ''{1}'' to object of type ''{2}'' because no setter or public field is defined, and the current value is null", name, propertyClass.getName(), findClassName(value));
+
+						if (propertyClass.isInstance(valueList)) {
+							if (! elementType.isObject()) {
+									List l = new ObjectList(valueList);
+									for (ListIterator<Object> i = l.listIterator(); i.hasNext(); ) {
+										Object v = i.next();
+										if (v != null && (! elementType.getInnerClass().isInstance(v))) {
+											i.set(bc.convertToType(v, elementType));
+										}
+									}
+									valueList = l;
+								}
+							if (setter != null)
+								setter.invoke(bean, valueList);
+							else
+								field.set(bean, valueList);
+							return r;
+						}
+						throw new BeanRuntimeException(beanMeta.c, "Cannot set property ''{0}'' of type ''{1}'' to object of type ''{2}'' because the assigned map cannot be converted to the specified type because the property type is abstract, and the property value is currently null", name, propertyClass.getName(), findClassName(value));
+					}
+					propList.clear();
+				} else {
+					if (propList == null) {
+						propList = (Collection)propertyClass.newInstance();
+						if (setter != null)
+							setter.invoke(bean, propList);
+						else if (field != null)
+							field.set(bean, propList);
+						else
+							throw new BeanRuntimeException(beanMeta.c, "Cannot set property ''{0}'' of type ''{1}'' to object of type ''{2}'' because no setter is defined on this property, and the existing property value is null", name, propertyClass.getName(), findClassName(value));
+					} else {
+						propList.clear();
+					}
+				}
+
+				// Set the values.
+				for (Object v : valueList) {
+					if (! elementType.isObject())
+						v = beanMeta.ctx.convertToType(v, elementType);
+					propList.add(v);
+				}
+
+			} else {
+				if (filter != null && value != null && isParentClass(filter.getFilteredClass(), value.getClass())) {
+						value = filter.unfilter(value, rawTypeMeta);
+				} else {
+						value = beanMeta.ctx.convertToType(value, rawTypeMeta);
+					}
+				if (setter != null)
+					setter.invoke(bean, new Object[] { value });
+				else if (field != null)
+					field.set(bean, value);
+			}
+
+			return r;
+
+		} catch (BeanRuntimeException e) {
+			throw e;
+		} catch (Exception e) {
+			if (beanMeta.ctx.ignoreInvocationExceptionsOnSetters) {
+					if (rawTypeMeta.isPrimitive())
+						return rawTypeMeta.getPrimitiveDefault();
+				return null;
+			}
+			throw new BeanRuntimeException(beanMeta.c, "Error occurred trying to set property ''{0}''", name).initCause(e);
+		}
+		} catch (ParseException e) {
+			throw new BeanRuntimeException(e);
+		}
+	}
+
+	/**
+	 * Sets an array field on this bean.
+	 * Works on both <code>Object</code> and primitive arrays.
+	 *
+	 * @param bean The bean of the field.
+	 * @param l The collection to use to set the array field.
+	 * @throws IllegalArgumentException Thrown by method invocation.
+	 * @throws IllegalAccessException Thrown by method invocation.
+	 * @throws InvocationTargetException Thrown by method invocation.
+	 */
+	protected void setArray(T bean, List l) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
+		Object array = ArrayUtils.toArray(l, this.rawTypeMeta.getElementType().getInnerClass());
+		if (setter != null)
+			setter.invoke(bean, array);
+		else if (field != null)
+			field.set(bean, array);
+		else
+			throw new BeanRuntimeException(beanMeta.c, "Attempt to initialize array property ''{0}'', but no setter or field defined.", name);
+	}
+
+	/**
+	 * Adds a value to a {@link Collection} or array property.
+	 * Note that adding values to an array property is inefficient for large
+	 * arrays since it must copy the array into a larger array on each operation.
+	 *
+	 * @param m The bean of the field being set.
+	 * @param value The value to add to the field.
+	 * @throws BeanRuntimeException If field is not a collection or array.
+	 */
+	public void add(BeanMap<T> m, Object value) throws BeanRuntimeException {
+
+		BeanContext bc = beanMeta.ctx;
+
+		// Read-only beans get their properties stored in a cache.
+		if (m.bean == null) {
+			if (! m.propertyCache.containsKey(name))
+				m.propertyCache.put(name, new ObjectList(bc));
+			((ObjectList)m.propertyCache.get(name)).add(value);
+			return;
+		}
+
+		boolean isCollection = rawTypeMeta.isCollection();
+		boolean isArray = rawTypeMeta.isArray();
+
+		if (! (isCollection || isArray))
+			throw new BeanRuntimeException(beanMeta.c, "Attempt to add element to property ''{0}'' which is not a collection or array", name);
+
+		Object bean = m.getBean(true);
+
+		ClassMeta<?> elementType = rawTypeMeta.getElementType();
+
+		try {
+			Object v = bc.convertToType(value, elementType);
+
+			if (isCollection) {
+				Collection c = null;
+				if (getter != null) {
+					c = (Collection)getter.invoke(bean, (Object[])null);
+				} else if (field != null) {
+					c = (Collection)field.get(bean);
+				} else {
+					throw new BeanRuntimeException(beanMeta.c, "Attempt to append to collection property ''{0}'', but no getter or field defined.", name);
+				}
+
+				if (c != null) {
+					c.add(v);
+					return;
+				}
+
+				if (rawTypeMeta.canCreateNewInstance())
+					c = (Collection)rawTypeMeta.newInstance();
+				else
+					c = new ObjectList(bc);
+
+				c.add(v);
+
+				if (setter != null)
+					setter.invoke(bean, c);
+				else if (field != null)
+					field.set(bean, c);
+				else
+					throw new BeanRuntimeException(beanMeta.c, "Attempt to initialize collection property ''{0}'', but no setter or field defined.", name);
+
+			} else /* isArray() */ {
+
+				if (m.arrayPropertyCache == null)
+					m.arrayPropertyCache = new TreeMap<String,List<?>>();
+
+				List l = m.arrayPropertyCache.get(name);
+				if (l == null) {
+					l = new LinkedList();  // ArrayLists and LinkLists appear to perform equally.
+					m.arrayPropertyCache.put(name, l);
+
+					// Copy any existing array values into the temporary list.
+					Object oldArray;
+				if (getter != null)
+						oldArray = getter.invoke(bean, (Object[])null);
+				else if (field != null)
+						oldArray = field.get(bean);
+				else
+					throw new BeanRuntimeException(beanMeta.c, "Attempt to append to array property ''{0}'', but no getter or field defined.", name);
+					ArrayUtils.copyToList(oldArray, l);
+				}
+
+				// Add new entry to our array.
+				l.add(v);
+			}
+
+		} catch (BeanRuntimeException e) {
+			throw e;
+		} catch (Exception e) {
+			throw new BeanRuntimeException(e);
+		}
+	}
+
+	/**
+	 * Returns all instances of the specified annotation in the hierarchy of this bean property.
+	 * <p>
+	 * Searches through the class hierarchy (e.g. superclasses, interfaces, packages) for all
+	 * instances of the specified annotation.
+	 *
+	 * @param a The class to find annotations for.
+	 * @return A list of annotations ordered in child-to-parent order.  Never <jk>null</jk>.
+	 */
+	public <A extends Annotation> List<A> findAnnotations(Class<A> a) {
+		List<A> l = new LinkedList<A>();
+		if (field != null) {
+			addIfNotNull(l, field.getAnnotation(a));
+			appendAnnotations(a, field.getType(), l);
+		}
+		if (getter != null) {
+			addIfNotNull(l, getter.getAnnotation(a));
+			appendAnnotations(a, getter.getReturnType(), l);
+		}
+		if (setter != null) {
+			addIfNotNull(l, setter.getAnnotation(a));
+			appendAnnotations(a, setter.getReturnType(), l);
+		}
+		appendAnnotations(a, this.getBeanMeta().getClassMeta().getInnerClass(), l);
+		return l;
+	}
+
+	private Object filter(Object o) throws SerializeException {
+		// First use filter defined via @BeanProperty.
+		if (filter != null)
+			return filter.filter(o);
+		if (o == null)
+			return null;
+		// Otherwise, look it up via bean context.
+		if (rawTypeMeta.hasChildPojoFilters()) {
+			Class c = o.getClass();
+			ClassMeta<?> cm = rawTypeMeta.innerClass == c ? rawTypeMeta : beanMeta.ctx.getClassMeta(c);
+			PojoFilter f = cm.getPojoFilter();
+			if (f != null)
+				return f.filter(o);
+		}
+		return o;
+	}
+
+	private Object unfilter(Object o) throws ParseException {
+		if (filter != null)
+			return filter.unfilter(o, rawTypeMeta);
+		if (o == null)
+			return null;
+		if (rawTypeMeta.hasChildPojoFilters()) {
+			Class c = o.getClass();
+			ClassMeta<?> cm = rawTypeMeta.innerClass == c ? rawTypeMeta : beanMeta.ctx.getClassMeta(c);
+			PojoFilter f = cm.getPojoFilter();
+			if (f != null)
+				return f.unfilter(o, rawTypeMeta);
+		}
+		return o;
+	}
+
+	private Object applyChildPropertiesFilter(ClassMeta cm, Object o) {
+		if (o == null)
+			return null;
+		if (cm.isBean())
+			return new BeanMap(o, new BeanMetaFiltered(cm.getBeanMeta(), properties));
+		if (cm.isMap())
+			return new FilteredMap((Map)o, properties);
+		if (cm.isObject()) {
+			if (o instanceof Map)
+				return new FilteredMap((Map)o, properties);
+			BeanMeta bm = this.getBeanMeta().ctx.getBeanMeta(o.getClass());
+			if (bm != null)
+				return new BeanMap(o, new BeanMetaFiltered(cm.getBeanMeta(), properties));
+		}
+		return o;
+	}
+
+	private String findClassName(Object o) {
+		if (o == null)
+			return null;
+		if (o instanceof Class)
+			return ((Class<?>)o).getName();
+		return o.getClass().getName();
+	}
+
+	@Override /* Object */
+	public String toString() {
+		return name + ": " + this.rawTypeMeta.getInnerClass().getName() + ", field=["+field+"], getter=["+getter+"], setter=["+setter+"]";
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/BeanProxyInvocationHandler.class
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/BeanProxyInvocationHandler.class b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/BeanProxyInvocationHandler.class
new file mode 100755
index 0000000..4b8f78d
Binary files /dev/null and b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/BeanProxyInvocationHandler.class differ

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/BeanProxyInvocationHandler.java
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/BeanProxyInvocationHandler.java b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/BeanProxyInvocationHandler.java
new file mode 100755
index 0000000..3e628aa
--- /dev/null
+++ b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/BeanProxyInvocationHandler.java
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * Licensed Materials - Property of IBM
+ * (c) Copyright IBM Corporation 2014, 2015. All Rights Reserved.
+ *
+ *  The source code for this program is not published or otherwise
+ *  divested of its trade secrets, irrespective of what has been
+ *  deposited with the U.S. Copyright Office.
+ *******************************************************************************/
+package com.ibm.juno.core;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+/**
+ * Provides an {@link InvocationHandler} for creating beans from bean interfaces.
+ * <p>
+ * 	If the {@code useInterfaceProxies} setting is enabled in {@link BeanContext}, this
+ * 	is the class that creates instances of beans from interfaces.
+ *
+ * @author Barry M. Caceres
+ * @param <T> The interface class
+ */
+public class BeanProxyInvocationHandler<T> implements InvocationHandler {
+
+	private final BeanMeta<T> meta;						// The BeanMeta for this instance
+	private Map<String, Object> beanProps;		// The map of property names to bean property values.
+
+	/**
+	 * Constructs with the specified {@link BeanMeta}.
+	 *
+	 * @param meta The bean meta data.
+	 */
+	public BeanProxyInvocationHandler(BeanMeta<T> meta) {
+		this.meta = meta;
+		this.beanProps = new HashMap<String, Object>();
+	}
+
+	/**
+	 * Implemented to handle the method called.
+	 */
+	@Override /* InvocationHandler */
+	public Object invoke(Object proxy, Method method, Object[] args) {
+		Class<?>[] paramTypes = method.getParameterTypes();
+		if (method.getName().equals("equals") && (paramTypes.length == 1) && (paramTypes[0] == java.lang.Object.class)) {
+			Object arg = args[0];
+			if (arg == null)
+				return false;
+			if (proxy == arg)
+				return true;
+			if (proxy.getClass() == arg.getClass()) {
+				InvocationHandler ih = Proxy.getInvocationHandler(arg);
+				if (ih instanceof BeanProxyInvocationHandler) {
+					return this.beanProps.equals(((BeanProxyInvocationHandler<?>)ih).beanProps);
+				}
+			}
+			BeanMap<Object> bean = this.meta.ctx.forBean(arg);
+			return this.beanProps.equals(bean);
+		}
+
+		if (method.getName().equals("hashCode") && (paramTypes.length == 0))
+			return Integer.valueOf(this.beanProps.hashCode());
+
+		if (method.getName().equals("toString") && (paramTypes.length == 0))
+			return this.beanProps.toString();
+
+		String prop = this.meta.getterProps.get(method);
+		if (prop != null)
+			return this.beanProps.get(prop);
+
+		prop = this.meta.setterProps.get(method);
+		if (prop != null) {
+			this.beanProps.put(prop, args[0]);
+			return null;
+		}
+
+		throw new UnsupportedOperationException("Unsupported bean method.  method=[ " + method + " ]");
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/BeanRuntimeException.class
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/BeanRuntimeException.class b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/BeanRuntimeException.class
new file mode 100755
index 0000000..e3247f1
Binary files /dev/null and b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/BeanRuntimeException.class differ

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/BeanRuntimeException.java
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/BeanRuntimeException.java b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/BeanRuntimeException.java
new file mode 100755
index 0000000..f931e98
--- /dev/null
+++ b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/BeanRuntimeException.java
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * Licensed Materials - Property of IBM
+ * (c) Copyright IBM Corporation 2014, 2015. All Rights Reserved.
+ *
+ * Note to U.S. Government Users Restricted Rights:  Use,
+ * duplication or disclosure restricted by GSA ADP Schedule
+ * Contract with IBM Corp.
+ *******************************************************************************/
+package com.ibm.juno.core;
+
+import java.text.*;
+
+/**
+ * General bean runtime operation exception.
+ *
+ * @author James Bognar (jbognar@us.ibm.com)
+ */
+public final class BeanRuntimeException extends RuntimeException {
+
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * Constructor.
+	 *
+	 * @param message The error message.
+	 */
+	public BeanRuntimeException(String message) {
+		super(message);
+	}
+
+	/**
+	 * Shortcut for calling <code><jk>new</jk> BeanRuntimeException(String.format(c.getName() + <js>": "</js> + message, args));</code>
+	 *
+	 * @param c The class name of the bean that caused the exception.
+	 * @param message The error message.
+	 * @param args Arguments passed in to the {@code String.format()} method.
+	 */
+	public BeanRuntimeException(Class<?> c, String message, Object... args) {
+		this(c.getName() + ": " + (args.length == 0 ? message : MessageFormat.format(message, args)));
+	}
+
+	/**
+	 * Constructor.
+	 *
+	 * @param cause The initial cause of the exception.
+	 */
+	public BeanRuntimeException(Throwable cause) {
+		super(cause == null ? null : cause.getLocalizedMessage());
+		initCause(cause);
+	}
+
+	/**
+	 * Sets the inner cause for this exception.
+	 *
+	 * @param cause The inner cause.
+	 * @return This object (for method chaining).
+	 */
+	@Override /* Throwable */
+	public synchronized BeanRuntimeException initCause(Throwable cause) {
+		super.initCause(cause);
+		return this;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/ClassMeta$1.class
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/ClassMeta$1.class b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/ClassMeta$1.class
new file mode 100755
index 0000000..6ff209f
Binary files /dev/null and b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/ClassMeta$1.class differ

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/ClassMeta$ClassCategory.class
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/ClassMeta$ClassCategory.class b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/ClassMeta$ClassCategory.class
new file mode 100755
index 0000000..28f91ed
Binary files /dev/null and b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/ClassMeta$ClassCategory.class differ

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/ClassMeta.class
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/ClassMeta.class b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/ClassMeta.class
new file mode 100755
index 0000000..7e0e41a
Binary files /dev/null and b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/ClassMeta.class differ

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/ClassMeta.java
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/ClassMeta.java b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/ClassMeta.java
new file mode 100755
index 0000000..a95bfdb
--- /dev/null
+++ b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/ClassMeta.java
@@ -0,0 +1,1262 @@
+/*******************************************************************************
+ * Licensed Materials - Property of IBM
+ * (c) Copyright IBM Corporation 2014, 2015. All Rights Reserved.
+ *
+ *  The source code for this program is not published or otherwise
+ *  divested of its trade secrets, irrespective of what has been
+ *  deposited with the U.S. Copyright Office.
+ *******************************************************************************/
+package com.ibm.juno.core;
+
+import static com.ibm.juno.core.ClassMeta.ClassCategory.*;
+import static com.ibm.juno.core.ClassMeta.ClassCategory.URI;
+import static com.ibm.juno.core.utils.ClassUtils.*;
+
+import java.io.*;
+import java.lang.reflect.*;
+import java.lang.reflect.Proxy;
+import java.net.*;
+import java.net.URI;
+import java.util.*;
+
+import com.ibm.juno.core.annotation.*;
+import com.ibm.juno.core.filter.*;
+import com.ibm.juno.core.filter.Filter;
+import com.ibm.juno.core.html.*;
+import com.ibm.juno.core.jena.*;
+import com.ibm.juno.core.json.*;
+import com.ibm.juno.core.urlencoding.*;
+import com.ibm.juno.core.utils.*;
+import com.ibm.juno.core.xml.*;
+
+/**
+ * A wrapper class around the {@link Class} object that provides cached information
+ * about that class.
+ *
+ * <p>
+ * 	Instances of this class can be created through the {@link BeanContext#getClassMeta(Class)} method.
+ * <p>
+ * 	The {@link BeanContext} class will cache and reuse instances of this class except for the following class types:
+ * <ul>
+ * 	<li>Arrays
+ * 	<li>Maps with non-Object key/values.
+ * 	<li>Collections with non-Object key/values.
+ * </ul>
+ * <p>
+ * 	This class is tied to the {@link BeanContext} class because it's that class that makes the determination
+ * 	of what is a bean.
+ *
+ * @author James Bognar (jbognar@us.ibm.com)
+ * @param <T> The class type of the wrapped class.
+ */
+@Bean(properties={"innerClass","classCategory","elementType","keyType","valueType","notABeanReason","initException","beanMeta"})
+public final class ClassMeta<T> implements Type {
+
+	/** Class categories. */
+	enum ClassCategory {
+		MAP, COLLECTION, NUMBER, DECIMAL, BOOLEAN, CHAR, DATE, ARRAY, ENUM, BEAN, UNKNOWN, OTHER, CHARSEQ, STR, OBJ, URI, BEANMAP, READER, INPUTSTREAM
+	}
+
+	final BeanContext beanContext;                    // The bean context that created this object.
+	ClassCategory classCategory = UNKNOWN;            // The class category.
+	final Class<T> innerClass;                        // The class being wrapped.
+	ClassMeta<?>
+		filteredClassMeta,                             // The filtered class type (in class has filter associated with it.
+		elementType = null,                            // If ARRAY or COLLECTION, the element class type.
+		keyType = null,                                // If MAP, the key class type.
+		valueType = null;                              // If MAP, the value class type.
+	InvocationHandler invocationHandler;              // The invocation handler for this class (if it has one).
+	volatile BeanMeta<T> beanMeta;                    // The bean meta for this bean class (if it's a bean).
+	Method valueOfMethod;                             // The static valueOf(String) or fromString(String) method (if it has one).
+	Constructor<? extends T> noArgConstructor;        // The no-arg constructor for this class (if it has one).
+	Constructor<T> stringConstructor;                 // The X(String) constructor (if it has one).
+	Constructor<T> objectMapConstructor;              // The X(ObjectMap) constructor (if it has one).
+	Method toObjectMapMethod;                         // The toObjectMap() method (if it has one).
+	Method namePropertyMethod;                        // The method to set the name on an object (if it has one).
+	Method parentPropertyMethod;                      // The method to set the parent on an object (if it has one).
+	String notABeanReason;                            // If this isn't a bean, the reason why.
+	PojoFilter<T,?> pojoFilter;                       // The object filter associated with this bean (if it has one).
+	BeanFilter<? extends T> beanFilter;               // The bean filter associated with this bean (if it has one).
+	boolean
+		isDelegate,                                    // True if this class extends Delegate.
+		isAbstract,                                    // True if this class is abstract.
+		isMemberClass;                                 // True if this is a non-static member class.
+
+	private XmlClassMeta xmlMeta;                      // Class-related metadata from the @Xml annotation found on this class or parent class.
+	private JsonClassMeta jsonMeta;                    // Class-related metadata from the @Json annotation found on this class or parent class.
+	private HtmlClassMeta htmlMeta;                    // Class-related metadata from the @Html annotation found on this class or parent class.
+	private UrlEncodingClassMeta urlEncodingMeta;      // Class-related metadata from the @UrlEncoding annotation found on this class or parent class.
+	private RdfClassMeta rdfMeta;                      // Class-related metadata from the @Rdf annotation found on this class or parent class.
+
+	private Throwable initException;                  // Any exceptions thrown in the init() method.
+	private boolean hasChildPojoFilters;              // True if this class or any subclass of this class has a PojoFilter associated with it.
+	private Object primitiveDefault;                  // Default value for primitive type classes.
+	private Map<String,Method> remoteableMethods,     // Methods annotated with @Remoteable.  Contains all public methods if class is annotated with @Remotable.
+		publicMethods;                                 // All public methods, including static methods.
+
+	private static final Boolean BOOLEAN_DEFAULT = false;
+	private static final Character CHARACTER_DEFAULT = (char)0;
+	private static final Short SHORT_DEFAULT = (short)0;
+	private static final Integer INTEGER_DEFAULT = 0;
+	private static final Long LONG_DEFAULT = 0l;
+	private static final Float FLOAT_DEFAULT = 0f;
+	private static final Double DOUBLE_DEFAULT = 0d;
+	private static final Byte BYTE_DEFAULT = (byte)0;
+
+	/**
+	 * Shortcut for calling <code>ClassMeta(innerClass, beanContext, <jk>false</jk>)</code>.
+	 */
+	ClassMeta(Class<T> innerClass, BeanContext beanContext) {
+		this(innerClass, beanContext, false);
+	}
+
+	/**
+	 * Construct a new {@code ClassMeta} based on the specified {@link Class}.
+	 *
+	 * @param innerClass The class being wrapped.
+	 * @param beanContext The bean context that created this object.
+	 * @param delayedInit Don't call init() in constructor.
+	 * 	Used for delayed initialization when the possibility of class reference loops exist.
+	 */
+	ClassMeta(Class<T> innerClass, BeanContext beanContext, boolean delayedInit) {
+		this.innerClass = innerClass;
+		this.beanContext = beanContext;
+		if (! delayedInit)
+			init();
+	}
+
+
+	@SuppressWarnings({ "unchecked", "rawtypes" })
+	ClassMeta init() {
+
+		try {
+			Filter filter = findFilter(beanContext);
+			if (filter != null) {
+				if (filter.getType() == Filter.FilterType.BEAN)
+					beanFilter = (BeanFilter)filter;
+				else
+					pojoFilter = (PojoFilter)filter;
+				filteredClassMeta = (pojoFilter == null ? this : beanContext.getClassMeta(pojoFilter.getFilteredClass()));
+			} else {
+				filteredClassMeta = this;
+			}
+
+			if (innerClass != Object.class) {
+				this.noArgConstructor = beanContext.getImplClassConstructor(innerClass, Visibility.PUBLIC);
+				if (noArgConstructor == null)
+					noArgConstructor = findNoArgConstructor(innerClass, Visibility.PUBLIC);
+			}
+
+			this.hasChildPojoFilters = beanContext.hasChildPojoFilters(innerClass);
+
+			this.xmlMeta = new XmlClassMeta(innerClass);
+			this.jsonMeta = new JsonClassMeta(innerClass);
+			this.htmlMeta = new HtmlClassMeta(innerClass);
+			this.urlEncodingMeta = new UrlEncodingClassMeta(innerClass);
+			this.rdfMeta = new RdfClassMeta(innerClass);
+
+			Class c = innerClass;
+
+			if (c.isPrimitive()) {
+				if (c == Boolean.TYPE)
+					classCategory = BOOLEAN;
+				else if (c == Byte.TYPE || c == Short.TYPE || c == Integer.TYPE || c == Long.TYPE || c == Float.TYPE || c == Double.TYPE) {
+					if (c == Float.TYPE || c == Double.TYPE)
+						classCategory = DECIMAL;
+					else
+						classCategory = NUMBER;
+				}
+				else if (c == Character.TYPE)
+					classCategory = CHAR;
+			} else {
+				if (isParentClass(Delegate.class, c))
+					isDelegate = true;
+				if (c == Object.class)
+					classCategory = OBJ;
+				else if (c.isEnum())
+					classCategory = ENUM;
+				else if (isParentClass(CharSequence.class, c)) {
+					if (c.equals(String.class))
+						classCategory = STR;
+					else
+						classCategory = CHARSEQ;
+				}
+				else if (isParentClass(Number.class, c)) {
+					if (isParentClass(Float.class, c) || isParentClass(Double.class, c))
+						classCategory = DECIMAL;
+					else
+						classCategory = NUMBER;
+				}
+				else if (isParentClass(Collection.class, c))
+					classCategory = COLLECTION;
+				else if (isParentClass(Map.class, c)) {
+					if (isParentClass(BeanMap.class, c))
+						classCategory = BEANMAP;
+					else
+						classCategory = MAP;
+				}
+				else if (c == Character.class)
+					classCategory = CHAR;
+				else if (c == Boolean.class)
+					classCategory = BOOLEAN;
+				else if (isParentClass(Date.class, c) || isParentClass(Calendar.class, c))
+					classCategory = DATE;
+				else if (c.isArray())
+					classCategory = ARRAY;
+				else if (isParentClass(URL.class, c) || isParentClass(URI.class, c) || c.isAnnotationPresent(com.ibm.juno.core.annotation.URI.class))
+					classCategory = URI;
+				else if (isParentClass(Reader.class, c))
+					classCategory = READER;
+				else if (isParentClass(InputStream.class, c))
+					classCategory = INPUTSTREAM;
+			}
+
+			isMemberClass = c.isMemberClass() && ! Modifier.isStatic(c.getModifiers());
+
+			// Find static fromString(String) or equivalent method.
+			// fromString() must be checked before valueOf() so that Enum classes can create their own
+			//		specialized fromString() methods to override the behavior of Enum.valueOf(String).
+			// valueOf() is used by enums.
+			// parse() is used by the java logging Level class.
+			// forName() is used by Class and Charset
+			for (String methodName : new String[]{"fromString","valueOf","parse","parseString","forName"}) {
+				if (this.valueOfMethod == null) {
+			for (Method m : c.getMethods()) {
+				int mod = m.getModifiers();
+				if (Modifier.isStatic(mod) && Modifier.isPublic(mod)) {
+					String mName = m.getName();
+							if (mName.equals(methodName) && m.getReturnType() == innerClass) {
+						Class<?>[] args = m.getParameterTypes();
+						if (args.length == 1 && args[0] == String.class) {
+							this.valueOfMethod = m;
+							break;
+						}
+					}
+				}
+			}
+				}
+			}
+
+			// Find toObjectMap() method if present.
+			for (Method m : c.getMethods()) {
+				int mod = m.getModifiers();
+				if (Modifier.isPublic(mod) && ! Modifier.isStatic(mod)) {
+					String mName = m.getName();
+					if (mName.equals("toObjectMap")) {
+						if (m.getParameterTypes().length == 0 && m.getReturnType() == ObjectMap.class) {
+							this.toObjectMapMethod = m;
+							break;
+						}
+					}
+				}
+			}
+
+			// Find @NameProperty and @ParentProperty methods if present.
+			for (Method m : c.getDeclaredMethods()) {
+				if (m.isAnnotationPresent(ParentProperty.class) && m.getParameterTypes().length == 1) {
+					m.setAccessible(true);
+					parentPropertyMethod = m;
+				}
+				if (m.isAnnotationPresent(NameProperty.class) && m.getParameterTypes().length == 1) {
+					m.setAccessible(true);
+					namePropertyMethod = m;
+				}
+			}
+
+			// Find constructor(String) method if present.
+			for (Constructor cs : c.getConstructors()) {
+				int mod = cs.getModifiers();
+				if (Modifier.isPublic(mod)) {
+					Class<?>[] args = cs.getParameterTypes();
+					if (args.length == (isMemberClass ? 2 : 1)) {
+						Class<?> arg = args[(isMemberClass ? 1 : 0)];
+						if (arg == String.class)
+						this.stringConstructor = cs;
+						else if (ObjectMap.class.isAssignableFrom(arg))
+							this.objectMapConstructor = cs;
+					}
+				}
+			}
+
+			// Note:  Primitive types are normally abstract.
+			isAbstract = Modifier.isAbstract(c.getModifiers()) && ! isPrimitive();
+
+			// If this is an array, get the element type.
+			if (classCategory == ARRAY)
+				elementType = beanContext.getClassMeta(innerClass.getComponentType());
+
+			// If this is a MAP, see if it's parameterized (e.g. AddressBook extends HashMap<String,Person>)
+			else if (classCategory == MAP) {
+				ClassMeta[] parameters = beanContext.findParameters(innerClass, innerClass);
+				if (parameters != null && parameters.length == 2) {
+					keyType = parameters[0];
+					valueType = parameters[1];
+				} else {
+					keyType = beanContext.getClassMeta(Object.class);
+					valueType = beanContext.getClassMeta(Object.class);
+				}
+			}
+
+			// If this is a COLLECTION, see if it's parameterized (e.g. AddressBook extends LinkedList<Person>)
+			else if (classCategory == COLLECTION) {
+				ClassMeta[] parameters = beanContext.findParameters(innerClass, innerClass);
+				if (parameters != null && parameters.length == 1) {
+					elementType = parameters[0];
+				} else {
+					elementType = beanContext.getClassMeta(Object.class);
+				}
+			}
+
+			// If the category is unknown, see if it's a bean.
+			// Note that this needs to be done after all other initialization has been done.
+			else if (classCategory == UNKNOWN) {
+
+				BeanMeta newMeta = new BeanMeta(this, beanContext, beanFilter);
+				try {
+					notABeanReason = newMeta.init();
+				} catch (RuntimeException e) {
+					notABeanReason = e.getMessage();
+					throw e;
+				}
+				if (notABeanReason != null)
+					classCategory = OTHER;
+				else {
+					beanMeta = newMeta;
+					classCategory = BEAN;
+				}
+			}
+
+			if (c.isPrimitive()) {
+				if (c == Boolean.TYPE)
+					primitiveDefault = BOOLEAN_DEFAULT;
+				else if (c == Character.TYPE)
+					primitiveDefault = CHARACTER_DEFAULT;
+				else if (c == Short.TYPE)
+					primitiveDefault = SHORT_DEFAULT;
+				else if (c == Integer.TYPE)
+					primitiveDefault = INTEGER_DEFAULT;
+				else if (c == Long.TYPE)
+					primitiveDefault = LONG_DEFAULT;
+				else if (c == Float.TYPE)
+					primitiveDefault = FLOAT_DEFAULT;
+				else if (c == Double.TYPE)
+					primitiveDefault = DOUBLE_DEFAULT;
+				else if (c == Byte.TYPE)
+					primitiveDefault = BYTE_DEFAULT;
+			} else {
+				if (c == Boolean.class)
+					primitiveDefault = BOOLEAN_DEFAULT;
+				else if (c == Character.class)
+					primitiveDefault = CHARACTER_DEFAULT;
+				else if (c == Short.class)
+					primitiveDefault = SHORT_DEFAULT;
+				else if (c == Integer.class)
+					primitiveDefault = INTEGER_DEFAULT;
+				else if (c == Long.class)
+					primitiveDefault = LONG_DEFAULT;
+				else if (c == Float.class)
+					primitiveDefault = FLOAT_DEFAULT;
+				else if (c == Double.class)
+					primitiveDefault = DOUBLE_DEFAULT;
+				else if (c == Byte.class)
+					primitiveDefault = BYTE_DEFAULT;
+			}
+		} catch (NoClassDefFoundError e) {
+			this.initException = e;
+		} catch (RuntimeException e) {
+			this.initException = e;
+			throw e;
+		}
+
+		if (innerClass.getAnnotation(Remoteable.class) != null) {
+			remoteableMethods = getPublicMethods();
+		} else {
+			for (Method m : innerClass.getMethods()) {
+				if (m.getAnnotation(Remoteable.class) != null) {
+					if (remoteableMethods == null)
+						remoteableMethods = new LinkedHashMap<String,Method>();
+					remoteableMethods.put(ClassUtils.getMethodSignature(m), m);
+				}
+			}
+		}
+		if (remoteableMethods != null)
+			remoteableMethods = Collections.unmodifiableMap(remoteableMethods);
+
+		return this;
+	}
+
+	/**
+	 * Returns the category of this class.
+	 *
+	 * @return The category of this class.
+	 */
+	public ClassCategory getClassCategory() {
+		return classCategory;
+	}
+
+	/**
+	 * Returns <jk>true</jk> if this class is a superclass of or the same as the specified class.
+	 *
+	 * @param c The comparison class.
+	 * @return <jk>true</jk> if this class is a superclass of or the same as the specified class.
+	 */
+	public boolean isAssignableFrom(Class<?> c) {
+		return isParentClass(innerClass, c);
+	}
+
+	/**
+	 * Returns <jk>true</jk> if this class as subtypes defined through {@link Bean#subTypes} or {@link BeanFilter#getSubTypes()}.
+	 *
+	 * @return <jk>true</jk> if this class has subtypes.
+	 */
+	public boolean hasSubTypes() {
+		return beanFilter != null && beanFilter.getSubTypeProperty() != null;
+	}
+
+	/**
+	 * Returns <jk>true</jk> if this class is a subclass of or the same as the specified class.
+	 *
+	 * @param c The comparison class.
+	 * @return <jk>true</jk> if this class is a subclass of or the same as the specified class.
+	 */
+	public boolean isInstanceOf(Class<?> c) {
+		return isParentClass(c, innerClass);
+	}
+
+	/**
+	 * Returns <jk>true</jk> if this class or any child classes has a {@link PojoFilter} associated with it.
+	 * <p>
+	 * Used when filtering bean properties to prevent having to look up filters if we know for certain
+	 * that no filters are associated with a bean property.
+	 *
+	 * @return <jk>true</jk> if this class or any child classes has a {@link PojoFilter} associated with it.
+	 */
+	public boolean hasChildPojoFilters() {
+		return hasChildPojoFilters;
+	}
+
+	private Filter findFilter(BeanContext context) {
+		try {
+			com.ibm.juno.core.annotation.Filter b = innerClass.getAnnotation(com.ibm.juno.core.annotation.Filter.class);
+			if (b != null) {
+				Class<? extends Filter> c = b.value();
+				if (c != Filter.NULL.class) {
+					Filter f = c.newInstance();
+					f.setBeanContext(context);
+					return f;
+				}
+			}
+			if (context == null)
+				return null;
+			Filter f = context.findBeanFilter(innerClass);
+			if (f != null)
+				return f;
+			f = context.findPojoFilter(innerClass);
+			if (f != null)
+				return f;
+			List<Bean> ba = ReflectionUtils.findAnnotations(Bean.class, innerClass);
+			if (! ba.isEmpty())
+				f = new AnnotationBeanFilter<T>(innerClass, ba);
+			return f;
+		} catch (Exception e) {
+			throw new RuntimeException(e);
+		}
+	}
+
+	/**
+	 * Locates the no-arg constructor for the specified class.
+	 * Constructor must match the visibility requirements specified by parameter 'v'.
+	 * If class is abstract, always returns <jk>null</jk>.
+	 * Note that this also returns the 1-arg constructor for non-static member classes.
+	 *
+	 * @param c The class from which to locate the no-arg constructor.
+	 * @param v The minimum visibility.
+	 * @return The constructor, or <jk>null</jk> if no no-arg constructor exists with the required visibility.
+	 */
+	@SuppressWarnings({"rawtypes","unchecked"})
+	protected static <T> Constructor<? extends T> findNoArgConstructor(Class<T> c, Visibility v) {
+		int mod = c.getModifiers();
+		if (Modifier.isAbstract(mod))
+			return null;
+		boolean isMemberClass = c.isMemberClass() && ! Modifier.isStatic(mod);
+		for (Constructor cc : c.getConstructors()) {
+			mod = cc.getModifiers();
+			if (cc.getParameterTypes().length == (isMemberClass ? 1 : 0) && v.isVisible(mod))
+				return v.filter(cc);
+		}
+		return null;
+	}
+
+	/**
+	 * Set element type on non-cached <code>Collection</code> types.
+	 *
+	 * @param elementType The class type for elements in the collection class represented by this metadata.
+	 * @return This object (for method chaining).
+	 */
+	protected ClassMeta<T> setElementType(ClassMeta<?> elementType) {
+		this.elementType = elementType;
+		return this;
+	}
+
+	/**
+	 * Set key type on non-cached <code>Map</code> types.
+	 *
+	 * @param keyType The class type for keys in the map class represented by this metadata.
+	 * @return This object (for method chaining).
+	 */
+	protected ClassMeta<T> setKeyType(ClassMeta<?> keyType) {
+		this.keyType = keyType;
+		return this;
+	}
+
+	/**
+	 * Set value type on non-cached <code>Map</code> types.
+	 *
+	 * @param valueType The class type for values in the map class represented by this metadata.
+	 * @return This object (for method chaining).
+	 */
+	protected ClassMeta<T> setValueType(ClassMeta<?> valueType) {
+		this.valueType = valueType;
+		return this;
+	}
+
+	/**
+	 * Returns the {@link Class} object that this class type wraps.
+	 *
+	 * @return The wrapped class object.
+	 */
+	public Class<T> getInnerClass() {
+		return innerClass;
+	}
+
+	/**
+	 * Returns the generalized form of this class if there is an {@link PojoFilter} associated with it.
+	 *
+	 * @return The filtered class type, or this object if no filter is associated with the class.
+	 */
+	@BeanIgnore
+	public ClassMeta<?> getFilteredClassMeta() {
+		return filteredClassMeta;
+	}
+
+	/**
+	 * For array and {@code Collection} types, returns the class type of the components of the array or {@code Collection}.
+	 *
+	 * @return The element class type, or <jk>null</jk> if this class is not an array or Collection.
+	 */
+	public ClassMeta<?> getElementType() {
+		return elementType;
+	}
+
+	/**
+	 * For {@code Map} types, returns the class type of the keys of the {@code Map}.
+	 *
+	 * @return The key class type, or <jk>null</jk> if this class is not a Map.
+	 */
+	public ClassMeta<?> getKeyType() {
+		return keyType;
+	}
+
+	/**
+	 * For {@code Map} types, returns the class type of the values of the {@code Map}.
+	 *
+	 * @return The value class type, or <jk>null</jk> if this class is not a Map.
+	 */
+	public ClassMeta<?> getValueType() {
+		return valueType;
+	}
+
+	/**
+	 * Returns <jk>true</jk> if this class implements {@link Delegate}, meaning
+	 * 	it's a representation of some other object.
+	 *
+	 * @return <jk>true</jk> if this class implements {@link Delegate}.
+	 */
+	public boolean isDelegate() {
+		return isDelegate;
+	}
+
+	/**
+	 * Returns <jk>true</jk> if this class is a subclass of {@link Map}.
+	 *
+	 * @return <jk>true</jk> if this class is a subclass of {@link Map}.
+	 */
+	public boolean isMap() {
+		return classCategory == MAP || classCategory == BEANMAP;
+	}
+
+	/**
+	 * Returns <jk>true</jk> if this class is a subclass of {@link BeanMap}.
+	 *
+	 * @return <jk>true</jk> if this class is a subclass of {@link BeanMap}.
+	 */
+	public boolean isBeanMap() {
+		return classCategory == BEANMAP;
+	}
+
+	/**
+	 * Returns <jk>true</jk> if this class is a subclass of {@link Collection}.
+	 *
+	 * @return <jk>true</jk> if this class is a subclass of {@link Collection}.
+	 */
+	public boolean isCollection() {
+		return classCategory == COLLECTION;
+	}
+
+	/**
+	 * Returns <jk>true</jk> if this class is an {@link Enum}.
+	 *
+	 * @return <jk>true</jk> if this class is an {@link Enum}.
+	 */
+	public boolean isEnum() {
+		return classCategory == ENUM;
+	}
+
+	/**
+	 * Returns <jk>true</jk> if this class is an array.
+	 *
+	 * @return <jk>true</jk> if this class is an array.
+	 */
+	public boolean isArray() {
+		return classCategory == ARRAY;
+	}
+
+	/**
+	 * Returns <jk>true</jk> if this class is a bean.
+	 *
+	 * @return <jk>true</jk> if this class is a bean.
+	 */
+	public boolean isBean() {
+		return classCategory == BEAN;
+	}
+
+	/**
+	 * Returns <jk>true</jk> if this class is {@link Object}.
+	 *
+	 * @return <jk>true</jk> if this class is {@link Object}.
+	 */
+	public boolean isObject() {
+		return classCategory == OBJ;
+	}
+
+	/**
+	 * Returns <jk>true</jk> if this class is not {@link Object}.
+	 *
+	 * @return <jk>true</jk> if this class is not {@link Object}.
+	 */
+	public boolean isNotObject() {
+		return classCategory != OBJ;
+	}
+
+	/**
+	 * Returns <jk>true</jk> if this class is a subclass of {@link Number}.
+	 *
+	 * @return <jk>true</jk> if this class is a subclass of {@link Number}.
+	 */
+	public boolean isNumber() {
+		return classCategory == NUMBER || classCategory == DECIMAL;
+	}
+
+	/**
+	 * Returns <jk>true</jk> if this class is a subclass of {@link Float} or {@link Double}.
+	 *
+	 * @return <jk>true</jk> if this class is a subclass of {@link Float} or {@link Double}.
+	 */
+	public boolean isDecimal() {
+		return classCategory == DECIMAL;
+	}
+
+	/**
+	 * Returns <jk>true</jk> if this class is a {@link Boolean}.
+	 *
+	 * @return <jk>true</jk> if this class is a {@link Boolean}.
+	 */
+	public boolean isBoolean() {
+		return classCategory == BOOLEAN;
+	}
+
+	/**
+	 * Returns <jk>true</jk> if this class is a subclass of {@link CharSequence}.
+	 *
+	 * @return <jk>true</jk> if this class is a subclass of {@link CharSequence}.
+	 */
+	public boolean isCharSequence() {
+		return classCategory == STR || classCategory == CHARSEQ;
+	}
+
+	/**
+	 * Returns <jk>true</jk> if this class is a {@link String}.
+	 *
+	 * @return <jk>true</jk> if this class is a {@link String}.
+	 */
+	public boolean isString() {
+		return classCategory == STR;
+	}
+
+	/**
+	 * Returns <jk>true</jk> if this class is a {@link Character}.
+	 *
+	 * @return <jk>true</jk> if this class is a {@link Character}.
+	 */
+	public boolean isChar() {
+		return classCategory == CHAR;
+	}
+
+	/**
+	 * Returns <jk>true</jk> if this class is a primitive.
+	 *
+	 * @return <jk>true</jk> if this class is a primitive.
+	 */
+	public boolean isPrimitive() {
+		return innerClass.isPrimitive();
+	}
+
+	/**
+	 * Returns <jk>true</jk> if this class is a {@link Date} or {@link Calendar}.
+	 *
+	 * @return <jk>true</jk> if this class is a {@link Date} or {@link Calendar}.
+	 */
+	public boolean isDate() {
+		return classCategory == DATE;
+	}
+
+	/**
+	 * Returns <jk>true</jk> if this class is a {@link URI} or {@link URL}.
+	 *
+	 * @return <jk>true</jk> if this class is a {@link URI} or {@link URL}.
+	 */
+	public boolean isUri() {
+		return classCategory == URI;
+	}
+
+	/**
+	 * Returns <jk>true</jk> if this class is a {@link Reader}.
+	 *
+	 * @return <jk>true</jk> if this class is a {@link Reader}.
+	 */
+	public boolean isReader() {
+		return classCategory == READER;
+	}
+
+	/**
+	 * Returns <jk>true</jk> if this class is an {@link InputStream}.
+	 *
+	 * @return <jk>true</jk> if this class is an {@link InputStream}.
+	 */
+	public boolean isInputStream() {
+		return classCategory == INPUTSTREAM;
+	}
+
+	/**
+	 * Returns <jk>true</jk> if instance of this object can be <jk>null</jk>.
+	 * <p>
+	 * 	Objects can be <jk>null</jk>, but primitives cannot, except for chars which can be represented
+	 * 	by <code>(<jk>char</jk>)0</code>.
+	 *
+	 * @return <jk>true</jk> if instance of this class can be null.
+	 */
+	public boolean isNullable() {
+		if (innerClass.isPrimitive())
+			return classCategory == CHAR;
+		return true;
+	}
+
+	/**
+	 * Returns <jk>true</jk> if this class or one of it's methods are annotated with {@link Remoteable @Remotable}.
+	 *
+	 * @return <jk>true</jk> if this class is remoteable.
+	 */
+	public boolean isRemoteable() {
+		return remoteableMethods != null;
+	}
+
+	/**
+	 * All methods on this class annotated with {@link Remoteable @Remotable}, or all public methods if class is annotated.
+	 * Keys are method signatures (see {@link ClassUtils#getMethodSignature(Method)})
+	 *
+	 * @return All remoteable methods on this class.
+	 */
+	public Map<String,Method> getRemoteableMethods() {
+		return remoteableMethods;
+	}
+
+	/**
+	 * All public methods on this class including static methods.
+	 * Keys are method signatures (see {@link ClassUtils#getMethodSignature(Method)}).
+	 *
+	 * @return The public methods on this class.
+	 */
+	public Map<String,Method> getPublicMethods() {
+		if (publicMethods == null) {
+			synchronized(this) {
+				Map<String,Method> map = new LinkedHashMap<String,Method>();
+				for (Method m : innerClass.getMethods())
+					if (Modifier.isPublic(m.getModifiers()))
+						map.put(ClassUtils.getMethodSignature(m), m);
+				publicMethods = Collections.unmodifiableMap(map);
+			}
+		}
+		return publicMethods;
+	}
+
+	/**
+	 * Returns the {@link PojoFilter} associated with this class.
+	 *
+	 * @return The {@link PojoFilter} associated with this class, or <jk>null</jk> if there is no POJO filter
+	 * 	associated with this class.
+	 */
+	public PojoFilter<T,?> getPojoFilter() {
+		return pojoFilter;
+	}
+
+	/**
+	 * Returns the {@link BeanMeta} associated with this class.
+	 *
+	 * @return The {@link BeanMeta} associated with this class, or <jk>null</jk> if there is no bean meta
+	 * 	associated with this class.
+	 */
+	public BeanMeta<T> getBeanMeta() {
+		return beanMeta;
+	}
+
+	/**
+	 * Returns the no-arg constructor for this class.
+	 *
+	 * @return The no-arg constructor for this class, or <jk>null</jk> if it does not exist.
+	 */
+	public Constructor<? extends T> getConstructor() {
+		return noArgConstructor;
+	}
+
+	/**
+	 * Returns the <ja>@Xml</ja> annotation defined on this class, superclass, or interface of this class.
+	 *
+	 * @return XML metadata on this class.  Never <jk>null</jk>.
+	 */
+	public XmlClassMeta getXmlMeta() {
+		return xmlMeta;
+	}
+
+	/**
+	 * Returns metadata from the <ja>@Json</ja> annotation defined on this class, superclass, or interface of this class.
+	 *
+	 * @return JSON metadata on this class.  Never <jk>null</jk>.
+	 */
+	public JsonClassMeta getJsonMeta() {
+		return jsonMeta;
+	}
+
+	/**
+	 * Returns metadata from the <ja>@Html</ja> annotation defined on this class, superclass, or interface of this class.
+	 *
+	 * @return HTML metadata on this class.  Never <jk>null</jk>.
+	 */
+	public HtmlClassMeta getHtmlMeta() {
+		return htmlMeta;
+	}
+
+	/**
+	 * Returns metadata from the <ja>@UrlEncoding</ja> annotation defined on this class, superclass, or interface of this class.
+	 *
+	 * @return URL-Encoding metadata on this class.  Never <jk>null</jk>.
+	 */
+	public UrlEncodingClassMeta getUrlEncodingMeta() {
+		return urlEncodingMeta;
+	}
+
+	/**
+	 * Returns metadata from the <ja>@Rdf</ja> annotation defined on this class, superclass, or interface of this class.
+	 *
+	 * @return RDF metadata on this class.  Never <jk>null</jk>.
+	 */
+	public RdfClassMeta getRdfMeta() {
+		return rdfMeta;
+	}
+
+	/**
+	 * Returns the interface proxy invocation handler for this class.
+	 *
+	 * @return The interface proxy invocation handler, or <jk>null</jk> if it does not exist.
+	 */
+	public InvocationHandler getProxyInvocationHandler() {
+		if (invocationHandler == null && beanMeta != null && beanContext.useInterfaceProxies && innerClass.isInterface())
+			invocationHandler = new BeanProxyInvocationHandler<T>(beanMeta);
+		return invocationHandler;
+	}
+
+	/**
+	 * Returns <jk>true</jk> if this class has a no-arg constructor or invocation handler.
+	 *
+	 * @return <jk>true</jk> if a new instance of this class can be constructed.
+	 */
+	public boolean canCreateNewInstance() {
+		if (isMemberClass)
+			return false;
+		if (noArgConstructor != null)
+			return true;
+		if (getProxyInvocationHandler() != null)
+			return true;
+		if (isArray() && elementType.canCreateNewInstance())
+			return true;
+		return false;
+	}
+
+	/**
+	 * Returns <jk>true</jk> if this class has a no-arg constructor or invocation handler.
+	 * Returns <jk>false</jk> if this is a non-static member class and the outer object does not match
+	 * 	the class type of the defining class.
+	 *
+	 * @param outer The outer class object for non-static member classes.  Can be <jk>null</jk> for non-member or static classes.
+	 * @return <jk>true</jk> if a new instance of this class can be created within the context of the specified outer object.
+	 */
+	public boolean canCreateNewInstance(Object outer) {
+		if (isMemberClass)
+			return outer != null && noArgConstructor != null && noArgConstructor.getParameterTypes()[0] == outer.getClass();
+		return canCreateNewInstance();
+	}
+
+	/**
+	 * Returns <jk>true</jk> if this class can be instantiated as a bean.
+	 * Returns <jk>false</jk> if this is a non-static member class and the outer object does not match
+	 * 	the class type of the defining class.
+	 *
+	 * @param outer The outer class object for non-static member classes.  Can be <jk>null</jk> for non-member or static classes.
+	 * @return <jk>true</jk> if a new instance of this bean can be created within the context of the specified outer object.
+	 */
+	public boolean canCreateNewBean(Object outer) {
+		if (beanMeta == null)
+			return false;
+		// Beans with filters with subtype properties are assumed to be constructable.
+		if (beanFilter != null && beanFilter.getSubTypeProperty() != null)
+			return true;
+		if (beanMeta.constructor == null)
+			return false;
+		if (isMemberClass)
+			return outer != null && beanMeta.constructor.getParameterTypes()[0] == outer.getClass();
+		return true;
+	}
+
+	/**
+	 * Returns <jk>true</jk> if this class can call the {@link #newInstanceFromString(Object, String)} method.
+	 *
+	 * @param outer The outer class object for non-static member classes.  Can be <jk>null</jk> for non-member or static classes.
+	 * @return <jk>true</jk> if this class has a no-arg constructor or invocation handler.
+	 */
+	public boolean canCreateNewInstanceFromString(Object outer) {
+		if (valueOfMethod != null)
+			return true;
+		if (stringConstructor != null) {
+			if (isMemberClass)
+				return outer != null && stringConstructor.getParameterTypes()[0] == outer.getClass();
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * Returns <jk>true</jk> if this class can call the {@link #newInstanceFromString(Object, String)} method.
+	 *
+	 * @param outer The outer class object for non-static member classes.  Can be <jk>null</jk> for non-member or static classes.
+	 * @return <jk>true</jk> if this class has a no-arg constructor or invocation handler.
+	 */
+	public boolean canCreateNewInstanceFromObjectMap(Object outer) {
+		if (objectMapConstructor != null) {
+			if (isMemberClass)
+				return outer != null && objectMapConstructor.getParameterTypes()[0] == outer.getClass();
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * Returns <jk>true</jk> if this class has an <code>ObjectMap toObjectMap()</code> method.
+	 *
+	 * @return <jk>true</jk> if class has a <code>toObjectMap()</code> method.
+	 */
+	public boolean hasToObjectMapMethod() {
+		return toObjectMapMethod != null;
+	}
+
+	/**
+	 * Returns the method annotated with {@link NameProperty @NameProperty}.
+	 *
+	 * @return The method annotated with {@link NameProperty @NameProperty} or <jk>null</jk> if method does not exist.
+	 */
+	public Method getNameProperty() {
+		return namePropertyMethod;
+ 	}
+
+	/**
+	 * Returns the method annotated with {@link ParentProperty @ParentProperty}.
+	 *
+	 * @return The method annotated with {@link ParentProperty @ParentProperty} or <jk>null</jk> if method does not exist.
+	 */
+	public Method getParentProperty() {
+		return parentPropertyMethod;
+ 	}
+
+	/**
+	 * Converts an instance of this class to an {@link ObjectMap}.
+	 *
+	 * @param t The object to convert to a map.
+	 * @return The converted object, or <jk>null</jk> if method does not have a <code>toObjectMap()</code> method.
+	 * @throws BeanRuntimeException Thrown by <code>toObjectMap()</code> method invocation.
+	 */
+	public ObjectMap toObjectMap(Object t) throws BeanRuntimeException {
+		try {
+			if (toObjectMapMethod != null)
+				return (ObjectMap)toObjectMapMethod.invoke(t);
+			return null;
+		} catch (Exception e) {
+			throw new BeanRuntimeException(e);
+		}
+	}
+
+	/**
+	 * Returns the reason why this class is not a bean, or <jk>null</jk> if it is a bean.
+	 *
+	 * @return The reason why this class is not a bean, or <jk>null</jk> if it is a bean.
+	 */
+	public synchronized String getNotABeanReason() {
+		return notABeanReason;
+	}
+
+	/**
+	 * Returns <jk>true</jk> if this class is abstract.
+	 * @return <jk>true</jk> if this class is abstract.
+	 */
+	public boolean isAbstract() {
+		return isAbstract;
+	}
+
+	/**
+	 * Returns any exception that was throw in the <code>init()</code> method.
+	 *
+	 * @return The cached exception.
+	 */
+	public Throwable getInitException() {
+		return initException;
+	}
+
+	/**
+	 * Returns the {@link BeanContext} that created this object.
+	 *
+	 * @return The bean context.
+	 */
+	public BeanContext getBeanContext() {
+		return beanContext;
+	}
+
+	/**
+	 * Returns the default value for primitives such as <jk>int</jk> or <jk>Integer</jk>.
+	 *
+	 * @return The default value, or <jk>null</jk> if this class type is not a primitive.
+	 */
+	@SuppressWarnings("unchecked")
+	public T getPrimitiveDefault() {
+		return (T)primitiveDefault;
+	}
+
+	/**
+	 * Create a new instance of the main class of this declared type from a <code>String</code> input.
+	 * <p>
+	 * In order to use this method, the class must have one of the following methods:
+	 * <ul>
+	 * 	<li><code><jk>public static</jk> T valueOf(String in);</code>
+	 * 	<li><code><jk>public static</jk> T fromString(String in);</code>
+	 * 	<li><code><jk>public</jk> T(String in);</code>
+	 * </ul>
+	 *
+	 * @param outer The outer class object for non-static member classes.  Can be <jk>null</jk> for non-member or static classes.
+	 * @param arg The input argument value.
+	 * @return A new instance of the object, or <jk>null</jk> if there is no no-arg constructor on the object.
+	 * @throws IllegalAccessException If the <code>Constructor</code> object enforces Java language access control and the underlying constructor is inaccessible.
+	 * @throws IllegalArgumentException If the parameter type on the method was invalid.
+	 * @throws InstantiationException If the class that declares the underlying constructor represents an abstract class, or
+	 * 	does not have one of the methods described above.
+	 * @throws InvocationTargetException If the underlying constructor throws an exception.
+	 */
+	@SuppressWarnings("unchecked")
+	public T newInstanceFromString(Object outer, String arg) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, InstantiationException {
+		Method m = valueOfMethod;
+		if (m != null)
+			return (T)m.invoke(null, arg);
+		Constructor<T> c = stringConstructor;
+		if (c != null) {
+			if (isMemberClass)
+				return c.newInstance(outer, arg);
+			return c.newInstance(arg);
+		}
+		throw new InstantiationError("No string constructor or valueOf(String) method found for class '"+getInnerClass().getName()+"'");
+	}
+
+	/**
+	 * Create a new instance of the main class of this declared type from an <code>ObjectMap</code> input.
+	 * <p>
+	 * In order to use this method, the class must have one of the following methods:
+	 * <ul>
+	 * 	<li><code><jk>public</jk> T(ObjectMap in);</code>
+	 * </ul>
+	 *
+	 * @param outer The outer class object for non-static member classes.  Can be <jk>null</jk> for non-member or static classes.
+	 * @param arg The input argument value.
+	 * @return A new instance of the object.
+	 * @throws IllegalAccessException If the <code>Constructor</code> object enforces Java language access control and the underlying constructor is inaccessible.
+	 * @throws IllegalArgumentException If the parameter type on the method was invalid.
+	 * @throws InstantiationException If the class that declares the underlying constructor represents an abstract class, or
+	 * 	does not have one of the methods described above.
+	 * @throws InvocationTargetException If the underlying constructor throws an exception.
+	 */
+	public T newInstanceFromObjectMap(Object outer, ObjectMap arg) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, InstantiationException {
+		Constructor<T> c = objectMapConstructor;
+		if (c != null) {
+			if (isMemberClass)
+				return c.newInstance(outer, arg);
+			return c.newInstance(arg);
+		}
+		throw new InstantiationError("No map constructor method found for class '"+getInnerClass().getName()+"'");
+	}
+
+	/**
+	 * Create a new instance of the main class of this declared type.
+	 *
+	 * @return A new instance of the object, or <jk>null</jk> if there is no no-arg constructor on the object.
+	 * @throws IllegalAccessException If the <code>Constructor</code> object enforces Java language access control and the underlying constructor is inaccessible.
+	 * @throws IllegalArgumentException If one of the following occurs:
+	 * 	<ul>
+	 * 		<li>The number of actual and formal parameters differ.
+	 * 		<li>An unwrapping conversion for primitive arguments fails.
+	 * 		<li>A parameter value cannot be converted to the corresponding formal parameter type by a method invocation conversion.
+	 * 		<li>The constructor pertains to an enum type.
+	 * 	</ul>
+	 * @throws InstantiationException If the class that declares the underlying constructor represents an abstract class.
+	 * @throws InvocationTargetException If the underlying constructor throws an exception.
+	 */
+	@SuppressWarnings("unchecked")
+	public T newInstance() throws IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException {
+		if (isArray())
+			return (T)Array.newInstance(getInnerClass().getComponentType(), 0);
+		Constructor<? extends T> c = getConstructor();
+		if (c != null)
+			return c.newInstance((Object[])null);
+		InvocationHandler h = getProxyInvocationHandler();
+		if (h != null)
+			return (T)Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[] { getInnerClass(), java.io.Serializable.class }, h);
+		if (isArray())
+			return (T)Array.newInstance(this.elementType.innerClass,0);
+		return null;
+	}
+
+	/**
+	 * Same as {@link #newInstance()} except for instantiating non-static member classes.
+	 *
+	 * @param outer The instance of the owning object of the member class instance.  Can be <jk>null</jk> if instantiating a non-member or static class.
+	 * @return A new instance of the object, or <jk>null</jk> if there is no no-arg constructor on the object.
+	 * @throws IllegalAccessException If the <code>Constructor</code> object enforces Java language access control and the underlying constructor is inaccessible.
+	 * @throws IllegalArgumentException If one of the following occurs:
+	 * 	<ul>
+	 * 		<li>The number of actual and formal parameters differ.
+	 * 		<li>An unwrapping conversion for primitive arguments fails.
+	 * 		<li>A parameter value cannot be converted to the corresponding formal parameter type by a method invocation conversion.
+	 * 		<li>The constructor pertains to an enum type.
+	 * 	</ul>
+	 * @throws InstantiationException If the class that declares the underlying constructor represents an abstract class.
+	 * @throws InvocationTargetException If the underlying constructor throws an exception.
+	 */
+	public T newInstance(Object outer) throws IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException {
+		if (isMemberClass)
+			return noArgConstructor.newInstance(outer);
+		return newInstance();
+	}
+
+	/**
+	 * Checks to see if the specified class type is the same as this one.
+	 *
+	 * @param t The specified class type.
+	 * @return <jk>true</jk> if the specified class type is the same as the class for this type.
+	 */
+	@Override /* Object */
+	public boolean equals(Object t) {
+		if (t == null || ! (t instanceof ClassMeta))
+			return false;
+		ClassMeta<?> t2 = (ClassMeta<?>)t;
+		return t2.getInnerClass() == this.getInnerClass();
+	}
+
+	@Override /* Object */
+	public String toString() {
+		return toString(false);
+	}
+
+	/**
+	 * Same as {@link #toString()} except use simple class names.
+	 *
+	 * @param simple Print simple class names only (no package).
+	 * @return A new string.
+	 */
+	public String toString(boolean simple) {
+		return toString(new StringBuilder(), simple).toString();
+	}
+
+	/**
+	 * Appends this object as a readable string to the specified string builder.
+	 *
+	 * @param sb The string builder to append this object to.
+	 * @param simple Print simple class names only (no package).
+	 * @return The same string builder passed in (for method chaining).
+	 */
+	protected StringBuilder toString(StringBuilder sb, boolean simple) {
+		String name = innerClass.getName();
+		if (simple) {
+			int i = name.lastIndexOf('.');
+			name = name.substring(i == -1 ? 0 : i+1).replace('$', '.');
+		}
+		switch(classCategory) {
+			case ARRAY:
+				return elementType.toString(sb, simple).append('[').append(']');
+			case MAP:
+				return sb.append(name).append(keyType.isObject() && valueType.isObject() ? "" : "<"+keyType.toString(simple)+","+valueType.toString(simple)+">");
+			case BEANMAP:
+				return sb.append(BeanMap.class.getName()).append("<").append(name).append(">");
+			case COLLECTION:
+				return sb.append(name).append(elementType.isObject() ? "" : "<"+elementType.toString(simple)+">");
+			case OTHER:
+				if (simple)
+					return sb.append(name);
+				sb.append("OTHER-").append(name).append(",notABeanReason=").append(notABeanReason);
+				if (initException != null)
+					sb.append(",initException=").append(initException);
+				return sb;
+			default:
+				return sb.append(name);
+		}
+	}
+
+	/**
+	 * Returns <jk>true</jk> if the specified object is an instance of this class.
+	 * This is a simple comparison on the base class itself and not on
+	 * any generic parameters.
+	 *
+	 * @param o The object to check.
+	 * @return <jk>true</jk> if the specified object is an instance of this class.
+	 */
+	public boolean isInstance(Object o) {
+		if (o != null)
+			return ClassUtils.isParentClass(this.innerClass, o.getClass());
+		return false;
+	}
+
+	/**
+	 * Returns a readable name for this class (e.g. <js>"java.lang.String"</js>, <js>"boolean[]"</js>). 
+	 *
+	 * @return The readable name for this class.
+	 */
+	public String getReadableName() {
+		return ClassUtils.getReadableClassName(this.innerClass);
+	}
+
+	@Override /* Object */
+	public int hashCode() {
+		return super.hashCode();
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/7e4f63e6/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/CoreApi.class
----------------------------------------------------------------------
diff --git a/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/CoreApi.class b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/CoreApi.class
new file mode 100755
index 0000000..44730ed
Binary files /dev/null and b/com.ibm.team.juno.releng/bin/core/com/ibm/juno/core/CoreApi.class differ