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/29 00:35:51 UTC

incubator-juneau git commit: Make fields in BeanMeta final.

Repository: incubator-juneau
Updated Branches:
  refs/heads/master ecc843021 -> 83f2b35ba


Make fields in BeanMeta final.

Project: http://git-wip-us.apache.org/repos/asf/incubator-juneau/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-juneau/commit/83f2b35b
Tree: http://git-wip-us.apache.org/repos/asf/incubator-juneau/tree/83f2b35b
Diff: http://git-wip-us.apache.org/repos/asf/incubator-juneau/diff/83f2b35b

Branch: refs/heads/master
Commit: 83f2b35ba002b4d0fbefa02358476e00e332e467
Parents: ecc8430
Author: jamesbognar <ja...@gmail.com>
Authored: Sun Aug 28 20:35:47 2016 -0400
Committer: jamesbognar <ja...@gmail.com>
Committed: Sun Aug 28 20:35:47 2016 -0400

----------------------------------------------------------------------
 .../main/java/org/apache/juneau/BeanMeta.java   | 517 ++++++++++---------
 .../org/apache/juneau/BeanMetaFiltered.java     |  32 +-
 .../org/apache/juneau/BeanPropertyMeta.java     |   6 +-
 .../main/java/org/apache/juneau/ClassMeta.java  |   5 +-
 4 files changed, 287 insertions(+), 273 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/83f2b35b/juneau-core/src/main/java/org/apache/juneau/BeanMeta.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/BeanMeta.java b/juneau-core/src/main/java/org/apache/juneau/BeanMeta.java
index 1453dbb..840b68b 100644
--- a/juneau-core/src/main/java/org/apache/juneau/BeanMeta.java
+++ b/juneau-core/src/main/java/org/apache/juneau/BeanMeta.java
@@ -62,44 +62,43 @@ import org.apache.juneau.utils.*;
 public class BeanMeta<T> {
 
 	/** The target class type that this meta object describes. */
-	protected ClassMeta<T> classMeta;
+	protected final ClassMeta<T> classMeta;
 
 	/** The target class that this meta object describes. */
-	protected Class<T> c;
+	protected final Class<T> c;
 
 	/** The properties on the target class. */
-	protected Map<String,BeanPropertyMeta> properties;
+	protected final Map<String,BeanPropertyMeta> properties;
 
 	/** The getter properties on the target class. */
-	protected Map<Method,String> getterProps = new HashMap<Method,String>();
+	protected final Map<Method,String> getterProps;
 
 	/** The setter properties on the target class. */
-	protected Map<Method,String> setterProps = new HashMap<Method,String>();
+	protected final Map<Method,String> setterProps;
 
 	/** The bean context that created this metadata object. */
-	protected BeanContext ctx;
+	protected final BeanContext ctx;
 
 	/** Optional bean filter associated with the target class. */
-	protected BeanFilter<? extends T> beanFilter;
+	protected final BeanFilter<? extends T> beanFilter;
 
 	/** Type variables implemented by this bean. */
-	protected Map<Class<?>,Class<?>[]> typeVarImpls;
+	protected final Map<Class<?>,Class<?>[]> typeVarImpls;
 
 	/** The constructor for this bean. */
-	protected Constructor<T> constructor;
+	protected final Constructor<T> constructor;
 
 	/** For beans with constructors with BeanConstructor annotation, this is the list of constructor arg properties. */
-	protected String[] constructorArgs = new String[0];
+	protected final String[] constructorArgs;
 
-	private MetadataMap extMeta = new MetadataMap();  // Extended metadata
+	private final MetadataMap extMeta;  // Extended metadata
 
 	// Other fields
-	BeanPropertyMeta uriProperty;                                 // The property identified as the URI for this bean (annotated with @BeanProperty.beanUri).
-	BeanPropertyMeta subTypeIdProperty;                           // The property indentified as the sub type differentiator property (identified by @Bean.subTypeProperty annotation).
-	PropertyNamer propertyNamer;                                     // Class used for calculating bean property names.
-	BeanPropertyMeta classProperty;                               // "_class" mock bean property.
+	final BeanPropertyMeta uriProperty;                                 // The property identified as the URI for this bean (annotated with @BeanProperty.beanUri).
+	final BeanPropertyMeta subTypeIdProperty;                           // The property indentified as the sub type differentiator property (identified by @Bean.subTypeProperty annotation).
+	private final BeanPropertyMeta classProperty;                               // "_class" mock bean property.
 
-	BeanMeta() {}
+	final String notABeanReason;
 
 	/**
 	 * Constructor.
@@ -107,253 +106,315 @@ public class BeanMeta<T> {
 	 * @param classMeta The target class.
 	 * @param ctx The bean context that created this object.
 	 * @param beanFilter Optional bean filter associated with the target class.  Can be <jk>null</jk>.
+	 * @param pNames Explicit list of property names and order of properties.  If <jk>null</jk>, determine automatically.
 	 */
-	protected BeanMeta(final ClassMeta<T> classMeta, BeanContext ctx, BeanFilter<? extends T> beanFilter) {
+	protected BeanMeta(final ClassMeta<T> classMeta, BeanContext ctx, BeanFilter<? extends T> beanFilter, String[] pNames) {
 		this.classMeta = classMeta;
 		this.ctx = ctx;
+		this.c = classMeta.getInnerClass();
+
+		Builder<T> b = new Builder<T>(classMeta, ctx, beanFilter, pNames);
+		this.notABeanReason = b.init(this);
+
 		this.beanFilter = beanFilter;
+		this.properties = b.properties;
+		this.getterProps = Collections.unmodifiableMap(b.getterProps);
+		this.setterProps = Collections.unmodifiableMap(b.setterProps);
+		this.typeVarImpls = b.typeVarImpls;
+		this.constructor = b.constructor;
+		this.constructorArgs = b.constructorArgs;
+		this.extMeta = b.extMeta;
+		this.uriProperty = b.uriProperty;
+		this.subTypeIdProperty = b.subTypeIdProperty;
 		this.classProperty = new BeanPropertyMeta(this, "_class", ctx.string());
-		this.c = classMeta.getInnerClass();
 	}
 
-	/**
-	 * Returns the {@link ClassMeta} of this bean.
-	 *
-	 * @return The {@link ClassMeta} of this bean.
-	 */
-	@BeanIgnore
-	public ClassMeta<T> getClassMeta() {
-		return classMeta;
-	}
 
-	/**
-	 * Initializes this bean meta, and returns an error message if the specified class is not
-	 * a bean for any reason.
-	 *
-	 * @return Reason why this class isn't a bean, or <jk>null</jk> if no problems detected.
-	 * @throws BeanRuntimeException If unexpected error occurs such as invalid annotations on the bean class.
-	 */
-	@SuppressWarnings("unchecked")
-	protected String init() throws BeanRuntimeException {
-
-		try {
-			Visibility
-				conVis = ctx.beanConstructorVisibility,
-				cVis = ctx.beanClassVisibility,
-				mVis = ctx.beanMethodVisibility,
-				fVis = ctx.beanFieldVisibility;
-
-			// If @Bean.interfaceClass is specified on the parent class, then we want
-			// to use the properties defined on that class, not the subclass.
-			Class<?> c2 = (beanFilter != null && beanFilter.getInterfaceClass() != null ? beanFilter.getInterfaceClass() : c);
-
-			Class<?> stopClass = (beanFilter != null ? beanFilter.getStopClass() : Object.class);
-			if (stopClass == null)
-				stopClass = Object.class;
-
-			Map<String,BeanPropertyMeta> normalProps = new LinkedHashMap<String,BeanPropertyMeta>();
-
-			/// See if this class matches one the patterns in the exclude-class list.
-			if (ctx.isNotABean(c))
-				return "Class matches exclude-class list";
-
-			if (! cVis.isVisible(c.getModifiers()))
-				return "Class is not public";
-
-			if (c.isAnnotationPresent(BeanIgnore.class))
-				return "Class is annotated with @BeanIgnore";
-
-			// Make sure it's serializable.
-			if (beanFilter == null && ctx.beansRequireSerializable && ! isParentClass(Serializable.class, c))
-				return "Class is not serializable";
-
-			// Look for @BeanConstructor constructor.
-			for (Constructor<?> x : c.getConstructors()) {
-				if (x.isAnnotationPresent(BeanConstructor.class)) {
-					if (constructor != null)
-						throw new BeanRuntimeException(c, "Multiple instances of '@BeanConstructor' found.");
-					constructor = (Constructor<T>)x;
-					constructorArgs = x.getAnnotation(BeanConstructor.class).properties();
-					if (constructorArgs.length != x.getParameterTypes().length)
-						throw new BeanRuntimeException(c, "Number of properties defined in '@BeanConstructor' annotation does not match number of parameters in constructor.");
-					if (! setAccessible(constructor))
-						throw new BeanRuntimeException(c, "Could not set accessibility to true on method with @BeanConstructor annotation.  Method=''{0}''", constructor.getName());
+	private static final class Builder<T> {
+		ClassMeta<T> classMeta;
+		BeanContext ctx;
+		BeanFilter<? extends T> beanFilter;
+		String[] pNames;
+		Map<String,BeanPropertyMeta> properties;
+		Map<Method,String> getterProps = new HashMap<Method,String>();
+		Map<Method,String> setterProps = new HashMap<Method,String>();
+		Map<Class<?>,Class<?>[]> typeVarImpls;
+		Constructor<T> constructor;
+		String[] constructorArgs = new String[0];
+		MetadataMap extMeta = new MetadataMap();
+		BeanPropertyMeta uriProperty;
+		BeanPropertyMeta subTypeIdProperty;
+		PropertyNamer propertyNamer;
+
+		private Builder(ClassMeta<T> classMeta, BeanContext ctx, BeanFilter<? extends T> beanFilter, String[] pNames) {
+			this.classMeta = classMeta;
+			this.ctx = ctx;
+			this.beanFilter = beanFilter;
+			this.pNames = pNames;
+		}
+
+		@SuppressWarnings("unchecked")
+		private String init(BeanMeta<T> beanMeta) {
+			Class<?> c = classMeta.getInnerClass();
+
+			try {
+				Visibility
+					conVis = ctx.beanConstructorVisibility,
+					cVis = ctx.beanClassVisibility,
+					mVis = ctx.beanMethodVisibility,
+					fVis = ctx.beanFieldVisibility;
+
+				// If @Bean.interfaceClass is specified on the parent class, then we want
+				// to use the properties defined on that class, not the subclass.
+				Class<?> c2 = (beanFilter != null && beanFilter.getInterfaceClass() != null ? beanFilter.getInterfaceClass() : c);
+
+				Class<?> stopClass = (beanFilter != null ? beanFilter.getStopClass() : Object.class);
+				if (stopClass == null)
+					stopClass = Object.class;
+
+				Map<String,BeanPropertyMeta> normalProps = new LinkedHashMap<String,BeanPropertyMeta>();
+
+				/// See if this class matches one the patterns in the exclude-class list.
+				if (ctx.isNotABean(c))
+					return "Class matches exclude-class list";
+
+				if (! cVis.isVisible(c.getModifiers()))
+					return "Class is not public";
+
+				if (c.isAnnotationPresent(BeanIgnore.class))
+					return "Class is annotated with @BeanIgnore";
+
+				// Make sure it's serializable.
+				if (beanFilter == null && ctx.beansRequireSerializable && ! isParentClass(Serializable.class, c))
+					return "Class is not serializable";
+
+				// Look for @BeanConstructor constructor.
+				for (Constructor<?> x : c.getConstructors()) {
+					if (x.isAnnotationPresent(BeanConstructor.class)) {
+						if (constructor != null)
+							throw new BeanRuntimeException(c, "Multiple instances of '@BeanConstructor' found.");
+						constructor = (Constructor<T>)x;
+						constructorArgs = x.getAnnotation(BeanConstructor.class).properties();
+						if (constructorArgs.length != x.getParameterTypes().length)
+							throw new BeanRuntimeException(c, "Number of properties defined in '@BeanConstructor' annotation does not match number of parameters in constructor.");
+						if (! setAccessible(constructor))
+							throw new BeanRuntimeException(c, "Could not set accessibility to true on method with @BeanConstructor annotation.  Method=''{0}''", constructor.getName());
+					}
 				}
-			}
 
-			// If this is an interface, look for impl classes defined in the context.
-			if (constructor == null)
-				constructor = (Constructor<T>)ctx.getImplClassConstructor(c, conVis);
+				// If this is an interface, look for impl classes defined in the context.
+				if (constructor == null)
+					constructor = (Constructor<T>)ctx.getImplClassConstructor(c, conVis);
 
-			if (constructor == null)
-				constructor = (Constructor<T>)ClassMeta.findNoArgConstructor(c, conVis);
+				if (constructor == null)
+					constructor = (Constructor<T>)ClassMeta.findNoArgConstructor(c, conVis);
 
-			if (constructor == null && beanFilter == null && ctx.beansRequireDefaultConstructor)
-				return "Class does not have the required no-arg constructor";
+				if (constructor == null && beanFilter == null && ctx.beansRequireDefaultConstructor)
+					return "Class does not have the required no-arg constructor";
 
-			if (! setAccessible(constructor))
-				throw new BeanRuntimeException(c, "Could not set accessibility to true on no-arg constructor");
+				if (! setAccessible(constructor))
+					throw new BeanRuntimeException(c, "Could not set accessibility to true on no-arg constructor");
 
-			// Explicitly defined property names in @Bean annotation.
-			Set<String> fixedBeanProps = new LinkedHashSet<String>();
+				// Explicitly defined property names in @Bean annotation.
+				Set<String> fixedBeanProps = new LinkedHashSet<String>();
 
-			if (beanFilter != null) {
+				if (beanFilter != null) {
 
-				// Get the 'properties' attribute if specified.
-				if (beanFilter.getProperties() != null)
-					for (String p : beanFilter.getProperties())
-						fixedBeanProps.add(p);
+					// Get the 'properties' attribute if specified.
+					if (beanFilter.getProperties() != null)
+						for (String p : beanFilter.getProperties())
+							fixedBeanProps.add(p);
 
-				if (beanFilter.getPropertyNamer() != null)
-					propertyNamer = beanFilter.getPropertyNamer();
-			}
+					if (beanFilter.getPropertyNamer() != null)
+						propertyNamer = beanFilter.getPropertyNamer();
+				}
 
-			if (propertyNamer == null)
-				propertyNamer = new PropertyNamerDefault();
-
-			// First populate the properties with those specified in the bean annotation to
-			// ensure that ordering first.
-			for (String name : fixedBeanProps)
-				normalProps.put(name, new BeanPropertyMeta(this, name));
-
-			if (ctx.useJavaBeanIntrospector) {
-				BeanInfo bi = null;
-				if (! c2.isInterface())
-					bi = Introspector.getBeanInfo(c2, stopClass);
-				else
-					bi = Introspector.getBeanInfo(c2, null);
-				if (bi != null) {
-					for (PropertyDescriptor pd : bi.getPropertyDescriptors()) {
-						String name = pd.getName();
-						if (! normalProps.containsKey(name))
-							normalProps.put(name, new BeanPropertyMeta(this, name));
-						normalProps.get(name).setGetter(pd.getReadMethod()).setSetter(pd.getWriteMethod());
+				if (propertyNamer == null)
+					propertyNamer = new PropertyNamerDefault();
+
+				// First populate the properties with those specified in the bean annotation to
+				// ensure that ordering first.
+				for (String name : fixedBeanProps)
+					normalProps.put(name, new BeanPropertyMeta(beanMeta, name));
+
+				if (ctx.useJavaBeanIntrospector) {
+					BeanInfo bi = null;
+					if (! c2.isInterface())
+						bi = Introspector.getBeanInfo(c2, stopClass);
+					else
+						bi = Introspector.getBeanInfo(c2, null);
+					if (bi != null) {
+						for (PropertyDescriptor pd : bi.getPropertyDescriptors()) {
+							String name = pd.getName();
+							if (! normalProps.containsKey(name))
+								normalProps.put(name, new BeanPropertyMeta(beanMeta, name));
+							normalProps.get(name).setGetter(pd.getReadMethod()).setSetter(pd.getWriteMethod());
+						}
 					}
-				}
 
-			} else /* Use 'better' introspection */ {
+				} else /* Use 'better' introspection */ {
 
-				for (Field f : findBeanFields(c2, stopClass, fVis)) {
-					String name = findPropertyName(f, fixedBeanProps);
-					if (name != null) {
-						if (! normalProps.containsKey(name))
-							normalProps.put(name, new BeanPropertyMeta(this, name));
-						normalProps.get(name).setField(f);
+					for (Field f : findBeanFields(c2, stopClass, fVis)) {
+						String name = findPropertyName(f, fixedBeanProps);
+						if (name != null) {
+							if (! normalProps.containsKey(name))
+								normalProps.put(name, new BeanPropertyMeta(beanMeta, name));
+							normalProps.get(name).setField(f);
+						}
 					}
-				}
 
-				List<BeanMethod> bms = findBeanMethods(c2, stopClass, mVis, fixedBeanProps, propertyNamer);
-
-				// Iterate through all the getters.
-				for (BeanMethod bm : bms) {
-					String pn = bm.propertyName;
-					Method m = bm.method;
-					if (! normalProps.containsKey(pn))
-						normalProps.put(pn, new BeanPropertyMeta(this, pn));
-					BeanPropertyMeta bpm = normalProps.get(pn);
-					if (! bm.isSetter)
-						bpm.setGetter(m);
-				}
+					List<BeanMethod> bms = findBeanMethods(c2, stopClass, mVis, fixedBeanProps, propertyNamer);
+
+					// Iterate through all the getters.
+					for (BeanMethod bm : bms) {
+						String pn = bm.propertyName;
+						Method m = bm.method;
+						if (! normalProps.containsKey(pn))
+							normalProps.put(pn, new BeanPropertyMeta(beanMeta, pn));
+						BeanPropertyMeta bpm = normalProps.get(pn);
+						if (! bm.isSetter)
+							bpm.setGetter(m);
+					}
 
-				// Now iterate through all the setters.
-				for (BeanMethod bm : bms) {
-					if (bm.isSetter) {
-						BeanPropertyMeta bpm = normalProps.get(bm.propertyName);
-						if (bm.matchesPropertyType(bpm))
-							bpm.setSetter(bm.method);
+					// Now iterate through all the setters.
+					for (BeanMethod bm : bms) {
+						if (bm.isSetter) {
+							BeanPropertyMeta bpm = normalProps.get(bm.propertyName);
+							if (bm.matchesPropertyType(bpm))
+								bpm.setSetter(bm.method);
+						}
 					}
 				}
-			}
 
-			typeVarImpls = new HashMap<Class<?>,Class<?>[]>();
-			findTypeVarImpls(c, typeVarImpls);
-			if (typeVarImpls.isEmpty())
-				typeVarImpls = null;
+				typeVarImpls = new HashMap<Class<?>,Class<?>[]>();
+				findTypeVarImpls(c, typeVarImpls);
+				if (typeVarImpls.isEmpty())
+					typeVarImpls = null;
 
-			// Eliminate invalid properties, and set the contents of getterProps and setterProps.
-			for (Iterator<BeanPropertyMeta> i = normalProps.values().iterator(); i.hasNext();) {
-				BeanPropertyMeta p = i.next();
-				try {
-					if (p.validate()) {
+				// Eliminate invalid properties, and set the contents of getterProps and setterProps.
+				for (Iterator<BeanPropertyMeta> i = normalProps.values().iterator(); i.hasNext();) {
+					BeanPropertyMeta p = i.next();
+					try {
+						if (p.validate(ctx, typeVarImpls)) {
 
-						if (p.getGetter() != null)
-							getterProps.put(p.getGetter(), p.getName());
+							if (p.getGetter() != null)
+								getterProps.put(p.getGetter(), p.getName());
 
-						if (p.getSetter() != null)
-							setterProps.put(p.getSetter(), p.getName());
+							if (p.getSetter() != null)
+								setterProps.put(p.getSetter(), p.getName());
 
-						if (p.isBeanUri())
-							uriProperty = p;
+							if (p.isBeanUri())
+								uriProperty = p;
 
-					} else {
-						i.remove();
+						} else {
+							i.remove();
+						}
+					} catch (ClassNotFoundException e) {
+						throw new BeanRuntimeException(c, e.getLocalizedMessage());
 					}
-				} catch (ClassNotFoundException e) {
-					throw new BeanRuntimeException(c, e.getLocalizedMessage());
 				}
-			}
-
-			// Check for missing properties.
-			for (String fp : fixedBeanProps)
-				if (! normalProps.containsKey(fp))
-					throw new BeanRuntimeException(c, "The property ''{0}'' was defined on the @Bean(properties=X) annotation but was not found on the class definition.", fp);
-
-			// Mark constructor arg properties.
-			for (String fp : constructorArgs) {
-				BeanPropertyMeta m = normalProps.get(fp);
-				if (m == null)
-					throw new BeanRuntimeException(c, "The property ''{0}'' was defined on the @BeanConstructor(properties=X) annotation but was not found on the class definition.", fp);
-				m.setAsConstructorArg();
-			}
-
-			// Make sure at least one property was found.
-			if (beanFilter == null && ctx.beansRequireSomeProperties && normalProps.size() == 0)
-				return "No properties detected on bean class";
 
-			boolean sortProperties = (ctx.sortProperties || (beanFilter != null && beanFilter.isSortProperties())) && fixedBeanProps.isEmpty();
+				// Check for missing properties.
+				for (String fp : fixedBeanProps)
+					if (! normalProps.containsKey(fp))
+						throw new BeanRuntimeException(c, "The property ''{0}'' was defined on the @Bean(properties=X) annotation but was not found on the class definition.", fp);
+
+				// Mark constructor arg properties.
+				for (String fp : constructorArgs) {
+					BeanPropertyMeta m = normalProps.get(fp);
+					if (m == null)
+						throw new BeanRuntimeException(c, "The property ''{0}'' was defined on the @BeanConstructor(properties=X) annotation but was not found on the class definition.", fp);
+					m.setAsConstructorArg();
+				}
 
-			properties = sortProperties ? new TreeMap<String,BeanPropertyMeta>() : new LinkedHashMap<String,BeanPropertyMeta>();
+				// Make sure at least one property was found.
+				if (beanFilter == null && ctx.beansRequireSomeProperties && normalProps.size() == 0)
+					return "No properties detected on bean class";
 
-			if (beanFilter != null && beanFilter.getSubTypeProperty() != null) {
-				String subTypeProperty = beanFilter.getSubTypeProperty();
-				this.subTypeIdProperty = new SubTypePropertyMeta(subTypeProperty, beanFilter.getSubTypes(), normalProps.remove(subTypeProperty));
-				properties.put(subTypeProperty, this.subTypeIdProperty);
-			}
+				boolean sortProperties = (ctx.sortProperties || (beanFilter != null && beanFilter.isSortProperties())) && fixedBeanProps.isEmpty();
 
-			properties.putAll(normalProps);
+				properties = sortProperties ? new TreeMap<String,BeanPropertyMeta>() : new LinkedHashMap<String,BeanPropertyMeta>();
 
-			// If a beanFilter is defined, look for inclusion and exclusion lists.
-			if (beanFilter != null) {
+				if (beanFilter != null && beanFilter.getSubTypeProperty() != null) {
+					String subTypeProperty = beanFilter.getSubTypeProperty();
+					this.subTypeIdProperty = new SubTypePropertyMeta(beanMeta, subTypeProperty, beanFilter.getSubTypes(), normalProps.remove(subTypeProperty));
+					properties.put(subTypeProperty, this.subTypeIdProperty);
+				}
 
-				// Eliminated excluded properties if BeanFilter.excludeKeys is specified.
-				String[] includeKeys = beanFilter.getProperties();
-				String[] excludeKeys = beanFilter.getExcludeProperties();
-				if (excludeKeys != null) {
-					for (String k : excludeKeys)
-						properties.remove(k);
+				properties.putAll(normalProps);
+
+				// If a beanFilter is defined, look for inclusion and exclusion lists.
+				if (beanFilter != null) {
+
+					// Eliminated excluded properties if BeanFilter.excludeKeys is specified.
+					String[] includeKeys = beanFilter.getProperties();
+					String[] excludeKeys = beanFilter.getExcludeProperties();
+					if (excludeKeys != null) {
+						for (String k : excludeKeys)
+							properties.remove(k);
+
+					// Only include specified properties if BeanFilter.includeKeys is specified.
+					// Note that the order must match includeKeys.
+					} else if (includeKeys != null) {
+						Map<String,BeanPropertyMeta> properties2 = new LinkedHashMap<String,BeanPropertyMeta>();
+						for (String k : includeKeys) {
+							if (properties.containsKey(k))
+								properties2.put(k, properties.get(k));
+						}
+						properties = properties2;
+					}
+				}
 
-				// Only include specified properties if BeanFilter.includeKeys is specified.
-				// Note that the order must match includeKeys.
-				} else if (includeKeys != null) {
+				if (pNames != null) {
 					Map<String,BeanPropertyMeta> properties2 = new LinkedHashMap<String,BeanPropertyMeta>();
-					for (String k : includeKeys) {
+					for (String k : pNames) {
 						if (properties.containsKey(k))
 							properties2.put(k, properties.get(k));
 					}
 					properties = properties2;
 				}
+
+				// We return this through the Bean.keySet() interface, so make sure it's not modifiable.
+				properties = Collections.unmodifiableMap(properties);
+
+			} catch (BeanRuntimeException e) {
+				throw e;
+			} catch (Exception e) {
+				return "Exception:  " + StringUtils.getStackTrace(e);
 			}
 
-			// We return this through the Bean.keySet() interface, so make sure it's not modifiable.
-			properties = Collections.unmodifiableMap(properties);
+			return null;
+		}
 
-		} catch (BeanRuntimeException e) {
-			throw e;
-		} catch (Exception e) {
-			return "Exception:  " + StringUtils.getStackTrace(e);
+		/*
+		 * Returns the property name of the specified field if it's a valid property.
+		 * Returns null if the field isn't a valid property.
+		 */
+		private String findPropertyName(Field f, Set<String> fixedBeanProps) {
+			BeanProperty bp = f.getAnnotation(BeanProperty.class);
+			if (bp != null && ! bp.name().equals("")) {
+				String name = bp.name();
+				if (fixedBeanProps.isEmpty() || fixedBeanProps.contains(name))
+					return name;
+				throw new BeanRuntimeException(classMeta.getInnerClass(), "Method property ''{0}'' identified in @BeanProperty, but missing from @Bean", name);
+			}
+			String name = propertyNamer.getPropertyName(f.getName());
+			if (fixedBeanProps.isEmpty() || fixedBeanProps.contains(name))
+				return name;
+			return null;
 		}
 
-		return null;
+	}
+
+
+	/**
+	 * Returns the {@link ClassMeta} of this bean.
+	 *
+	 * @return The {@link ClassMeta} of this bean.
+	 */
+	@BeanIgnore
+	public ClassMeta<T> getClassMeta() {
+		return classMeta;
 	}
 
 	/**
@@ -621,24 +682,6 @@ public class BeanMeta<T> {
 		return null;
 	}
 
-	/*
-	 * Returns the property name of the specified field if it's a valid property.
-	 * Returns null if the field isn't a valid property.
-	 */
-	private String findPropertyName(Field f, Set<String> fixedBeanProps) {
-		BeanProperty bp = f.getAnnotation(BeanProperty.class);
-		if (bp != null && ! bp.name().equals("")) {
-			String name = bp.name();
-			if (fixedBeanProps.isEmpty() || fixedBeanProps.contains(name))
-				return name;
-			throw new BeanRuntimeException(c, "Method property ''{0}'' identified in @BeanProperty, but missing from @Bean", name);
-		}
-		String name = propertyNamer.getPropertyName(f.getName());
-		if (fixedBeanProps.isEmpty() || fixedBeanProps.contains(name))
-			return name;
-		return null;
-	}
-
 	/**
 	 * Recursively determines the classes represented by parameterized types in the class hierarchy of
 	 * the specified type, and puts the results in the specified map.<br>
@@ -699,15 +742,17 @@ public class BeanMeta<T> {
 	 * Bean property for getting and setting bean subtype.
 	 */
 	@SuppressWarnings({"rawtypes","unchecked"})
-	private class SubTypePropertyMeta extends BeanPropertyMeta {
+	private static class SubTypePropertyMeta extends BeanPropertyMeta {
 
 		private Map<Class<?>,String> subTypes;
 		private BeanPropertyMeta realProperty;  // Bean property if bean actually has a real subtype field.
+		private BeanMeta<?> beanMeta;
 
-		SubTypePropertyMeta(String subTypeAttr, Map<Class<?>,String> subTypes, BeanPropertyMeta realProperty) {
-			super(BeanMeta.this, subTypeAttr, ctx.string());
+		SubTypePropertyMeta(BeanMeta beanMeta, String subTypeAttr, Map<Class<?>,String> subTypes, BeanPropertyMeta realProperty) {
+			super(beanMeta, subTypeAttr, beanMeta.ctx.string());
 			this.subTypes = subTypes;
 			this.realProperty = realProperty;
+			this.beanMeta = beanMeta;
 		}
 
 		/*
@@ -721,7 +766,7 @@ public class BeanMeta<T> {
 			for (Entry<Class<?>,String> e : subTypes.entrySet()) {
 				if (e.getValue().equals(subTypeId)) {
 					Class subTypeClass = e.getKey();
-					m.meta = ctx.getBeanMeta(subTypeClass);
+					m.meta = beanMeta.ctx.getBeanMeta(subTypeClass);
 					try {
 						m.setBean(subTypeClass.newInstance());
 						if (realProperty != null)
@@ -736,14 +781,14 @@ public class BeanMeta<T> {
 					return null;
 				}
 			}
-			throw new BeanRuntimeException(c, "Unknown subtype ID ''{0}''", subTypeId);
+			throw new BeanRuntimeException(beanMeta.c, "Unknown subtype ID ''{0}''", subTypeId);
 		}
 
 		@Override /* BeanPropertyMeta */
 		public Object get(BeanMap<?> m) throws BeanRuntimeException {
-			String subTypeId = beanFilter.getSubTypes().get(c);
+			String subTypeId = beanMeta.beanFilter.getSubTypes().get(beanMeta.c);
 			if (subTypeId == null)
-				throw new BeanRuntimeException(c, "Unmapped sub type class");
+				throw new BeanRuntimeException(beanMeta.c, "Unmapped sub type class");
 			return subTypeId;
 		}
 	}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/83f2b35b/juneau-core/src/main/java/org/apache/juneau/BeanMetaFiltered.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/BeanMetaFiltered.java b/juneau-core/src/main/java/org/apache/juneau/BeanMetaFiltered.java
index b9d1d9e..f731d9d 100644
--- a/juneau-core/src/main/java/org/apache/juneau/BeanMetaFiltered.java
+++ b/juneau-core/src/main/java/org/apache/juneau/BeanMetaFiltered.java
@@ -25,8 +25,6 @@ import org.apache.juneau.annotation.*;
  */
 public final class BeanMetaFiltered<T> extends BeanMeta<T> {
 
-	private final BeanMeta<T> innerMeta;
-
 	/**
 	 * Wrapper constructor.
 	 *
@@ -34,10 +32,7 @@ public final class BeanMetaFiltered<T> extends BeanMeta<T> {
 	 * @param pNames The list of transformed property names.
 	 */
 	public BeanMetaFiltered(BeanMeta<T> innerMeta, String[] pNames) {
-		this.innerMeta = innerMeta;
-		this.properties = new LinkedHashMap<String,BeanPropertyMeta>();
-		for (String p : pNames)
-			properties.put(p, innerMeta.getPropertyMeta(p));
+		super(innerMeta.classMeta, innerMeta.ctx, innerMeta.beanFilter, pNames);
 	}
 
 	/**
@@ -49,29 +44,4 @@ public final class BeanMetaFiltered<T> extends BeanMeta<T> {
 	public BeanMetaFiltered(BeanMeta<T> innerMeta, Collection<String> pNames) {
 		this(innerMeta, pNames.toArray(new String[pNames.size()]));
 	}
-
-	@Override /* Delagate */
-	public ClassMeta<T> getClassMeta() {
-		return innerMeta.classMeta;
-	}
-
-	@Override /* Delagate */
-	public <M extends BeanMetaExtended> M getExtendedMeta(Class<M> m) {
-		return innerMeta.getExtendedMeta(m);
-	}
-
-	@Override /* BeanMeta */
-	public Collection<BeanPropertyMeta> getPropertyMetas() {
-		return properties.values();
-	}
-
-	@Override /* BeanMeta */
-	public BeanPropertyMeta getPropertyMeta(String name) {
-		return properties.get(name);
-	}
-
-	@Override /* Object */
-	public String toString() {
-		return innerMeta.c.getName();
-	}
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/83f2b35b/juneau-core/src/main/java/org/apache/juneau/BeanPropertyMeta.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/BeanPropertyMeta.java b/juneau-core/src/main/java/org/apache/juneau/BeanPropertyMeta.java
index b9d18b9..0d0a8b4 100644
--- a/juneau-core/src/main/java/org/apache/juneau/BeanPropertyMeta.java
+++ b/juneau-core/src/main/java/org/apache/juneau/BeanPropertyMeta.java
@@ -233,10 +233,7 @@ public class BeanPropertyMeta {
 		return extMeta.get(c, this);
 	}
 
-	boolean validate() throws Exception {
-
-		BeanContext f = beanMeta.ctx;
-		Map<Class<?>,Class<?>[]> typeVarImpls = beanMeta.typeVarImpls;
+	boolean validate(BeanContext f, Map<Class<?>,Class<?>[]> typeVarImpls) throws Exception {
 
 		if (field == null && getter == null)
 			return false;
@@ -565,6 +562,7 @@ public class BeanPropertyMeta {
 		} catch (BeanRuntimeException e) {
 			throw e;
 		} catch (Exception e) {
+			e.printStackTrace();
 			if (beanMeta.ctx.ignoreInvocationExceptionsOnSetters) {
 					if (rawTypeMeta.isPrimitive())
 						return rawTypeMeta.getPrimitiveDefault();

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/83f2b35b/juneau-core/src/main/java/org/apache/juneau/ClassMeta.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/ClassMeta.java b/juneau-core/src/main/java/org/apache/juneau/ClassMeta.java
index 6da687c..eb60730 100644
--- a/juneau-core/src/main/java/org/apache/juneau/ClassMeta.java
+++ b/juneau-core/src/main/java/org/apache/juneau/ClassMeta.java
@@ -299,9 +299,10 @@ public final class ClassMeta<T> implements Type {
 			// 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);
+				BeanMeta newMeta = null;
 				try {
-					notABeanReason = newMeta.init();
+					newMeta = new BeanMeta(this, beanContext, beanFilter, null);
+					notABeanReason = newMeta.notABeanReason;
 				} catch (RuntimeException e) {
 					notABeanReason = e.getMessage();
 					throw e;