juneau-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jamesbog...@apache.org
Subject [01/51] [partial] incubator-juneau git commit: Add project hierarchies, part 1
Date Sat, 02 Sep 2017 14:10:23 GMT
Repository: incubator-juneau
Updated Branches:
  refs/heads/master b37d99bac -> 75b0d8ee6


http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/75b0d8ee/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java
----------------------------------------------------------------------
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java
new file mode 100644
index 0000000..70ffaf3
--- /dev/null
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java
@@ -0,0 +1,1776 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              *
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau;
+
+import static org.apache.juneau.Visibility.*;
+import static org.apache.juneau.internal.ClassUtils.*;
+import static org.apache.juneau.internal.StringUtils.*;
+
+import java.beans.*;
+import java.io.*;
+import java.lang.reflect.*;
+import java.util.*;
+import java.util.concurrent.*;
+
+import org.apache.juneau.annotation.*;
+import org.apache.juneau.http.*;
+import org.apache.juneau.internal.*;
+import org.apache.juneau.json.*;
+import org.apache.juneau.parser.*;
+import org.apache.juneau.serializer.*;
+import org.apache.juneau.transform.*;
+
+/**
+ * Core class of the Juneau architecture.
+ *
+ * <p>
+ * This class servers multiple purposes:
+ * <ul class='spaced-list'>
+ * 	<li>
+ * 		Provides the ability to wrap beans inside {@link Map} interfaces.
+ * 	<li>
+ * 		Serves as a repository for metadata on POJOs, such as associated {@link BeanFilter beanFilters},
+ * 		{@link PropertyNamer property namers}, etc...  which are used to tailor how POJOs are serialized and parsed.
+ * 	<li>
+ * 		Serves as a common utility class for all {@link Serializer Serializers} and {@link Parser Parsers}
+ * 		for serializing and parsing Java beans.
+ * </ul>
+ *
+ * <p>
+ * All serializer and parser contexts extend from this context.
+ *
+ * <h5 class='topic'>Bean Contexts</h5>
+ *
+ * Bean contexts are created through the {@link PropertyStore#getContext(Class)} method.
+ * These context objects are read-only, reusable, and thread-safe.
+ * The {@link PropertyStore} class will typically cache copies of <code>Context</code> objects based on
+ * the current settings on the factory.
+ *
+ * <p>
+ * Each bean context maintains a cache of {@link ClassMeta} objects that describe information about classes encountered.
+ * These <code>ClassMeta</code> objects are time-consuming to construct.
+ * Therefore, instances of {@link BeanContext} that share the same <js>"BeanContext.*"</js> property values share
+ * the same cache.  This allows for efficient reuse of <code>ClassMeta</code> objects so that the information about
+ * classes only needs to be calculated once.
+ * Because of this, many of the properties defined on the {@link BeanContext} class cannot be overridden on the session.
+ *
+ * <h5 class='topic'>Bean Sessions</h5>
+ *
+ * Whereas <code>BeanContext</code> objects are permanent, unchangeable, cached, and thread-safe,
+ * {@link BeanSession} objects are ephemeral and not thread-safe.
+ * They are meant to be used as quickly-constructed scratchpads for creating bean maps.
+ * {@link BeanMap} objects can only be created through the session.
+ *
+ * <h5 class='topic'>BeanContext configuration properties</h5>
+ *
+ * <code>BeanContexts</code> have several configuration properties that can be used to tweak behavior on how beans are
+ * handled.  These are denoted as the static <jsf>BEAN_*</jsf> fields on this class.
+ *
+ * <p>
+ * Some settings (e.g. {@link BeanContext#BEAN_beansRequireDefaultConstructor}) are used to differentiate between bean
+ * and non-bean classes.
+ * Attempting to create a bean map around one of these objects will throw a {@link BeanRuntimeException}.
+ * The purpose for this behavior is so that the serializers can identify these non-bean classes and convert them to
+ * plain strings using the {@link Object#toString()} method.
+ *
+ * <p>
+ * Some settings (e.g. {@link BeanContext#BEAN_beanFieldVisibility}) are used to determine what kinds of properties are
+ * detected on beans.
+ *
+ * <p>
+ * Some settings (e.g. {@link BeanContext#BEAN_beanMapPutReturnsOldValue}) change the runtime behavior of bean maps.
+ *
+ * <p>
+ * Settings are specified using the {@link PropertyStore#setProperty(String, Object)} method and related convenience
+ * methods.
+ *
+ * <h5 class='section'>Example:</h5>
+ *
+ * <p class='bcode'>
+ * 	<jc>// Construct a context from scratch.</jc>
+ * 	BeanContext beanContext = PropertyStore.<jsm>create</jsm>()
+ * 		.property(BeanContext.<jsf>BEAN_beansRequireDefaultConstructor</jsf>, <jk>true</jk>)
+ * 		.notBeanClasses(Foo.<jk>class</jk>)
+ * 		.getBeanContext();
+ *
+ * 	<jc>// Clone an existing property store.</jc>
+ * 	BeanContext beanContext = PropertyStore.<jsm>create</jsm>(otherConfig)
+ * 		.property(BeanContext.<jsf>BEAN_beansRequireDefaultConstructor</jsf>, <jk>true</jk>)
+ * 		.notBeanClasses(Foo.<jk>class</jk>)
+ * 		.getBeanContext();
+ * </p>
+ *
+ * <h5 class='topic'>Bean Maps</h5>
+ *
+ * {@link BeanMap BeanMaps} are wrappers around Java beans that allow properties to be retrieved and
+ * set using the common {@link Map#put(Object,Object)} and {@link Map#get(Object)} methods.
+ *
+ * <p>
+ * Bean maps are created in two ways...
+ * <ol>
+ * 	<li>{@link BeanSession#toBeanMap(Object) BeanSession.toBeanMap()} - Wraps an existing bean inside a {@code Map}
+ * 		wrapper.
+ * 	<li>{@link BeanSession#newBeanMap(Class) BeanSession.newBeanMap()} - Create a new bean instance wrapped in a
+ * 		{@code Map} wrapper.
+ * </ol>
+ *
+ * <h5 class='section'>Example:</h5>
+ *
+ * <p class='bcode'>
+ * 	<jc>// A sample bean class</jc>
+ * 	<jk>public class</jk> Person {
+ * 		<jk>public</jk> String getName();
+ * 		<jk>public void</jk> setName(String name);
+ * 		<jk>public int</jk> getAge();
+ * 		<jk>public void</jk> setAge(<jk>int</jk> age);
+ * 	}
+ *
+ * 	<jc>// Create a new bean session</jc>
+ * 	BeanSession session = BeanContext.<jsf>DEFAULT</jsf>.createSession();
+ *
+ * 	<jc>// Wrap an existing bean in a new bean map</jc>
+ * 	BeanMap&lt;Person&gt; m1 = session.toBeanMap(<jk>new</jk> Person());
+ * 	m1.put(<js>"name"</js>, <js>"John Smith"</js>);
+ * 	m1.put(<js>"age"</js>, 45);
+ *
+ * 	<jc>// Create a new bean instance wrapped in a new bean map</jc>
+ * 	BeanMap&lt;Person&gt; m2 = session.newBeanMap(Person.<jk>class</jk>);
+ * 	m2.put(<js>"name"</js>, <js>"John Smith"</js>);
+ * 	m2.put(<js>"age"</js>, 45);
+ * 	Person p = m2.getBean();  <jc>// Get the bean instance that was created.</jc>
+ * </p>
+ *
+ * <h5 class='topic'>Bean Annotations</h5>
+ *
+ * This package contains annotations that can be applied to class definitions to override what properties are detected
+ * on a bean.
+ *
+ * <h5 class='section'>Example:</h5>
+ *
+ * <p class='bcode'>
+ * 	<jc>// Bean class definition where only property 'name' is detected.</jc>
+ * 	<ja>&#64;Bean</ja>(properties=<js>"name"</js>)
+ * 	<jk>public class</jk> Person {
+ * 		<jk>public</jk> String getName();
+ * 		<jk>public void</jk> setName(String name);
+ * 		<jk>public int</jk> getAge();
+ * 		<jk>public void</jk> setAge(<jk>int</jk> age);
+ * 	}
+ * </p>
+ *
+ * <p>
+ * See {@link Bean @Bean} and {@link BeanProperty @BeanProperty} for more information.
+ *
+ * <h5 class='topic'>Beans with read-only properties</h5>
+ *
+ * Bean maps can also be defined on top of beans with read-only properties by adding a
+ * {@link BeanConstructor @BeanConstructor} annotation to one of the constructors on the
+ * bean class.  This will allow read-only properties to be set through constructor arguments.
+ *
+ * <p>
+ * When the <code>@BeanConstructor</code> annotation is present, bean instantiation is delayed until the call to
+ * {@link BeanMap#getBean()}.
+ * Until then, bean property values are stored in a local cache until <code>getBean()</code> is called.
+ * Because of this additional caching step, parsing into read-only beans tends to be slower and use more memory than
+ * parsing into beans with writable properties.
+ *
+ * <p>
+ * Attempting to call {@link BeanMap#put(String,Object)} on a read-only property after calling {@link BeanMap#getBean()}
+ * will result in a {@link BeanRuntimeException} being thrown.
+ * Multiple calls to {@link BeanMap#getBean()} will return the same bean instance.
+ *
+ * <p>
+ * Beans can be defined with a combination of read-only and read-write properties.
+ *
+ * <p>
+ * See {@link BeanConstructor @BeanConstructor} for more information.
+ *
+ * <h5 class='topic'>BeanFilters and PojoSwaps</h5>
+ *
+ * 	{@link BeanFilter BeanFilters} and {@link PojoSwap PojoSwaps} are used to tailor how beans and POJOs are handled.
+ * 	<ol class='spaced-list'>
+ * 		<li>
+ * 			{@link BeanFilter} - Allows you to tailor handling of bean classes.
+ * 			This class can be considered a programmatic equivalent to the {@link Bean} annotation when
+ * 			annotating classes are not possible (e.g. you don't have access to the source).
+ * 			This includes specifying which properties are visible and the ability to programmatically override the
+ * 			execution of properties.
+ * 		<li>
+ * 			{@link PojoSwap} - Allows you to swap out non-serializable objects with serializable replacements.
+ * 	</ol>
+ *
+ * <p>
+ * See <a class='doclink' href='transform/package-summary.html#TOC'>org.apache.juneau.transform</a> for more
+ * information.
+ *
+ * <h5 class='topic'>ClassMetas</h5>
+ *
+ * The {@link ClassMeta} class is a wrapper around {@link Class} object that provides cached information about that
+ * class (e.g. whether it's a {@link Map} or {@link Collection} or bean).
+ *
+ * <p>
+ * As a general rule, it's best to reuse bean contexts (and therefore serializers and parsers too) whenever possible
+ * since it takes some time to populate the internal {@code ClassMeta} object cache.
+ * By reusing bean contexts, the class type metadata only needs to be calculated once which significantly improves
+ * performance.
+ *
+ * <p>
+ * See {@link ClassMeta} for more information.
+ */
+@SuppressWarnings({"unchecked","rawtypes"})
+public class BeanContext extends Context {
+
+	/**
+	 * <b>Configuration property:</b>  Beans require no-arg constructors.
+	 *
+	 * <ul>
+	 * 	<li><b>Name:</b> <js>"BeanContext.beansRequireDefaultConstructor"</js>
+	 * 	<li><b>Data type:</b> <code>Boolean</code>
+	 * 	<li><b>Default:</b> <jk>false</jk>
+	 * 	<li><b>Session-overridable:</b> <jk>false</jk>
+	 * </ul>
+	 *
+	 * <p>
+	 * If <jk>true</jk>, a Java class must implement a default no-arg constructor to be considered a bean.
+	 *
+	 * <p>
+	 * The {@link Bean @Bean} annotation can be used on a class to override this setting when <jk>true</jk>.
+	 */
+	public static final String BEAN_beansRequireDefaultConstructor = "BeanContext.beansRequireDefaultConstructor";
+
+	/**
+	 * <b>Configuration property:</b>  Beans require {@link Serializable} interface.
+	 *
+	 * <ul>
+	 * 	<li><b>Name:</b> <js>"BeanContext.beansRequireSerializable"</js>
+	 * 	<li><b>Data type:</b> <code>Boolean</code>
+	 * 	<li><b>Default:</b> <jk>false</jk>
+	 * 	<li><b>Session-overridable:</b> <jk>false</jk>
+	 * </ul>
+	 *
+	 * <p>
+	 * If <jk>true</jk>, a Java class must implement the {@link Serializable} interface to be considered a bean.
+	 *
+	 * <p>
+	 * The {@link Bean @Bean} annotation can be used on a class to override this setting when <jk>true</jk>.
+	 */
+	public static final String BEAN_beansRequireSerializable = "BeanContext.beansRequireSerializable";
+
+	/**
+	 * <b>Configuration property:</b>  Beans require setters for getters.
+	 *
+	 * <ul>
+	 * 	<li><b>Name:</b> <js>"BeanContext.beansRequireSettersForGetters"</js>
+	 * 	<li><b>Data type:</b> <code>Boolean</code>
+	 * 	<li><b>Default:</b> <jk>false</jk>
+	 * 	<li><b>Session-overridable:</b> <jk>false</jk>
+	 * </ul>
+	 *
+	 * <p>
+	 * If <jk>true</jk>, only getters that have equivalent setters will be considered as properties on a bean.
+	 * Otherwise, they will be ignored.
+	 */
+	public static final String BEAN_beansRequireSettersForGetters = "BeanContext.beansRequireSettersForGetters";
+
+	/**
+	 * <b>Configuration property:</b>  Beans require at least one property.
+	 *
+	 * <ul>
+	 * 	<li><b>Name:</b> <js>"BeanContext.beansRequireSomeProperties"</js>
+	 * 	<li><b>Data type:</b> <code>Boolean</code>
+	 * 	<li><b>Default:</b> <jk>true</jk>
+	 * 	<li><b>Session-overridable:</b> <jk>false</jk>
+	 * </ul>
+	 *
+	 * <p>
+	 * If <jk>true</jk>, then a Java class must contain at least 1 property to be considered a bean.
+	 *
+	 * <p>
+	 * The {@link Bean @Bean} annotation can be used on a class to override this setting when <jk>true</jk>.
+	 */
+	public static final String BEAN_beansRequireSomeProperties = "BeanContext.beansRequireSomeProperties";
+
+	/**
+	 * <b>Configuration property:</b>  {@link BeanMap#put(String,Object) BeanMap.put()} method will return old property
+	 * value.
+	 *
+	 * <ul>
+	 * 	<li><b>Name:</b> <js>"BeanContext.beanMapPutReturnsOldValue"</js>
+	 * 	<li><b>Data type:</b> <code>Boolean</code>
+	 * 	<li><b>Default:</b> <jk>false</jk>
+	 * 	<li><b>Session-overridable:</b> <jk>false</jk>
+	 * </ul>
+	 *
+	 * <p>
+	 * If <jk>true</jk>, then the {@link BeanMap#put(String,Object) BeanMap.put()} method will return old property
+	 * values.
+	 *
+	 * <p>
+	 * Disabled by default because it introduces a slight performance penalty.
+	 */
+	public static final String BEAN_beanMapPutReturnsOldValue = "BeanContext.beanMapPutReturnsOldValue";
+
+	/**
+	 * <b>Configuration property:</b>  Look for bean constructors with the specified minimum visibility.
+	 *
+	 * <ul>
+	 * 	<li><b>Name:</b> <js>"BeanContext.beanConstructorVisibility"</js>
+	 * 	<li><b>Data type:</b> {@link Visibility}
+	 * 	<li><b>Default:</b> {@link Visibility#PUBLIC}
+	 * 	<li><b>Session-overridable:</b> <jk>false</jk>
+	 * </ul>
+	 */
+	public static final String BEAN_beanConstructorVisibility = "BeanContext.beanConstructorVisibility";
+
+	/**
+	 * <b>Configuration property:</b>  Look for bean classes with the specified minimum visibility.
+	 *
+	 * <ul>
+	 * 	<li><b>Name:</b> <js>"BeanContext.beanClassVisibility"</js>
+	 * 	<li><b>Data type:</b> {@link Visibility}
+	 * 	<li><b>Default:</b> {@link Visibility#PUBLIC}
+	 * 	<li><b>Session-overridable:</b> <jk>false</jk>
+	 * </ul>
+	 *
+	 * <p>
+	 * Classes are not considered beans unless they meet the minimum visibility requirements.
+	 * For example, if the visibility is <code>PUBLIC</code> and the bean class is <jk>protected</jk>, then the class
+	 * will not be interpreted as a bean class.
+	 */
+	public static final String BEAN_beanClassVisibility = "BeanContext.beanClassVisibility";
+
+	/**
+	 * <b>Configuration property:</b>  Look for bean fields with the specified minimum visibility.
+	 *
+	 * <ul>
+	 * 	<li><b>Name:</b> <js>"BeanContext.beanFieldVisibility"</js>
+	 * 	<li><b>Data type:</b> {@link Visibility}
+	 * 	<li><b>Default:</b> {@link Visibility#PUBLIC}
+	 * 	<li><b>Session-overridable:</b> <jk>false</jk>
+	 * </ul>
+	 *
+	 * <p>
+	 * Fields are not considered bean properties unless they meet the minimum visibility requirements.
+	 * For example, if the visibility is <code>PUBLIC</code> and the bean field is <jk>protected</jk>, then the field
+	 * will not be interpreted as a bean property.
+	 *
+	 * <p>
+	 * Use {@link Visibility#NONE} to prevent bean fields from being interpreted as bean properties altogether.
+	 */
+	public static final String BEAN_beanFieldVisibility = "BeanContext.beanFieldVisibility";
+
+	/**
+	 * <b>Configuration property:</b>  Look for bean methods with the specified minimum visibility.
+	 *
+	 * <ul>
+	 * 	<li><b>Name:</b> <js>"BeanContext.methodVisibility"</js>
+	 * 	<li><b>Data type:</b> {@link Visibility}
+	 * 	<li><b>Default:</b> {@link Visibility#PUBLIC}
+	 * 	<li><b>Session-overridable:</b> <jk>false</jk>
+	 * </ul>
+	 *
+	 * <p>
+	 * Methods are not considered bean getters/setters unless they meet the minimum visibility requirements.
+	 * For example, if the visibility is <code>PUBLIC</code> and the bean method is <jk>protected</jk>, then the method
+	 * will not be interpreted as a bean getter or setter.
+	 */
+	public static final String BEAN_methodVisibility = "BeanContext.methodVisibility";
+
+	/**
+	 * <b>Configuration property:</b>  Use Java {@link Introspector} for determining bean properties.
+	 *
+	 * <ul>
+	 * 	<li><b>Name:</b> <js>"BeanContext.useJavaBeanIntrospector"</js>
+	 * 	<li><b>Data type:</b> <code>Boolean</code>
+	 * 	<li><b>Default:</b> <jk>false</jk>
+	 * 	<li><b>Session-overridable:</b> <jk>false</jk>
+	 * </ul>
+	 *
+	 * <p>
+	 * Using the built-in Java bean introspector will not pick up fields or non-standard getters/setters.
+	 * Most {@link Bean @Bean} annotations will be ignored.
+	 */
+	public static final String BEAN_useJavaBeanIntrospector = "BeanContext.useJavaBeanIntrospector";
+
+	/**
+	 * <b>Configuration property:</b>  Use interface proxies.
+	 *
+	 * <ul>
+	 * 	<li><b>Name:</b> <js>"BeanContext.useInterfaceProxies"</js>
+	 * 	<li><b>Data type:</b> <code>Boolean</code>
+	 * 	<li><b>Default:</b> <jk>true</jk>
+	 * 	<li><b>Session-overridable:</b> <jk>false</jk>
+	 * </ul>
+	 *
+	 * <p>
+	 * If <jk>true</jk>, then interfaces will be instantiated as proxy classes through the use of an
+	 * {@link InvocationHandler} if there is no other way of instantiating them.
+	 */
+	public static final String BEAN_useInterfaceProxies = "BeanContext.useInterfaceProxies";
+
+	/**
+	 * <b>Configuration property:</b>  Ignore unknown properties.
+	 *
+	 * <ul>
+	 * 	<li><b>Name:</b> <js>"BeanContext.ignoreUnknownBeanProperties"</js>
+	 * 	<li><b>Data type:</b> <code>Boolean</code>
+	 * 	<li><b>Default:</b> <jk>false</jk>
+	 * 	<li><b>Session-overridable:</b> <jk>false</jk>
+	 * </ul>
+	 *
+	 * <p>
+	 * If <jk>true</jk>, trying to set a value on a non-existent bean property will silently be ignored.
+	 * Otherwise, a {@code RuntimeException} is thrown.
+	 */
+	public static final String BEAN_ignoreUnknownBeanProperties = "BeanContext.ignoreUnknownBeanProperties";
+
+	/**
+	 * <b>Configuration property:</b>  Ignore unknown properties with null values.
+	 *
+	 * <ul>
+	 * 	<li><b>Name:</b> <js>"BeanContext.ignoreUnknownNullBeanProperties"</js>
+	 * 	<li><b>Data type:</b> <code>Boolean</code>
+	 * 	<li><b>Default:</b> <jk>true</jk>
+	 * 	<li><b>Session-overridable:</b> <jk>false</jk>
+	 * </ul>
+	 *
+	 * <p>
+	 * If <jk>true</jk>, trying to set a <jk>null</jk> value on a non-existent bean property will silently be ignored.
+	 * Otherwise, a {@code RuntimeException} is thrown.
+	 */
+	public static final String BEAN_ignoreUnknownNullBeanProperties = "BeanContext.ignoreUnknownNullBeanProperties";
+
+	/**
+	 * <b>Configuration property:</b>  Ignore properties without setters.
+	 *
+	 * <ul>
+	 * 	<li><b>Name:</b> <js>"BeanContext.ignorePropertiesWithoutSetters"</js>
+	 * 	<li><b>Data type:</b> <code>Boolean</code>
+	 * 	<li><b>Default:</b> <jk>true</jk>
+	 * 	<li><b>Session-overridable:</b> <jk>false</jk>
+	 * </ul>
+	 *
+	 * <p>
+	 * If <jk>true</jk>, trying to set a value on a bean property without a setter will silently be ignored.
+	 * Otherwise, a {@code RuntimeException} is thrown.
+	 */
+	public static final String BEAN_ignorePropertiesWithoutSetters = "BeanContext.ignorePropertiesWithoutSetters";
+
+	/**
+	 * <b>Configuration property:</b>  Ignore invocation errors on getters.
+	 *
+	 * <ul>
+	 * 	<li><b>Name:</b> <js>"BeanContext.ignoreInvocationExceptionsOnGetters"</js>
+	 * 	<li><b>Data type:</b> <code>Boolean</code>
+	 * 	<li><b>Default:</b> <jk>false</jk>
+	 * 	<li><b>Session-overridable:</b> <jk>false</jk>
+	 * </ul>
+	 *
+	 * <p>
+	 * If <jk>true</jk>, errors thrown when calling bean getter methods will silently be ignored.
+	 * Otherwise, a {@code BeanRuntimeException} is thrown.
+	 */
+	public static final String BEAN_ignoreInvocationExceptionsOnGetters = "BeanContext.ignoreInvocationExceptionsOnGetters";
+
+	/**
+	 * <b>Configuration property:</b>  Ignore invocation errors on setters.
+	 *
+	 * <ul>
+	 * 	<li><b>Name:</b> <js>"BeanContext.ignoreInvocationExceptionsOnSetters"</js>
+	 * 	<li><b>Data type:</b> <code>Boolean</code>
+	 * 	<li><b>Default:</b> <jk>false</jk>
+	 * 	<li><b>Session-overridable:</b> <jk>false</jk>
+	 * </ul>
+	 *
+	 * <p>
+	 * If <jk>true</jk>, errors thrown when calling bean setter methods will silently be ignored.
+	 * Otherwise, a {@code BeanRuntimeException} is thrown.
+	 */
+	public static final String BEAN_ignoreInvocationExceptionsOnSetters = "BeanContext.ignoreInvocationExceptionsOnSetters";
+
+	/**
+	 * <b>Configuration property:</b>  Sort bean properties in alphabetical order.
+	 *
+	 * <ul>
+	 * 	<li><b>Name:</b> <js>"BeanContext.sortProperties"</js>
+	 * 	<li><b>Data type:</b> <code>Boolean</code>
+	 * 	<li><b>Default:</b> <jk>false</jk>
+	 * 	<li><b>Session-overridable:</b> <jk>false</jk>
+	 * </ul>
+	 *
+	 * <p>
+	 * When <jk>true</jk>, all bean properties will be serialized and access in alphabetical order.
+	 * Otherwise, the natural order of the bean properties is used which is dependent on the JVM vendor.
+	 * On IBM JVMs, the bean properties are ordered based on their ordering in the Java file.
+	 * On Oracle JVMs, the bean properties are not ordered (which follows the official JVM specs).
+	 *
+	 * <p>
+	 * This property is disabled by default so that IBM JVM users don't have to use {@link Bean @Bean} annotations
+	 * to force bean properties to be in a particular order and can just alter the order of the fields/methods
+	 * in the Java file.
+	 */
+	public static final String BEAN_sortProperties = "BeanContext.sortProperties";
+
+	/**
+	 * <b>Configuration property:</b>  Packages whose classes should not be considered beans.
+	 *
+	 * <ul>
+	 * 	<li><b>Name:</b> <js>"BeanContext.notBeanPackages.set"</js>
+	 * 	<li><b>Data type:</b> <code>Set&lt;String&gt;</code>
+	 * 	<li><b>Default:</b>
+	 * 	<ul>
+	 * 		<li><code>java.lang</code>
+	 * 		<li><code>java.lang.annotation</code>
+	 * 		<li><code>java.lang.ref</code>
+	 * 		<li><code>java.lang.reflect</code>
+	 * 		<li><code>java.io</code>
+	 * 		<li><code>java.net</code>
+	 * 		<li><code>java.nio.*</code>
+	 * 		<li><code>java.util.*</code>
+	 * 	</ul>
+	 * 	<li><b>Session-overridable:</b> <jk>false</jk>
+	 * </ul>
+	 *
+	 * <p>
+	 * When specified, the current list of ignore packages are appended to.
+	 *
+	 * <p>
+	 * Any classes within these packages will be serialized to strings using {@link Object#toString()}.
+	 *
+	 * <p>
+	 * Note that you can specify prefix patterns to include all subpackages.
+	 */
+	public static final String BEAN_notBeanPackages = "BeanContext.notBeanPackages.set";
+
+	/**
+	 * <b>Configuration property:</b>  Add to packages whose classes should not be considered beans.
+	 */
+	public static final String BEAN_notBeanPackages_add = "BeanContext.notBeanPackages.set.add";
+
+	/**
+	 * <b>Configuration property:</b>  Remove from packages whose classes should not be considered beans.
+	 */
+	public static final String BEAN_notBeanPackages_remove = "BeanContext.notBeanPackages.set.remove";
+
+	/**
+	 * <b>Configuration property:</b>  Classes to be excluded from consideration as being beans.
+	 *
+	 * <ul>
+	 * 	<li><b>Name:</b> <js>"BeanContext.notBeanClasses.set"</js>
+	 * 	<li><b>Data type:</b> <code>Set&lt;Class&gt;</code>
+	 * 	<li><b>Default:</b> empty set
+	 * 	<li><b>Session-overridable:</b> <jk>false</jk>
+	 * </ul>
+	 *
+	 * <p>
+	 * Not-bean classes are typically converted to <code>Strings</code> during serialization even if they appear to be
+	 * bean-like.
+	 */
+	public static final String BEAN_notBeanClasses = "BeanContext.notBeanClasses.set";
+
+	/**
+	 * <b>Configuration property:</b>  Add to classes that should not be considered beans.
+	 */
+	public static final String BEAN_notBeanClasses_add = "BeanContext.notBeanClasses.set.add";
+
+	/**
+	 * <b>Configuration property:</b>  Remove from classes that should not be considered beans.
+	 */
+	public static final String BEAN_notBeanClasses_remove = "BeanContext.notBeanClasses.set.remove";
+
+	/**
+	 * <b>Configuration property:</b>  Bean filters to apply to beans.
+	 *
+	 * <ul>
+	 * 	<li><b>Name:</b> <js>"BeanContext.beanFilters.list"</js>
+	 * 	<li><b>Data type:</b> <code>List&lt;Class&gt;</code>
+	 * 	<li><b>Default:</b> empty list
+	 * 	<li><b>Session-overridable:</b> <jk>false</jk>
+	 * </ul>
+	 *
+	 * <p>
+	 * This is a programmatic equivalent to the {@link Bean @Bean} annotation.
+	 * It's useful when you want to use the Bean annotation functionality, but you don't have the ability to alter the
+	 * bean classes.
+	 *
+	 * <p>
+	 * There are two category of classes that can be passed in through this method:
+	 * <ul class='spaced-list'>
+	 * 	<li>
+	 * 		Subclasses of {@link BeanFilterBuilder}.
+	 * 		These must have a public no-arg constructor.
+	 * 	<li>
+	 * 		Bean interface classes.
+	 * 		A shortcut for defining a {@link InterfaceBeanFilterBuilder}.
+	 * 		Any subclasses of an interface class will only have properties defined on the interface.
+	 * 		All other bean properties will be ignored.
+	 * </ul>
+	 */
+	public static final String BEAN_beanFilters = "BeanContext.beanFilters.list";
+
+	/**
+	 * <b>Configuration property:</b>  Add to bean filters.
+	 */
+	public static final String BEAN_beanFilters_add = "BeanContext.beanFilters.list.add";
+
+	/**
+	 * <b>Configuration property:</b>  Remove from bean filters.
+	 */
+	public static final String BEAN_beanFilters_remove = "BeanContext.beanFilters.list.remove";
+
+	/**
+	 * <b>Configuration property:</b>  POJO swaps to apply to Java objects.
+	 *
+	 * <ul>
+	 * 	<li><b>Name:</b> <js>"BeanContext.pojoSwaps.list"</js>
+	 * 	<li><b>Data type:</b> <code>List&lt;Class&gt;</code>
+	 * 	<li><b>Default:</b> empty list
+	 * 	<li><b>Session-overridable:</b> <jk>false</jk>
+	 * </ul>
+	 *
+	 * <p>
+	 * There are two category of classes that can be passed in through this method:
+	 * <ul>
+	 * 	<li>Subclasses of {@link PojoSwap}.
+	 * 	<li>Surrogate classes.  A shortcut for defining a {@link SurrogateSwap}.
+	 * </ul>
+	 */
+	public static final String BEAN_pojoSwaps = "BeanContext.pojoSwaps.list";
+
+	/**
+	 * <b>Configuration property:</b>  Add to POJO swap classes.
+	 */
+	public static final String BEAN_pojoSwaps_add = "BeanContext.pojoSwaps.list.add";
+
+	/**
+	 * <b>Configuration property:</b>  Remove from POJO swap classes.
+	 */
+	public static final String BEAN_pojoSwaps_remove = "BeanContext.pojoSwaps.list.remove";
+
+	/**
+	 * <b>Configuration property:</b>  Implementation classes for interfaces and abstract classes.
+	 *
+	 * <ul>
+	 * 	<li><b>Name:</b> <js>"BeanContext.implClasses.map"</js>
+	 * 	<li><b>Data type:</b> <code>Map&lt;Class,Class&gt;</code>
+	 * 	<li><b>Default:</b> empty map
+	 * 	<li><b>Session-overridable:</b> <jk>false</jk>
+	 * </ul>
+	 *
+	 * <p>
+	 * For interfaces and abstract classes this method can be used to specify an implementation class for the
+	 * interface/abstract class so that instances of the implementation class are used when instantiated (e.g. during a
+	 * parse).
+	 */
+	public static final String BEAN_implClasses = "BeanContext.implClasses.map";
+
+	/**
+	 * <b>Configuration property:</b>  Add an implementation class.
+	 */
+	public static final String BEAN_implClasses_put = "BeanContext.implClasses.map.put";
+
+	/**
+	 * <b>Configuration property:</b>  Explicitly specify visible bean properties.
+	 *
+	 * <ul>
+	 * 	<li><b>Name:</b> <js>"BeanContext.includeProperties"</js>
+	 * 	<li><b>Data type:</b> <code>Map&lt;String,String&gt;</code>
+	 * 	<li><b>Default:</b> <code>{}</code>
+	 * 	<li><b>Session-overridable:</b> <jk>false</jk>
+	 * </ul>
+	 *
+	 * <p>
+	 * Specifies to only include the specified list of properties for the specified bean classes.
+	 *
+	 * <p>
+	 * The keys are either fully-qualified or simple class names, and the values are comma-delimited lists of property
+	 *	names.
+	 * The key <js>"*"</js> means all bean classes.
+	 *
+	 * <p>
+	 * For example, <code>{Bean1:<js>'foo,bar'</js>}</code> means only serialize the <code>foo</code> and
+	 * <code>bar</code> properties on the specified bean.
+	 *
+	 * <p>
+	 * Setting applies to specified class and all subclasses.
+	 */
+	public static final String BEAN_includeProperties = "BeanContext.includeProperties.map";
+
+	/**
+	 * <b>Configuration property:</b>  Explicitly specify visible bean properties.
+	 */
+	public static final String BEAN_includeProperties_put = "BeanContext.includeProperties.map.put";
+
+	/**
+	 * <b>Configuration property:</b>  Exclude specified properties from beans.
+	 *
+	 * <ul>
+	 * 	<li><b>Name:</b> <js>"BeanContext.excludeProperties"</js>
+	 * 	<li><b>Data type:</b> <code>Map&lt;String,String&gt;</code>
+	 * 	<li><b>Default:</b> <code>{}</code>
+	 * 	<li><b>Session-overridable:</b> <jk>false</jk>
+	 * </ul>
+	 *
+	 * <p>
+	 * Specifies to exclude the specified list of properties for the specified bean class.
+	 *
+	 * <p>
+	 * The keys are either fully-qualified or simple class names, and the values are comma-delimited lists of property
+	 * names.
+	 * The key <js>"*"</js> means all bean classes.
+	 *
+	 * <p>
+	 * For example, <code>{Bean1:<js>'foo,bar'</js>}</code> means don't serialize the <code>foo</code> and
+	 * <code>bar</code> properties on the specified bean.
+	 *
+	 * <p>
+	 * Setting applies to specified class and all subclasses.
+	 */
+	public static final String BEAN_excludeProperties = "BeanContext.excludeProperties.map";
+
+	/**
+	 * <b>Configuration property:</b>  Exclude specified properties from beans.
+	 */
+	public static final String BEAN_excludeProperties_put = "BeanContext.excludeProperties.map.put";
+
+	/**
+	 * <b>Configuration property:</b>  Bean lookup dictionary.
+	 *
+	 * <ul>
+	 * 	<li><b>Name:</b> <js>"BeanContext.beanDictionary.list"</js>
+	 * 	<li><b>Data type:</b> <code>List&lt;Class&gt;</code>
+	 * 	<li><b>Default:</b> empty list
+	 * 	<li><b>Session-overridable:</b> <jk>false</jk>
+	 * </ul>
+	 *
+	 * <p>
+	 * This list can consist of the following class types:
+	 * <ul>
+	 * 	<li>Any bean class that specifies a value for {@link Bean#typeName() @Bean.typeName()}.
+	 * 	<li>Any subclass of {@link BeanDictionaryList} containing a collection of bean classes with type name
+	 * 		annotations.
+	 * 	<li>Any subclass of {@link BeanDictionaryMap} containing a mapping of type names to classes without type name
+	 * 		annotations.
+	 * </ul>
+	 */
+	public static final String BEAN_beanDictionary = "BeanContext.beanDictionary.list";
+
+	/**
+	 * <b>Configuration property:</b>  Add to bean dictionary.
+	 */
+	public static final String BEAN_beanDictionary_add = "BeanContext.beanDictionary.list.add";
+
+	/**
+	 * <b>Configuration property:</b>  Remove from bean dictionary.
+	 */
+	public static final String BEAN_beanDictionary_remove = "BeanContext.beanDictionary.list.remove";
+
+	/**
+	 * <b>Configuration property:</b>  Name to use for the bean type properties used to represent a bean type.
+	 *
+	 * <ul>
+	 * 	<li><b>Name:</b> <js>"BeanContext.beanTypePropertyName"</js>
+	 * 	<li><b>Data type:</b> <code>String</code>
+	 * 	<li><b>Default:</b> <js>"_type"</js>
+	 * 	<li><b>Session-overridable:</b> <jk>false</jk>
+	 * </ul>
+	 */
+	public static final String BEAN_beanTypePropertyName = "BeanContext.beanTypePropertyName";
+
+	/**
+	 * <b>Configuration property:</b>  Default parser to use when converting <code>Strings</code> to POJOs.
+	 *
+	 * <ul>
+	 * 	<li><b>Name:</b> <js>"BeanContext.defaultParser"</js>
+	 * 	<li><b>Data type:</b> <code>Class</code>
+	 * 	<li><b>Default:</b> {@link JsonSerializer}
+	 * 	<li><b>Session-overridable:</b> <jk>false</jk>
+	 * </ul>
+	 *
+	 * <p>
+	 * Used in the in the {@link BeanSession#convertToType(Object, Class)} method.
+	 */
+	public static final String BEAN_defaultParser = "BeanContext.defaultParser";
+
+	/**
+	 * <b>Configuration property:</b>  Locale.
+	 *
+	 * <ul>
+	 * 	<li><b>Name:</b> <js>"BeanContext.locale"</js>
+	 * 	<li><b>Data type:</b> <code>Locale</code>
+	 * 	<li><b>Default:</b> <code>Locale.getDefault()</code>
+	 * 	<li><b>Session-overridable:</b> <jk>true</jk>
+	 * </ul>
+	 *
+	 * <p>
+	 * Used in the in the {@link BeanSession#convertToType(Object, Class)} method.
+	 */
+	public static final String BEAN_locale = "BeanContext.locale";
+
+	/**
+	 * <b>Configuration property:</b>  TimeZone.
+	 *
+	 * <ul>
+	 * 	<li><b>Name:</b> <js>"BeanContext.timeZone"</js>
+	 * 	<li><b>Data type:</b> <code>TimeZone</code>
+	 * 	<li><b>Default:</b> <jk>null</jk>
+	 * 	<li><b>Session-overridable:</b> <jk>true</jk>
+	 * </ul>
+	 *
+	 * <p>
+	 * Used in the in the {@link BeanSession#convertToType(Object, Class)} method.
+	 */
+	public static final String BEAN_timeZone = "BeanContext.timeZone";
+
+	/**
+	 * <b>Configuration property:</b>  Media type.
+	 *
+	 * <ul>
+	 * 	<li><b>Name:</b> <js>"BeanContext.mediaType"</js>
+	 * 	<li><b>Data type:</b> <code>MediaType</code>
+	 * 	<li><b>Default:</b> <jk>null</jk>
+	 * 	<li><b>Session-overridable:</b> <jk>true</jk>
+	 * </ul>
+	 *
+	 * <p>
+	 * Specifies a default media type value for serializer and parser sessions.
+	 */
+	public static final String BEAN_mediaType = "BeanContext.mediaType";
+
+	/**
+	 * <b>Configuration property:</b>  Debug mode.
+	 *
+	 * <ul>
+	 * 	<li><b>Name:</b> <js>"BeanContext.debug"</js>
+	 * 	<li><b>Data type:</b> <code>Boolean</code>
+	 * 	<li><b>Default:</b> <jk>false</jk>
+	 * 	<li><b>Session-overridable:</b> <jk>true</jk>
+	 * </ul>
+	 *
+	 * <p>
+	 * Enables the following additional information during serialization:
+	 * <ul class='spaced-list'>
+	 * 	<li>
+	 * 		When bean getters throws exceptions, the exception includes the object stack information
+	 * 		in order to determine how that method was invoked.
+	 * 	<li>
+	 * 		Enables {@link SerializerContext#SERIALIZER_detectRecursions}.
+	 * </ul>
+	 *
+	 * <p>
+	 * Enables the following additional information during parsing:
+	 * <ul class='spaced-list'>
+	 * 	<li>
+	 * 		When bean setters throws exceptions, the exception includes the object stack information
+	 * 		in order to determine how that method was invoked.
+	 * </ul>
+	 */
+	public static final String BEAN_debug = "BeanContext.debug";
+
+	/*
+	 * The default package pattern exclusion list.
+	 * Any beans in packages in this list will not be considered beans.
+	 */
+	private static final String[] DEFAULT_NOTBEAN_PACKAGES = {
+		"java.lang",
+		"java.lang.annotation",
+		"java.lang.ref",
+		"java.lang.reflect",
+		"java.io",
+		"java.net",
+		"java.nio.*",
+		"java.util.*"
+	};
+
+	/*
+	 * The default bean class exclusion list.
+	 * Anything in this list will not be considered beans.
+	 */
+	private static final Class<?>[] DEFAULT_NOTBEAN_CLASSES = {
+		Map.class,
+		Collection.class,
+		Reader.class,
+		Writer.class,
+		InputStream.class,
+		OutputStream.class,
+		Throwable.class
+	};
+
+
+	static final void loadDefaults(PropertyStore config) {
+		config.setProperty(BEAN_notBeanPackages, DEFAULT_NOTBEAN_PACKAGES);
+		config.setProperty(BEAN_notBeanClasses, DEFAULT_NOTBEAN_CLASSES);
+	}
+
+
+	// This map is important!
+	// We may have many ConfigFactory objects that have identical BeanContext properties.
+	// This map ensures that if the BeanContext properties in the ConfigFactory are the same,
+	// then we reuse the same Class->ClassMeta cache map.
+	// This significantly reduces the number of times we need to construct ClassMeta objects which can be expensive.
+	private static final ConcurrentHashMap<Integer,Map<Class,ClassMeta>> cmCacheCache
+		= new ConcurrentHashMap<Integer,Map<Class,ClassMeta>>();
+
+	/** Default config.  All default settings. */
+	public static final BeanContext DEFAULT = PropertyStore.create().getContext(BeanContext.class);
+
+	/** Default config.  All default settings except sort bean properties. */
+	public static final BeanContext DEFAULT_SORTED = PropertyStore.create().setProperty(BEAN_sortProperties, true).getContext(BeanContext.class);
+
+	final boolean
+		beansRequireDefaultConstructor,
+		beansRequireSerializable,
+		beansRequireSettersForGetters,
+		beansRequireSomeProperties,
+		beanMapPutReturnsOldValue,
+		useInterfaceProxies,
+		ignoreUnknownBeanProperties,
+		ignoreUnknownNullBeanProperties,
+		ignorePropertiesWithoutSetters,
+		ignoreInvocationExceptionsOnGetters,
+		ignoreInvocationExceptionsOnSetters,
+		useJavaBeanIntrospector,
+		sortProperties,
+		debug;
+
+	final Visibility
+		beanConstructorVisibility,
+		beanClassVisibility,
+		beanMethodVisibility,
+		beanFieldVisibility;
+
+	final Class<?>[] notBeanClasses, beanDictionaryClasses;
+	final String[] notBeanPackageNames, notBeanPackagePrefixes;
+	final BeanFilter[] beanFilters;
+	final PojoSwap<?,?>[] pojoSwaps;
+	final BeanRegistry beanRegistry;
+	final Map<Class<?>,Class<?>> implClasses;
+	final Class<?>[] implKeyClasses, implValueClasses;
+	final ClassLoader classLoader;
+	final Locale locale;
+	final TimeZone timeZone;
+	final MediaType mediaType;
+	final Map<String,String[]> includeProperties, excludeProperties;
+
+	final Map<Class,ClassMeta> cmCache;
+	final ClassMeta<Object> cmObject;  // Reusable ClassMeta that represents general Objects.
+	final ClassMeta<String> cmString;  // Reusable ClassMeta that represents general Strings.
+	final ClassMeta<Class> cmClass;  // Reusable ClassMeta that represents general Classes.
+
+	// Optional default parser set by setDefaultParser().
+	final ReaderParser defaultParser;
+
+	final String beanTypePropertyName;
+
+	final int hashCode;
+
+	/**
+	 * Constructor.
+	 *
+	 * <p>
+	 * Typically only called from {@link PropertyStore#getContext(Class)} or {@link PropertyStore#getBeanContext()}.
+	 *
+	 * @param ps The property store that created this context.
+	 */
+	public BeanContext(PropertyStore ps) {
+		super(ps);
+
+		PropertyStore.PropertyMap pm = ps.getPropertyMap("BeanContext");
+		hashCode = pm.hashCode();
+		classLoader = ps.classLoader;
+		defaultParser = ps.defaultParser;
+
+		beansRequireDefaultConstructor = pm.get(BEAN_beansRequireDefaultConstructor, boolean.class, false);
+		beansRequireSerializable = pm.get(BEAN_beansRequireSerializable, boolean.class, false);
+		beansRequireSettersForGetters = pm.get(BEAN_beansRequireSettersForGetters, boolean.class, false);
+		beansRequireSomeProperties = pm.get(BEAN_beansRequireSomeProperties, boolean.class, true);
+		beanMapPutReturnsOldValue = pm.get(BEAN_beanMapPutReturnsOldValue, boolean.class, false);
+		useInterfaceProxies = pm.get(BEAN_useInterfaceProxies, boolean.class, true);
+		ignoreUnknownBeanProperties = pm.get(BEAN_ignoreUnknownBeanProperties, boolean.class, false);
+		ignoreUnknownNullBeanProperties = pm.get(BEAN_ignoreUnknownNullBeanProperties, boolean.class, true);
+		ignorePropertiesWithoutSetters = pm.get(BEAN_ignorePropertiesWithoutSetters, boolean.class, true);
+		ignoreInvocationExceptionsOnGetters = pm.get(BEAN_ignoreInvocationExceptionsOnGetters, boolean.class, false);
+		ignoreInvocationExceptionsOnSetters = pm.get(BEAN_ignoreInvocationExceptionsOnSetters, boolean.class, false);
+		useJavaBeanIntrospector = pm.get(BEAN_useJavaBeanIntrospector, boolean.class, false);
+		sortProperties = pm.get(BEAN_sortProperties, boolean.class, false);
+		beanTypePropertyName = pm.get(BEAN_beanTypePropertyName, String.class, "_type");
+		debug = ps.getProperty(BEAN_debug, boolean.class, false);
+
+		beanConstructorVisibility = pm.get(BEAN_beanConstructorVisibility, Visibility.class, PUBLIC);
+		beanClassVisibility = pm.get(BEAN_beanClassVisibility, Visibility.class, PUBLIC);
+		beanMethodVisibility = pm.get(BEAN_methodVisibility, Visibility.class, PUBLIC);
+		beanFieldVisibility = pm.get(BEAN_beanFieldVisibility, Visibility.class, PUBLIC);
+
+		notBeanClasses = pm.get(BEAN_notBeanClasses, Class[].class, new Class[0]);
+
+		List<String> l1 = new LinkedList<String>();
+		List<String> l2 = new LinkedList<String>();
+		for (String s : pm.get(BEAN_notBeanPackages, String[].class, new String[0])) {
+			if (s.endsWith(".*"))
+				l2.add(s.substring(0, s.length()-2));
+			else
+				l1.add(s);
+		}
+		notBeanPackageNames = l1.toArray(new String[l1.size()]);
+		notBeanPackagePrefixes = l2.toArray(new String[l2.size()]);
+
+		LinkedList<BeanFilter> lbf = new LinkedList<BeanFilter>();
+		for (Class<?> c : pm.get(BEAN_beanFilters, Class[].class, new Class[0])) {
+			if (isParentClass(BeanFilter.class, c))
+				lbf.add(newInstance(BeanFilter.class, c));
+			else if (isParentClass(BeanFilterBuilder.class, c))
+				lbf.add(newInstance(BeanFilterBuilder.class, c).build());
+			else
+				lbf.add(new InterfaceBeanFilterBuilder(c).build());
+		}
+		beanFilters = lbf.toArray(new BeanFilter[0]);
+
+		LinkedList<PojoSwap<?,?>> lpf = new LinkedList<PojoSwap<?,?>>();
+		for (Class<?> c : pm.get(BEAN_pojoSwaps, Class[].class, new Class[0])) {
+			if (isParentClass(PojoSwap.class, c))
+				lpf.add(newInstance(PojoSwap.class, c));
+			else
+				lpf.addAll(SurrogateSwap.findPojoSwaps(c));
+		}
+		pojoSwaps = lpf.toArray(new PojoSwap[0]);
+
+		implClasses = new TreeMap<Class<?>,Class<?>>(new ClassComparator());
+		Map<Class,Class> m = pm.getMap(BEAN_implClasses, Class.class, Class.class, null);
+		if (m != null)
+			for (Map.Entry<Class,Class> e : m.entrySet())
+				implClasses.put(e.getKey(), e.getValue());
+		implKeyClasses = implClasses.keySet().toArray(new Class[0]);
+		implValueClasses = implClasses.values().toArray(new Class[0]);
+
+		Map<String,String[]> m2 = pm.getMap(BEAN_includeProperties, String.class, String[].class, null);
+		includeProperties = m2 == null ? Collections.EMPTY_MAP : Collections.unmodifiableMap(m2);
+		m2 = pm.getMap(BEAN_excludeProperties, String.class, String[].class, null);
+		excludeProperties = m2 == null ? Collections.EMPTY_MAP : Collections.unmodifiableMap(m2);
+
+		locale = pm.get(BEAN_locale, Locale.class, null);
+		timeZone = pm.get(BEAN_timeZone, TimeZone.class, null);
+		mediaType = pm.get(BEAN_mediaType, MediaType.class, null);
+
+		if (! cmCacheCache.containsKey(hashCode)) {
+			ConcurrentHashMap<Class,ClassMeta> cm = new ConcurrentHashMap<Class,ClassMeta>();
+			cm.putIfAbsent(String.class, new ClassMeta(String.class, this, null, null, findPojoSwap(String.class), findChildPojoSwaps(String.class)));
+			cm.putIfAbsent(Object.class, new ClassMeta(Object.class, this, null, null, findPojoSwap(Object.class), findChildPojoSwaps(Object.class)));
+			cmCacheCache.putIfAbsent(hashCode, cm);
+		}
+		this.cmCache = cmCacheCache.get(hashCode);
+		this.cmString = cmCache.get(String.class);
+		this.cmObject = cmCache.get(Object.class);
+		this.cmClass = cmCache.get(Class.class);
+
+		this.beanDictionaryClasses = pm.get(BEAN_beanDictionary, Class[].class, new Class[0]);
+		this.beanRegistry = new BeanRegistry(this, null);
+	}
+
+	/**
+	 * Create a new bean session based on the properties defined on this context.
+	 *
+	 * @param args
+	 * 	The session arguments.
+	 * @return A new session object.
+	 */
+	public BeanSession createSession(BeanSessionArgs args) {
+		return new BeanSession(this, args);
+	}
+
+	/**
+	 * Create a new bean session based on the properties defined on this context.
+	 *
+	 * <p>
+	 * Use this method for creating sessions if you don't need to override any
+	 * properties or locale/timezone currently set on this context.
+	 *
+	 * @return A new session object.
+	 */
+	public BeanSession createSession() {
+		return new BeanSession(this, new BeanSessionArgs(null, this.locale, this.timeZone, this.mediaType));
+	}
+
+	/**
+	 * Returns <jk>true</jk> if the specified bean context shares the same cache as this bean context.
+	 *
+	 * <p>
+	 * Useful for testing purposes.
+	 *
+	 * @param bc The bean context to compare to.
+	 * @return <jk>true</jk> if the bean contexts have equivalent settings and thus share caches.
+	 */
+	public final boolean hasSameCache(BeanContext bc) {
+		return bc.cmCache == this.cmCache;
+	}
+
+	/**
+	 * Determines whether the specified class is ignored as a bean class based on the various exclusion parameters
+	 * specified on this context class.
+	 *
+	 * @param c The class type being tested.
+	 * @return <jk>true</jk> if the specified class matches any of the exclusion parameters.
+	 */
+	protected final boolean isNotABean(Class<?> c) {
+		if (c.isArray() || c.isPrimitive() || c.isEnum() || c.isAnnotation())
+			return true;
+		Package p = c.getPackage();
+		if (p != null) {
+			for (String p2 : notBeanPackageNames)
+				if (p.getName().equals(p2))
+					return true;
+			for (String p2 : notBeanPackagePrefixes)
+				if (p.getName().startsWith(p2))
+					return true;
+		}
+		for (Class exclude : notBeanClasses)
+			if (isParentClass(exclude, c))
+				return true;
+		return false;
+	}
+
+	/**
+	 * Returns <jk>true</jk> if the specified object is a bean.
+	 *
+	 * @param o The object to test.
+	 * @return <jk>true</jk> if the specified object is a bean.  <jk>false</jk> if the bean is <jk>null</jk>.
+	 */
+	public boolean isBean(Object o) {
+		if (o == null)
+			return false;
+		return getClassMetaForObject(o).isBean();
+	}
+
+	/**
+	 * Prints meta cache statistics to <code>System.out</code>.
+	 */
+	protected static void dumpCacheStats() {
+		try {
+			int ctCount = 0;
+			for (Map<Class,ClassMeta> cm : cmCacheCache.values())
+				ctCount += cm.size();
+			System.out.println(format("ClassMeta cache: {0} instances in {1} caches", ctCount, cmCacheCache.size())); // NOT DEBUG
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+
+	/**
+	 * Returns the {@link BeanMeta} class for the specified class.
+	 *
+	 * @param <T> The class type to get the meta-data on.
+	 * @param c The class to get the meta-data on.
+	 * @return
+	 * 	The {@link BeanMeta} for the specified class, or <jk>null</jk> if the class is not a bean per the settings on
+	 * 	this context.
+	 */
+	public final <T> BeanMeta<T> getBeanMeta(Class<T> c) {
+		if (c == null)
+			return null;
+		return getClassMeta(c).getBeanMeta();
+	}
+
+	/**
+	 * Construct a {@code ClassMeta} wrapper around a {@link Class} object.
+	 *
+	 * @param <T> The class type being wrapped.
+	 * @param type The class to resolve.
+	 * @return
+	 * 	If the class is not an array, returns a cached {@link ClassMeta} object.
+	 * 	Otherwise, returns a new {@link ClassMeta} object every time.
+	 */
+	public final <T> ClassMeta<T> getClassMeta(Class<T> type) {
+		return getClassMeta(type, true);
+	}
+
+	/**
+	 * Construct a {@code ClassMeta} wrapper around a {@link Class} object.
+	 *
+	 * @param <T> The class type being wrapped.
+	 * @param type The class to resolve.
+	 * @param waitForInit
+	 * 	If <jk>true</jk>, wait for the ClassMeta constructor to finish before returning.
+	 * @return
+	 * 	If the class is not an array, returns a cached {@link ClassMeta} object.
+	 * 	Otherwise, returns a new {@link ClassMeta} object every time.
+	 */
+	final <T> ClassMeta<T> getClassMeta(Class<T> type, boolean waitForInit) {
+
+		// If this is an array, then we want it wrapped in an uncached ClassMeta object.
+		// Note that if it has a pojo swap, we still want to cache it so that
+		// we can cache something like byte[] with ByteArrayBase64Swap.
+		if (type.isArray() && findPojoSwap(type) == null)
+			return new ClassMeta(type, this, findImplClass(type), findBeanFilter(type), findPojoSwap(type), findChildPojoSwaps(type));
+
+		// This can happen if we have transforms defined against String or Object.
+		if (cmCache == null)
+			return null;
+
+		ClassMeta<T> cm = cmCache.get(type);
+		if (cm == null) {
+
+			synchronized (this) {
+				// Make sure someone didn't already set it while this thread was blocked.
+				cm = cmCache.get(type);
+				if (cm == null)
+					cm = new ClassMeta<T>(type, this, findImplClass(type), findBeanFilter(type), findPojoSwap(type), findChildPojoSwaps(type));
+			}
+		}
+		if (waitForInit)
+			cm.waitForInit();
+		return cm;
+	}
+
+	/**
+	 * Used to resolve <code>ClassMetas</code> of type <code>Collection</code> and <code>Map</code> that have
+	 * <code>ClassMeta</code> values that themselves could be collections or maps.
+	 *
+	 * <p>
+	 * <code>Collection</code> meta objects are assumed to be followed by zero or one meta objects indicating the element type.
+	 *
+	 * <p>
+	 * <code>Map</code> meta objects are assumed to be followed by zero or two meta objects indicating the key and value types.
+	 *
+	 * <p>
+	 * The array can be arbitrarily long to indicate arbitrarily complex data structures.
+	 *
+	 * <h5 class='section'>Examples:</h5>
+	 * <ul>
+	 * 	<li><code>getClassMeta(String.<jk>class</jk>);</code> - A normal type.
+	 * 	<li><code>getClassMeta(List.<jk>class</jk>);</code> - A list containing objects.
+	 * 	<li><code>getClassMeta(List.<jk>class</jk>, String.<jk>class</jk>);</code> - A list containing strings.
+	 * 	<li><code>getClassMeta(LinkedList.<jk>class</jk>, String.<jk>class</jk>);</code> - A linked-list containing
+	 * 		strings.
+	 * 	<li><code>getClassMeta(LinkedList.<jk>class</jk>, LinkedList.<jk>class</jk>, String.<jk>class</jk>);</code> -
+	 * 		A linked-list containing linked-lists of strings.
+	 * 	<li><code>getClassMeta(Map.<jk>class</jk>);</code> - A map containing object keys/values.
+	 * 	<li><code>getClassMeta(Map.<jk>class</jk>, String.<jk>class</jk>, String.<jk>class</jk>);</code> - A map
+	 * 		containing string keys/values.
+	 * 	<li><code>getClassMeta(Map.<jk>class</jk>, String.<jk>class</jk>, List.<jk>class</jk>, MyBean.<jk>class</jk>);</code> -
+	 * 		A map containing string keys and values of lists containing beans.
+	 * </ul>
+	 *
+	 * @param type
+	 * 	The class to resolve.
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
+	 * 	{@link GenericArrayType}
+	 * @param args
+	 * 	The type arguments of the class if it's a collection or map.
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
+	 * 	{@link GenericArrayType}
+	 * 	<br>Ignored if the main type is not a map or collection.
+	 * @return The resolved class meta.
+	 */
+	public final <T> ClassMeta<T> getClassMeta(Type type, Type...args) {
+		if (type == null)
+			return null;
+		ClassMeta<T> cm = type instanceof Class ? getClassMeta((Class)type) : resolveClassMeta(type, null);
+		if (args.length == 0)
+			return cm;
+		ClassMeta<?>[] cma = new ClassMeta[args.length+1];
+		cma[0] = cm;
+		for (int i = 0; i < Array.getLength(args); i++) {
+			Type arg = (Type)Array.get(args, i);
+			cma[i+1] = arg instanceof Class ? getClassMeta((Class)arg) : resolveClassMeta(arg, null);
+		}
+		return (ClassMeta<T>) getTypedClassMeta(cma, 0);
+	}
+
+	/*
+	 * Resolves the 'genericized' class meta at the specified position in the ClassMeta array.
+	 */
+	private ClassMeta<?> getTypedClassMeta(ClassMeta<?>[] c, int pos) {
+		ClassMeta<?> cm = c[pos++];
+		if (cm.isCollection()) {
+			ClassMeta<?> ce = c.length == pos ? object() : getTypedClassMeta(c, pos);
+			return (ce.isObject() ? cm : new ClassMeta(cm, null, null, ce));
+		} else if (cm.isMap()) {
+			ClassMeta<?> ck = c.length == pos ? object() : c[pos++];
+			ClassMeta<?> cv = c.length == pos ? object() : getTypedClassMeta(c, pos);
+			return (ck.isObject() && cv.isObject() ? cm : new ClassMeta(cm, ck, cv, null));
+		}
+		return cm;
+	}
+
+	final ClassMeta resolveClassMeta(Type o, Map<Class<?>,Class<?>[]> typeVarImpls) {
+		if (o == null)
+			return null;
+
+		if (o instanceof ClassMeta) {
+			ClassMeta<?> cm = (ClassMeta)o;
+
+			// This classmeta could have been created by a different context.
+			// Need to re-resolve it to pick up PojoSwaps and stuff on this context.
+			if (cm.getBeanContext() == this)
+				return cm;
+			if (cm.isMap())
+				return getClassMeta(cm.innerClass, cm.getKeyType(), cm.getValueType());
+			if (cm.isCollection())
+				return getClassMeta(cm.innerClass, cm.getElementType());
+			return getClassMeta(cm.innerClass);
+		}
+
+		Class c = resolve(o, typeVarImpls);
+
+		// This can happen when trying to resolve the "E getFirst()" method on LinkedList, whose type is a TypeVariable
+		// These should just resolve to Object.
+		if (c == null)
+			return object();
+
+		ClassMeta rawType = getClassMeta(c);
+
+		// If this is a Map or Collection, and the parameter types aren't part
+		// of the class definition itself (e.g. class AddressBook extends List<Person>),
+		// then we need to figure out the parameters.
+		if (rawType.isMap() || rawType.isCollection()) {
+			ClassMeta[] params = findParameters(o, c);
+			if (params == null)
+				return rawType;
+			if (rawType.isMap()) {
+				if (params.length != 2)
+					return rawType;
+				if (params[0].isObject() && params[1].isObject())
+					return rawType;
+				return new ClassMeta(rawType, params[0], params[1], null);
+			}
+			if (rawType.isCollection()) {
+				if (params.length != 1)
+					return rawType;
+				if (params[0].isObject())
+					return rawType;
+				return new ClassMeta(rawType, null, null, params[0]);
+			}
+		}
+
+		return rawType;
+	}
+
+	/**
+	 * Convert a Type to a Class if possible.
+	 * Return null if not possible.
+	 */
+	final Class resolve(Type t, Map<Class<?>,Class<?>[]> typeVarImpls) {
+
+		if (t instanceof Class)
+			return (Class)t;
+
+		if (t instanceof ParameterizedType)
+			// A parameter (e.g. <String>.
+			return (Class)((ParameterizedType)t).getRawType();
+
+		if (t instanceof GenericArrayType) {
+			// An array parameter (e.g. <byte[]>).
+			Type gatct = ((GenericArrayType)t).getGenericComponentType();
+
+			if (gatct instanceof Class)
+				return Array.newInstance((Class)gatct, 0).getClass();
+
+			if (gatct instanceof ParameterizedType)
+				return Array.newInstance((Class)((ParameterizedType)gatct).getRawType(), 0).getClass();
+
+			if (gatct instanceof GenericArrayType)
+				return Array.newInstance(resolve(gatct, typeVarImpls), 0).getClass();
+
+			return null;
+
+		} else if (t instanceof TypeVariable) {
+			if (typeVarImpls != null) {
+				TypeVariable tv = (TypeVariable)t;
+				String varName = tv.getName();
+				int varIndex = -1;
+				Class gc = (Class)tv.getGenericDeclaration();
+				TypeVariable[] tvv = gc.getTypeParameters();
+				for (int i = 0; i < tvv.length; i++) {
+					if (tvv[i].getName().equals(varName)) {
+						varIndex = i;
+					}
+				}
+				if (varIndex != -1) {
+
+					// If we couldn't find a type variable implementation, that means
+					// the type was defined at runtime (e.g. Bean b = new Bean<Foo>();)
+					// in which case the type is lost through erasure.
+					// Assume java.lang.Object as the type.
+					if (! typeVarImpls.containsKey(gc))
+						return null;
+
+					return typeVarImpls.get(gc)[varIndex];
+				}
+			}
+		}
+		return null;
+	}
+
+	final ClassMeta[] findParameters(Type o, Class c) {
+		if (o == null)
+			o = c;
+
+		// Loop until we find a ParameterizedType
+		if (! (o instanceof ParameterizedType)) {
+			loop: do {
+				o = c.getGenericSuperclass();
+				if (o instanceof ParameterizedType)
+					break loop;
+				for (Type t : c.getGenericInterfaces()) {
+					o = t;
+					if (o instanceof ParameterizedType)
+						break loop;
+				}
+				c = c.getSuperclass();
+			} while (c != null);
+		}
+
+		if (o instanceof ParameterizedType) {
+			ParameterizedType pt = (ParameterizedType)o;
+			if (! pt.getRawType().equals(Enum.class)) {
+				List<ClassMeta<?>> l = new LinkedList<ClassMeta<?>>();
+				for (Type pt2 : pt.getActualTypeArguments()) {
+					if (pt2 instanceof WildcardType || pt2 instanceof TypeVariable)
+						return null;
+					l.add(resolveClassMeta(pt2, null));
+				}
+				if (l.isEmpty())
+					return null;
+				return l.toArray(new ClassMeta[l.size()]);
+			}
+		}
+
+		return null;
+	}
+
+	/**
+	 * Shortcut for calling {@code getClassMeta(o.getClass())}.
+	 *
+	 * @param <T> The class of the object being passed in.
+	 * @param o The class to find the class type for.
+	 * @return The ClassMeta object, or <jk>null</jk> if {@code o} is <jk>null</jk>.
+	 */
+	public final <T> ClassMeta<T> getClassMetaForObject(T o) {
+		if (o == null)
+			return null;
+		return (ClassMeta<T>)getClassMeta(o.getClass());
+	}
+
+
+	/**
+	 * Used for determining the class type on a method or field where a {@code @BeanProperty} annotation may be present.
+	 *
+	 * @param <T> The class type we're wrapping.
+	 * @param p The property annotation on the type if there is one.
+	 * @param t The type.
+	 * @param typeVarImpls
+	 * 	Contains known resolved type parameters on the specified class so that we can result
+	 * 	{@code ParameterizedTypes} and {@code TypeVariables}.
+	 * 	Can be <jk>null</jk> if the information is not known.
+	 * @return The new {@code ClassMeta} object wrapped around the {@code Type} object.
+	 */
+	protected final <T> ClassMeta<T> resolveClassMeta(BeanProperty p, Type t, Map<Class<?>,Class<?>[]> typeVarImpls) {
+		ClassMeta<T> cm = resolveClassMeta(t, typeVarImpls);
+		ClassMeta<T> cm2 = cm;
+		if (p != null) {
+
+			if (p.type() != Object.class)
+				cm2 = resolveClassMeta(p.type(), typeVarImpls);
+
+			if (cm2.isMap()) {
+				Class<?>[] pParams = (p.params().length == 0 ? new Class[]{Object.class, Object.class} : p.params());
+				if (pParams.length != 2)
+					throw new FormattedRuntimeException("Invalid number of parameters specified for Map (must be 2): {0}", pParams.length);
+				ClassMeta<?> keyType = resolveType(pParams[0], cm2.getKeyType(), cm.getKeyType());
+				ClassMeta<?> valueType = resolveType(pParams[1], cm2.getValueType(), cm.getValueType());
+				if (keyType.isObject() && valueType.isObject())
+					return cm2;
+				return new ClassMeta<T>(cm2, keyType, valueType, null);
+			}
+
+			if (cm2.isCollection()) {
+				Class<?>[] pParams = (p.params().length == 0 ? new Class[]{Object.class} : p.params());
+				if (pParams.length != 1)
+					throw new FormattedRuntimeException("Invalid number of parameters specified for Collection (must be 1): {0}", pParams.length);
+				ClassMeta<?> elementType = resolveType(pParams[0], cm2.getElementType(), cm.getElementType());
+				if (elementType.isObject())
+					return cm2;
+				return new ClassMeta<T>(cm2, null, null, elementType);
+			}
+
+			return cm2;
+		}
+
+		return cm;
+	}
+
+	private ClassMeta<?> resolveType(Type...t) {
+		for (Type tt : t) {
+			if (tt != null) {
+				ClassMeta<?> cm = getClassMeta(tt);
+				if (tt != cmObject)
+					return cm;
+			}
+		}
+		return cmObject;
+	}
+
+	/**
+	 * Returns the {@link PojoSwap} associated with the specified class, or <jk>null</jk> if there is no POJO swap
+	 * associated with the class.
+	 *
+	 * @param <T> The class associated with the swap.
+	 * @param c The class associated with the swap.
+	 * @return The swap associated with the class, or null if there is no association.
+	 */
+	private final <T> PojoSwap findPojoSwap(Class<T> c) {
+		// Note:  On first
+		if (c != null)
+			for (PojoSwap f : pojoSwaps)
+				if (isParentClass(f.getNormalClass(), c))
+					return f;
+		return null;
+	}
+
+	/**
+	 * Checks whether a class has a {@link PojoSwap} associated with it in this bean context.
+	 *
+	 * @param c The class to check.
+	 * @return <jk>true</jk> if the specified class or one of its subclasses has a {@link PojoSwap} associated with it.
+	 */
+	private final PojoSwap[] findChildPojoSwaps(Class<?> c) {
+		if (c == null || pojoSwaps.length == 0)
+			return null;
+		List<PojoSwap> l = null;
+		for (PojoSwap f : pojoSwaps) {
+			if (isParentClass(c, f.getNormalClass())) {
+				if (l == null)
+					l = new ArrayList<PojoSwap>();
+				l.add(f);
+			}
+		}
+		return l == null ? null : l.toArray(new PojoSwap[l.size()]);
+	}
+
+	/**
+	 * Returns the {@link BeanFilter} associated with the specified class, or <jk>null</jk> if there is no bean filter
+	 * associated with the class.
+	 *
+	 * @param <T> The class associated with the bean filter.
+	 * @param c The class associated with the bean filter.
+	 * @return The bean filter associated with the class, or null if there is no association.
+	 */
+	private final <T> BeanFilter findBeanFilter(Class<T> c) {
+		if (c != null)
+			for (BeanFilter f : beanFilters)
+				if (isParentClass(f.getBeanClass(), c))
+					return f;
+		return null;
+	}
+
+	/**
+	 * Returns the type property name as defined by {@link BeanContext#BEAN_beanTypePropertyName}.
+	 *
+	 * @return The type property name.  Never <jk>null</jk>.
+	 */
+	protected final String getBeanTypePropertyName() {
+		return beanTypePropertyName;
+	}
+
+	/**
+	 * Returns the bean registry defined in this bean context defined by {@link BeanContext#BEAN_beanDictionary}.
+	 *
+	 * @return The bean registry defined in this bean context.  Never <jk>null</jk>.
+	 */
+	protected final BeanRegistry getBeanRegistry() {
+		return beanRegistry;
+	}
+
+	/**
+	 * Gets the no-arg constructor for the specified class.
+	 *
+	 * @param <T> The class to check.
+	 * @param c The class to check.
+	 * @param v The minimum visibility for the constructor.
+	 * @return The no arg constructor, or <jk>null</jk> if the class has no no-arg constructor.
+	 */
+	protected final <T> Constructor<? extends T> getImplClassConstructor(Class<T> c, Visibility v) {
+		if (implClasses.isEmpty())
+			return null;
+		Class cc = c;
+		while (cc != null) {
+			Class implClass = implClasses.get(cc);
+			if (implClass != null)
+				return findNoArgConstructor(implClass, v);
+			for (Class ic : cc.getInterfaces()) {
+				implClass = implClasses.get(ic);
+				if (implClass != null)
+					return findNoArgConstructor(implClass, v);
+			}
+			cc = cc.getSuperclass();
+		}
+		return null;
+	}
+
+	private final <T> Class<? extends T> findImplClass(Class<T> c) {
+		if (implClasses.isEmpty())
+			return null;
+		Class cc = c;
+		while (cc != null) {
+			Class implClass = implClasses.get(cc);
+			if (implClass != null)
+				return implClass;
+			for (Class ic : cc.getInterfaces()) {
+				implClass = implClasses.get(ic);
+				if (implClass != null)
+					return implClass;
+			}
+			cc = cc.getSuperclass();
+		}
+		return null;
+	}
+
+	/**
+	 * Returns the {@link #BEAN_includeProperties} setting for the specified class.
+	 *
+	 * @param c The class.
+	 * @return The properties to include for the specified class, or <jk>null</jk> if it's not defined for the class.
+	 */
+	public String[] getIncludeProperties(Class<?> c) {
+		if (includeProperties.isEmpty())
+			return null;
+		String[] s = null;
+		for (Iterator<Class<?>> i = ClassUtils.getParentClasses(c, false, true); i.hasNext();) {
+			Class<?> c2 = i.next();
+			s = includeProperties.get(c2.getName());
+			if (s != null)
+				return s;
+			s = includeProperties.get(c2.getSimpleName());
+			if (s != null)
+				return s;
+		}
+		return includeProperties.get("*");
+	}
+
+	/**
+	 * Returns the {@link #BEAN_excludeProperties} setting for the specified class.
+	 *
+	 * @param c The class.
+	 * @return The properties to exclude for the specified class, or <jk>null</jk> if it's not defined for the class.
+	 */
+	public String[] getExcludeProperties(Class<?> c) {
+		if (excludeProperties.isEmpty())
+			return null;
+		String[] s = null;
+		for (Iterator<Class<?>> i = ClassUtils.getParentClasses(c, false, true); i.hasNext();) {
+			Class<?> c2 = i.next();
+			s = excludeProperties.get(c2.getName());
+			if (s != null)
+				return s;
+			s = excludeProperties.get(c2.getSimpleName());
+			if (s != null)
+				return s;
+		}
+		return excludeProperties.get("*");
+	}
+
+	/**
+	 * Returns a reusable {@link ClassMeta} representation for the class <code>Object</code>.
+	 *
+	 * <p>
+	 * This <code>ClassMeta</code> is often used to represent "any object type" when an object type is not known.
+	 *
+	 * <p>
+	 * This method is identical to calling <code>getClassMeta(Object.<jk>class</jk>)</code> but uses a cached copy to
+	 * avoid a hashmap lookup.
+	 *
+	 * @return The {@link ClassMeta} object associated with the <code>Object</code> class.
+	 */
+	protected final ClassMeta<Object> object() {
+		return cmObject;
+	}
+
+	/**
+	 * Returns a reusable {@link ClassMeta} representation for the class <code>String</code>.
+	 *
+	 * <p>
+	 * This <code>ClassMeta</code> is often used to represent key types in maps.
+	 *
+	 * <p>
+	 * This method is identical to calling <code>getClassMeta(String.<jk>class</jk>)</code> but uses a cached copy to
+	 * avoid a hashmap lookup.
+	 *
+	 * @return The {@link ClassMeta} object associated with the <code>String</code> class.
+	 */
+	protected final ClassMeta<String> string() {
+		return cmString;
+	}
+
+	/**
+	 * Returns a reusable {@link ClassMeta} representation for the class <code>Class</code>.
+	 *
+	 * <p>
+	 * This <code>ClassMeta</code> is often used to represent key types in maps.
+	 *
+	 * <p>
+	 * This method is identical to calling <code>getClassMeta(Class.<jk>class</jk>)</code> but uses a cached copy to
+	 * avoid a hashmap lookup.
+	 *
+	 * @return The {@link ClassMeta} object associated with the <code>String</code> class.
+	 */
+	protected final ClassMeta<Class> _class() {
+		return cmClass;
+	}
+
+	@Override /* Object */
+	public int hashCode() {
+		return hashCode;
+	}
+
+	@Override /* Object */
+	public boolean equals(Object o) {
+		if (this == o)
+			return true;
+		if (o instanceof BeanContext)
+			return ((BeanContext)o).hashCode == hashCode;
+		return false;
+	}
+
+	@Override /* Context */
+	public ObjectMap asMap() {
+		return super.asMap()
+			.append("BeanContext", new ObjectMap()
+				.append("id", System.identityHashCode(this))
+				.append("beansRequireDefaultConstructor", beansRequireDefaultConstructor)
+				.append("beansRequireSerializable", beansRequireSerializable)
+				.append("beansRequireSettersForGetters", beansRequireSettersForGetters)
+				.append("beansRequireSomeProperties", beansRequireSomeProperties)
+				.append("beanMapPutReturnsOldValue", beanMapPutReturnsOldValue)
+				.append("beanConstructorVisibility", beanConstructorVisibility)
+				.append("beanClassVisibility", beanClassVisibility)
+				.append("beanMethodVisibility", beanMethodVisibility)
+				.append("beanFieldVisibility", beanFieldVisibility)
+				.append("useInterfaceProxies", useInterfaceProxies)
+				.append("ignoreUnknownBeanProperties", ignoreUnknownBeanProperties)
+				.append("ignoreUnknownNullBeanProperties", ignoreUnknownNullBeanProperties)
+				.append("ignorePropertiesWithoutSetters", ignorePropertiesWithoutSetters)
+				.append("ignoreInvocationExceptionsOnGetters", ignoreInvocationExceptionsOnGetters)
+				.append("ignoreInvocationExceptionsOnSetters", ignoreInvocationExceptionsOnSetters)
+				.append("useJavaBeanIntrospector", useJavaBeanIntrospector)
+				.append("beanFilters", beanFilters)
+				.append("pojoSwaps", pojoSwaps)
+				.append("notBeanClasses", notBeanClasses)
+				.append("implClasses", implClasses)
+				.append("sortProperties", sortProperties)
+				.append("locale", locale)
+				.append("timeZone", timeZone)
+				.append("mediaType", mediaType)
+				.append("includeProperties", includeProperties)
+				.append("excludeProperties", excludeProperties)
+			);
+	}
+}
\ No newline at end of file


Mime
View raw message