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 2022/01/22 18:22:15 UTC

[juneau] branch master updated: BeanStore refactoring.

This is an automated email from the ASF dual-hosted git repository.

jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git


The following commit(s) were added to refs/heads/master by this push:
     new 7e742f8  BeanStore refactoring.
7e742f8 is described below

commit 7e742f845ac10c0dd873705c6ca5857542b240bd
Author: JamesBognar <ja...@salesforce.com>
AuthorDate: Sat Jan 22 13:21:30 2022 -0500

    BeanStore refactoring.
---
 .../apache/juneau/dto/swagger/ui/SwaggerUI.java    |    2 +-
 .../main/java/org/apache/juneau/BeanBuilder.java   |   84 +-
 .../src/main/java/org/apache/juneau/ClassMeta.java |   43 +-
 .../src/main/java/org/apache/juneau/Context.java   |   20 +-
 .../org/apache/juneau/assertions/AnyAssertion.java |    6 +-
 .../apache/juneau/assertions/ArrayAssertion.java   |    9 +-
 .../org/apache/juneau/assertions/Assertion.java    |   15 +-
 .../juneau/assertions/AssertionPredicate.java      |   12 +-
 .../org/apache/juneau/assertions/Assertions.java   |   84 +-
 .../apache/juneau/assertions/BeanAssertion.java    |    6 +-
 .../juneau/assertions/BeanListAssertion.java       |   10 +-
 .../apache/juneau/assertions/BooleanAssertion.java |    6 +-
 .../juneau/assertions/ByteArrayAssertion.java      |    6 +-
 .../juneau/assertions/CollectionAssertion.java     |    6 +-
 .../juneau/assertions/ComparableAssertion.java     |    6 +-
 .../apache/juneau/assertions/DateAssertion.java    |    6 +-
 .../juneau/assertions/FluentAnyAssertion.java      |    6 +-
 .../juneau/assertions/FluentArrayAssertion.java    |   54 +-
 .../apache/juneau/assertions/FluentAssertion.java  |    6 +-
 .../juneau/assertions/FluentBeanAssertion.java     |    2 +-
 .../juneau/assertions/FluentBeanListAssertion.java |    6 +-
 .../juneau/assertions/FluentBooleanAssertion.java  |   10 +-
 .../assertions/FluentByteArrayAssertion.java       |    2 +-
 .../assertions/FluentCollectionAssertion.java      |   20 +-
 .../assertions/FluentComparableAssertion.java      |   16 +-
 .../juneau/assertions/FluentDateAssertion.java     |   18 +-
 .../juneau/assertions/FluentIntegerAssertion.java  |    2 +-
 .../juneau/assertions/FluentListAssertion.java     |   47 +-
 .../juneau/assertions/FluentLongAssertion.java     |    2 +-
 .../juneau/assertions/FluentMapAssertion.java      |   16 +-
 .../juneau/assertions/FluentObjectAssertion.java   |   42 +-
 .../assertions/FluentPrimitiveArrayAssertion.java  |   20 +-
 .../juneau/assertions/FluentStringAssertion.java   |   53 +-
 .../assertions/FluentStringListAssertion.java      |    6 +-
 .../assertions/FluentThrowableAssertion.java       |   12 +-
 .../juneau/assertions/FluentVersionAssertion.java  |    2 +-
 .../assertions/FluentZonedDateTimeAssertion.java   |   18 +-
 .../apache/juneau/assertions/IntegerAssertion.java |    6 +-
 .../apache/juneau/assertions/ListAssertion.java    |   23 +-
 .../apache/juneau/assertions/LongAssertion.java    |    6 +-
 .../org/apache/juneau/assertions/MapAssertion.java |    6 +-
 .../apache/juneau/assertions/ObjectAssertion.java  |    6 +-
 .../juneau/assertions/PrimitiveArrayAssertion.java |    6 +-
 .../apache/juneau/assertions/StringAssertion.java  |    7 +-
 .../juneau/assertions/StringListAssertion.java     |   10 +-
 .../juneau/assertions/ThrowableAssertion.java      |    6 +-
 .../java/org/apache/juneau/assertions/Verify.java  |   18 +-
 .../apache/juneau/assertions/VersionAssertion.java |    6 +-
 .../juneau/assertions/ZonedDateTimeAssertion.java  |    6 +-
 .../apache/juneau/cp/BeanCreateMethodFinder.java   |   82 +-
 .../java/org/apache/juneau/cp/BeanCreator.java     |  313 +++---
 .../main/java/org/apache/juneau/cp/BeanStore.java  |  635 ++++++-----
 .../java/org/apache/juneau/cp/BeanStoreEntry.java  |  135 +++
 .../main/java/org/apache/juneau/cp/FileFinder.java |   56 +-
 .../main/java/org/apache/juneau/cp/Messages.java   |   33 +-
 .../org/apache/juneau/encoders/EncoderSet.java     |   44 +-
 .../org/apache/juneau/http/header/HeaderList.java  |   22 +-
 .../java/org/apache/juneau/http/part/PartList.java |   19 +-
 .../juneau/http/remote/RrpcInterfaceMeta.java      |    6 +-
 .../juneau/httppart/bean/RequestBeanMeta.java      |    4 +-
 .../httppart/bean/RequestBeanPropertyMeta.java     |    4 +-
 .../org/apache/juneau/internal/ClassUtils.java     |   53 +-
 .../org/apache/juneau/internal/SimpleLock.java     |    9 +-
 ...impleReadWriteLock.java => SimpleNoOpLock.java} |    6 +-
 .../juneau/internal/SimpleReadWriteLock.java       |   24 +
 .../apache/juneau/internal/UnmodifiableArray.java  |   64 +-
 .../java/org/apache/juneau/parser/ParserSet.java   |   42 +-
 .../org/apache/juneau/reflect/AnnotationInfo.java  |    4 +-
 .../java/org/apache/juneau/reflect/ClassInfo.java  |  329 +++---
 .../org/apache/juneau/reflect/ConstructorInfo.java |   27 +
 .../org/apache/juneau/reflect/ExecutableInfo.java  |   15 +-
 .../java/org/apache/juneau/reflect/MethodInfo.java |   58 +-
 .../java/org/apache/juneau/reflect/Mutaters.java   |   28 +-
 .../java/org/apache/juneau/reflect/ParamInfo.java  |   10 +
 .../apache/juneau/serializer/SerializerSet.java    |   40 +-
 .../java/org/apache/juneau/svl/VarResolver.java    |   41 +-
 .../java/org/apache/juneau/swap/SurrogateSwap.java |   12 +-
 .../java/org/apache/juneau/swaps/TemporalSwap.java |   11 +-
 .../org/apache/juneau/rest/client/RestClient.java  |    6 +-
 .../juneau/rest/client/remote/RemoteMeta.java      |    7 +-
 .../rest/client/remote/RemoteOperationArg.java     |    2 +-
 .../juneau/rest/springboot/SpringBeanStore.java    |   21 +-
 .../java/org/apache/juneau/rest/RestChildren.java  |   40 +-
 .../java/org/apache/juneau/rest/RestContext.java   |  374 +++----
 .../java/org/apache/juneau/rest/RestOpContext.java |   43 +-
 .../org/apache/juneau/rest/RestOperations.java     |   43 +-
 .../org/apache/juneau/rest/arg/RestOpArgList.java  |   51 +-
 .../juneau/rest/converter/RestConverterList.java   |   48 +-
 .../apache/juneau/rest/debug/DebugEnablement.java  |   46 +-
 .../apache/juneau/rest/guard/RestGuardList.java    |   47 +-
 .../juneau/rest/httppart/NamedAttributeList.java   |   20 +-
 .../rest/logging/BasicDisabledRestLogger.java      |    2 +-
 .../juneau/rest/logging/BasicRestLogger.java       |    3 +-
 .../rest/logging/BasicTestCaptureRestLogger.java   |   10 +-
 .../juneau/rest/logging/BasicTestRestLogger.java   |   10 +-
 .../org/apache/juneau/rest/logging/RestLogger.java |   50 +-
 .../apache/juneau/rest/logging/RestLoggerRule.java |   47 +-
 .../juneau/rest/matcher/RestMatcherList.java       |   47 +-
 .../rest/processor/ResponseProcessorList.java      |   44 +-
 .../org/apache/juneau/rest/servlet/RestObject.java |    2 +-
 .../juneau/rest/staticfile/BasicStaticFiles.java   |    7 +-
 .../apache/juneau/rest/staticfile/StaticFiles.java |   43 +-
 .../apache/juneau/rest/stats/MethodExecStats.java  |   37 +-
 .../apache/juneau/rest/stats/MethodExecStore.java  |   53 +-
 .../apache/juneau/rest/stats/MethodInvoker.java    |   10 +-
 .../org/apache/juneau/rest/stats/ThrownStats.java  |   31 +-
 .../org/apache/juneau/rest/stats/ThrownStore.java  |   52 +-
 .../juneau/rest/swagger/BasicSwaggerProvider.java  |    9 +-
 .../juneau/rest/swagger/SwaggerProvider.java       |   50 +-
 .../apache/juneau/assertions/Assertions_Test.java  |    4 +-
 .../org/apache/juneau/cp/BeanCreator_Test.java     |  419 --------
 .../java/org/apache/juneau/cp/BeanStore_Test.java  | 1114 +++++++++++++++++---
 .../java/org/apache/juneau/cp/FileFinder_Test.java |  522 ++++-----
 .../apache/juneau/http/BasicHttpResource_Test.java |   34 +-
 .../juneau/http/SerializedHttpEntity_Test.java     |    2 +-
 .../apache/juneau/mstat/MethodExecStore_Test.java  |   18 +-
 .../org/apache/juneau/mstat/ThrownStore_Test.java  |   16 +-
 .../apache/juneau/reflection/ClassInfoTest.java    |  189 +---
 .../juneau/reflection/ExecutableInfoTest.java      |   66 +-
 .../apache/juneau/reflection/ParamInfoTest.java    |   24 +-
 .../juneau/rest/annotation/Rest_Debug_Test.java    |    2 +-
 .../rest/client/RestClient_Headers_Test.java       |    2 +-
 .../rest/client/RestClient_Response_Body_Test.java |    6 +-
 .../apache/juneau/utils/StringVarResolverTest.java |    2 +-
 124 files changed, 3501 insertions(+), 3087 deletions(-)

diff --git a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/ui/SwaggerUI.java b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/ui/SwaggerUI.java
index d6218b7..5442268 100644
--- a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/ui/SwaggerUI.java
+++ b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/swagger/ui/SwaggerUI.java
@@ -38,7 +38,7 @@ import org.apache.juneau.swap.*;
 public class SwaggerUI extends ObjectSwap<Swagger,Div> {
 
 	static final FileFinder RESOURCES = FileFinder
-		.create()
+		.create(BeanStore.INSTANCE)
 		.cp(SwaggerUI.class, null, true)
 		.dir(",")
 		.caching(Boolean.getBoolean("RestContext.disableClasspathResourceCaching.b") ? -1 : 1_000_000)
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanBuilder.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanBuilder.java
index b666272..b2030c5 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanBuilder.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanBuilder.java
@@ -34,16 +34,26 @@ public class BeanBuilder<T> {
 
 	private Class<? extends T> type, defaultType;
 	private T impl;
-	private Object outer;
-	private BeanStore beanStore = BeanStore.INSTANCE;
+	private final BeanStore beanStore;
 
 	/**
 	 * Constructor.
 	 *
+	 * @param beanStore The bean store to use for creating beans.
 	 * @param defaultType The default bean type that this builder creates.
 	 */
-	protected BeanBuilder(Class<? extends T> defaultType) {
+	protected BeanBuilder(Class<? extends T> defaultType, BeanStore beanStore) {
 		this.defaultType = type = defaultType;
+		this.beanStore = beanStore;
+	}
+
+	/**
+	 * Constructor.
+	 *
+	 * @param defaultType The type of bean being created.
+	 */
+	protected BeanBuilder(Class<? extends T> defaultType) {
+		this(defaultType, BeanStore.INSTANCE);
 	}
 
 	/**
@@ -54,20 +64,10 @@ public class BeanBuilder<T> {
 	protected BeanBuilder(BeanBuilder<T> copyFrom) {
 		type = copyFrom.type;
 		impl = copyFrom.impl;
-		outer = copyFrom.outer;
 		beanStore = copyFrom.beanStore;
 	}
 
 	/**
-	 * Creates a copy of this builder.
-	 *
-	 * @return A copy of this builder.
-	 */
-	public BeanBuilder<T> copy() {
-		return new BeanBuilder<>(this);
-	}
-
-	/**
 	 * Creates the bean.
 	 *
 	 * @return A new bean.
@@ -90,9 +90,8 @@ public class BeanBuilder<T> {
 	 */
 	protected BeanCreator<? extends T> creator() {
 		return beanStore
-			.creator(type().orElseThrow(()->runtimeException("Type not specified.")))
-			.outer(outer)
-			.builder(this);
+			.createBean(type().orElseThrow(()->runtimeException("Type not specified.")))
+			.builder(BeanBuilder.class, this);
 	}
 
 	/**
@@ -102,9 +101,8 @@ public class BeanBuilder<T> {
 	 */
 	protected T buildDefault() {
 		return beanStore
-			.creator(type().orElseThrow(()->runtimeException("Type not specified.")))
-			.outer(outer)
-			.builder(this)
+			.createBean(type().orElseThrow(()->runtimeException("Type not specified.")))
+			.builder(BeanBuilder.class, this)
 			.run();
 	}
 
@@ -159,52 +157,12 @@ public class BeanBuilder<T> {
 	}
 
 	/**
-	 * Specifies the outer bean context.
-	 *
-	 * <p>
-	 * This should be the instance of the outer object such as the servlet object when constructing inner classes
-	 * of the servlet class.
-	 *
-	 * @param value The setting value.
-	 * @return  This object.
-	 */
-	@FluentSetter
-	public BeanBuilder<T> outer(Object value) {
-		outer = value;
-		return this;
-	}
-
-	/**
-	 * Returns the outer bean context specified via {@link #outer(Object)}.
-	 *
-	 * @return The outer bean context specified via {@link #outer(Object)}.
-	 */
-	public Optional<Object> outer() {
-		return ofNullable(outer);
-	}
-
-	/**
-	 * The bean store to use for instantiating the bean.
-	 *
-	 * <p>
-	 * The bean store can be used to inject beans into parameters of the constructor of the bean.
-	 *
-	 * @param value The setting value.
-	 * @return  This object.
-	 */
-	@FluentSetter
-	public BeanBuilder<T> beanStore(BeanStore value) {
-		beanStore = value;
-		return this;
-	}
-
-	/**
-	 * Returns the bean store specified via {@link #outer(Object)}.
+	 * Returns the bean store passed in through the constructor.
 	 *
-	 * @return The bean store specified via {@link #outer(Object)}.
+	 * @return The bean store passed in through the constructor.
 	 */
-	public Optional<BeanStore> beanStore() {
-		return ofNullable(beanStore);
+	public BeanStore beanStore() {
+		return beanStore;
 	}
 
 	// <FluentSetters>
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
index f5368e1..f3d948f 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
@@ -16,7 +16,7 @@ import static org.apache.juneau.ClassMeta.ClassCategory.*;
 import static org.apache.juneau.internal.ClassUtils.*;
 import static org.apache.juneau.internal.ThrowableUtils.*;
 import static org.apache.juneau.internal.ObjectUtils.*;
-import static org.apache.juneau.reflect.ReflectFlags.*;
+import static java.util.Optional.*;
 
 import java.io.*;
 import java.lang.annotation.*;
@@ -435,24 +435,26 @@ public final class ClassMeta<T> implements Type {
 			// valueOf() is used by enums.
 			// parse() is used by the java logging Level class.
 			// forName() is used by Class and Charset
-			for (String methodName : new String[]{"fromString","fromValue","valueOf","parse","parseString","forName","forString"}) {
-				if (fromStringMethod == null) {
-					for (MethodInfo m : ci.getPublicMethods()) {
-						if (m.isAll(STATIC, PUBLIC, NOT_DEPRECATED) && m.hasName(methodName) && m.hasReturnType(c) && m.hasParamTypes(String.class)) {
-							fromStringMethod = m.inner();
-							break;
-						}
-					}
-				}
-			}
+			String[] fromStringMethodNames = {"fromString","fromValue","valueOf","parse","parseString","forName","forString"};
+			fromStringMethod = ofNullable(
+				ci.getPublicMethod(
+					x -> x.isStatic()
+					&& x.isNotDeprecated()
+					&& x.hasReturnType(c) 
+					&& x.hasParamTypes(String.class) 
+					&& ArrayUtils.contains(x.getName(), fromStringMethodNames))
+				).map(x -> x.inner())
+				.orElse(null);
 
 			// Find example() method if present.
-			for (MethodInfo m : ci.getPublicMethods()) {
-				if (m.isAll(PUBLIC, NOT_DEPRECATED, STATIC) && m.hasName("example") && m.hasFuzzyParamTypes(BeanSession.class)) {
-					exampleMethod = m.inner();
-					break;
-				}
-			}
+			exampleMethod = ofNullable(
+				ci.getPublicMethod(
+					x -> x.isStatic()
+					&& x.isNotDeprecated()
+					&& x.hasName("example") 
+					&& x.hasFuzzyParamTypes(BeanSession.class))
+				).map(x -> x.inner())
+				.orElse(null);
 
 			for (FieldInfo f : ci.getAllFieldsParentFirst()) {
 				if (bc.hasAnnotation(ParentProperty.class, f)) {
@@ -522,9 +524,10 @@ public final class ClassMeta<T> implements Type {
 
 			primitiveDefault = ci.getPrimitiveDefault();
 
-			for (MethodInfo m : ci.getPublicMethods())
-				if (m.isAll(PUBLIC, NOT_DEPRECATED))
-					publicMethods.put(m.getSignature(), m.inner());
+			ci.getPublicMethods(
+				x -> x.isNotDeprecated(), 
+				x -> publicMethods.put(x.getSignature(), x.inner())
+			);
 
 			BeanFilter beanFilter = findBeanFilter(bc);
 			MarshalledFilter marshalledFilter = findMarshalledFilter(bc);
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/Context.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/Context.java
index c48cd8a..32ccc82 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/Context.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/Context.java
@@ -95,7 +95,21 @@ public abstract class Context implements MetaProvider {
 		try {
 			MethodInfo mi = BUILDER_CREATE_METHODS.get(type);
 			if (mi == null) {
-				mi = ClassInfo.of(type).getBuilderCreateMethod().orElseThrow(()->runtimeException("Could not find builder create method on class {0}", type));
+				ClassInfo c = ClassInfo.ofc(type);
+				for (ConstructorInfo ci : c.getPublicConstructors()) {
+					if (ci.matches(x -> x.hasNumParams(1) && ! x.getParam(0).getParameterType().is(type))) {
+						mi = c.getPublicMethod(
+							x -> x.isStatic()
+							&& x.isNotDeprecated()
+							&& x.hasName("create")
+							&& x.hasReturnType(ci.getParam(0).getParameterType())
+						);
+						if (mi != null)
+							break;
+					}
+				}
+				if (mi == null)
+					throw runtimeException("Could not find builder create method on class {0}", type);
 				BUILDER_CREATE_METHODS.put(type, mi);
 			}
 			Builder b = (Builder)mi.invoke(null);
@@ -833,7 +847,7 @@ public abstract class Context implements MetaProvider {
 			try {
 				ClassInfo ci = ClassInfo.of(a.getClass());
 
-				MethodInfo mi = ci.getMethod("onClass");
+				MethodInfo mi = ci.getPublicMethod(x -> x.hasName("onClass"));
 				if (mi != null) {
 					if (! mi.getReturnType().is(Class[].class))
 						throw new ConfigException("Invalid annotation @{0} used in BEAN_annotations property.  Annotation must define an onClass() method that returns a Class array.", a.getClass().getSimpleName());
@@ -841,7 +855,7 @@ public abstract class Context implements MetaProvider {
 						rmb.append(c.getName(), a);
 				}
 
-				mi = ci.getMethod("on");
+				mi = ci.getPublicMethod(x -> x.hasName("on"));
 				if (mi != null) {
 					if (! mi.getReturnType().is(String[].class))
 						throw new ConfigException("Invalid annotation @{0} used in BEAN_annotations property.  Annotation must define an on() method that returns a String array.", a.getClass().getSimpleName());
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/AnyAssertion.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/AnyAssertion.java
index cf030d4..3f641e4 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/AnyAssertion.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/AnyAssertion.java
@@ -117,7 +117,7 @@ import org.apache.juneau.serializer.*;
 public class AnyAssertion<T> extends FluentAnyAssertion<T,AnyAssertion<T>> {
 
 	//-----------------------------------------------------------------------------------------------------------------
-	// Constructors
+	// Static
 	//-----------------------------------------------------------------------------------------------------------------
 
 	/**
@@ -132,6 +132,10 @@ public class AnyAssertion<T> extends FluentAnyAssertion<T,AnyAssertion<T>> {
 		return new AnyAssertion<>(value);
 	}
 
+	//-----------------------------------------------------------------------------------------------------------------
+	// Instance
+	//-----------------------------------------------------------------------------------------------------------------
+
 	/**
 	 * Constructor.
 	 *
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/ArrayAssertion.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/ArrayAssertion.java
index 5082006..dd7832b 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/ArrayAssertion.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/ArrayAssertion.java
@@ -64,6 +64,9 @@ import org.apache.juneau.serializer.*;
  * <h5 class='topic'>Transform Methods</h5>
  * 	<ul>
  * 		<li class='jm'>{@link FluentArrayAssertion#asStrings()}
+ * 		<li class='jm'>{@link FluentArrayAssertion#asStrings(Function)}
+ * 		<li class='jm'>{@link FluentArrayAssertion#asCdl()}
+ * 		<li class='jm'>{@link FluentArrayAssertion#asCdl(Function)}
  * 		<li class='jm'>{@link FluentArrayAssertion#asBeanList()}
  * 		<li class='jm'>{@link FluentArrayAssertion#item(int)}
  * 		<li class='jm'>{@link FluentArrayAssertion#sorted()}
@@ -97,7 +100,7 @@ import org.apache.juneau.serializer.*;
 public class ArrayAssertion<E> extends FluentArrayAssertion<E,ArrayAssertion<E>> {
 
 	//-----------------------------------------------------------------------------------------------------------------
-	// Constructors
+	// Static
 	//-----------------------------------------------------------------------------------------------------------------
 
 	/**
@@ -112,6 +115,10 @@ public class ArrayAssertion<E> extends FluentArrayAssertion<E,ArrayAssertion<E>>
 		return new ArrayAssertion<>(value);
 	}
 
+	//-----------------------------------------------------------------------------------------------------------------
+	// Instance
+	//-----------------------------------------------------------------------------------------------------------------
+
 	/**
 	 * Constructor.
 	 *
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/Assertion.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/Assertion.java
index c9a39e6..c10d293 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/Assertion.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/Assertion.java
@@ -54,20 +54,25 @@ import org.apache.juneau.internal.*;
 @FluentSetters
 public class Assertion {
 
+	//-----------------------------------------------------------------------------------------------------------------
+	// Static
+	//-----------------------------------------------------------------------------------------------------------------
+
 	private static final Messages MESSAGES = Messages.of(Assertion.class, "Messages");
+
 	static final String
 		MSG_parameterCannotBeNull = MESSAGES.getString("parameterCannotBeNull"),
 		MSG_causedBy = MESSAGES.getString("causedBy");
 
+	//-----------------------------------------------------------------------------------------------------------------
+	// Instance
+	//-----------------------------------------------------------------------------------------------------------------
+
 	private String msg;
 	private Object[] msgArgs;
 	private PrintStream out = System.err;
 	private Class<? extends RuntimeException> throwable;
 
-	//-----------------------------------------------------------------------------------------------------------------
-	// Constructors
-	//-----------------------------------------------------------------------------------------------------------------
-
 	/**
 	 * Constructor used when this assertion is being created from within another assertion.
 	 *
@@ -228,7 +233,7 @@ public class Assertion {
 					.addBean(Throwable.class, cause)
 					.addBean(String.class, msg)
 					.addBean(Object[].class,new Object[0])
-					.creator(throwable)
+					.createBean(throwable)
 					.run();
 			} catch (ExecutableException e) {
 				// If we couldn't create requested exception, just throw a RuntimeException.
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/AssertionPredicate.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/AssertionPredicate.java
index 07ca901..904c756 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/AssertionPredicate.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/AssertionPredicate.java
@@ -56,6 +56,10 @@ import org.apache.juneau.cp.*;
  */
 public class AssertionPredicate<T> implements Predicate<T> {
 
+	//-----------------------------------------------------------------------------------------------------------------
+	// Static
+	//-----------------------------------------------------------------------------------------------------------------
+
 	/**
 	 * Argument placeholder for tested value.
 	 */
@@ -66,15 +70,15 @@ public class AssertionPredicate<T> implements Predicate<T> {
 		MSG_valueDidNotPassTest = MESSAGES.getString("valueDidNotPassTest"),
 		MSG_valueDidNotPassTestWithValue = MESSAGES.getString("valueDidNotPassTestWithValue");
 
+	//-----------------------------------------------------------------------------------------------------------------
+	// Instance
+	//-----------------------------------------------------------------------------------------------------------------
+
 	private final Predicate<T> inner;
 	private final String message;
 	private final Object[] args;
 	final ThreadLocal<String> failedMessage = new ThreadLocal<>();
 
-	//-----------------------------------------------------------------------------------------------------------------
-	// Constructors
-	//-----------------------------------------------------------------------------------------------------------------
-
 	/**
 	 * Constructor.
 	 *
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/Assertions.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/Assertions.java
index b1beb07..5ed738e 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/Assertions.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/Assertions.java
@@ -18,6 +18,7 @@ import static org.apache.juneau.internal.IOUtils.*;
 import java.io.*;
 import java.time.*;
 import java.util.*;
+import java.util.stream.*;
 
 import org.apache.juneau.*;
 import org.apache.juneau.cp.*;
@@ -315,6 +316,34 @@ public class Assertions {
 	}
 
 	/**
+	 * Performs an assertion on the contents of an input stream.
+	 *
+	 * <h5 class='section'>Example:</h5>
+	 * <p class='bcode w800'>
+	 * 	<jk>import static</jk> org.apache.juneau.assertions.Assertions.*;
+	 *
+	 * 	<jc>// Asserts that the stream contains the string "foo".</jc>
+	 * 	<jsm>assertBytes</jsm>(<jv>myStream</jv>)
+	 * 		.asHex().is(<js>"666F6F"</js>);
+	 * </p>
+	 *
+	 * <p>
+	 * See {@doc jm.FluentAssertions Fluent Assertions} for general assertion usage and {@link ByteArrayAssertion} for supported operations on this type.
+	 *
+	 * @param value
+	 * 	The object being tested.
+	 * 	<br>Can be <jk>null</jk>.
+	 * 	<br>Stream is automatically closed.
+	 * @return
+	 * 	A new assertion object.
+	 * 	<br>Never <jk>null</jk>.
+	 * @throws IOException If thrown while reading contents from stream.
+	 */
+	public static final ByteArrayAssertion assertBytes(InputStream value) throws IOException {
+		return assertBytes(value == null ? null : readBytes(value));
+	}
+
+	/**
 	 * Performs an assertion on a char array.
 	 *
 	 * <h5 class='section'>Example:</h5>
@@ -558,6 +587,33 @@ public class Assertions {
 	}
 
 	/**
+	 * Performs an assertion on a stream of POJOs.
+	 *
+	 * <h5 class='section'>Example:</h5>
+	 * <p class='bcode w800'>
+	 * 	<jk>import static</jk> org.apache.juneau.assertions.Assertions.*;
+	 *
+	 * 	<jc>// Assert that the first entry in a list is "{foo:'bar'}" when serialized to simplified JSON.</jc>
+	 * 	<jsm>assertList</jsm>(<jv>myStream</jv>)
+	 * 		.item(0)
+	 * 			.asJson().is(<js>"{foo:'bar'}"</js>);
+	 * </p>
+	 *
+	 * <p>
+	 * See {@doc jm.FluentAssertions Fluent Assertions} for general assertion usage and {@link ListAssertion} for supported operations on this type.
+	 *
+	 * @param value
+	 * 	The object being tested.
+	 * 	<br>Can be <jk>null</jk>.
+	 * @return
+	 * 	A new assertion object.
+	 * 	<br>Never <jk>null</jk>.
+	 */
+	public static final <E> ListAssertion<E> assertList(Stream<E> value) {
+		return ListAssertion.create(value);
+	}
+
+	/**
 	 * Performs an assertion on a Long.
 	 *
 	 * <h5 class='section'>Example:</h5>
@@ -751,34 +807,6 @@ public class Assertions {
 	}
 
 	/**
-	 * Performs an assertion on the contents of an input stream.
-	 *
-	 * <h5 class='section'>Example:</h5>
-	 * <p class='bcode w800'>
-	 * 	<jk>import static</jk> org.apache.juneau.assertions.Assertions.*;
-	 *
-	 * 	<jc>// Asserts that the stream contains the string "foo".</jc>
-	 * 	<jsm>assertStream</jsm>(<jv>myStream</jv>)
-	 * 		.asHex().is(<js>"666F6F"</js>);
-	 * </p>
-	 *
-	 * <p>
-	 * See {@doc jm.FluentAssertions Fluent Assertions} for general assertion usage and {@link ByteArrayAssertion} for supported operations on this type.
-	 *
-	 * @param value
-	 * 	The object being tested.
-	 * 	<br>Can be <jk>null</jk>.
-	 * 	<br>Stream is automatically closed.
-	 * @return
-	 * 	A new assertion object.
-	 * 	<br>Never <jk>null</jk>.
-	 * @throws IOException If thrown while reading contents from stream.
-	 */
-	public static final ByteArrayAssertion assertStream(InputStream value) throws IOException {
-		return assertBytes(value == null ? null : readBytes(value));
-	}
-
-	/**
 	 * Performs an assertion on a String.
 	 *
 	 * <h5 class='section'>Example:</h5>
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/BeanAssertion.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/BeanAssertion.java
index 30a4b47..3cd7ded 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/BeanAssertion.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/BeanAssertion.java
@@ -85,7 +85,7 @@ import org.apache.juneau.serializer.*;
 public class BeanAssertion<T> extends FluentBeanAssertion<T,BeanAssertion<T>> {
 
 	//-----------------------------------------------------------------------------------------------------------------
-	// Constructors
+	// Static
 	//-----------------------------------------------------------------------------------------------------------------
 
 	/**
@@ -100,6 +100,10 @@ public class BeanAssertion<T> extends FluentBeanAssertion<T,BeanAssertion<T>> {
 		return new BeanAssertion<>(value);
 	}
 
+	//-----------------------------------------------------------------------------------------------------------------
+	// Instance
+	//-----------------------------------------------------------------------------------------------------------------
+
 	/**
 	 * Constructor.
 	 *
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/BeanListAssertion.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/BeanListAssertion.java
index 86f494a..3425913 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/BeanListAssertion.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/BeanListAssertion.java
@@ -65,6 +65,10 @@ import org.apache.juneau.serializer.*;
  * 	<ul>
  * 		<li class='jm'>{@link FluentBeanListAssertion#extract(String...)}
  * 		<li class='jm'>{@link FluentBeanListAssertion#property(String)}
+ * 		<li class='jm'>{@link FluentListAssertion#asStrings()}
+ * 		<li class='jm'>{@link FluentListAssertion#asStrings(Function)}
+ * 		<li class='jm'>{@link FluentListAssertion#asCdl()}
+ * 		<li class='jm'>{@link FluentListAssertion#asCdl(Function)}
  * 		<li class='jm'>{@link FluentListAssertion#item(int)}
  * 		<li class='jm'>{@link FluentListAssertion#sorted()}
  * 		<li class='jm'>{@link FluentListAssertion#sorted(Comparator)}
@@ -99,7 +103,7 @@ import org.apache.juneau.serializer.*;
 public class BeanListAssertion<E> extends FluentBeanListAssertion<E,BeanListAssertion<E>> {
 
 	//-----------------------------------------------------------------------------------------------------------------
-	// Constructors
+	// Static
 	//-----------------------------------------------------------------------------------------------------------------
 
 	/**
@@ -114,6 +118,10 @@ public class BeanListAssertion<E> extends FluentBeanListAssertion<E,BeanListAsse
 		return new BeanListAssertion<>(value);
 	}
 
+	//-----------------------------------------------------------------------------------------------------------------
+	// Instance
+	//-----------------------------------------------------------------------------------------------------------------
+
 	/**
 	 * Constructor.
 	 *
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/BooleanAssertion.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/BooleanAssertion.java
index b0fd5eb..1d3081b 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/BooleanAssertion.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/BooleanAssertion.java
@@ -79,7 +79,7 @@ import org.apache.juneau.serializer.*;
 public class BooleanAssertion extends FluentBooleanAssertion<BooleanAssertion> {
 
 	//-----------------------------------------------------------------------------------------------------------------
-	// Constructors
+	// Static
 	//-----------------------------------------------------------------------------------------------------------------
 
 	/**
@@ -94,6 +94,10 @@ public class BooleanAssertion extends FluentBooleanAssertion<BooleanAssertion> {
 		return new BooleanAssertion(value);
 	}
 
+	//-----------------------------------------------------------------------------------------------------------------
+	// Instance
+	//-----------------------------------------------------------------------------------------------------------------
+
 	/**
 	 * Constructor.
 	 *
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/ByteArrayAssertion.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/ByteArrayAssertion.java
index a677732..34b1cb8 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/ByteArrayAssertion.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/ByteArrayAssertion.java
@@ -95,7 +95,7 @@ import org.apache.juneau.serializer.*;
 public class ByteArrayAssertion extends FluentByteArrayAssertion<ByteArrayAssertion> {
 
 	//-----------------------------------------------------------------------------------------------------------------
-	// Constructors
+	// Static
 	//-----------------------------------------------------------------------------------------------------------------
 
 	/**
@@ -110,6 +110,10 @@ public class ByteArrayAssertion extends FluentByteArrayAssertion<ByteArrayAssert
 		return new ByteArrayAssertion(value);
 	}
 
+	//-----------------------------------------------------------------------------------------------------------------
+	// Instance
+	//-----------------------------------------------------------------------------------------------------------------
+
 	/**
 	 * Constructor.
 	 *
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/CollectionAssertion.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/CollectionAssertion.java
index c68b909..7d0a701 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/CollectionAssertion.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/CollectionAssertion.java
@@ -90,7 +90,7 @@ import org.apache.juneau.serializer.*;
 public class CollectionAssertion<E> extends FluentCollectionAssertion<E,CollectionAssertion<E>> {
 
 	//-----------------------------------------------------------------------------------------------------------------
-	// Constructors
+	// Static
 	//-----------------------------------------------------------------------------------------------------------------
 
 	/**
@@ -105,6 +105,10 @@ public class CollectionAssertion<E> extends FluentCollectionAssertion<E,Collecti
 		return new CollectionAssertion<>(value);
 	}
 
+	//-----------------------------------------------------------------------------------------------------------------
+	// Instance
+	//-----------------------------------------------------------------------------------------------------------------
+
 	/**
 	 * Constructor.
 	 *
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/ComparableAssertion.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/ComparableAssertion.java
index 83dcad5..b08f7a3 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/ComparableAssertion.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/ComparableAssertion.java
@@ -79,7 +79,7 @@ import org.apache.juneau.serializer.*;
 public class ComparableAssertion<T extends Comparable<T>> extends FluentComparableAssertion<T,ComparableAssertion<T>> {
 
 	//-----------------------------------------------------------------------------------------------------------------
-	// Constructors
+	// Static
 	//-----------------------------------------------------------------------------------------------------------------
 
 	/**
@@ -94,6 +94,10 @@ public class ComparableAssertion<T extends Comparable<T>> extends FluentComparab
 		return new ComparableAssertion<>(value);
 	}
 
+	//-----------------------------------------------------------------------------------------------------------------
+	// Instance
+	//-----------------------------------------------------------------------------------------------------------------
+
 	/**
 	 * Constructor.
 	 *
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/DateAssertion.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/DateAssertion.java
index df853b4..141d54d 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/DateAssertion.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/DateAssertion.java
@@ -93,7 +93,7 @@ import org.apache.juneau.serializer.*;
 public class DateAssertion extends FluentDateAssertion<DateAssertion> {
 
 	//-----------------------------------------------------------------------------------------------------------------
-	// Constructors
+	// Static
 	//-----------------------------------------------------------------------------------------------------------------
 
 	/**
@@ -108,6 +108,10 @@ public class DateAssertion extends FluentDateAssertion<DateAssertion> {
 		return new DateAssertion(value);
 	}
 
+	//-----------------------------------------------------------------------------------------------------------------
+	// Instance
+	//-----------------------------------------------------------------------------------------------------------------
+
 	/**
 	 * Constructor.
 	 *
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentAnyAssertion.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentAnyAssertion.java
index 91dca56..51d6cdb 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentAnyAssertion.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentAnyAssertion.java
@@ -125,12 +125,16 @@ import org.apache.juneau.serializer.*;
 @FluentSetters(returns="FluentAnyAssertion<T,R>")
 public class FluentAnyAssertion<T,R> extends FluentObjectAssertion<T,R> {
 
+	//-----------------------------------------------------------------------------------------------------------------
+	// Static
+	//-----------------------------------------------------------------------------------------------------------------
+
 	private static final Messages MESSAGES = Messages.of(FluentAnyAssertion.class, "Messages");
 	private static final String
 		MSG_objectWasNotType = MESSAGES.getString("objectWasNotType");
 
 	//-----------------------------------------------------------------------------------------------------------------
-	// Constructors
+	// Instance
 	//-----------------------------------------------------------------------------------------------------------------
 
 	/**
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentArrayAssertion.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentArrayAssertion.java
index 4da05e0..20ad794 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentArrayAssertion.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentArrayAssertion.java
@@ -64,6 +64,9 @@ import org.apache.juneau.serializer.*;
  * <h5 class='topic'>Transform Methods</h5>
  * 	<ul>
  * 		<li class='jm'>{@link FluentArrayAssertion#asStrings()}
+ * 		<li class='jm'>{@link FluentArrayAssertion#asStrings(Function)}
+ * 		<li class='jm'>{@link FluentArrayAssertion#asCdl()}
+ * 		<li class='jm'>{@link FluentArrayAssertion#asCdl(Function)}
  * 		<li class='jm'>{@link FluentArrayAssertion#asBeanList()}
  * 		<li class='jm'>{@link FluentArrayAssertion#item(int)}
  * 		<li class='jm'>{@link FluentArrayAssertion#sorted()}
@@ -97,6 +100,10 @@ import org.apache.juneau.serializer.*;
 @FluentSetters(returns="FluentArrayAssertion<E,R>")
 public class FluentArrayAssertion<E,R> extends FluentObjectAssertion<E[],R> {
 
+	//-----------------------------------------------------------------------------------------------------------------
+	// Static
+	//-----------------------------------------------------------------------------------------------------------------
+
 	private static final Messages MESSAGES = Messages.of(FluentArrayAssertion.class, "Messages");
 	private static final String
 		MSG_arrayWasNotEmpty = MESSAGES.getString("arrayWasNotEmpty"),
@@ -109,7 +116,7 @@ public class FluentArrayAssertion<E,R> extends FluentObjectAssertion<E[],R> {
 		MSG_arrayContainedNonMatchingValueAt = MESSAGES.getString("arrayContainedNonMatchingValueAt");
 
 	//-----------------------------------------------------------------------------------------------------------------
-	// Constructors
+	// Instance
 	//-----------------------------------------------------------------------------------------------------------------
 
 	/**
@@ -172,6 +179,37 @@ public class FluentArrayAssertion<E,R> extends FluentObjectAssertion<E[],R> {
 	}
 
 	/**
+	 * Runs the stringify function against all values in this list and returns it as a fluent string list assertion.
+	 *
+	 * @param function The function to apply to all values in this list.
+	 * @return A new fluent string list assertion.  Never <jk>null</jk>.
+	 */
+	public FluentStringListAssertion<R> asStrings(Function<E,String> function) {
+		List<String> l = valueIsNull() ? null : stream(value()).map(x -> function.apply(x)).collect(Collectors.toList());
+		return new FluentStringListAssertion<>(this, l, returns());
+	}
+
+	/**
+	 * Converts the entries in this list to a simple comma-delimited list and returns the value as a fluent string assertion.
+	 *
+	 * @return A fluent string assertion.  Never <jk>null</jk>.
+	 */
+	public FluentStringAssertion<R> asCdl() {
+		return new FluentStringAssertion<>(this, valueIsNull() ? null : StringUtils.join(value(), ','), returns());
+	}
+
+	/**
+	 * Converts the entries to strings using the specified stringify function, combines them into a simple comma-delimited list, and returns the value as a fluent string assertion.
+	 *
+	 * @param function The function to apply to all values in this list.
+	 * @return A fluent string assertion.  Never <jk>null</jk>.
+	 */
+	public FluentStringAssertion<R> asCdl(Function<E,String> function) {
+		List<String> l = valueIsNull() ? null : stream(value()).map(x -> function.apply(x)).collect(Collectors.toList());
+		return new FluentStringAssertion<>(this, join(l, ','), returns());
+	}
+
+	/**
 	 * Converts this assertion into a {@link FluentBeanListAssertion}.
 	 *
 	 * <h5 class='section'>Example:</h5>
@@ -260,7 +298,7 @@ public class FluentArrayAssertion<E,R> extends FluentObjectAssertion<E[],R> {
 	 * Asserts that at least one value in the array passes the specified test.
 	 *
 	 * @param test The predicate test.
-	 * @return The object to return after the test.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed or value was <jk>null</jk>.
 	 */
 	public R any(Predicate<E> test) throws AssertionError {
@@ -275,7 +313,7 @@ public class FluentArrayAssertion<E,R> extends FluentObjectAssertion<E[],R> {
 	 * Asserts that all values in the array passes the specified test.
 	 *
 	 * @param test The predicate test.
-	 * @return The object to return after the test.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed or value was <jk>null</jk>.
 	 */
 	public R all(Predicate<E> test) throws AssertionError {
@@ -289,7 +327,7 @@ public class FluentArrayAssertion<E,R> extends FluentObjectAssertion<E[],R> {
 	/**
 	 * Asserts that the collection exists and is empty.
 	 *
-	 * @return The object to return after the test.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R isEmpty() throws AssertionError {
@@ -301,7 +339,7 @@ public class FluentArrayAssertion<E,R> extends FluentObjectAssertion<E[],R> {
 	/**
 	 * Asserts that the collection exists and is not empty.
 	 *
-	 * @return The object to return after the test.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R isNotEmpty() throws AssertionError {
@@ -314,7 +352,7 @@ public class FluentArrayAssertion<E,R> extends FluentObjectAssertion<E[],R> {
 	 * Asserts that the collection exists and is the specified size.
 	 *
 	 * @param size The expected size.
-	 * @return The object to return after the test.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R isSize(int size) throws AssertionError {
@@ -327,7 +365,7 @@ public class FluentArrayAssertion<E,R> extends FluentObjectAssertion<E[],R> {
 	 * Asserts that the array contains the expected value.
 	 *
 	 * @param entry The value to check for.
-	 * @return The object to return after the test.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R contains(E entry) throws AssertionError {
@@ -341,7 +379,7 @@ public class FluentArrayAssertion<E,R> extends FluentObjectAssertion<E[],R> {
 	 * Asserts that the array does not contain the expected value.
 	 *
 	 * @param entry The value to check for.
-	 * @return The object to return after the test.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R doesNotContain(E entry) throws AssertionError {
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentAssertion.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentAssertion.java
index aa28078..41f09d9 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentAssertion.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentAssertion.java
@@ -79,12 +79,12 @@ import org.apache.juneau.internal.*;
 @FluentSetters(returns="FluentAssertion<R>")
 public abstract class FluentAssertion<R> extends Assertion {
 
-	private final R returns;
-
 	//-----------------------------------------------------------------------------------------------------------------
-	// Constructors
+	// Instance
 	//-----------------------------------------------------------------------------------------------------------------
 
+	private final R returns;
+
 	/**
 	 * Constructor.
 	 *
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentBeanAssertion.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentBeanAssertion.java
index 318755d..e186cc5 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentBeanAssertion.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentBeanAssertion.java
@@ -83,7 +83,7 @@ import org.apache.juneau.serializer.*;
 public class FluentBeanAssertion<T,R> extends FluentObjectAssertion<T,R> {
 
 	//-----------------------------------------------------------------------------------------------------------------
-	// Constructors
+	// Instance
 	//-----------------------------------------------------------------------------------------------------------------
 
 	/**
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentBeanListAssertion.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentBeanListAssertion.java
index 2eeb705..adcf72c 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentBeanListAssertion.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentBeanListAssertion.java
@@ -60,6 +60,10 @@ import org.apache.juneau.serializer.*;
  * 	<ul>
  * 		<li class='jm'>{@link FluentBeanListAssertion#extract(String...)}
  * 		<li class='jm'>{@link FluentBeanListAssertion#property(String)}
+ * 		<li class='jm'>{@link FluentListAssertion#asStrings()}
+ * 		<li class='jm'>{@link FluentListAssertion#asStrings(Function)}
+ * 		<li class='jm'>{@link FluentListAssertion#asCdl()}
+ * 		<li class='jm'>{@link FluentListAssertion#asCdl(Function)}
  * 		<li class='jm'>{@link FluentListAssertion#item(int)}
  * 		<li class='jm'>{@link FluentListAssertion#sorted()}
  * 		<li class='jm'>{@link FluentListAssertion#sorted(Comparator)}
@@ -95,7 +99,7 @@ import org.apache.juneau.serializer.*;
 public class FluentBeanListAssertion<E,R> extends FluentListAssertion<E,R> {
 
 	//-----------------------------------------------------------------------------------------------------------------
-	// Constructors
+	// Instance
 	//-----------------------------------------------------------------------------------------------------------------
 
 	/**
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentBooleanAssertion.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentBooleanAssertion.java
index dffffd9..6553aed 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentBooleanAssertion.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentBooleanAssertion.java
@@ -82,13 +82,17 @@ import org.apache.juneau.serializer.*;
 @FluentSetters(returns="FluentBooleanAssertion<R>")
 public class FluentBooleanAssertion<R> extends FluentComparableAssertion<Boolean,R> {
 
+	//-----------------------------------------------------------------------------------------------------------------
+	// Static
+	//-----------------------------------------------------------------------------------------------------------------
+
 	private static final Messages MESSAGES = Messages.of(FluentBooleanAssertion.class, "Messages");
 	private static final String
 		MSG_valueWasFalse = MESSAGES.getString("valueWasFalse"),
 		MSG_valueWasTrue = MESSAGES.getString("valueWasTrue");
 
 	//-----------------------------------------------------------------------------------------------------------------
-	// Constructors
+	// Instance
 	//-----------------------------------------------------------------------------------------------------------------
 
 	/**
@@ -134,7 +138,7 @@ public class FluentBooleanAssertion<R> extends FluentComparableAssertion<Boolean
 	/**
 	 * Asserts that the value is true.
 	 *
-	 * @return This object.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R isTrue() throws AssertionError {
@@ -146,7 +150,7 @@ public class FluentBooleanAssertion<R> extends FluentComparableAssertion<Boolean
 	/**
 	 * Asserts that the value is false.
 	 *
-	 * @return This object.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R isFalse() throws AssertionError {
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentByteArrayAssertion.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentByteArrayAssertion.java
index adb4f90..0198b6b 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentByteArrayAssertion.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentByteArrayAssertion.java
@@ -93,7 +93,7 @@ import org.apache.juneau.serializer.*;
 public class FluentByteArrayAssertion<R> extends FluentPrimitiveArrayAssertion<Byte,byte[],R> {
 
 	//-----------------------------------------------------------------------------------------------------------------
-	// Constructors
+	// Instance
 	//-----------------------------------------------------------------------------------------------------------------
 
 	/**
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentCollectionAssertion.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentCollectionAssertion.java
index b82b715..57e6139 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentCollectionAssertion.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentCollectionAssertion.java
@@ -89,6 +89,10 @@ import org.apache.juneau.serializer.*;
 @FluentSetters(returns="FluentCollectionAssertion<E,R>")
 public class FluentCollectionAssertion<E,R> extends FluentObjectAssertion<Collection<E>,R> {
 
+	//-----------------------------------------------------------------------------------------------------------------
+	// Static
+	//-----------------------------------------------------------------------------------------------------------------
+
 	private static final Messages MESSAGES = Messages.of(FluentCollectionAssertion.class, "Messages");
 	private static final String
 		MSG_collectionWasNotEmpty = MESSAGES.getString("collectionWasNotEmpty"),
@@ -99,7 +103,7 @@ public class FluentCollectionAssertion<E,R> extends FluentObjectAssertion<Collec
 		MSG_collectionDidNotHaveExpectedSize = MESSAGES.getString("collectionDidNotHaveExpectedSize");
 
 	//-----------------------------------------------------------------------------------------------------------------
-	// Constructors
+	// Instance
 	//-----------------------------------------------------------------------------------------------------------------
 
 	/**
@@ -177,7 +181,7 @@ public class FluentCollectionAssertion<E,R> extends FluentObjectAssertion<Collec
 	/**
 	 * Asserts that the collection exists and is empty.
 	 *
-	 * @return The object to return after the test.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed or value was <jk>null</jk>.
 	 */
 	public R isEmpty() throws AssertionError {
@@ -189,7 +193,7 @@ public class FluentCollectionAssertion<E,R> extends FluentObjectAssertion<Collec
 	/**
 	 * Asserts that the collection exists and is not empty.
 	 *
-	 * @return The object to return after the test.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed or value was <jk>null</jk>.
 	 */
 	public R isNotEmpty() throws AssertionError {
@@ -202,7 +206,7 @@ public class FluentCollectionAssertion<E,R> extends FluentObjectAssertion<Collec
 	 * Asserts that the collection contains the expected value.
 	 *
 	 * @param entry The value to check for.
-	 * @return The object to return after the test.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed or value was <jk>null</jk>.
 	 */
 	public R contains(E entry) throws AssertionError {
@@ -216,7 +220,7 @@ public class FluentCollectionAssertion<E,R> extends FluentObjectAssertion<Collec
 	 * Asserts that the collection contains the expected value.
 	 *
 	 * @param entry The value to check for.
-	 * @return The object to return after the test.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed or value was <jk>null</jk>.
 	 */
 	public R doesNotContain(E entry) throws AssertionError {
@@ -230,7 +234,7 @@ public class FluentCollectionAssertion<E,R> extends FluentObjectAssertion<Collec
 	 * Asserts that at least one value in the collection passes the specified test.
 	 *
 	 * @param test The predicate test.
-	 * @return The object to return after the test.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed or value was <jk>null</jk>.
 	 */
 	public R any(Predicate<E> test) throws AssertionError {
@@ -246,7 +250,7 @@ public class FluentCollectionAssertion<E,R> extends FluentObjectAssertion<Collec
 	 * Asserts that all values in the collection pass the specified test.
 	 *
 	 * @param test The predicate test.
-	 * @return The object to return after the test.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed or value was <jk>null</jk>.
 	 */
 	public R all(Predicate<E> test) throws AssertionError {
@@ -262,7 +266,7 @@ public class FluentCollectionAssertion<E,R> extends FluentObjectAssertion<Collec
 	 * Asserts that the collection exists and is the specified size.
 	 *
 	 * @param size The expected size.
-	 * @return The object to return after the test.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed or value was <jk>null</jk>.
 	 */
 	public R isSize(int size) throws AssertionError {
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentComparableAssertion.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentComparableAssertion.java
index ca47ace..7d55eb9 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentComparableAssertion.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentComparableAssertion.java
@@ -83,6 +83,10 @@ import org.apache.juneau.serializer.*;
 @SuppressWarnings("rawtypes")
 public class FluentComparableAssertion<T extends Comparable,R> extends FluentObjectAssertion<T,R> {
 
+	//-----------------------------------------------------------------------------------------------------------------
+	// Static
+	//-----------------------------------------------------------------------------------------------------------------
+
 	private static final Messages MESSAGES = Messages.of(FluentComparableAssertion.class, "Messages");
 	private static final String
 		MSG_valueWasNotGreaterThanExpected = MESSAGES.getString("valueWasNotGreaterThanExpected"),
@@ -91,7 +95,7 @@ public class FluentComparableAssertion<T extends Comparable,R> extends FluentObj
 		MSG_valueWasNotLessOrEqualsToExpected = MESSAGES.getString("valueWasNotLessOrEqualsToExpected");
 
 	//-----------------------------------------------------------------------------------------------------------------
-	// Constructors
+	// Instance
 	//-----------------------------------------------------------------------------------------------------------------
 
 	/**
@@ -147,7 +151,7 @@ public class FluentComparableAssertion<T extends Comparable,R> extends FluentObj
 	 * Asserts that the value is greater than the specified value.
 	 *
 	 * @param value The values to check against.
-	 * @return This object.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R isGt(Comparable value) throws AssertionError {
@@ -161,7 +165,7 @@ public class FluentComparableAssertion<T extends Comparable,R> extends FluentObj
 	 * Asserts that the value is greater than or equal to the specified value.
 	 *
 	 * @param value The values to check against.
-	 * @return This object.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R isGte(Comparable value) throws AssertionError {
@@ -175,7 +179,7 @@ public class FluentComparableAssertion<T extends Comparable,R> extends FluentObj
 	 * Asserts that the value is less than the specified value.
 	 *
 	 * @param value The values to check against.
-	 * @return This object.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R isLt(Comparable value) throws AssertionError {
@@ -189,7 +193,7 @@ public class FluentComparableAssertion<T extends Comparable,R> extends FluentObj
 	 * Asserts that the value is less than or equals to the specified value.
 	 *
 	 * @param value The values to check against.
-	 * @return This object.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R isLte(Comparable value) throws AssertionError {
@@ -204,7 +208,7 @@ public class FluentComparableAssertion<T extends Comparable,R> extends FluentObj
 	 *
 	 * @param lower The lower value to check against.
 	 * @param upper The upper value to check against.
-	 * @return This object.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R isBetween(Comparable lower, Comparable upper) throws AssertionError {
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentDateAssertion.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentDateAssertion.java
index 420334f..b1f218e 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentDateAssertion.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentDateAssertion.java
@@ -101,6 +101,10 @@ import org.apache.juneau.serializer.*;
 @FluentSetters(returns="FluentDateAssertion<R>")
 public class FluentDateAssertion<R> extends FluentComparableAssertion<Date,R> {
 
+	//-----------------------------------------------------------------------------------------------------------------
+	// Static
+	//-----------------------------------------------------------------------------------------------------------------
+
 	private static final Messages MESSAGES = Messages.of(FluentDateAssertion.class, "Messages");
 	private static final String
 		MSG_unexpectedValue = MESSAGES.getString("unexpectedValue"),
@@ -108,7 +112,7 @@ public class FluentDateAssertion<R> extends FluentComparableAssertion<Date,R> {
 		MSG_valueWasNotBeforeExpected = MESSAGES.getString("valueWasNotBeforeExpected");
 
 	//-----------------------------------------------------------------------------------------------------------------
-	// Constructors
+	// Instance
 	//-----------------------------------------------------------------------------------------------------------------
 
 	/**
@@ -186,7 +190,7 @@ public class FluentDateAssertion<R> extends FluentComparableAssertion<Date,R> {
 	 *
 	 * @param value The value to check against.
 	 * @param precision The precision (e.g. {@link ChronoUnit#SECONDS}.
-	 * @return This object.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R is(Date value, ChronoUnit precision) throws AssertionError {
@@ -199,7 +203,7 @@ public class FluentDateAssertion<R> extends FluentComparableAssertion<Date,R> {
 	 * Asserts that the value is after the specified value.
 	 *
 	 * @param value The values to check against.
-	 * @return This object.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R isAfter(Date value) throws AssertionError {
@@ -212,7 +216,7 @@ public class FluentDateAssertion<R> extends FluentComparableAssertion<Date,R> {
 	/**
 	 * Asserts that the value is after the current date.
 	 *
-	 * @return This object.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R isAfterNow() throws AssertionError {
@@ -223,7 +227,7 @@ public class FluentDateAssertion<R> extends FluentComparableAssertion<Date,R> {
 	 * Asserts that the value is before the specified value.
 	 *
 	 * @param value The values to check against.
-	 * @return This object.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R isBefore(Date value) throws AssertionError {
@@ -236,7 +240,7 @@ public class FluentDateAssertion<R> extends FluentComparableAssertion<Date,R> {
 	/**
 	 * Asserts that the value is before the current date.
 	 *
-	 * @return This object.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R isBeforeNow() throws AssertionError {
@@ -248,7 +252,7 @@ public class FluentDateAssertion<R> extends FluentComparableAssertion<Date,R> {
 	 *
 	 * @param lower The lower value to check against.
 	 * @param upper The upper value to check against.
-	 * @return This object.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R isBetween(Date lower, Date upper) throws AssertionError {
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentIntegerAssertion.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentIntegerAssertion.java
index e97e9d7..ee6eab1 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentIntegerAssertion.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentIntegerAssertion.java
@@ -89,7 +89,7 @@ import org.apache.juneau.serializer.*;
 public class FluentIntegerAssertion<R> extends FluentComparableAssertion<Integer,R> {
 
 	//-----------------------------------------------------------------------------------------------------------------
-	// Constructors
+	// Instance
 	//-----------------------------------------------------------------------------------------------------------------
 
 	/**
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentListAssertion.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentListAssertion.java
index 1b13267..90d433d 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentListAssertion.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentListAssertion.java
@@ -13,6 +13,8 @@
 package org.apache.juneau.assertions;
 
 import static java.util.Arrays.*;
+import static java.util.stream.Collectors.*;
+import static org.apache.juneau.internal.StringUtils.*;
 
 import java.io.*;
 import java.util.*;
@@ -59,6 +61,10 @@ import org.apache.juneau.serializer.*;
  *
  * <h5 class='topic'>Transform Methods</h5>
  * 	<ul>
+ * 		<li class='jm'>{@link FluentListAssertion#asStrings()}
+ * 		<li class='jm'>{@link FluentListAssertion#asStrings(Function)}
+ * 		<li class='jm'>{@link FluentListAssertion#asCdl()}
+ * 		<li class='jm'>{@link FluentListAssertion#asCdl(Function)}
  * 		<li class='jm'>{@link FluentListAssertion#item(int)}
  * 		<li class='jm'>{@link FluentListAssertion#sorted()}
  * 		<li class='jm'>{@link FluentListAssertion#sorted(Comparator)}
@@ -93,12 +99,16 @@ import org.apache.juneau.serializer.*;
 @FluentSetters(returns="FluentListAssertion<E,R>")
 public class FluentListAssertion<E,R> extends FluentCollectionAssertion<E,R> {
 
+	//-----------------------------------------------------------------------------------------------------------------
+	// Static
+	//-----------------------------------------------------------------------------------------------------------------
+
 	private static final Messages MESSAGES = Messages.of(FluentListAssertion.class, "Messages");
 	private static final String
 		MSG_listDidNotContainExpectedValueAt = MESSAGES.getString("listDidNotContainExpectedValueAt");
 
 	//-----------------------------------------------------------------------------------------------------------------
-	// Constructors
+	// Instance
 	//-----------------------------------------------------------------------------------------------------------------
 
 	/**
@@ -233,6 +243,37 @@ public class FluentListAssertion<E,R> extends FluentCollectionAssertion<E,R> {
 		return new FluentListAssertion<>(this, valueIsNull() ? null : value().subList(start, end), returns());
 	}
 
+	/**
+	 * Runs the stringify function against all values in this list and returns it as a fluent string list assertion.
+	 *
+	 * @param function The function to apply to all values in this list.
+	 * @return A new fluent string list assertion.  Never <jk>null</jk>.
+	 */
+	public FluentStringListAssertion<R> asStrings(Function<E,String> function) {
+		List<String> l = valueIsNull() ? null : value().stream().map(x -> function.apply(x)).collect(toList());
+		return new FluentStringListAssertion<>(this, l, returns());
+	}
+
+	/**
+	 * Converts the entries in this list to a simple comma-delimited list and returns the value as a fluent string assertion.
+	 *
+	 * @return A fluent string assertion.  Never <jk>null</jk>.
+	 */
+	public FluentStringAssertion<R> asCdl() {
+		return new FluentStringAssertion<>(this, valueIsNull() ? null : StringUtils.join(value(), ','), returns());
+	}
+
+	/**
+	 * Converts the entries to strings using the specified stringify function, combines them into a simple comma-delimited list, and returns the value as a fluent string assertion.
+	 *
+	 * @param function The function to apply to all values in this list.
+	 * @return A fluent string assertion.  Never <jk>null</jk>.
+	 */
+	public FluentStringAssertion<R> asCdl(Function<E,String> function) {
+		List<String> l = valueIsNull() ? null : value().stream().map(x -> function.apply(x)).collect(toList());
+		return new FluentStringAssertion<>(this, join(l, ','), returns());
+	}
+
 	//-----------------------------------------------------------------------------------------------------------------
 	// Test methods
 	//-----------------------------------------------------------------------------------------------------------------
@@ -241,7 +282,7 @@ public class FluentListAssertion<E,R> extends FluentCollectionAssertion<E,R> {
 	 * Asserts that the contents of this list contain the specified values.
 	 *
 	 * @param entries The expected entries in this list.
-	 * @return This object.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	@SuppressWarnings("unchecked")
@@ -256,7 +297,7 @@ public class FluentListAssertion<E,R> extends FluentCollectionAssertion<E,R> {
 	 * @param tests
 	 * 	The tests to run.
 	 * <jk>null</jk> predicates are ignored.
-	 * @return This object.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	@SafeVarargs
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentLongAssertion.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentLongAssertion.java
index d811801..395d872 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentLongAssertion.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentLongAssertion.java
@@ -90,7 +90,7 @@ import org.apache.juneau.serializer.*;
 public class FluentLongAssertion<R> extends FluentComparableAssertion<Long,R> {
 
 	//-----------------------------------------------------------------------------------------------------------------
-	// Constructors
+	// Instance
 	//-----------------------------------------------------------------------------------------------------------------
 
 	/**
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentMapAssertion.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentMapAssertion.java
index d491cb1..8404536 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentMapAssertion.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentMapAssertion.java
@@ -91,6 +91,10 @@ import org.apache.juneau.serializer.*;
 @FluentSetters(returns="FluentMapAssertion<K,V,R>")
 public class FluentMapAssertion<K,V,R> extends FluentObjectAssertion<Map<K,V>,R>  {
 
+	//-----------------------------------------------------------------------------------------------------------------
+	// Static
+	//-----------------------------------------------------------------------------------------------------------------
+
 	private static final Messages MESSAGES = Messages.of(FluentMapAssertion.class, "Messages");
 	private static final String
 		MSG_mapWasNotEmpty = MESSAGES.getString("mapWasNotEmpty"),
@@ -100,7 +104,7 @@ public class FluentMapAssertion<K,V,R> extends FluentObjectAssertion<Map<K,V>,R>
 		MSG_mapDidNotHaveTheExpectedSize = MESSAGES.getString("mapDidNotHaveTheExpectedSize");
 
 	//-----------------------------------------------------------------------------------------------------------------
-	// Constructors
+	// Instance
 	//-----------------------------------------------------------------------------------------------------------------
 
 	/**
@@ -212,7 +216,7 @@ public class FluentMapAssertion<K,V,R> extends FluentObjectAssertion<Map<K,V>,R>
 	/**
 	 * Asserts that the map exists and is empty.
 	 *
-	 * @return The object to return after the test.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed or value was <jk>null</jk>.
 	 */
 	public R isEmpty() throws AssertionError {
@@ -224,7 +228,7 @@ public class FluentMapAssertion<K,V,R> extends FluentObjectAssertion<Map<K,V>,R>
 	/**
 	 * Asserts that the map exists and is not empty.
 	 *
-	 * @return The object to return after the test.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed or value was <jk>null</jk>.
 	 */
 	public R isNotEmpty() throws AssertionError {
@@ -237,7 +241,7 @@ public class FluentMapAssertion<K,V,R> extends FluentObjectAssertion<Map<K,V>,R>
 	 * Asserts that the map contains the expected key.
 	 *
 	 * @param name The key name to check for.
-	 * @return The object to return after the test.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed or value was <jk>null</jk>.
 	 */
 	public R containsKey(String name) throws AssertionError {
@@ -250,7 +254,7 @@ public class FluentMapAssertion<K,V,R> extends FluentObjectAssertion<Map<K,V>,R>
 	 * Asserts that the map contains the expected key.
 	 *
 	 * @param name The key name to check for.
-	 * @return The object to return after the test.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed or value was <jk>null</jk>.
 	 */
 	public R doesNotContainKey(String name) throws AssertionError {
@@ -263,7 +267,7 @@ public class FluentMapAssertion<K,V,R> extends FluentObjectAssertion<Map<K,V>,R>
 	 * Asserts that the map exists and is the specified size.
 	 *
 	 * @param size The expected size.
-	 * @return The object to return after the test.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed or value was <jk>null</jk>.
 	 */
 	public R isSize(int size) throws AssertionError {
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentObjectAssertion.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentObjectAssertion.java
index 7664325..8c8b433 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentObjectAssertion.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentObjectAssertion.java
@@ -82,6 +82,10 @@ import org.apache.juneau.serializer.*;
 @FluentSetters(returns="FluentObjectAssertion<T,R>")
 public class FluentObjectAssertion<T,R> extends FluentAssertion<R> {
 
+	//-----------------------------------------------------------------------------------------------------------------
+	// Static
+	//-----------------------------------------------------------------------------------------------------------------
+
 	private static final Messages MESSAGES = Messages.of(FluentObjectAssertion.class, "Messages");
 	private static final String
 		MSG_unexpectedType = MESSAGES.getString("unexpectedType"),
@@ -106,12 +110,12 @@ public class FluentObjectAssertion<T,R> extends FluentAssertion<R> {
 		.sortMaps()
 		.build();
 
-	private final T value;
-
 	//-----------------------------------------------------------------------------------------------------------------
-	// Constructors
+	// Instance
 	//-----------------------------------------------------------------------------------------------------------------
 
+	private final T value;
+
 	/**
 	 * Constructor.
 	 *
@@ -273,7 +277,7 @@ public class FluentObjectAssertion<T,R> extends FluentAssertion<R> {
 	 * <p>
 	 * Equivalent to {@link #isNotNull()}.
 	 *
-	 * @return This object.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R exists() throws AssertionError {
@@ -286,7 +290,7 @@ public class FluentObjectAssertion<T,R> extends FluentAssertion<R> {
 	 * <p>
 	 * Equivalent to {@link #isNotNull()}.
 	 *
-	 * @return This object.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R isNull() throws AssertionError {
@@ -301,7 +305,7 @@ public class FluentObjectAssertion<T,R> extends FluentAssertion<R> {
 	 * <p>
 	 * Equivalent to {@link #isNotNull()}.
 	 *
-	 * @return This object.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R isNotNull() throws AssertionError {
@@ -314,7 +318,7 @@ public class FluentObjectAssertion<T,R> extends FluentAssertion<R> {
 	 * Asserts that the value equals the specified value.
 	 *
 	 * @param value The value to check against.
-	 * @return This object.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R is(T value) throws AssertionError {
@@ -329,7 +333,7 @@ public class FluentObjectAssertion<T,R> extends FluentAssertion<R> {
 	 * Asserts that the value converted to a string equals the specified value.
 	 *
 	 * @param value The value to check against.
-	 * @return This object.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R isString(String value) {
@@ -340,7 +344,7 @@ public class FluentObjectAssertion<T,R> extends FluentAssertion<R> {
 	 * Asserts that the value does not equal the specified value.
 	 *
 	 * @param value The value to check against.
-	 * @return This object.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R isNot(T value) throws AssertionError {
@@ -353,7 +357,7 @@ public class FluentObjectAssertion<T,R> extends FluentAssertion<R> {
 	 * Asserts that the value is one of the specified values.
 	 *
 	 * @param values The values to check against.
-	 * @return This object.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	@SuppressWarnings("unchecked")
@@ -368,7 +372,7 @@ public class FluentObjectAssertion<T,R> extends FluentAssertion<R> {
 	 * Asserts that the value is not one of the specified values.
 	 *
 	 * @param values The values to check against.
-	 * @return This object.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	@SuppressWarnings("unchecked")
@@ -383,7 +387,7 @@ public class FluentObjectAssertion<T,R> extends FluentAssertion<R> {
 	 * Asserts that the specified object is the same object as this object.
 	 *
 	 * @param value The value to check against.
-	 * @return This object.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R isSame(T value) throws AssertionError {
@@ -396,7 +400,7 @@ public class FluentObjectAssertion<T,R> extends FluentAssertion<R> {
 	 * Verifies that two objects are equivalent after converting them both to JSON.
 	 *
 	 * @param o The object to compare against.
-	 * @return This object.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R isSameJsonAs(Object o) throws AssertionError {
@@ -410,7 +414,7 @@ public class FluentObjectAssertion<T,R> extends FluentAssertion<R> {
 	 * Properties, maps, and collections are all sorted on both objects before comparison.
 	 *
 	 * @param o The object to compare against.
-	 * @return This object.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R isSameSortedJsonAs(Object o) {
@@ -422,7 +426,7 @@ public class FluentObjectAssertion<T,R> extends FluentAssertion<R> {
 	 *
 	 * @param o The object to compare against.
 	 * @param serializer The serializer to use to serialize this object.
-	 * @return This object.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R isSameSerializedAs(Object o, WriterSerializer serializer) {
@@ -443,7 +447,7 @@ public class FluentObjectAssertion<T,R> extends FluentAssertion<R> {
 	 * </p>
 	 *
 	 * @param parent The value to check against.
-	 * @return This object.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R isType(Class<?> parent) throws AssertionError {
@@ -463,7 +467,7 @@ public class FluentObjectAssertion<T,R> extends FluentAssertion<R> {
 	 * </p>
 	 *
 	 * @param type The value to check against.
-	 * @return This object.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R isExactType(Class<?> type) throws AssertionError {
@@ -477,7 +481,7 @@ public class FluentObjectAssertion<T,R> extends FluentAssertion<R> {
 	 * Asserts that the value passes the specified predicate test.
 	 *
 	 * @param test The predicate to use to test the value.
-	 * @return This object.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R is(Predicate<T> test) throws AssertionError {
@@ -496,7 +500,7 @@ public class FluentObjectAssertion<T,R> extends FluentAssertion<R> {
 	 * </p>
 	 *
 	 * @param value The expected string value.
-	 * @return This object.
+	 * @return The fluent return object.
 	 */
 	public R isJson(String value) {
 		return asJson().is(value);
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentPrimitiveArrayAssertion.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentPrimitiveArrayAssertion.java
index 619b0e9..ef9a0d1 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentPrimitiveArrayAssertion.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentPrimitiveArrayAssertion.java
@@ -94,6 +94,10 @@ import org.apache.juneau.serializer.*;
 @FluentSetters(returns="FluentPrimitiveArrayAssertion<E,T,R>")
 public class FluentPrimitiveArrayAssertion<E,T,R> extends FluentObjectAssertion<T,R> {
 
+	//-----------------------------------------------------------------------------------------------------------------
+	// Static
+	//-----------------------------------------------------------------------------------------------------------------
+
 	private static final Map<Class<?>,Function<Object,String>> STRINGIFIERS = new HashMap<>();
 	static {
 		STRINGIFIERS.put(boolean.class, (x) -> Arrays.toString((boolean[])x));
@@ -119,7 +123,7 @@ public class FluentPrimitiveArrayAssertion<E,T,R> extends FluentObjectAssertion<
 		MSG_arrayContainedNonMatchingValueAt = MESSAGES.getString("arrayContainedNonMatchingValueAt");
 
 	//-----------------------------------------------------------------------------------------------------------------
-	// Constructors
+	// Instance
 	//-----------------------------------------------------------------------------------------------------------------
 
 	/**
@@ -245,7 +249,7 @@ public class FluentPrimitiveArrayAssertion<E,T,R> extends FluentObjectAssertion<
 	 * Asserts that at least one value in the array passes the specified test.
 	 *
 	 * @param test The predicate test.
-	 * @return The object to return after the test.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed or value was <jk>null</jk>.
 	 */
 	public R any(Predicate<E> test) throws AssertionError {
@@ -260,7 +264,7 @@ public class FluentPrimitiveArrayAssertion<E,T,R> extends FluentObjectAssertion<
 	 * Asserts that all values in the array pass the specified test.
 	 *
 	 * @param test The predicate test.
-	 * @return The object to return after the test.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed or value was <jk>null</jk>.
 	 */
 	public R all(Predicate<E> test) throws AssertionError {
@@ -274,7 +278,7 @@ public class FluentPrimitiveArrayAssertion<E,T,R> extends FluentObjectAssertion<
 	/**
 	 * Asserts that the collection exists and is empty.
 	 *
-	 * @return The object to return after the test.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R isEmpty() throws AssertionError {
@@ -286,7 +290,7 @@ public class FluentPrimitiveArrayAssertion<E,T,R> extends FluentObjectAssertion<
 	/**
 	 * Asserts that the collection exists and is not empty.
 	 *
-	 * @return The object to return after the test.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R isNotEmpty() throws AssertionError {
@@ -299,7 +303,7 @@ public class FluentPrimitiveArrayAssertion<E,T,R> extends FluentObjectAssertion<
 	 * Asserts that the collection exists and is the specified size.
 	 *
 	 * @param size The expected size.
-	 * @return The object to return after the test.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R isSize(int size) throws AssertionError {
@@ -312,7 +316,7 @@ public class FluentPrimitiveArrayAssertion<E,T,R> extends FluentObjectAssertion<
 	 * Asserts that the array contains the expected entry.
 	 *
 	 * @param entry The value to check for.
-	 * @return The object to return after the test.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R contains(E entry) throws AssertionError {
@@ -326,7 +330,7 @@ public class FluentPrimitiveArrayAssertion<E,T,R> extends FluentObjectAssertion<
 	 * Asserts that the array does not contain the expected value.
 	 *
 	 * @param entry The value to check for.
-	 * @return The object to return after the test.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R doesNotContain(E entry) throws AssertionError {
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentStringAssertion.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentStringAssertion.java
index 4cc8fa4..1f43880 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentStringAssertion.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentStringAssertion.java
@@ -50,6 +50,7 @@ import org.apache.juneau.serializer.*;
  * 		<li class='jm'>{@link FluentStringAssertion#doesNotContain(String...)}
  * 		<li class='jm'>{@link FluentStringAssertion#isEmpty()}
  * 		<li class='jm'>{@link FluentStringAssertion#isNotEmpty()}
+ * 		<li class='jm'>{@link FluentStringAssertion#isString(Object)}
  * 		<li class='jm'>{@link FluentStringAssertion#matches(String)}
  * 		<li class='jm'>{@link FluentStringAssertion#regex(String)}
  * 		<li class='jm'>{@link FluentStringAssertion#regex(String,int)}
@@ -114,6 +115,10 @@ import org.apache.juneau.serializer.*;
 @FluentSetters(returns="FluentStringAssertion<R>")
 public class FluentStringAssertion<R> extends FluentObjectAssertion<String,R> {
 
+	//-----------------------------------------------------------------------------------------------------------------
+	// Static
+	//-----------------------------------------------------------------------------------------------------------------
+
 	private static final Messages MESSAGES = Messages.of(FluentStringAssertion.class, "Messages");
 	private static final String
 		MSG_stringDifferedAtPosition = MESSAGES.getString("stringDifferedAtPosition"),
@@ -129,12 +134,12 @@ public class FluentStringAssertion<R> extends FluentObjectAssertion<String,R> {
 		MSG_stringDidNotStartWithExpected = MESSAGES.getString("stringDidNotStartWithExpected"),
 		MSG_stringDidNotEndWithExpected = MESSAGES.getString("stringDidNotEndWithExpected");
 
-	private boolean javaStrings;
-
 	//-----------------------------------------------------------------------------------------------------------------
-	// Constructors
+	// Instance
 	//-----------------------------------------------------------------------------------------------------------------
 
+	private boolean javaStrings;
+
 	/**
 	 * Constructor.
 	 *
@@ -312,7 +317,7 @@ public class FluentStringAssertion<R> extends FluentObjectAssertion<String,R> {
 	 * @param value
 	 * 	The value to check against.
 	 * 	<br>If multiple values are specified, they are concatenated with newlines.
-	 * @return This object.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	@Override
@@ -327,7 +332,7 @@ public class FluentStringAssertion<R> extends FluentObjectAssertion<String,R> {
 	 * Asserts that the text equals the specified value.
 	 *
 	 * @param value The value to check against.
-	 * @return This object.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	@Override
@@ -357,7 +362,7 @@ public class FluentStringAssertion<R> extends FluentObjectAssertion<String,R> {
 	 * @param lines
 	 * 	The value to check against.
 	 * 	<br>If multiple values are specified, they are concatenated with newlines.
-	 * @return This object.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R isLines(String...lines) throws AssertionError {
@@ -388,7 +393,7 @@ public class FluentStringAssertion<R> extends FluentObjectAssertion<String,R> {
 	 * @param lines
 	 * 	The value to check against.
 	 * 	<br>If multiple values are specified, they are concatenated with newlines.
-	 * @return This object.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R isSortedLines(String...lines) {
@@ -414,7 +419,7 @@ public class FluentStringAssertion<R> extends FluentObjectAssertion<String,R> {
 	 * Asserts that the text equals the specified value ignoring case.
 	 *
 	 * @param value The value to check against.
-	 * @return This object.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R isIc(String value) throws AssertionError {
@@ -428,7 +433,7 @@ public class FluentStringAssertion<R> extends FluentObjectAssertion<String,R> {
 	 * Asserts that the text does not equal the specified value ignoring case.
 	 *
 	 * @param value The value to check against.
-	 * @return This object.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R isNotIc(String value) throws AssertionError {
@@ -442,7 +447,7 @@ public class FluentStringAssertion<R> extends FluentObjectAssertion<String,R> {
 	 * Asserts that the text contains all of the specified substrings.
 	 *
 	 * @param values The values to check against.
-	 * @return This object.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R contains(String...values) throws AssertionError {
@@ -458,7 +463,7 @@ public class FluentStringAssertion<R> extends FluentObjectAssertion<String,R> {
 	 * Asserts that the text doesn't contain any of the specified substrings.
 	 *
 	 * @param values The values to check against.
-	 * @return This object.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R doesNotContain(String...values) throws AssertionError {
@@ -473,7 +478,7 @@ public class FluentStringAssertion<R> extends FluentObjectAssertion<String,R> {
 	/**
 	 * Asserts that the text is empty.
 	 *
-	 * @return This object.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R isEmpty() throws AssertionError {
@@ -486,7 +491,7 @@ public class FluentStringAssertion<R> extends FluentObjectAssertion<String,R> {
 	/**
 	 * Asserts that the text is not null or empty.
 	 *
-	 * @return This object.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R isNotEmpty() throws AssertionError {
@@ -505,7 +510,7 @@ public class FluentStringAssertion<R> extends FluentObjectAssertion<String,R> {
 	 * The <js>"*"</js> meta character can be used to represent zero or more characters..
 	 *
 	 * @param searchPattern The search pattern.
-	 * @return This object.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R matches(String searchPattern) throws AssertionError {
@@ -517,7 +522,7 @@ public class FluentStringAssertion<R> extends FluentObjectAssertion<String,R> {
 	 * Asserts that the text matches the specified regular expression.
 	 *
 	 * @param regex The pattern to test for.
-	 * @return This object.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R regex(String regex) throws AssertionError {
@@ -529,7 +534,7 @@ public class FluentStringAssertion<R> extends FluentObjectAssertion<String,R> {
 	 *
 	 * @param regex The pattern to test for.
 	 * @param flags Pattern match flags.  See {@link Pattern#compile(String, int)}.
-	 * @return This object.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R regex(String regex, int flags) throws AssertionError {
@@ -545,7 +550,7 @@ public class FluentStringAssertion<R> extends FluentObjectAssertion<String,R> {
 	 * Asserts that the text matches the specified regular expression pattern.
 	 *
 	 * @param pattern The pattern to test for.
-	 * @return This object.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R regex(Pattern pattern) throws AssertionError {
@@ -560,7 +565,7 @@ public class FluentStringAssertion<R> extends FluentObjectAssertion<String,R> {
 	 * Asserts that the text starts with the specified string.
 	 *
 	 * @param string The string to test for.
-	 * @return This object.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R startsWith(String string) {
@@ -575,7 +580,7 @@ public class FluentStringAssertion<R> extends FluentObjectAssertion<String,R> {
 	 * Asserts that the text ends with the specified string.
 	 *
 	 * @param string The string to test for.
-	 * @return This object.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R endsWith(String string) {
@@ -586,6 +591,16 @@ public class FluentStringAssertion<R> extends FluentObjectAssertion<String,R> {
 		return returns();
 	}
 
+	/**
+	 * Asserts that the text equals the specified object after calling {@link #toString()} on the object.
+	 *
+	 * @param value The value to check against.
+	 * @return The fluent return object.
+	 */
+	public R isString(Object value) {
+		return is(value == null ? null : toString());
+	}
+
 	//-----------------------------------------------------------------------------------------------------------------
 	// Fluent setters
 	//-----------------------------------------------------------------------------------------------------------------
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentStringListAssertion.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentStringListAssertion.java
index 45a2f62..8cf5ba5 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentStringListAssertion.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentStringListAssertion.java
@@ -61,6 +61,10 @@ import org.apache.juneau.serializer.*;
  * 		<li class='jm'>{@link FluentStringListAssertion#join(String)}
  * 		<li class='jm'>{@link FluentStringListAssertion#join(String,String,String)}
  * 		<li class='jm'>{@link FluentStringListAssertion#trim()}
+ * 		<li class='jm'>{@link FluentListAssertion#asStrings()}
+ * 		<li class='jm'>{@link FluentListAssertion#asStrings(Function)}
+ * 		<li class='jm'>{@link FluentListAssertion#asCdl()}
+ * 		<li class='jm'>{@link FluentListAssertion#asCdl(Function)}
  * 		<li class='jm'>{@link FluentListAssertion#item(int)}
  * 		<li class='jm'>{@link FluentListAssertion#sorted()}
  * 		<li class='jm'>{@link FluentListAssertion#sorted(Comparator)}
@@ -95,7 +99,7 @@ import org.apache.juneau.serializer.*;
 public class FluentStringListAssertion<R> extends FluentListAssertion<String,R> {
 
 	//-----------------------------------------------------------------------------------------------------------------
-	// Constructors
+	// Instance
 	//-----------------------------------------------------------------------------------------------------------------
 
 	/**
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentThrowableAssertion.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentThrowableAssertion.java
index 7e802c0..4b99277 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentThrowableAssertion.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentThrowableAssertion.java
@@ -88,6 +88,10 @@ import org.apache.juneau.serializer.*;
 @FluentSetters(returns="FluentThrowableAssertion<T,R>")
 public class FluentThrowableAssertion<T extends Throwable,R> extends FluentObjectAssertion<T,R> {
 
+	//-----------------------------------------------------------------------------------------------------------------
+	// Static
+	//-----------------------------------------------------------------------------------------------------------------
+
 	private static final Messages MESSAGES = Messages.of(FluentThrowableAssertion.class, "Messages");
 	private static final String
 		MSG_exceptionWasNotExpectedType = MESSAGES.getString("exceptionWasNotExpectedType"),
@@ -95,7 +99,7 @@ public class FluentThrowableAssertion<T extends Throwable,R> extends FluentObjec
 		MSG_causedByExceptionNotExpectedType = MESSAGES.getString("causedByExceptionNotExpectedType");
 
 	//-----------------------------------------------------------------------------------------------------------------
-	// Constructors
+	// Instance
 	//-----------------------------------------------------------------------------------------------------------------
 
 	/**
@@ -317,7 +321,7 @@ public class FluentThrowableAssertion<T extends Throwable,R> extends FluentObjec
 	 * </p>
 	 *
 	 * @param parent The type.
-	 * @return This object.
+	 * @return The fluent return object.
 	 */
 	@Override
 	public R isType(Class<?> parent) {
@@ -338,7 +342,7 @@ public class FluentThrowableAssertion<T extends Throwable,R> extends FluentObjec
 	 * </p>
 	 *
 	 * @param type The type.
-	 * @return This object.
+	 * @return The fluent return object.
 	 */
 	@Override
 	public R isExactType(Class<?> type) {
@@ -357,7 +361,7 @@ public class FluentThrowableAssertion<T extends Throwable,R> extends FluentObjec
 	 * 	ThrowableAssertion.<jsm>assertThrown</jsm>(() -&gt; {<jv>foo</jv>.getBar();}).exists();
 	 * </p>
 	 *
-	 * @return This object.
+	 * @return The fluent return object.
 	 */
 	@Override
 	public R exists() {
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentVersionAssertion.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentVersionAssertion.java
index e790f6b..bf10d3f 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentVersionAssertion.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentVersionAssertion.java
@@ -93,7 +93,7 @@ import org.apache.juneau.serializer.*;
 public class FluentVersionAssertion<R> extends FluentComparableAssertion<Version,R> {
 
 	//-----------------------------------------------------------------------------------------------------------------
-	// Constructors
+	// Instance
 	//-----------------------------------------------------------------------------------------------------------------
 
 	/**
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentZonedDateTimeAssertion.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentZonedDateTimeAssertion.java
index b75bdd6..0191094 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentZonedDateTimeAssertion.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentZonedDateTimeAssertion.java
@@ -98,6 +98,10 @@ import org.apache.juneau.serializer.*;
 @FluentSetters(returns="FluentZonedDateTimeAssertion<R>")
 public class FluentZonedDateTimeAssertion<R> extends FluentComparableAssertion<ZonedDateTime,R> {
 
+	//-----------------------------------------------------------------------------------------------------------------
+	// Static
+	//-----------------------------------------------------------------------------------------------------------------
+
 	private static final Messages MESSAGES = Messages.of(FluentZonedDateTimeAssertion.class, "Messages");
 	private static final String
 		MSG_unexpectedValue = MESSAGES.getString("unexpectedValue"),
@@ -105,7 +109,7 @@ public class FluentZonedDateTimeAssertion<R> extends FluentComparableAssertion<Z
 		MSG_valueWasNotBeforeExpected = MESSAGES.getString("valueWasNotBeforeExpected");
 
 	//-----------------------------------------------------------------------------------------------------------------
-	// Constructors
+	// Instance
 	//-----------------------------------------------------------------------------------------------------------------
 
 	/**
@@ -153,7 +157,7 @@ public class FluentZonedDateTimeAssertion<R> extends FluentComparableAssertion<Z
 	 *
 	 * @param value The value to check against.
 	 * @param precision The precision (e.g. {@link ChronoUnit#SECONDS}.
-	 * @return This object.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R is(ZonedDateTime value, ChronoUnit precision) throws AssertionError {
@@ -173,7 +177,7 @@ public class FluentZonedDateTimeAssertion<R> extends FluentComparableAssertion<Z
 	 * Asserts that the value is after the specified value.
 	 *
 	 * @param value The values to check against.
-	 * @return This object.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R isAfter(ZonedDateTime value) throws AssertionError {
@@ -186,7 +190,7 @@ public class FluentZonedDateTimeAssertion<R> extends FluentComparableAssertion<Z
 	/**
 	 * Asserts that the value is after the current date.
 	 *
-	 * @return This object.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R isAfterNow() throws AssertionError {
@@ -197,7 +201,7 @@ public class FluentZonedDateTimeAssertion<R> extends FluentComparableAssertion<Z
 	 * Asserts that the value is before the specified value.
 	 *
 	 * @param value The values to check against.
-	 * @return This object.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R isBefore(ZonedDateTime value) throws AssertionError {
@@ -210,7 +214,7 @@ public class FluentZonedDateTimeAssertion<R> extends FluentComparableAssertion<Z
 	/**
 	 * Asserts that the value is before the current date.
 	 *
-	 * @return This object.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R isBeforeNow() throws AssertionError {
@@ -222,7 +226,7 @@ public class FluentZonedDateTimeAssertion<R> extends FluentComparableAssertion<Z
 	 *
 	 * @param lower The lower value to check against.
 	 * @param upper The upper value to check against.
-	 * @return This object.
+	 * @return The fluent return object.
 	 * @throws AssertionError If assertion failed.
 	 */
 	public R isBetween(ZonedDateTime lower, ZonedDateTime upper) throws AssertionError {
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/IntegerAssertion.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/IntegerAssertion.java
index c143b30..30e9b87 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/IntegerAssertion.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/IntegerAssertion.java
@@ -83,7 +83,7 @@ import org.apache.juneau.serializer.*;
 public class IntegerAssertion extends FluentIntegerAssertion<IntegerAssertion> {
 
 	//-----------------------------------------------------------------------------------------------------------------
-	// Constructors
+	// Static
 	//-----------------------------------------------------------------------------------------------------------------
 
 	/**
@@ -98,6 +98,10 @@ public class IntegerAssertion extends FluentIntegerAssertion<IntegerAssertion> {
 		return new IntegerAssertion(value);
 	}
 
+	//-----------------------------------------------------------------------------------------------------------------
+	// Instance
+	//-----------------------------------------------------------------------------------------------------------------
+
 	/**
 	 * Constructor.
 	 *
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/ListAssertion.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/ListAssertion.java
index 9e446d8..e8322ee 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/ListAssertion.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/ListAssertion.java
@@ -15,6 +15,7 @@ package org.apache.juneau.assertions;
 import java.io.*;
 import java.util.*;
 import java.util.function.*;
+import java.util.stream.*;
 
 import org.apache.juneau.internal.*;
 import org.apache.juneau.serializer.*;
@@ -61,6 +62,10 @@ import org.apache.juneau.serializer.*;
  *
  * <h5 class='topic'>Transform Methods</h5>
  * 	<ul>
+ * 		<li class='jm'>{@link FluentListAssertion#asStrings()}
+ * 		<li class='jm'>{@link FluentListAssertion#asStrings(Function)}
+ * 		<li class='jm'>{@link FluentListAssertion#asCdl()}
+ * 		<li class='jm'>{@link FluentListAssertion#asCdl(Function)}
  * 		<li class='jm'>{@link FluentListAssertion#item(int)}
  * 		<li class='jm'>{@link FluentListAssertion#sorted()}
  * 		<li class='jm'>{@link FluentListAssertion#sorted(Comparator)}
@@ -95,7 +100,7 @@ import org.apache.juneau.serializer.*;
 public class ListAssertion<E> extends FluentListAssertion<E,ListAssertion<E>> {
 
 	//-----------------------------------------------------------------------------------------------------------------
-	// Constructors
+	// Static
 	//-----------------------------------------------------------------------------------------------------------------
 
 	/**
@@ -111,6 +116,22 @@ public class ListAssertion<E> extends FluentListAssertion<E,ListAssertion<E>> {
 	}
 
 	/**
+	 * Static creator.
+	 *
+	 * @param value
+	 * 	The object being tested.
+	 * 	<br>Can be <jk>null</jk>.
+	 * @return A new assertion object.
+	 */
+	public static <E> ListAssertion<E> create(Stream<E> value) {
+		return new ListAssertion<>(value == null ? null : value.collect(Collectors.toList()));
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Instance
+	//-----------------------------------------------------------------------------------------------------------------
+
+	/**
 	 * Constructor.
 	 *
 	 * @param value
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/LongAssertion.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/LongAssertion.java
index c7b408c..9590b82 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/LongAssertion.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/LongAssertion.java
@@ -84,7 +84,7 @@ import org.apache.juneau.serializer.*;
 public class LongAssertion extends FluentLongAssertion<LongAssertion> {
 
 	//-----------------------------------------------------------------------------------------------------------------
-	// Constructors
+	// Static
 	//-----------------------------------------------------------------------------------------------------------------
 
 	/**
@@ -99,6 +99,10 @@ public class LongAssertion extends FluentLongAssertion<LongAssertion> {
 		return new LongAssertion(value);
 	}
 
+	//-----------------------------------------------------------------------------------------------------------------
+	// Instance
+	//-----------------------------------------------------------------------------------------------------------------
+
 	/**
 	 * Constructor.
 	 *
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/MapAssertion.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/MapAssertion.java
index 8c4963b..9d2b3ce 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/MapAssertion.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/MapAssertion.java
@@ -91,7 +91,7 @@ import org.apache.juneau.serializer.*;
 public class MapAssertion<K,V> extends FluentMapAssertion<K,V,MapAssertion<K,V>> {
 
 	//-----------------------------------------------------------------------------------------------------------------
-	// Constructors
+	// Static
 	//-----------------------------------------------------------------------------------------------------------------
 
 	/**
@@ -106,6 +106,10 @@ public class MapAssertion<K,V> extends FluentMapAssertion<K,V,MapAssertion<K,V>>
 		return new MapAssertion<>(value);
 	}
 
+	//-----------------------------------------------------------------------------------------------------------------
+	// Instance
+	//-----------------------------------------------------------------------------------------------------------------
+
 	/**
 	 * Constructor.
 	 *
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/ObjectAssertion.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/ObjectAssertion.java
index 9de5e7f..fed0f0b 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/ObjectAssertion.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/ObjectAssertion.java
@@ -80,7 +80,7 @@ import org.apache.juneau.serializer.*;
 public class ObjectAssertion<T> extends FluentObjectAssertion<T,ObjectAssertion<T>> {
 
 	//-----------------------------------------------------------------------------------------------------------------
-	// Constructors
+	// Static
 	//-----------------------------------------------------------------------------------------------------------------
 
 	/**
@@ -95,6 +95,10 @@ public class ObjectAssertion<T> extends FluentObjectAssertion<T,ObjectAssertion<
 		return new ObjectAssertion<>(value);
 	}
 
+	//-----------------------------------------------------------------------------------------------------------------
+	// Instance
+	//-----------------------------------------------------------------------------------------------------------------
+
 	/**
 	 * Constructor.
 	 *
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/PrimitiveArrayAssertion.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/PrimitiveArrayAssertion.java
index 82d954f..80ae57e 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/PrimitiveArrayAssertion.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/PrimitiveArrayAssertion.java
@@ -92,7 +92,7 @@ import org.apache.juneau.serializer.*;
 public class PrimitiveArrayAssertion<E,T> extends FluentPrimitiveArrayAssertion<E,T,PrimitiveArrayAssertion<E,T>> {
 
 	//-----------------------------------------------------------------------------------------------------------------
-	// Constructors
+	// Static
 	//-----------------------------------------------------------------------------------------------------------------
 
 	/**
@@ -107,6 +107,10 @@ public class PrimitiveArrayAssertion<E,T> extends FluentPrimitiveArrayAssertion<
 		return new PrimitiveArrayAssertion<>(value);
 	}
 
+	//-----------------------------------------------------------------------------------------------------------------
+	// Instance
+	//-----------------------------------------------------------------------------------------------------------------
+
 	/**
 	 * Constructor.
 	 *
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/StringAssertion.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/StringAssertion.java
index 9116e0e..74205fd 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/StringAssertion.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/StringAssertion.java
@@ -44,6 +44,7 @@ import org.apache.juneau.serializer.*;
  * 		<li class='jm'>{@link FluentStringAssertion#doesNotContain(String...)}
  * 		<li class='jm'>{@link FluentStringAssertion#isEmpty()}
  * 		<li class='jm'>{@link FluentStringAssertion#isNotEmpty()}
+ * 		<li class='jm'>{@link FluentStringAssertion#isString(Object)}
  * 		<li class='jm'>{@link FluentStringAssertion#matches(String)}
  * 		<li class='jm'>{@link FluentStringAssertion#regex(String)}
  * 		<li class='jm'>{@link FluentStringAssertion#regex(String,int)}
@@ -107,7 +108,7 @@ import org.apache.juneau.serializer.*;
 public class StringAssertion extends FluentStringAssertion<StringAssertion> {
 
 	//-----------------------------------------------------------------------------------------------------------------
-	// Constructors
+	// Static
 	//-----------------------------------------------------------------------------------------------------------------
 
 	/**
@@ -122,6 +123,10 @@ public class StringAssertion extends FluentStringAssertion<StringAssertion> {
 		return new StringAssertion(value);
 	}
 
+	//-----------------------------------------------------------------------------------------------------------------
+	// Instance
+	//-----------------------------------------------------------------------------------------------------------------
+
 	/**
 	 * Constructor.
 	 *
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/StringListAssertion.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/StringListAssertion.java
index bcc3d28..a4bde7c 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/StringListAssertion.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/StringListAssertion.java
@@ -59,6 +59,10 @@ import org.apache.juneau.serializer.*;
  * 		<li class='jm'>{@link FluentStringListAssertion#join(String)}
  * 		<li class='jm'>{@link FluentStringListAssertion#join(String,String,String)}
  * 		<li class='jm'>{@link FluentStringListAssertion#trim()}
+ * 		<li class='jm'>{@link FluentListAssertion#asStrings()}
+ * 		<li class='jm'>{@link FluentListAssertion#asStrings(Function)}
+ * 		<li class='jm'>{@link FluentListAssertion#asCdl()}
+ * 		<li class='jm'>{@link FluentListAssertion#asCdl(Function)}
  * 		<li class='jm'>{@link FluentListAssertion#item(int)}
  * 		<li class='jm'>{@link FluentListAssertion#sorted()}
  * 		<li class='jm'>{@link FluentListAssertion#sorted(Comparator)}
@@ -91,7 +95,7 @@ import org.apache.juneau.serializer.*;
 public class StringListAssertion extends FluentStringListAssertion<StringListAssertion> {
 
 	//-----------------------------------------------------------------------------------------------------------------
-	// Constructors
+	// Static
 	//-----------------------------------------------------------------------------------------------------------------
 
 	/**
@@ -106,6 +110,10 @@ public class StringListAssertion extends FluentStringListAssertion<StringListAss
 		return new StringListAssertion(value);
 	}
 
+	//-----------------------------------------------------------------------------------------------------------------
+	// Instance
+	//-----------------------------------------------------------------------------------------------------------------
+
 	/**
 	 * Constructor.
 	 *
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/ThrowableAssertion.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/ThrowableAssertion.java
index 5b29ba0..17cdb1e 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/ThrowableAssertion.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/ThrowableAssertion.java
@@ -88,7 +88,7 @@ import org.apache.juneau.serializer.*;
 public class ThrowableAssertion<T extends Throwable> extends FluentThrowableAssertion<T,ThrowableAssertion<T>> {
 
 	//-----------------------------------------------------------------------------------------------------------------
-	// Constructors
+	// Static
 	//-----------------------------------------------------------------------------------------------------------------
 
 	/**
@@ -103,6 +103,10 @@ public class ThrowableAssertion<T extends Throwable> extends FluentThrowableAsse
 		return new ThrowableAssertion<>(value);
 	}
 
+	//-----------------------------------------------------------------------------------------------------------------
+	// Instance
+	//-----------------------------------------------------------------------------------------------------------------
+
 	/**
 	 * Constructor.
 	 *
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/Verify.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/Verify.java
index 790b69e..bcb1557 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/Verify.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/Verify.java
@@ -40,18 +40,15 @@ import org.apache.juneau.internal.*;
  */
 public class Verify {
 
+	//-----------------------------------------------------------------------------------------------------------------
+	// Static
+	//-----------------------------------------------------------------------------------------------------------------
+
 	private static final Messages MESSAGES = Messages.of(Verify.class, "Messages");
 	static final String
 		MSG_unexpectedType = MESSAGES.getString("unexpectedType"),
 		MSG_unexpectedValue = MESSAGES.getString("unexpectedValue");
 
-	private final Object o;
-	private Supplier<String> msg;
-
-	//-----------------------------------------------------------------------------------------------------------------
-	// Constructors
-	//-----------------------------------------------------------------------------------------------------------------
-
 	/**
 	 * Create a new verifier object.
 	 *
@@ -62,6 +59,13 @@ public class Verify {
 		return new Verify(o);
 	}
 
+	//-----------------------------------------------------------------------------------------------------------------
+	// Instance
+	//-----------------------------------------------------------------------------------------------------------------
+
+	private final Object o;
+	private Supplier<String> msg;
+
 	/**
 	 * Create a new verifier object.
 	 *
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/VersionAssertion.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/VersionAssertion.java
index 1e8b55d..dc40c85 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/VersionAssertion.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/VersionAssertion.java
@@ -88,7 +88,7 @@ import org.apache.juneau.serializer.*;
 public class VersionAssertion extends FluentVersionAssertion<VersionAssertion> {
 
 	//-----------------------------------------------------------------------------------------------------------------
-	// Constructors
+	// Static
 	//-----------------------------------------------------------------------------------------------------------------
 
 	/**
@@ -103,6 +103,10 @@ public class VersionAssertion extends FluentVersionAssertion<VersionAssertion> {
 		return new VersionAssertion(value);
 	}
 
+	//-----------------------------------------------------------------------------------------------------------------
+	// Instance
+	//-----------------------------------------------------------------------------------------------------------------
+
 	/**
 	 * Constructor.
 	 *
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/ZonedDateTimeAssertion.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/ZonedDateTimeAssertion.java
index cd08346..03b136e 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/ZonedDateTimeAssertion.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/ZonedDateTimeAssertion.java
@@ -91,7 +91,7 @@ import org.apache.juneau.serializer.*;
 public class ZonedDateTimeAssertion extends FluentZonedDateTimeAssertion<ZonedDateTimeAssertion> {
 
 	//-----------------------------------------------------------------------------------------------------------------
-	// Constructors
+	// Static
 	//-----------------------------------------------------------------------------------------------------------------
 
 	/**
@@ -106,6 +106,10 @@ public class ZonedDateTimeAssertion extends FluentZonedDateTimeAssertion<ZonedDa
 		return new ZonedDateTimeAssertion(value);
 	}
 
+	//-----------------------------------------------------------------------------------------------------------------
+	// Instance
+	//-----------------------------------------------------------------------------------------------------------------
+
 	/**
 	 * Constructor.
 	 *
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/BeanCreateMethodFinder.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/BeanCreateMethodFinder.java
index 26c81f6..2370a0e 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/BeanCreateMethodFinder.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/BeanCreateMethodFinder.java
@@ -13,8 +13,6 @@
 package org.apache.juneau.cp;
 
 import static org.apache.juneau.assertions.Assertions.*;
-import static org.apache.juneau.reflect.ReflectFlags.*;
-
 import java.util.*;
 import java.util.function.*;
 
@@ -23,11 +21,55 @@ import org.apache.juneau.annotation.*;
 import org.apache.juneau.reflect.*;
 
 /**
- * Used for finding methods on an object that take in arbitrary parameters and returns bean instances.
+ * Utility class for creating beans through creator methods.
+ *
+ * <p>
+ * Used for finding and invoking methods on an object that take in arbitrary parameters and returns bean instances.
+ *
+ * <p>
+ * This class is instantiated through the following methods:
+ * <ul class='javatree'>
+ * 	<li class='jc'>{@link BeanStore}
+ * 		<ul class='javatreec'>
+ * 			<li class='jm'>{@link BeanStore#createMethodFinder(Class)}
+ * 			<li class='jm'>{@link BeanStore#createMethodFinder(Class,Class)}
+ * 			<li class='jm'>{@link BeanStore#createMethodFinder(Class,Object)}
+ * 		</ul>
+ * 	</li>
+ * </ul>
+ *
+ * <h5 class='section'>Example:</h5>
+ * <p class='bcode w800'>
+ * 	<jc>// The bean we want to create.</jc>
+ * 	<jk>public class</jk> A {}
  *
- * See {@link BeanStore#createMethodFinder(Class, Object)} for usage.
+ * 	<jc>// The bean that has a creator method for the bean above.</jc>
+ * 	<jk>public class</jk> B {
+ *
+ * 		<jc>// Creator method.</jc>
+ * 		<jc>// Bean store must have a C bean and optionally a D bean.</jc>
+ * 		<jk>public</jk> A createA(C <mv>c</mv>, Optional&lt;D&gt; <mv>d</mv>) {
+ * 			<jk>return new</jk> A(<mv>c</mv>, <mv>d</mv>.orElse(<jk>null</jk>));
+ * 		}
+ * 	}
+ *
+ * 	<jc>// Instantiate the bean with the creator method.</jc>
+ * 	B <mv>b</mv> = <jk>new</jk> B();
+ *
+ *  <jc>// Create a bean store with some mapped beans.</jc>
+ * 	BeanStore <mv>beanStore</mv> = BeanStore.<jsm>create</jsm>().addBean(C.<jk>class</jk>, <jk>new</jk> C());
+ *
+ * 	<jc>// Instantiate the bean using the creator method.</jc>
+ * 	A <mv>a</mv> = <mv>beanStore</mv>
+ * 		.createMethodFinder(A.<jk>class</jk>, <mv>b</mv>)  <jc>// Looking for creator for A on b object.</jc>
+ * 		.find(<js>"createA"</js>)                         <jc>// Look for method called "createA".</jc>
+ * 		.thenFind(<js>"createA2"</js>)                    <jc>// Then look for method called "createA2".</jc>
+ * 		.withDefault(()-&gt;<jk>new</jk> A())                        <jc>// Optionally supply a default value if method not found.</jc>
+ * 		.run();                                  <jc>// Execute.</jc>
+ * </p>
  *
  * <ul class='seealso'>
+ * 	<li class='jc'>{@link BeanStore}
  * 	<li class='extlink'>{@source}
  * </ul>
  *
@@ -46,16 +88,16 @@ public class BeanCreateMethodFinder<T> {
 	private Supplier<T> def = ()->null;
 
 	BeanCreateMethodFinder(Class<T> beanType, Object resource, BeanStore beanStore) {
-		this.beanType = beanType;
-		this.resource = resource;
+		this.beanType = assertArgNotNull("beanType", beanType);
+		this.resource = assertArgNotNull("resource", resource);
 		this.resourceClass = resource.getClass();
 		this.beanStore = BeanStore.of(beanStore, resource);
 	}
 
 	BeanCreateMethodFinder(Class<T> beanType, Class<?> resourceClass, BeanStore beanStore) {
-		this.beanType = beanType;
+		this.beanType = assertArgNotNull("beanType", beanType);
 		this.resource = null;
-		this.resourceClass = resourceClass;
+		this.resourceClass = assertArgNotNull("resourceClass", resourceClass);
 		this.beanStore = BeanStore.of(beanStore);
 	}
 
@@ -98,16 +140,17 @@ public class BeanCreateMethodFinder<T> {
 	 */
 	public BeanCreateMethodFinder<T> find(String methodName, Class<?>...requiredParams) {
 		if (method == null) {
-			ClassInfo ci = ClassInfo.of(resourceClass);
-			for (MethodInfo m : ci.getPublicMethods()) {
-				if (m.isAll(NOT_DEPRECATED) && m.hasReturnType(beanType) && m.getSimpleName().equals(methodName) && (!m.hasAnnotation(BeanIgnore.class))) {
-					List<ClassInfo> missing = beanStore.getMissingParamTypes(m.getParams());
-					if (missing.isEmpty() && m.hasAllArgs(requiredParams) && (m.isNotStatic() || resource != null)) {
-						this.method = m;
-						this.args = beanStore.getParams(m.getParams());
-					}
-				}
-			}
+			method = ClassInfo.ofc(resourceClass).getPublicMethod(
+				x -> x.isNotDeprecated()
+				&& x.hasReturnType(beanType)
+				&& x.hasName(methodName)
+				&& x.hasNoAnnotation(BeanIgnore.class)
+				&& x.hasAllArgs(requiredParams)
+				&& beanStore.hasAllParams(x)
+				&& (x.isStatic() || resource != null)
+			);
+			if (method != null)
+				args = beanStore.getParams(method);
 		}
 		return this;
 	}
@@ -152,7 +195,7 @@ public class BeanCreateMethodFinder<T> {
 	 * @throws ExecutableException If method invocation threw an exception.
 	 */
 	@SuppressWarnings("unchecked")
-	public T run() throws ExecutableException  {
+	public T run() throws ExecutableException {
 		if (method != null)
 			return (T)method.invoke(resource, args);
 		return def.get();
@@ -170,5 +213,4 @@ public class BeanCreateMethodFinder<T> {
 		Optional.ofNullable(t).ifPresent(consumer);
 		return t;
 	}
-
 }
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/BeanCreator.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/BeanCreator.java
index 6021d71..277c118 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/BeanCreator.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/BeanCreator.java
@@ -15,19 +15,98 @@ package org.apache.juneau.cp;
 import static java.util.stream.Collectors.*;
 import static org.apache.juneau.reflect.ReflectFlags.*;
 
-import java.lang.annotation.*;
 import java.util.*;
 import java.util.function.*;
 
 import org.apache.juneau.*;
 import org.apache.juneau.annotation.*;
-import org.apache.juneau.collections.*;
 import org.apache.juneau.reflect.*;
 
 /**
- * Utility class for creating beans.
+ * Utility class for creating beans through constructors, creator methods, and builders.
+ *
+ * <p>
+ * Uses a {@link BeanStore} to find available ways to construct beans via injection of beans from the store.
+ *
+ * <p>
+ * This class is instantiated through the following method:
+ * <ul class='javatree'>
+ * 	<li class='jc'>{@link BeanStore}
+ * 		<ul class='javatreec'>
+ * 			<li class='jm'>{@link BeanStore#createBean(Class)}
+ * 		</ul>
+ * 	</li>
+ * </ul>
+ *
+ * <h5 class='section'>Example:</h5>
+ * <p class='bcode w800'>
+ * 	<jc>// Construct and throw a RuntimeException using a bean store.</jc>
+ * 	<jk>throw</jk> BeanStore
+ * 		.<jsm>create</jsm>()
+ * 		.build()
+ * 		.addBean(Throwable.<jk>class</jk>, <jv>cause</jv>)
+ * 		.addBean(String.<jk>class</jk>, <jv>msg</jv>)
+ * 		.addBean(Object[].<jk>class</jk>, <jv>args</jv>)
+ * 		.createBean(RuntimeException.<jk>class</jk>)
+ * 		.run();
+ * </p>
+ *
+ * <p>
+ * Looks for the following methods for creating a bean:
+ * <ol class='spaced-list'>
+ * 	<li>Looks for a singleton no-arg method of the form:
+ * 		<p class='bcode w800'>
+ * 	<jk>public static</jk> MyClass <jsm>getInstance</jsm>();
+ * 		</p>
+ * 		<ul>
+ * 			<li>Deprecated and {@link BeanIgnore @BeanIgnore-annotated} methods are ignored.
+ * 			<li>Enabled by {@linnk #findSingleton()}.
+ *		</ul>
+ * 	<li>Looks for a static creator method of the form:
+ * 		<p class='bcode w800'>
+ * 	<jk>public static</jk> MyClass <jsm>create</jsm>(<ja>&lt;args&gt;</ja>);
+ * 		</p>
+ * 		<ul>
+ * 			<li>All arguments except {@link Optional} and {@link List} parameters must have beans available in the store.
+ * 			<li>If multiple methods are found, the one with the most matching parameters is used.
+ * 			<li>Deprecated and {@link BeanIgnore @BeanIgnore-annotated} methods are ignored.
+ * 		</ul>
+ * 	<li>Looks for a public constructor of the form:
+ * 		<p class='bcode w800'>
+ * 	<jk>public</jk> MyClass(<ja>&lt;args&gt;</ja>);
+ * 		</p>
+ * 		<ul>
+ * 			<li>All arguments except {@link Optional} and {@link List} parameters must have beans available in the store.
+ * 			<li>If multiple methods are found, the one with the most matching parameters is used.
+ * 			<li>Deprecated and {@link BeanIgnore @BeanIgnore-annotated} methods are ignored.
+ *		</ul>
+ * 	<li>Looks for a protected constructor of the form:
+ * 		<p class='bcode w800'>
+ * 	<jk>protected</jk> MyClass(<ja>&lt;args&gt;</ja>);
+ * 		</p>
+ * 		<ul>
+ * 			<li>All arguments except {@link Optional} and {@link List} parameters must have beans available in the store.
+ * 			<li>If multiple methods are found, the one with the most matching parameters is used.
+ * 			<li>Deprecated and {@link BeanIgnore @BeanIgnore-annotated} methods are ignored.
+ *		</ul>
+ * 	<li>Looks for a static no-arg create method that returns a builder object that can be passed in to a protected constructor.
+ * 		<p class='bcode w800'>
+ * 	<jk>public static</jk> MyClass.Builder <jsm>create</jsm>();
+ *
+ * 	<jk>protected</jk> MyClass(MyClass.Builder <jv>builder</jv>);
+ * 		</p>
+ * 		<ul>
+ * 			<li>Deprecated and {@link BeanIgnore @BeanIgnore-annotated} methods are ignored.
+ *		</ul>
+ * </ol>
+ *
+ * <ul class='spaced-list'>
+ * 	<li class='note'>The {@link #builder(Class,Object)} method can be used to set an existing initialized builder object to pass to a constructor.
+ * 	<li class='note'>An existing initialized builder can be set using the {@link #builder(Class,Object)} method.
+ * </ul>
  *
  * <ul class='seealso'>
+ * 	<li class='jc'>{@link BeanStore}
  * 	<li class='extlink'>{@source}
  * </ul>
  *
@@ -35,53 +114,20 @@ import org.apache.juneau.reflect.*;
  */
 public class BeanCreator<T> {
 
+	private final BeanStore store;
 	private ClassInfo type;
-	private BeanStore store = BeanStore.INSTANCE;
-	private Object outer;
 	private Object builder;
-	private boolean findSingleton;
 	private T impl;
 
 	/**
-	 * Static creator.
-	 *
-	 * @param type The bean type being created.
-	 * @return A new creator object.
-	 */
-	public static <T> BeanCreator<T> of(Class<T> type) {
-		return new BeanCreator<>(type);
-	}
-
-	/**
 	 * Constructor.
 	 *
 	 * @param type The bean type being created.
+	 * @param store The bean store creating this creator.
 	 */
-	protected BeanCreator(Class<T> type) {
+	protected BeanCreator(Class<T> type, BeanStore store) {
 		this.type = ClassInfo.ofc(type);
-	}
-
-	/**
-	 * Copy constructor.
-	 *
-	 * @param copyFrom The creator being copied.
-	 */
-	protected BeanCreator(BeanCreator<T> copyFrom) {
-		type = copyFrom.type;
-		store = copyFrom.store;
-		outer = copyFrom.outer;
-		builder = copyFrom.builder;
-		findSingleton = copyFrom.findSingleton;
-		impl = copyFrom.impl;
-	}
-
-	/**
-	 * Creates a copy of this bean creator.
-	 *
-	 * @return A copy of this bean creator.
-	 */
-	public BeanCreator<T> copy() {
-		return new BeanCreator<>(this);
+		this.store = BeanStore.of(store, store.outer.orElse(null));
 	}
 
 	/**
@@ -108,47 +154,26 @@ public class BeanCreator<T> {
 		impl = (T)value;
 		return this;
 	}
-	/**
-	 * Specifies a bean store for looking up matching parameters on constructors and static creator methods.
-	 *
-	 * @param value The value for this setting.
-	 * @return This object.
-	 */
-	public BeanCreator<T> store(BeanStore value) {
-		if (value != null)
-			store = value;
-		return this;
-	}
-
-	/**
-	 * Specifies the outer "this" parameter to an inner class constructor.
-	 *
-	 * @param value The value for this setting.
-	 * @return This object.
-	 */
-	public BeanCreator<T> outer(Object value) {
-		outer = value;
-		return this;
-	}
 
 	/**
 	 * Specifies a builder object for the bean type.
 	 *
+	 * <ul class='notes'>
+	 * 	<li class='note'>When specified, we don't look for a static creator method.
+	 * </ul>
+	 *
+	 * @param type The class type of the builder.
 	 * @param value The value for this setting.
 	 * @return This object.
 	 */
-	public BeanCreator<T> builder(Object value) {
+	@SuppressWarnings("unchecked")
+	public <B> BeanCreator<T> builder(Class<B> type, B value) {
 		builder = value;
-		return this;
-	}
-
-	/**
-	 * Specifies to look for the existence of a <c>getInstance()</c> method that returns a singleton.
-	 *
-	 * @return This object.
-	 */
-	public BeanCreator<T> findSingleton() {
-		findSingleton = true;
+		Class<?> t = value.getClass();
+		do {
+			store.add((Class<T>)t, (T)value);
+			t = t.getSuperclass();
+		} while(t != null && ! t.equals(type));
 		return this;
 	}
 
@@ -167,11 +192,34 @@ public class BeanCreator<T> {
 
 		String found = null;
 
+		// Look for getInstance(Builder).
+		if (builder != null) {
+			MethodInfo m = type.getPublicMethod(
+				x -> x.isStatic()
+				&& x.isNotDeprecated()
+				&& x.getParamCount() == 1
+				&& x.getParam(0).canAccept(builder)
+				&& x.hasReturnType(type)
+				&& x.hasNoAnnotation(BeanIgnore.class)
+				&& x.hasName("getInstance")
+			);
+			if (m != null)
+				return m.invoke(null, builder);
+		}
+
 		// Look for getInstance().
-		if (builder == null || findSingleton)
-			for (MethodInfo m : type.getPublicMethods())
-				if (isSingletonMethod(m))
-					return m.invoke(null);
+		if (builder == null) {
+			MethodInfo m = type.getPublicMethod(
+				x -> x.isStatic()
+				&& x.isNotDeprecated()
+				&& x.getParamCount() == 0
+				&& x.hasReturnType(type)
+				&& x.hasNoAnnotation(BeanIgnore.class)
+				&& x.hasName("getInstance")
+			);
+			if (m != null)
+				return m.invoke(null);
+		}
 
 		if (builder == null) {
 			// Look for static creator methods.
@@ -183,7 +231,7 @@ public class BeanCreator<T> {
 			for (MethodInfo m : type.getPublicMethods()) {
 				if (isStaticCreateMethod(m)) {
 					found = "STATIC_CREATOR";
-					if (hasAllParams(m.getParams())) {
+					if (store.hasAllParams(m)) {
 						if (m.getParamCount() > matchedCreatorParams) {
 							matchedCreatorParams = m.getParamCount();
 							matchedCreator = m;
@@ -193,7 +241,7 @@ public class BeanCreator<T> {
 			}
 
 			if (matchedCreator != null)
-				return matchedCreator.invoke(null, getParams(matchedCreator.getParams()));
+				return matchedCreator.invoke(null, store.getParams(matchedCreator));
 		}
 
 		if (type.isInterface())
@@ -209,7 +257,7 @@ public class BeanCreator<T> {
 		for (ConstructorInfo cc : type.getPublicConstructors()) {
 			if (found == null)
 				found = "PUBLIC_CONSTRUCTOR";
-			if (hasAllParams(cc.getParams())) {
+			if (store.hasAllParams(cc)) {
 				if (cc.getParamCount() > matchedConstructorParams) {
 					matchedConstructorParams = cc.getParamCount();
 					matchedConstructor = cc;
@@ -223,7 +271,7 @@ public class BeanCreator<T> {
 				if (cc.isProtected()) {
 					if (found == null)
 						found = "PROTECTED_CONSTRUCTOR";
-					if (hasAllParams(cc.getParams())) {
+					if (store.hasAllParams(cc)) {
 						if (cc.getParamCount() > matchedConstructorParams) {
 							matchedConstructorParams = cc.getParamCount();
 							matchedConstructor = cc.accessible();
@@ -235,18 +283,17 @@ public class BeanCreator<T> {
 
 		// Execute.
 		if (matchedConstructor != null)
-			return matchedConstructor.invoke(getParams(matchedConstructor.getParams()));
+			return matchedConstructor.invoke(store.getParams(matchedConstructor));
 
 		if (builder == null) {
 			// Look for static-builder/protected-constructor pair.
 			for (ConstructorInfo cc2 : type.getDeclaredConstructors()) {
 				if (cc2.getParamCount() == 1 && cc2.isVisible(Visibility.PROTECTED)) {
 					Class<?> pt = cc2.getParam(0).getParameterType().inner();
-					for (MethodInfo m : type.getPublicMethods()) {
-						if (isStaticCreateMethod(m, pt)) {
-							Object builder = m.invoke(null);
-							return cc2.accessible().invoke(builder);
-						}
+					MethodInfo m = type.getPublicMethod(x -> isStaticCreateMethod(x, pt));
+					if (m != null) {
+						Object builder = m.invoke(null);
+						return cc2.accessible().invoke(builder);
 					}
 				}
 			}
@@ -256,11 +303,12 @@ public class BeanCreator<T> {
 		if (found == null) {
 			msg = "No public/protected constructors found";
 		} else if (found.equals("STATIC_CREATOR")) {
-			msg = "Static creator found but could not find prerequisites: " + type.getPublicMethods().stream().filter(x -> isStaticCreateMethod(x)).map(x -> getMissingParams(x.getParams())).sorted().collect(joining(" or "));
+
+			msg = "Static creator found but could not find prerequisites: " + type.getPublicMethods().stream().filter(x -> isStaticCreateMethod(x)).map(x -> store.getMissingParams(x)).sorted().collect(joining(" or "));
 		} else if (found.equals("PUBLIC_CONSTRUCTOR")) {
-			msg = "Public constructor found but could not find prerequisites: " + type.getPublicConstructors().stream().map(x -> getMissingParams(x.getParams())).sorted().collect(joining(" or "));
+			msg = "Public constructor found but could not find prerequisites: " + type.getPublicConstructors().stream().map(x -> store.getMissingParams(x)).sorted().collect(joining(" or "));
 		} else {
-			msg = "Protected constructor found but could not find prerequisites: " + type.getDeclaredConstructors().stream().filter(x -> x.isProtected()).map(x -> getMissingParams(x.getParams())).sorted().collect(joining(" or "));
+			msg = "Protected constructor found but could not find prerequisites: " + type.getDeclaredConstructors().stream().filter(x -> x.isProtected()).map(x -> store.getMissingParams(x)).sorted().collect(joining(" or "));
 		}
 		throw new ExecutableException("Could not instantiate class {0}: {1}.", type.getName(), msg);
 	}
@@ -274,26 +322,6 @@ public class BeanCreator<T> {
 		return ()->run();
 	}
 
-	private boolean hasAllParams(List<ParamInfo> params) {
-		loop: for (int i = 0; i < params.size(); i++) {
-			ParamInfo pi = params.get(i);
-			ClassInfo pt = pi.getParameterType();
-			ClassInfo ptu = pt.unwrap(Optional.class);
-			if (i == 0 && ptu.isInstance(outer))
-				continue loop;
-			if (pt.is(Optional.class))
-				continue loop;
-			if (ptu.isInstance(builder))
-					continue loop;
-			String beanName = findBeanName(pi);
-			if (beanName == null)
-				beanName = ptu.inner().getName();
-			if (! store.hasBean(beanName))
-				return false;
-		}
-		return true;
-	}
-
 	private boolean isStaticCreateMethod(MethodInfo m) {
 		return isStaticCreateMethod(m, type.inner());
 	}
@@ -301,68 +329,7 @@ public class BeanCreator<T> {
 	private boolean isStaticCreateMethod(MethodInfo m, Class<?> type) {
 		return m.isAll(STATIC, NOT_DEPRECATED)
 			&& m.hasReturnType(type)
-			&& (!m.hasAnnotation(BeanIgnore.class))
-			&& m.getSimpleName().equals("create");
-	}
-
-	private boolean isSingletonMethod(MethodInfo m) {
-		return m.isAll(STATIC, NOT_DEPRECATED)
-			&& m.getParamCount() == 0
-			&& m.hasReturnType(type)
-			&& (!m.hasAnnotation(BeanIgnore.class))
-			&& m.getSimpleName().equals("getInstance");
-	}
-
-	private Object[] getParams(List<ParamInfo> params) {
-		Object[] o = new Object[params.size()];
-		for (int i = 0; i < params.size(); i++) {
-			ParamInfo pi = params.get(i);
-			ClassInfo pt = pi.getParameterType();
-			ClassInfo ptu = pt.unwrap(Optional.class);
-			if (i == 0 && ptu.isInstance(outer))
-				o[i] = outer;
-			else {
-				if (pt.isInstance(builder))
-					o[i] = builder;
-				else {
-					String beanName = findBeanName(pi);
-					if (pt.is(Optional.class)) {
-						o[i] = store.getBean(beanName, ptu.inner());
-					} else {
-						o[i] = store.getBean(beanName, ptu.inner()).get();
-					}
-				}
-			}
-		}
-		return o;
-	}
-
-	private String getMissingParams(List<ParamInfo> params) {
-		List<String> l = AList.create();
-		loop: for (int i = 0; i < params.size(); i++) {
-			ParamInfo pi = params.get(i);
-			ClassInfo pt = pi.getParameterType();
-			ClassInfo ptu = pt.unwrap(Optional.class);
-			if (i == 0 && ptu.isInstance(outer))
-				continue loop;
-			if (pt.is(Optional.class))
-				continue loop;
-			String beanName = findBeanName(pi);
-			if (beanName != null) {
-				if (! store.hasBean(beanName))
-					l.add(beanName);
-			} else {
-				if (! store.hasBean(pt.inner()))
-					l.add(pt.inner().getSimpleName());
-			}
-		}
-		return l.stream().sorted().collect(joining(","));
-	}
-
-	private String findBeanName(ParamInfo pi) {
-		Optional<Annotation> namedAnnotation = pi.getAnnotations(Annotation.class).stream().filter(x->x.annotationType().getSimpleName().equals("Named")).findFirst();
-		if (namedAnnotation.isPresent())
-			return AnnotationInfo.of((ClassInfo)null, namedAnnotation.get()).getValue(String.class, "value").orElse(null);
-		return null;
+			&& m.hasNoAnnotation(BeanIgnore.class)
+			&& m.hasName("create");
 	}
 }
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/BeanStore.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/BeanStore.java
index c6a099e..309f22c 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/BeanStore.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/BeanStore.java
@@ -15,12 +15,14 @@ package org.apache.juneau.cp;
 import static org.apache.juneau.collections.OMap.*;
 import static org.apache.juneau.internal.ThrowableUtils.*;
 import static java.util.Optional.*;
+import static java.util.stream.Collectors.*;
+
 import java.lang.annotation.*;
 import java.util.*;
 import java.util.concurrent.*;
 import java.util.function.*;
+import java.util.stream.*;
 
-import org.apache.juneau.*;
 import org.apache.juneau.collections.*;
 import org.apache.juneau.internal.*;
 import org.apache.juneau.reflect.*;
@@ -29,7 +31,47 @@ import org.apache.juneau.reflect.*;
  * Java bean store.
  *
  * <p>
- * Used for bean injection.
+ * A simple storage database for beans keyed by type and name.
+ * Used to retrieve and instantiate beans using an injection-like API.
+ * It's similar in concept to the injection framework of Spring but greatly simplified in function and not intended to implement a full-fledged injection framework.
+ *
+ * <p>
+ * Beans can be stored with or without names.  Named beans are typically resolved using
+ * the <ja>@Named</ja> or <ja>@Qualified</ja> annotations on constructor or method parameters.
+ *
+ * <p>
+ * Beans are added through the following methods:
+ * <ul class='javatreec'>
+ * 	<li class='jm'>{@link #add(Class,Object) add(Class,Object)}
+ * 	<li class='jm'>{@link #add(Class,Object,String) add(Class,Object,String)}
+ * 	<li class='jm'>{@link #addBean(Class,Object) addBean(Class,Object)}
+ * 	<li class='jm'>{@link #addBean(Class,Object,String) addBean(Class,Object,String)}
+ * 	<li class='jm'>{@link #addSupplier(Class,Supplier) addSupplier(Class,Supplier)}
+ * 	<li class='jm'>{@link #addSupplier(Class,Supplier,String) addSupplier(Class,Supplier,String)}
+ * </ul>
+ *
+ * <p>
+ * Beans are retrieved through the following methods:
+ * <ul class='javatreec'>
+ * 	<li class='jm'>{@link #getBean(Class) getBean(Class)}
+ * 	<li class='jm'>{@link #getBean(Class,String) getBean(Class,String)}
+ * 	<li class='jm'>{@link #stream(Class) stream(Class)}
+ * </ul>
+ *
+ * <p>
+ * Beans are created through the following methods:
+ * <ul class='javatreec'>
+ * 	<li class='jm'>{@link #createBean(Class) createBean(Class)}
+ * 	<li class='jm'>{@link #createMethodFinder(Class) createMethodFinder(Class)}
+ * 	<li class='jm'>{@link #createMethodFinder(Class,Class) createMethodFinder(Class,Class)}
+ * 	<li class='jm'>{@link #createMethodFinder(Class,Object) createMethodFinder(Class,Object)}
+ * </ul>
+ *
+ * <ul>
+ * 	<li class='note'>Bean stores can be nested using {@link Builder#parent(BeanStore)}.
+ * 	<li class='note'>Bean stores can be made read-only using {@link Builder#readOnly()}.
+ * 	<li class='note'>Bean stores can be made thread-safe using {@link Builder#threadSafe()}.
+ * </ul>
  *
  * <ul class='seealso'>
  * 	<li class='extlink'>{@source}
@@ -89,48 +131,50 @@ public class BeanStore {
 	 * Builder class.
 	 */
 	@FluentSetters
-	public static class Builder extends BeanBuilder<BeanStore> {
+	public static class Builder {
 
 		BeanStore parent;
-		boolean readOnly;
+		boolean readOnly, threadSafe;
+		Object outer;
+		Class<? extends BeanStore> type;
+		BeanStore impl;
 
 		/**
 		 * Constructor.
 		 */
-		protected Builder() {
-			super(BeanStore.class);
-		}
-
-		/**
-		 * Copy constructor.
-		 *
-		 * @param copyFrom The bean store to copy from.
-		 */
-		protected Builder(BeanStore copyFrom) {
-			super(copyFrom.getClass());
-			parent = copyFrom.parent.orElse(null);
-			readOnly = copyFrom.readOnly;
-		}
+		protected Builder() {}
 
 		/**
-		 * Copy constructor.
+		 * Instantiates this bean store.
 		 *
-		 * @param copyFrom The bean store to copy from.
+		 * @return A new bean store.
 		 */
-		protected Builder(Builder copyFrom) {
-			super(copyFrom);
-			parent = copyFrom.parent;
-			readOnly = copyFrom.readOnly;
-		}
-
-		@Override /* BeanBuilder */
-		protected BeanStore buildDefault() {
-			return new BeanStore(this);
-		}
-
-		@Override /* BeanBuilder */
-		public Builder copy() {
-			return new Builder(this);
+		public BeanStore build() {
+			if (impl != null)
+				return impl;
+			if (type == null || type == BeanStore.class)
+				return new BeanStore(this);
+
+			ClassInfo c = ClassInfo.ofc(type);
+
+			MethodInfo m = c.getDeclaredMethod(
+				x -> x.isPublic() 
+				&& x.hasNoParams() 
+				&& x.isStatic() 
+				&& x.hasName("getInstance")
+			);
+			if (m != null)
+				return m.invoke(null);
+
+			Optional<ConstructorInfo> ci = c.publicConstructors().filter(x -> x.canAccept(this)).findFirst();
+			if (ci.isPresent())
+				return ci.get().invoke(this);
+
+			ci = c.protectedConstructors().filter(x -> x.canAccept(this)).findFirst();
+			if (ci.isPresent())
+				return ci.get().accessible().invoke(this);
+
+			throw runtimeException("Could not find a way to instantiate class {0}", type);
 		}
 
 		//-------------------------------------------------------------------------------------------------------------
@@ -166,48 +210,79 @@ public class BeanStore {
 			return this;
 		}
 
-		// <FluentSetters>
-
-		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
-		public Builder beanStore(BeanStore value) {
-			super.beanStore(value);
+		/**
+		 * Specifies that the bean store being created should be thread-safe.
+		 *
+		 * @return  This object.
+		 */
+		@FluentSetter
+		public Builder threadSafe() {
+			threadSafe = true;
 			return this;
 		}
 
-		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
-		public Builder impl(Object value) {
-			super.impl(value);
+		/**
+		 * Specifies the outer bean context.
+		 *
+		 * <p>
+		 * The outer context bean to use when calling constructors on inner classes.
+		 *
+		 * @param value The outer bean context.  Can be <jk>null</jk>.
+		 * @return  This object.
+		 */
+		@FluentSetter
+		public Builder outer(Object value) {
+			this.outer = value;
 			return this;
 		}
 
-		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
-		public Builder outer(Object value) {
-			super.outer(value);
+		/**
+		 * Overrides the bean to return from the {@link #build()} method.
+		 *
+		 * @param value The bean to return from the {@link #build()} method.
+		 * @return This object.
+		 */
+		@FluentSetter
+		public Builder impl(BeanStore value) {
+			this.impl = value;
 			return this;
 		}
 
-		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
-		public Builder type(Class<?> value) {
-			super.type(value);
+		/**
+		 * Overrides the bean store type.
+		 *
+		 * <p>
+		 * The specified type must have one of the following:
+		 * <ul>
+		 * 	<li>A static <c>getInstance()</c> method.
+		 * 	<li>A public constructor that takes in this builder.
+		 * 	<li>A protected constructor that takes in this builder.
+		 * </ul>
+		 *
+		 * @param value The bean store type.
+		 * @return This object.
+		 */
+		@FluentSetter
+		public Builder type(Class<? extends BeanStore> value) {
+			this.type = value;
 			return this;
 		}
-
-		// </FluentSetters>
 	}
 
 	//-----------------------------------------------------------------------------------------------------------------
 	// Instance
 	//-----------------------------------------------------------------------------------------------------------------
 
-	private final Map<String,Supplier<?>> beanMap = new ConcurrentHashMap<>();
+	private final Deque<BeanStoreEntry<?>> entries;
+	private final Map<Class<?>,BeanStoreEntry<?>> unnamedEntries;
+
 	final Optional<BeanStore> parent;
 	final Optional<Object> outer;
-	final boolean readOnly;
+	final boolean readOnly, threadSafe;
+	final SimpleReadWriteLock lock;
 
 	BeanStore() {
-		this.parent = empty();
-		this.outer = empty();
-		this.readOnly = false;
+		this(create());
 	}
 
 	/**
@@ -216,344 +291,412 @@ public class BeanStore {
 	 * @param builder The builder containing the settings for this bean.
 	 */
 	protected BeanStore(Builder builder) {
-		this.parent = ofNullable(builder.parent);
-		this.outer = builder.outer();
-		this.readOnly = builder.readOnly;
+		parent = ofNullable(builder.parent);
+		outer = ofNullable(builder.outer);
+		readOnly = builder.readOnly;
+		threadSafe = builder.threadSafe;
+		lock = threadSafe ? new SimpleReadWriteLock() : SimpleReadWriteLock.NO_OP;
+		entries = threadSafe ? new ConcurrentLinkedDeque<>() : new LinkedList<>();
+		unnamedEntries = threadSafe ? new ConcurrentHashMap<>() : new LinkedHashMap<>();
 	}
 
 	/**
-	 * Creates a copy of this bean store.
+	 * Adds an unnamed bean of the specified type to this factory.
 	 *
-	 * @return A mutable copy of this bean store.
+	 * @param <T> The class to associate this bean with.
+	 * @param beanType The class to associate this bean with.
+	 * @param bean The bean.  Can be <jk>null</jk>.
+	 * @return This object.
 	 */
-	public Builder copy() {
-		return new Builder(this);
+	public <T> BeanStore addBean(Class<T> beanType, T bean) {
+		return addBean(beanType, bean, null);
 	}
 
 	/**
-	 * Returns the named bean of the specified type.
+	 * Adds a named bean of the specified type to this factory.
 	 *
-	 * @param <T> The type of bean to return.
-	 * @param c The type of bean to return.
-	 * @param name The bean name.
-	 * @return The bean.
+	 * @param beanType The class to associate this bean with.
+	 * @param bean The bean.  Can be <jk>null</jk>.
+	 * @param name The bean name if this is a named bean.  Can be <jk>null</jk>.
+	 * @return This object.
 	 */
-	@SuppressWarnings("unchecked")
-	public <T> Optional<T> getBean(String name, Class<T> c) {
-		String key = name == null ? c.getName() : name;
-		Supplier<?> o = beanMap.get(key);
-		if (o == null && parent.isPresent())
-			return parent.get().getBean(name, c);
-		T t = (T)(o == null ? null : o.get());
-		return Optional.ofNullable(t);
+	public <T> BeanStore addBean(Class<T> beanType, T bean, String name) {
+		return addSupplier(beanType, ()->bean, name);
 	}
 
 	/**
-	 * Returns the bean of the specified type.
+	 * Adds a supplier for an unnamed bean of the specified type to this factory.
 	 *
-	 * @param <T> The type of bean to return.
-	 * @param c The type of bean to return.
-	 * @return The bean.
+	 * @param <T> The class to associate this bean with.
+	 * @param beanType The class to associate this bean with.
+	 * @param bean The bean supplier.
+	 * @return This object.
 	 */
-	public <T> Optional<T> getBean(Class<T> c) {
-		return getBean(c.getName(), c);
+	public <T> BeanStore addSupplier(Class<T> beanType, Supplier<T> bean) {
+		return addSupplier(beanType, bean, null);
 	}
 
 	/**
-	 * Adds a bean of the specified type to this factory.
+	 * Adds a supplier for a named bean of the specified type to this factory.
 	 *
 	 * @param <T> The class to associate this bean with.
-	 * @param c The class to associate this bean with.
-	 * @param t The bean.
+	 * @param beanType The class to associate this bean with.
+	 * @param bean The bean supplier.
+	 * @param name The bean name if this is a named bean.  Can be <jk>null</jk>.
 	 * @return This object.
 	 */
-	public <T> BeanStore addBean(Class<T> c, T t) {
+	public <T> BeanStore addSupplier(Class<T> beanType, Supplier<T> bean, String name) {
 		assertCanWrite();
-		return addBean(c.getName(), t);
+		BeanStoreEntry<T> e = createEntry(beanType, bean, name);
+		try (SimpleLock x = lock.write()) {
+			entries.addFirst(e);
+			if (name == null) unnamedEntries.put(beanType, e);
+		}
+		return this;
 	}
 
 	/**
-	 * Same as {@link #addBean(Class, Object)} but returns the bean instead of this object.
+	 * Same as {@link #addBean(Class,Object)} but returns the bean instead of this object for fluent calls.
 	 *
 	 * @param <T> The class to associate this bean with.
-	 * @param c The class to associate this bean with.
-	 * @param t The bean.
+	 * @param beanType The class to associate this bean with.
+	 * @param bean The bean.  Can be <jk>null</jk>.
 	 * @return The bean.
 	 */
-	public <T> T add(Class<T> c, T t) {
-		assertCanWrite();
-		addBean(c.getName(), t);
-		return t;
+	public <T> T add(Class<T> beanType, T bean) {
+		add(beanType, bean, null);
+		return bean;
 	}
 
 	/**
-	 * Same as {@link #addBean(String, Object)} but returns the bean instead of this object.
+	 * Same as {@link #addBean(Class,Object,String)} but returns the bean instead of this object for fluent calls.
 	 *
-	 * @param name The name to associate this bean with.
-	 * @param t The bean.
+	 * @param beanType The class to associate this bean with.
+	 * @param bean The bean.  Can be <jk>null</jk>.
+	 * @param name The bean name if this is a named bean.  Can be <jk>null</jk>.
 	 * @return The bean.
 	 */
-	public <T> T add(String name, T t) {
-		assertCanWrite();
-		addBean(name, t);
-		return t;
+	public <T> T add(Class<T> beanType, T bean, String name) {
+		addBean(beanType, bean, name);
+		return bean;
 	}
 
 	/**
-	 * Adds a named bean of the specified type to this factory.
+	 * Clears out all bean in this bean store.
+	 *
+	 * <p>
+	 * Does not affect the parent bean store.
 	 *
-	 * @param <T> The class to associate this bean with.
-	 * @param t The bean.
-	 * @param name The bean name if this is a named bean.
 	 * @return This object.
 	 */
-	public <T> BeanStore addBean(String name, T t) {
+	public BeanStore clear() {
 		assertCanWrite();
-		if (t == null)
-			beanMap.remove(name);
-		else
-			beanMap.put(name, ()->t);
+		try (SimpleLock x = lock.write()) {
+			unnamedEntries.clear();
+			entries.clear();
+		}
 		return this;
 	}
 
 	/**
-	 * Same as {@link #addBean(Class, Object)} but also adds subtypes of the bean.
+	 * Returns the unnamed bean of the specified type.
 	 *
-	 * @param <T> The class to associate this bean with.
-	 * @param c The class to associate this bean with.
-	 * @param t The bean.
-	 * @return This object.
+	 * @param beanType The type of bean to return.
+	 * @return The bean.
 	 */
 	@SuppressWarnings("unchecked")
-	public <T> BeanStore addBeans(Class<T> c, T t) {
-		assertCanWrite();
-		if (t == null)
-			beanMap.remove(c.getName());
-		else {
-			addBean(c, t);
-			Class<T> c2 = (Class<T>)t.getClass();
-			while (c2 != c) {
-				addBean(c2, t);
-				c2 = (Class<T>) c2.getSuperclass();
-			}
+	public <T> Optional<T> getBean(Class<T> beanType) {
+		try (SimpleLock x = lock.read()) {
+			BeanStoreEntry<T> e = (BeanStoreEntry<T>) unnamedEntries.get(beanType);
+			if (e != null)
+				return ofNullable(e.get());
+			if (parent.isPresent())
+				return parent.get().getBean(beanType);
+			return empty();
 		}
-		return this;
 	}
 
 	/**
-	 * Adds a bean supplier of the specified type to this factory.
+	 * Returns the named bean of the specified type.
 	 *
-	 * @param <T> The class to associate this bean with.
-	 * @param c The class to associate this bean with.
-	 * @param t The bean supplier.
-	 * @return This object.
+	 * @param beanType The type of bean to return.
+	 * @param name The bean name.  Can be <jk>null</jk>.
+	 * @return The bean.
 	 */
-	public <T> BeanStore addSupplier(Class<T> c, Supplier<T> t) {
-		assertCanWrite();
-		return addSupplier(c.getName(), t);
+	@SuppressWarnings("unchecked")
+	public <T> Optional<T> getBean(Class<T> beanType, String name)  {
+		try (SimpleLock x = lock.read()) {
+			BeanStoreEntry<T> e = (BeanStoreEntry<T>)entries.stream().filter(x2 -> x2.matches(beanType, name)).findFirst().orElse(null);
+			if (e != null)
+				return ofNullable(e.get());
+			if (parent.isPresent())
+				return parent.get().getBean(beanType, name);
+			return empty();
+		}
 	}
 
 	/**
-	 * Adds a named bean supplier of the specified type to this factory.
+	 * Returns all the beans in this store of the specified type.
 	 *
-	 * @param <T> The class to associate this bean with.
-	 * @param t The bean supplier.
-	 * @param name The bean name.
-	 * @return This object.
+	 * <p>
+	 * Returns both named and unnamed beans.
+	 *
+	 * <p>
+	 * The results from the parent bean store are appended to the list of beans from this beans store.
+	 *
+	 * @param beanType The bean type to return.
+	 * @return The bean entries.  Never <jk>null</jk>.
 	 */
-	public <T> BeanStore addSupplier(String name, Supplier<T> t) {
-		assertCanWrite();
-		if (t == null)
-			beanMap.remove(name);
-		else
-			beanMap.put(name, t);
-		return this;
+	public <T> Stream<BeanStoreEntry<T>> stream(Class<T> beanType)  {
+		@SuppressWarnings("unchecked")
+		Stream<BeanStoreEntry<T>> s = entries.stream().filter(x -> x.matches(beanType)).map(x -> (BeanStoreEntry<T>)x);
+		if (parent.isPresent())
+			s = Stream.concat(s, parent.get().stream(beanType));
+		return s;
 	}
 
 	/**
-	 * Removes a bean from this store.
+	 * Removes an unnamed bean from this store.
 	 *
-	 * <p>
-	 * This is equivalent to setting the bean type bean to <jk>null</jk>.
+	 * @param beanType The bean type being removed.
+	 * @return This object.
+	 */
+	public BeanStore removeBean(Class<?> beanType) {
+		return removeBean(beanType, null);
+	}
+
+	/**
+	 * Removes a named bean from this store.
 	 *
-	 * @param c The bean type being removed.
+	 * @param beanType The bean type being removed.
+	 * @param name The bean name to remove.
 	 * @return This object.
 	 */
-	public BeanStore removeBean(Class<?> c) {
-		return addBean(c.getName(), null);
+	public BeanStore removeBean(Class<?> beanType, String name) {
+		assertCanWrite();
+		try (SimpleLock x = lock.write()) {
+			if (name == null) unnamedEntries.remove(beanType);
+			entries.removeIf(y -> y.matches(beanType, name));
+		}
+		return this;
 	}
 
 	/**
-	 * Returns <jk>true</jk> if this factory contains the specified bean type instance.
+	 * Returns <jk>true</jk> if this store contains the specified unnamed bean type.
 	 *
-	 * @param c The bean type to check.
-	 * @return <jk>true</jk> if this factory contains the specified bean type instance.
+	 * @param beanType The bean type to check.
+	 * @return <jk>true</jk> if this store contains the specified unnamed bean type.
 	 */
-	public boolean hasBean(Class<?> c) {
-		return hasBean(c.getName());
+	public boolean hasBean(Class<?> beanType) {
+		return unnamedEntries.containsKey(beanType) || parent.map(x -> x.hasBean(beanType)).orElse(false);
 	}
 
 	/**
-	 * Returns <jk>true</jk> if this factory contains a bean with the specified name.
+	 * Returns <jk>true</jk> if this store contains the specified named bean type.
 	 *
+	 * @param beanType The bean type to check.
 	 * @param name The bean name.
-	 * @return <jk>true</jk> if this factory contains a bean with the specified name.
+	 * @return <jk>true</jk> if this store contains the specified named bean type.
 	 */
-	public boolean hasBean(String name) {
-		if (getBean(name, Object.class).isPresent())
-			return true;
-		if (parent.isPresent())
-			return parent.get().hasBean(name);
-		return false;
+	public boolean hasBean(Class<?> beanType, String name) {
+		return entries.stream().anyMatch(x -> x.matches(beanType, name)) || parent.map(x -> x.hasBean(beanType, name)).orElse(false);
 	}
 
 	/**
 	 * Instantiates a bean creator.
 	 *
-	 * @param c The bean type to create.
+	 * <ul class='seealso'>
+	 * 	<li class='jc'>{@link BeanCreator} for usage.
+	 * </ul>
+	 *
+	 * @param beanType The bean type to create.
 	 * @return A new bean creator.
 	 */
-	public <T> BeanCreator<T> creator(Class<T> c) {
-		return new BeanCreator<>(c).store(this).outer(outer.orElse(null));
+	public <T> BeanCreator<T> createBean(Class<T> beanType) {
+		return new BeanCreator<>(beanType, this);
 	}
 
 	/**
 	 * Create a method finder for finding bean creation methods.
 	 *
-	 * <h5 class='section'>Example:</h5>
-	 * <p class='bcode w800'>
-	 * 	<jc>// The bean we want to create.</jc>
-	 * 	<jk>public class</jk> A {}
-	 *
-	 * 	<jc>// The bean that has a creator method for the bean above.</jc>
-	 * 	<jk>public class</jk> B {
-	 *
-	 * 		<jc>// Creator method.</jc>
-	 * 		<jc>// Bean store must have a C bean and optionally a D bean.</jc>
-	 * 		<jk>public</jk> A createA(C <mv>c</mv>, Optional&lt;D&gt; <mv>d</mv>) {
-	 * 			<jk>return new</jk> A(<mv>c</mv>, <mv>d</mv>.orElse(<jk>null</jk>));
-	 * 		}
-	 * 	}
-	 *
-	 * 	<jc>// Instantiate the bean with the creator method.</jc>
-	 * 	B <mv>b</mv> = <jk>new</jk> B();
-	 *
-	 *  <jc>// Create a bean store with some mapped beans.</jc>
-	 * 	BeanStore <mv>beanStore</mv> = BeanStore.<jsm>create</jsm>().addBean(C.<jk>class</jk>, <jk>new</jk> C());
-	 *
-	 * 	<jc>// Instantiate the bean using the creator method.</jc>
-	 * 	A <mv>a</mv> = <mv>beanStore</mv>
-	 * 		.beanCreateMethodFinder(A.<jk>class</jk>, <mv>b</mv>)  <jc>// Looking for creator for A on b object.</jc>
-	 * 		.find(<js>"createA"</js>)                         <jc>// Look for method called "createA".</jc>
-	 * 		.thenFind(<js>"createA2"</js>)                    <jc>// Then look for method called "createA2".</jc>
-	 * 		.withDefault(()-&gt;<jk>new</jk> A())                        <jc>// Optionally supply a default value if method not found.</jc>
-	 * 		.run();                                  <jc>// Execute.</jc>
-	 * </p>
+	 * <ul class='seealso'>
+	 * 	<li class='jc'>{@link BeanCreateMethodFinder} for usage.
+	 * </ul>
 	 *
 	 * @param <T> The bean type to create.
-	 * @param c The bean type to create.
+	 * @param beanType The bean type to create.
 	 * @param resource The class containing the bean creator method.
-	 * @return The created bean or the default value if method could not be found.
+	 * @return The method finder.  Never <jk>null</jk>.
 	 */
-	public <T> BeanCreateMethodFinder<T> createMethodFinder(Class<T> c, Object resource) {
-		return new BeanCreateMethodFinder<>(c, resource, this);
+	public <T> BeanCreateMethodFinder<T> createMethodFinder(Class<T> beanType, Object resource) {
+		return new BeanCreateMethodFinder<>(beanType, resource, this);
 	}
 
 	/**
-	 * Constructor.
+	 * Create a method finder for finding bean creation methods.
+	 *
+	 * <p>
+	 * Same as {@link #createMethodFinder(Class,Class)} but looks for only static methods on the specified resource class
+	 * and not also instance methods within the context of a bean.
 	 *
-	 * @param c The bean type to create.
+	 * <ul class='seealso'>
+	 * 	<li class='jc'>{@link BeanCreateMethodFinder} for usage.
+	 * </ul>
+	 *
+	 * @param beanType The bean type to create.
 	 * @param resourceClass The class containing the bean creator method.
-	 * @return The created bean or the default value if method could not be found.
+	 * @return The method finder.  Never <jk>null</jk>.
 	 */
-	public <T> BeanCreateMethodFinder<T> createMethodFinder(Class<T> c, Class<?> resourceClass) {
-		return new BeanCreateMethodFinder<>(c, resourceClass, this);
+	public <T> BeanCreateMethodFinder<T> createMethodFinder(Class<T> beanType, Class<?> resourceClass) {
+		return new BeanCreateMethodFinder<>(beanType, resourceClass , this);
 	}
 
 	/**
-	 * Constructor.
+	 * Create a method finder for finding bean creation methods.
+	 *
+	 * <p>
+	 * Same as {@link #createMethodFinder(Class,Object)} but uses {@link Builder#outer(Object)} as the resource bean.
+	 *
+	 * <ul class='seealso'>
+	 * 	<li class='jc'>{@link BeanCreateMethodFinder} for usage.
+	 * </ul>
+	 *
+	 * @param beanType The bean type to create.
+	 * @return The method finder.  Never <jk>null</jk>.
+	 */
+	public <T> BeanCreateMethodFinder<T> createMethodFinder(Class<T> beanType) {
+		return new BeanCreateMethodFinder<>(beanType, outer.orElseThrow(()->runtimeException("Method cannot be used without outer bean definition.")), this);
+	}
+
+	/**
+	 * Given an executable, returns a list of types that are missing from this factory.
 	 *
-	 * @param c The bean type to create.
-	 * @return The created bean or the default value if method could not be found.
+	 * @param executable The constructor or method to get the params for.
+	 * @return A comma-delimited list of types that are missing from this factory, or <jk>null</jk> if none are missing.
 	 */
-	public <T> BeanCreateMethodFinder<T> beanCreateMethodFinder(Class<T> c) {
-		if (outer == null)
-			throw runtimeException("Method cannot be used without outer bean definition.");
-		return new BeanCreateMethodFinder<>(c, outer, this);
+	public String getMissingParams(ExecutableInfo executable) {
+		List<ParamInfo> params = executable.getParams();
+		List<String> l = AList.create();
+		loop: for (int i = 0; i < params.size(); i++) {
+			ParamInfo pi = params.get(i);
+			ClassInfo pt = pi.getParameterType();
+			if (i == 0 && outer.isPresent() && pt.isInstance(outer.get()))
+				continue loop;
+			if (pt.is(Optional.class) || pt.is(BeanStore.class))
+				continue loop;
+			String beanName = findBeanName(pi);
+			Class<?> ptc = pt.inner();
+			if (beanName == null && !hasBean(ptc))
+				l.add(pt.getSimpleName());
+			if (beanName != null && !hasBean(ptc, beanName))
+				l.add(pt.getSimpleName() + '@' + beanName);
+		}
+		return l.isEmpty() ? null : l.stream().sorted().collect(joining(","));
 	}
 
 	/**
-	 * Given the list of param types, returns a list of types that are missing from this factory.
+	 * Given the list of param types, returns <jk>true</jk> if this factory has all the parameters for the specified executable.
 	 *
-	 * @param params The param types to chec.
-	 * @return A list of types that are missing from this factory.
+	 * @param executable The constructor or method to get the params for.
+	 * @return A comma-delimited list of types that are missing from this factory.
 	 */
-	public List<ClassInfo> getMissingParamTypes(List<ParamInfo> params) {
-		List<ClassInfo> l = AList.create();
+	public boolean hasAllParams(ExecutableInfo executable) {
+		List<ParamInfo> params = executable.getParams();
 		loop: for (int i = 0; i < params.size(); i++) {
 			ParamInfo pi = params.get(i);
 			ClassInfo pt = pi.getParameterType();
-			ClassInfo ptu = pt.unwrap(Optional.class);
-			if (i == 0 && ptu.isInstance(outer.orElse(null)))
+			if (i == 0 && outer.isPresent() && pt.isInstance(outer.get()))
 				continue loop;
-			if (pt.is(Optional.class))
+			if (pt.is(Optional.class) || pt.is(BeanStore.class))
 				continue loop;
 			String beanName = findBeanName(pi);
-			if (beanName == null)
-				beanName = ptu.inner().getName();
-			if (! hasBean(beanName))
-				l.add(pt);
+			Class<?> ptc = pt.inner();
+			if (beanName == null && !hasBean(ptc))
+				return false;
+			if (beanName != null && !hasBean(ptc, beanName))
+				return false;
 		}
-		return l;
+		return true;
 	}
 
+
 	/**
 	 * Returns the corresponding beans in this factory for the specified param types.
 	 *
-	 * @param params The parameters to get from this factory.
+	 * @param executable The constructor or method to get the params for.
 	 * @return The corresponding beans in this factory for the specified param types.
 	 */
-	public Object[] getParams(List<ParamInfo> params) {
+	public Object[] getParams(ExecutableInfo executable) {
+		List<ParamInfo> params = executable.getParams();
 		Object[] o = new Object[params.size()];
 		for (int i = 0; i < params.size(); i++) {
 			ParamInfo pi = params.get(i);
 			ClassInfo pt = pi.getParameterType();
-			ClassInfo ptu = pt.unwrap(Optional.class);
-			if (i == 0 && ptu.isInstance(outer.orElse(null)))
+			if (i == 0 && outer.isPresent() && pt.isInstance(outer.get())) {
 				o[i] = outer.get();
-			else {
+			} else if (pt.is(BeanStore.class)) {
+				o[i] = this;
+			} else {
 				String beanName = findBeanName(pi);
-				if (pt.is(Optional.class)) {
-					o[i] = getBean(beanName, ptu.inner());
-				} else {
-					o[i] = getBean(beanName, ptu.inner()).get();
-				}
+				Class<?> ptc = pt.unwrap(Optional.class).inner();
+				Optional<?> o2 = beanName == null ? getBean(ptc) : getBean(ptc, beanName);
+				o[i] = pt.is(Optional.class) ? o2 : o2.orElse(null);
 			}
 		}
 		return o;
 	}
 
+	@Override /* Object */
+	public String toString() {
+		return properties().asString();
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Extension methods
+	//-----------------------------------------------------------------------------------------------------------------
+
+	/**
+	 * Creates an entry in this store for the specified bean.
+	 *
+	 * <p>
+	 * Subclasses can override this method to create their own entry subtypes.
+	 *
+	 * @param type The class type to associate with the bean.
+	 * @param bean The bean supplier.
+	 * @param name Optional name to associate with the bean.  Can be <jk>null</jk>.
+	 * @return A new bean store entry.
+	 */
+	protected <T> BeanStoreEntry<T> createEntry(Class<T> type, Supplier<T> bean, String name) {
+		return BeanStoreEntry.create(type, bean, name);
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Helper methods
+	//-----------------------------------------------------------------------------------------------------------------
 	private String findBeanName(ParamInfo pi) {
-		Optional<Annotation> namedAnnotation = pi.getAnnotations(Annotation.class).stream().filter(x->x.annotationType().getSimpleName().equals("Named")).findFirst();
+		Optional<Annotation> namedAnnotation = pi.getAnnotations(Annotation.class).stream().filter(x->isNamedAnnotation(x.annotationType())).findFirst();
 		if (namedAnnotation.isPresent())
 			return AnnotationInfo.of((ClassInfo)null, namedAnnotation.get()).getValue(String.class, "value").orElse(null);
 		return null;
 	}
 
+	private boolean isNamedAnnotation(Class<?> c) {
+		String s = c.getSimpleName();
+		return s.equals("Named");
+	}
+
 	private void assertCanWrite() {
 		if (readOnly)
 			throw runtimeException("Method cannot be used because BeanStore is read-only.");
 	}
 
-	OMap properties() {
+	private OMap properties() {
 		return filteredMap()
-			.a("beanMap", beanMap.keySet())
-			.a("outer", ObjectUtils.identity(outer))
-			.a("parent", parent.map(x->x.properties()).orElse(null));
-	}
-
-	@Override /* Object */
-	public String toString() {
-		return properties().asString();
+			.a("entries", entries.stream().map(x -> x.properties()).collect(toList()))
+			.a("outer", ObjectUtils.identity(outer.orElse(null)))
+			.a("parent", parent.map(x->x.properties()).orElse(null))
+			.appendSkipFalse("readOnly", readOnly)
+			.appendSkipFalse("threadSafe", threadSafe)
+		;
 	}
 }
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/BeanStoreEntry.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/BeanStoreEntry.java
new file mode 100644
index 0000000..e52f12b
--- /dev/null
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/BeanStoreEntry.java
@@ -0,0 +1,135 @@
+// ***************************************************************************************************************************
+// * 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.cp;
+
+import static org.apache.juneau.assertions.Assertions.*;
+import static org.apache.juneau.collections.OMap.*;
+import static org.apache.juneau.internal.ClassUtils.*;
+
+import java.util.function.*;
+
+import org.apache.juneau.collections.*;
+import org.apache.juneau.internal.*;
+
+/**
+ * Represents a bean in a {@link BeanStore}.
+ *
+ * <p>
+ * A bean entry consists of the following:
+ * <ul>
+ * 	<li>A class type.
+ * 	<li>A bean or bean supplier that returns an instance of the class type.  This can be a subclass of the type.
+ * 	<li>An optional name.
+ * </ul>
+ *
+ * @param <T> The bean type.
+ */
+public class BeanStoreEntry<T> {
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Static
+	//-----------------------------------------------------------------------------------------------------------------
+
+	/**
+	 * Static creator.
+	 *
+	 * @param type The class type to associate with the bean.
+	 * @param bean The bean supplier.
+	 * @param name Optional name to associate with the bean.  Can be <jk>null</jk>.
+	 * @return A new bean store entry.
+	 */
+	public static <T> BeanStoreEntry<T> create(Class<T> type, Supplier<T> bean, String name) {
+		return new BeanStoreEntry<>(type, bean, name);
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Instance
+	//-----------------------------------------------------------------------------------------------------------------
+
+	final Supplier<T> bean;
+	final Class<T> type;
+	final String name;
+
+	/**
+	 * Constructor.
+	 *
+	 * @param type The class type to associate with the bean.
+	 * @param bean The bean supplier.
+	 * @param name Optional name to associate with the bean.  Can be <jk>null</jk>.
+	 */
+	protected BeanStoreEntry(Class<T> type, Supplier<T> bean, String name) {
+		this.bean = assertArgNotNull("bean", bean);
+		this.type = assertArgNotNull("type", type);
+		this.name = name;
+	}
+
+	/**
+	 * Returns <jk>true</jk> if this bean is exactly of the specified type.
+	 *
+	 * @param type The class to check.  Returns <jk>false</jk> if <jk>null</jk>.
+	 * @return <jk>true</jk> if this bean is exactly of the specified type.
+	 */
+	public boolean matches(Class<?> type) {
+		return this.type.equals(type);
+	}
+
+	/**
+	 * Returns <jk>true</jk> if this bean is exactly of the specified type and has the specified name.
+	 *
+	 * @param type The class to check.  Returns <jk>false</jk> if <jk>null</jk>.
+	 * @param name The name to check.  Can be <jk>null</jk> to only match if name of entry is <jk>null</jk>.
+	 * @return <jk>true</jk> if this bean is exactly of the specified type and has the specified name.
+	 */
+	public boolean matches(Class<?> type, String name) {
+		return matches(type) && StringUtils.eq(this.name, name);
+	}
+
+	/**
+	 * Returns the bean associated with this entry.
+	 *
+	 * @return The bean associated with this entry.
+	 */
+	public T get() {
+		return bean.get();
+	}
+
+	/**
+	 * Returns the type this bean is associated with.
+	 *
+	 * @return The type this bean is associated with.
+	 */
+	public Class<T> getType() {
+		return type;
+	}
+
+	/**
+	 * Returns the name associated with this entry.
+	 *
+	 * @return the name associated with this entry.  <jk>null</jk> if no name is associated.
+	 */
+	public String getName() {
+		return name;
+	}
+
+	/**
+	 * Returns the properties in this object as a simple map for debugging purposes.
+	 *
+	 * @return The properties in this object as a simple map.
+	 */
+	protected OMap properties() {
+		return filteredMap()
+			.a("type", simpleClassName(getType()))
+			.a("bean", ObjectUtils.identity(get()))
+			.a("name", getName());
+	}
+}
\ No newline at end of file
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/FileFinder.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/FileFinder.java
index 2819340..1d8587a 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/FileFinder.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/FileFinder.java
@@ -78,8 +78,8 @@ import org.apache.juneau.internal.*;
  * Subclasses must provide a public constructor that takes in any of the following arguments:
  * <ul>
  * 	<li>{@link Builder} - The builder object.
- * 	<li>Any beans present in the registered {@link Builder#beanStore(BeanStore) bean store}.
- * 	<li>Any {@link Optional} beans optionally present in the registered {@link Builder#beanStore(BeanStore) bean store}.
+ * 	<li>Any beans present in the bean store passed into the constructor.
+ * 	<li>Any {@link Optional} beans optionally present in bean store passed into the constructor.
  * </ul>
  *
  * <ul class='seealso'>
@@ -96,12 +96,22 @@ public interface FileFinder {
 	public abstract class Null implements FileFinder {}
 
 	/**
-	 * Instantiate a new builder.
+	 * Static creator.
 	 *
-	 * @return A new builder.
+	 * @param beanStore The bean store to use for creating beans.
+	 * @return A new builder for this object.
+	 */
+	public static Builder create(BeanStore beanStore) {
+		return new Builder(beanStore);
+	}
+
+	/**
+	 * Static creator.
+	 *
+	 * @return A new builder for this object.
 	 */
 	public static Builder create() {
-		return new Builder();
+		return new Builder(BeanStore.INSTANCE);
 	}
 
 	//-----------------------------------------------------------------------------------------------------------------
@@ -120,38 +130,22 @@ public interface FileFinder {
 
 		/**
 		 * Constructor.
+		 *
+		 * @param beanStore The bean store to use for creating beans.
 		 */
-		protected Builder() {
-			super(BasicFileFinder.class);
+		protected Builder(BeanStore beanStore) {
+			super(BasicFileFinder.class, beanStore);
 			roots = new LinkedHashSet<>();
 			cachingLimit = -1;
 			include = AList.of(Pattern.compile(".*"));
 			exclude = AList.create();
 		}
 
-		/**
-		 * Copy constructor.
-		 *
-		 * @param copyFrom The builder being copied.
-		 */
-		protected Builder(Builder copyFrom) {
-			super(copyFrom);
-			roots = new LinkedHashSet<>(copyFrom.roots);
-			cachingLimit = copyFrom.cachingLimit;
-			include = AList.of(copyFrom.include);
-			exclude = AList.of(copyFrom.exclude);
-		}
-
 		@Override /* BeanBuilder */
 		protected FileFinder buildDefault() {
 			return new BasicFileFinder(this);
 		}
 
-		@Override /* BeanBuilder */
-		public Builder copy() {
-			return new Builder(this);
-		}
-
 		//-------------------------------------------------------------------------------------------------------------
 		// Properties
 		//-------------------------------------------------------------------------------------------------------------
@@ -241,24 +235,12 @@ public interface FileFinder {
 		// <FluentSetters>
 
 		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
-		public Builder beanStore(BeanStore value) {
-			super.beanStore(value);
-			return this;
-		}
-
-		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
 		public Builder impl(Object value) {
 			super.impl(value);
 			return this;
 		}
 
 		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
-		public Builder outer(Object value) {
-			super.outer(value);
-			return this;
-		}
-
-		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
 		public Builder type(Class<?> value) {
 			super.type(value);
 			return this;
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/Messages.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/Messages.java
index e96ee29..ac4edcd 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/Messages.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/cp/Messages.java
@@ -174,27 +174,13 @@ public class Messages extends ResourceBundle {
 		 * @param forClass The base class.
 		 */
 		protected Builder(Class<?> forClass) {
-			super(Messages.class);
+			super(Messages.class, BeanStore.INSTANCE);
 			this.forClass = forClass;
 			this.name = forClass.getSimpleName();
 			locations = new ArrayList<>();
 			locale = Locale.getDefault();
 		}
 
-		/**
-		 * Copy constructor.
-		 *
-		 * @param copyFrom The builder being copied.
-		 */
-		protected Builder(Builder copyFrom) {
-			super(copyFrom);
-			forClass = copyFrom.forClass;
-			locale = copyFrom.locale;
-			name = copyFrom.name;
-			parent = copyFrom.parent;
-			locations = new ArrayList<>(copyFrom.locations);
-		}
-
 		@Override /* BeanBuilder */
 		protected Messages buildDefault() {
 
@@ -231,11 +217,6 @@ public class Messages extends ResourceBundle {
 			public String locale;
 		}
 
-		@Override /* BeanBuilder */
-		public Builder copy() {
-			return new Builder(this);
-		}
-
 		//-------------------------------------------------------------------------------------------------------------
 		// Properties
 		//-------------------------------------------------------------------------------------------------------------
@@ -323,24 +304,12 @@ public class Messages extends ResourceBundle {
 		// <FluentSetters>
 
 		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
-		public Builder beanStore(BeanStore value) {
-			super.beanStore(value);
-			return this;
-		}
-
-		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
 		public Builder impl(Object value) {
 			super.impl(value);
 			return this;
 		}
 
 		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
-		public Builder outer(Object value) {
-			super.outer(value);
-			return this;
-		}
-
-		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
 		public Builder type(Class<?> value) {
 			super.type(value);
 			return this;
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/encoders/EncoderSet.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/encoders/EncoderSet.java
index 041c0ef..311e36a 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/encoders/EncoderSet.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/encoders/EncoderSet.java
@@ -95,12 +95,22 @@ public final class EncoderSet {
 	public static abstract class NoInherit extends Encoder {}
 
 	/**
-	 * Instantiates a new clean-slate {@link EncoderSet.Builder} object.
+	 * Static creator.
 	 *
-	 * @return A new {@link EncoderSet.Builder} object.
+	 * @param beanStore The bean store to use for creating beans.
+	 * @return A new builder for this object.
+	 */
+	public static Builder create(BeanStore beanStore) {
+		return new Builder(beanStore);
+	}
+
+	/**
+	 * Static creator.
+	 *
+	 * @return A new builder for this object.
 	 */
 	public static Builder create() {
-		return new Builder();
+		return new Builder(BeanStore.INSTANCE);
 	}
 
 	//-----------------------------------------------------------------------------------------------------------------
@@ -117,9 +127,11 @@ public final class EncoderSet {
 
 		/**
 		 * Constructor.
+		 *
+		 * @param beanStore The bean store to use for creating beans.
 		 */
-		protected Builder() {
-			super(EncoderSet.class);
+		protected Builder(BeanStore beanStore) {
+			super(EncoderSet.class, beanStore);
 			entries = AList.create();
 		}
 
@@ -138,7 +150,11 @@ public final class EncoderSet {
 			return new EncoderSet(this);
 		}
 
-		@Override /* BeanBuilder */
+		/**
+		 * Makes a copy of this builder.
+		 *
+		 * @return A new copy of this builder.
+		 */
 		public Builder copy() {
 			return new Builder(this);
 		}
@@ -254,24 +270,12 @@ public final class EncoderSet {
 		// <FluentSetters>
 
 		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
-		public Builder beanStore(BeanStore value) {
-			super.beanStore(value);
-			return this;
-		}
-
-		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
 		public Builder impl(Object value) {
 			super.impl(value);
 			return this;
 		}
 
 		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
-		public Builder outer(Object value) {
-			super.outer(value);
-			return this;
-		}
-
-		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
 		public Builder type(Class<?> value) {
 			super.type(value);
 			return this;
@@ -314,7 +318,7 @@ public final class EncoderSet {
 	 * @param builder The builder for this object.
 	 */
 	protected EncoderSet(Builder builder) {
-		entries = builder.entries.stream().map(x -> instantiate(builder.beanStore().orElse(BeanStore.INSTANCE), x)).toArray(Encoder[]::new);
+		entries = builder.entries.stream().map(x -> instantiate(builder.beanStore(), x)).toArray(Encoder[]::new);
 
 		List<String> lc = AList.create();
 		List<Encoder> l = AList.create();
@@ -333,7 +337,7 @@ public final class EncoderSet {
 		if (o instanceof Encoder)
 			return (Encoder)o;
 		try {
-			return bs.creator(Encoder.class).type((Class<?>)o).run();
+			return bs.createBean(Encoder.class).type((Class<?>)o).run();
 		} catch (ExecutableException e) {
 			throw runtimeException(e);
 		}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/header/HeaderList.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/header/HeaderList.java
index 23f5607..bf8b22b 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/header/HeaderList.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/header/HeaderList.java
@@ -260,7 +260,7 @@ public class HeaderList {
 		 * Constructor.
 		 */
 		protected Builder() {
-			super(HeaderList.class);
+			super(HeaderList.class, BeanStore.INSTANCE);
 			entries = new ArrayList<>();
 		}
 
@@ -270,7 +270,7 @@ public class HeaderList {
 		 * @param copyFrom The bean to copy.
 		 */
 		protected Builder(HeaderList copyFrom) {
-			super(copyFrom.getClass());
+			super(copyFrom.getClass(), BeanStore.INSTANCE);
 			entries = new ArrayList<>(copyFrom.entries.length);
 			for (int i = 0; i < copyFrom.entries.length; i++)
 				entries.add(copyFrom.entries[i]);
@@ -295,7 +295,11 @@ public class HeaderList {
 			return entries.isEmpty() && defaultEntries == null ? EMPTY : new HeaderList(this);
 		}
 
-		@Override /* BeanBuilder */
+		/**
+		 * Makes a copy of this builder.
+		 *
+		 * @return A new copy of this builder.
+		 */
 		public Builder copy() {
 			return new Builder(this);
 		}
@@ -1165,24 +1169,12 @@ public class HeaderList {
 		// <FluentSetters>
 
 		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
-		public Builder beanStore(BeanStore value) {
-			super.beanStore(value);
-			return this;
-		}
-
-		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
 		public Builder impl(Object value) {
 			super.impl(value);
 			return this;
 		}
 
 		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
-		public Builder outer(Object value) {
-			super.outer(value);
-			return this;
-		}
-
-		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
 		public Builder type(Class<?> value) {
 			super.type(value);
 			return this;
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/part/PartList.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/part/PartList.java
index d7a6fac..01fd59c 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/part/PartList.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/part/PartList.java
@@ -23,7 +23,6 @@ import java.util.stream.*;
 import org.apache.http.*;
 import org.apache.http.util.*;
 import org.apache.juneau.*;
-import org.apache.juneau.cp.*;
 import org.apache.juneau.http.HttpParts;
 import org.apache.juneau.http.annotation.*;
 import org.apache.juneau.internal.*;
@@ -283,7 +282,11 @@ public class PartList {
 			return entries.isEmpty() && defaultEntries == null ? EMPTY : new PartList(this);
 		}
 
-		@Override /* BeanBuilder */
+		/**
+		 * Makes a copy of this builder.
+		 *
+		 * @return A new copy of this builder.
+		 */
 		public Builder copy() {
 			return new Builder(this);
 		}
@@ -1147,24 +1150,12 @@ public class PartList {
 		// <FluentSetters>
 
 		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
-		public Builder beanStore(BeanStore value) {
-			super.beanStore(value);
-			return this;
-		}
-
-		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
 		public Builder impl(Object value) {
 			super.impl(value);
 			return this;
 		}
 
 		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
-		public Builder outer(Object value) {
-			super.outer(value);
-			return this;
-		}
-
-		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
 		public Builder type(Class<?> value) {
 			super.type(value);
 			return this;
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/remote/RrpcInterfaceMeta.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/remote/RrpcInterfaceMeta.java
index b4d1539..e13e861 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/remote/RrpcInterfaceMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/remote/RrpcInterfaceMeta.java
@@ -57,8 +57,10 @@ public class RrpcInterfaceMeta {
 				path = trimSlashes(r.path());
 
 		AMap<Method,RrpcInterfaceMethodMeta> methods = AMap.create();
-		for (MethodInfo m : ci.getPublicMethods())
-			methods.put(m.inner(), new RrpcInterfaceMethodMeta(uri, m.inner()));
+		ci.getPublicMethods(
+			x -> true, 
+			x -> methods.put(x.inner(), new RrpcInterfaceMethodMeta(uri, x.inner()))
+		);
 
 		AMap<String,RrpcInterfaceMethodMeta> methodsByPath = AMap.create();
 		for (RrpcInterfaceMethodMeta rmm : methods.values())
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/bean/RequestBeanMeta.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/bean/RequestBeanMeta.java
index 8ce8732..ee79b31 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/bean/RequestBeanMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/bean/RequestBeanMeta.java
@@ -71,8 +71,8 @@ public class RequestBeanMeta {
 
 	RequestBeanMeta(Builder b) {
 		this.cm = b.cm;
-		this.serializer = BeanCreator.of(HttpPartSerializer.class).type(b.serializer).run();
-		this.parser = BeanCreator.of(HttpPartParser.class).type(b.parser).run();
+		this.serializer = BeanStore.INSTANCE.createBean(HttpPartSerializer.class).type(b.serializer).run();
+		this.parser = BeanStore.INSTANCE.createBean(HttpPartParser.class).type(b.parser).run();
 		Map<String,RequestBeanPropertyMeta> properties = new LinkedHashMap<>();
 		for (Map.Entry<String,RequestBeanPropertyMeta.Builder> e : b.properties.entrySet())
 			properties.put(e.getKey(), e.getValue().build(serializer, parser));
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/bean/RequestBeanPropertyMeta.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/bean/RequestBeanPropertyMeta.java
index 3e608b0..434f203 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/bean/RequestBeanPropertyMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/bean/RequestBeanPropertyMeta.java
@@ -56,8 +56,8 @@ public class RequestBeanPropertyMeta {
 		this.partType = b.partType;
 		this.schema = b.schema;
 		this.getter = b.getter;
-		this.serializer = ofNullable(schema.getSerializer() == null ? serializer : BeanCreator.of(HttpPartSerializer.class).type(schema.getSerializer()).run());
-		this.parser = schema.getParser() == null ? parser : BeanCreator.of(HttpPartParser.class).type(schema.getParser()).run();
+		this.serializer = ofNullable(schema.getSerializer() == null ? serializer : BeanStore.INSTANCE.createBean(HttpPartSerializer.class).type(schema.getSerializer()).run());
+		this.parser = schema.getParser() == null ? parser : BeanStore.INSTANCE.createBean(HttpPartParser.class).type(schema.getParser()).run();
 	}
 
 	static class Builder {
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ClassUtils.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ClassUtils.java
index 86a5350..3be64eb 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ClassUtils.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/ClassUtils.java
@@ -13,10 +13,10 @@
 package org.apache.juneau.internal;
 
 import static org.apache.juneau.internal.ThrowableUtils.*;
-
 import java.lang.reflect.*;
 import java.util.*;
 
+import org.apache.juneau.*;
 import org.apache.juneau.collections.*;
 import org.apache.juneau.reflect.*;
 
@@ -112,7 +112,8 @@ public final class ClassUtils {
 			try {
 				ClassInfo c3 = ClassInfo.of((Class<?>)c2);
 
-				MethodInfo mi = fuzzyArgs ? c3.getStaticCreatorFuzzy(args) : c3.getStaticCreator(args);
+				MethodInfo mi = fuzzyArgs ? getStaticCreatorFuzzy(c3, args) : getStaticCreator(c3, args);
+
 				if (mi != null)
 					return fuzzyArgs ? (T)mi.invokeFuzzy(null, args) : mi.invoke(null, args);
 
@@ -134,7 +135,7 @@ public final class ClassUtils {
 
 				// Finally use fuzzy matching.
 				if (fuzzyArgs) {
-					mi = c3.getStaticCreatorFuzzy(args);
+					mi = getStaticCreatorFuzzy(c3, args);
 					if (mi != null)
 						return mi.invoke(null, getMatchingArgs(mi.getParamTypes(), args));
 
@@ -154,6 +155,32 @@ public final class ClassUtils {
 		}
 	}
 
+
+	private static MethodInfo getStaticCreatorFuzzy(ClassInfo c, Object...args) {
+		int bestCount = -1;
+		MethodInfo bestMatch = null;
+		for (MethodInfo m : c.getPublicMethods()) {
+			if (m.matches(x -> x.isStatic() && x.isNotDeprecated() && x.hasReturnType(c) && x.hasName("create","getInstance"))) {
+				int mn = m.canAcceptFuzzy(args);
+				if (mn > bestCount) {
+					bestCount = mn;
+					bestMatch = m;
+				}
+			}
+		}
+		return bestMatch;
+	}
+
+	private static MethodInfo getStaticCreator(ClassInfo c, Object...args) {
+		return c.getPublicMethod(
+			x -> x.isStatic()
+			&& x.isNotDeprecated()
+			&& x.hasReturnType(c)
+			&& x.hasName("create","getInstance")
+			&& x.canAccept(args)
+		);
+	}
+
 	/**
 	 * Matches arguments to a list of parameter types.
 	 *
@@ -273,7 +300,7 @@ public final class ClassUtils {
 	}
 
 	/**
-	 * Returns the class name for the specified object.
+	 * Returns the fully-qualified class name for the specified object.
 	 *
 	 * @param value The object to get the class name for.
 	 * @return The name of the class or <jk>null</jk> if the value was null.
@@ -281,4 +308,22 @@ public final class ClassUtils {
 	public static String className(Object value) {
 		return value == null ? null : value instanceof Class<?> ? ((Class<?>)value).getName() : value.getClass().getName();
 	}
+
+	/**
+	 * Returns the simple class name for the specified object.
+	 *
+	 * @param value The object to get the class name for.
+	 * @return The name of the class or <jk>null</jk> if the value was null.
+	 */
+	public static String simpleClassName(Object value) {
+		if (value == null)
+			return null;
+		if (value instanceof ClassInfo)
+			return ((ClassInfo)value).getSimpleName();
+		if (value instanceof ClassMeta)
+			return ((ClassMeta<?>)value).getSimpleName();
+		if (value instanceof Class)
+			return ((Class<?>)value).getSimpleName();
+		return value.getClass().getSimpleName();
+	}
 }
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/SimpleLock.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/SimpleLock.java
index 610b885..7e37978 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/SimpleLock.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/SimpleLock.java
@@ -19,6 +19,11 @@ import java.util.concurrent.locks.Lock;
  */
 public class SimpleLock implements AutoCloseable {
 
+	/**
+	 * A simple no-op lock.
+	 */
+	public static final SimpleLock NO_OP = new SimpleLock(null);
+
 	private final Lock lock;
 
 	/**
@@ -28,11 +33,11 @@ public class SimpleLock implements AutoCloseable {
 	 */
 	public SimpleLock(Lock lock) {
 		this.lock = lock;
-		this.lock.lock();
+		if (lock != null) lock.lock();
 	}
 
 	@Override
 	public void close() {
-		this.lock.unlock();
+		if (lock != null) lock.unlock();
 	}
 }
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/SimpleReadWriteLock.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/SimpleNoOpLock.java
similarity index 94%
copy from juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/SimpleReadWriteLock.java
copy to juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/SimpleNoOpLock.java
index 8bc61d6..d1d2e93 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/SimpleReadWriteLock.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/SimpleNoOpLock.java
@@ -18,13 +18,13 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
  * An extension of {@link ReentrantReadWriteLock} with convenience methods for creating
  * auto-closeable locks.
  */
-public class SimpleReadWriteLock extends ReentrantReadWriteLock {
+public class SimpleNoOpLock extends ReentrantReadWriteLock {
 	private static final long serialVersionUID = 1L;
 
 	/**
 	 * Constructor.
 	 */
-	public SimpleReadWriteLock() {
+	public SimpleNoOpLock() {
 		super();
 	}
 
@@ -33,7 +33,7 @@ public class SimpleReadWriteLock extends ReentrantReadWriteLock {
 	 *
 	 * @param fair <jk>true</jk> if this lock should use a fair ordering policy.
 	 */
-	public SimpleReadWriteLock(boolean fair) {
+	public SimpleNoOpLock(boolean fair) {
 		super(fair);
 	}
 
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/SimpleReadWriteLock.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/SimpleReadWriteLock.java
index 8bc61d6..f43d968 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/SimpleReadWriteLock.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/SimpleReadWriteLock.java
@@ -21,6 +21,30 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
 public class SimpleReadWriteLock extends ReentrantReadWriteLock {
 	private static final long serialVersionUID = 1L;
 
+	//-----------------------------------------------------------------------------------------------------------------
+	// Static
+	//-----------------------------------------------------------------------------------------------------------------
+
+	/**
+	 * A no-op lock.
+	 */
+	public static SimpleReadWriteLock NO_OP = new SimpleReadWriteLock() {
+		private static final long serialVersionUID = 1L;
+
+		@Override
+		public SimpleLock write() {
+			return SimpleLock.NO_OP;
+		}
+		@Override
+		public SimpleLock read(){
+			return SimpleLock.NO_OP;
+		}
+	};
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Instance
+	//-----------------------------------------------------------------------------------------------------------------
+
 	/**
 	 * Constructor.
 	 */
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/UnmodifiableArray.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/UnmodifiableArray.java
index b208834..0e68ae0 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/UnmodifiableArray.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/internal/UnmodifiableArray.java
@@ -28,11 +28,11 @@ import java.util.*;
  * 	<li class='extlink'>{@source}
  * </ul>
  *
- * @param <T> Array element type.
+ * @param <E> Array element type.
  */
-public class UnmodifiableArray<T> implements List<T> {
+public class UnmodifiableArray<E> implements List<E> {
 
-	final T[] array;
+	final E[] array;
 	final int length;
 	private final boolean reversed;
 
@@ -41,7 +41,7 @@ public class UnmodifiableArray<T> implements List<T> {
 	 *
 	 * @param array The array being wrapped.
 	 */
-	public UnmodifiableArray(T[] array) {
+	public UnmodifiableArray(E[] array) {
 		this(array, false);
 	}
 
@@ -52,8 +52,8 @@ public class UnmodifiableArray<T> implements List<T> {
 	 * @param reversed <jk>true</jk> if elements of array should be addressed in reverse.
 	 */
 	@SuppressWarnings("unchecked")
-	public UnmodifiableArray(T[] array, boolean reversed) {
-		this.array = array == null ? (T[])new Object[0] : array;
+	public UnmodifiableArray(E[] array, boolean reversed) {
+		this.array = array == null ? (E[])new Object[0] : array;
 		this.length = this.array.length;
 		this.reversed = reversed;
 	}
@@ -74,9 +74,9 @@ public class UnmodifiableArray<T> implements List<T> {
 	}
 
 	@Override
-	public Iterator<T> iterator() {
+	public Iterator<E> iterator() {
 		if (reversed) {
-			return new Iterator<T>() {
+			return new Iterator<E>() {
 				int i = length-1;
 
 				@Override
@@ -85,12 +85,12 @@ public class UnmodifiableArray<T> implements List<T> {
 				}
 
 				@Override
-				public T next() {
+				public E next() {
 					return array[i--];
 				}
 			};
 		}
-		return new Iterator<T>() {
+		return new Iterator<E>() {
 			int i = 0;
 
 			@Override
@@ -99,7 +99,7 @@ public class UnmodifiableArray<T> implements List<T> {
 			}
 
 			@Override
-			public T next() {
+			public E next() {
 				return array[i++];
 			}
 		};
@@ -124,7 +124,7 @@ public class UnmodifiableArray<T> implements List<T> {
 	}
 
 	@Override
-	public boolean add(T e) {
+	public boolean add(E e) {
 		throw unsupportedOperationException("Object is read-only.");
 	}
 
@@ -142,12 +142,12 @@ public class UnmodifiableArray<T> implements List<T> {
 	}
 
 	@Override
-	public boolean addAll(Collection<? extends T> c) {
+	public boolean addAll(Collection<? extends E> c) {
 		throw unsupportedOperationException("Object is read-only.");
 	}
 
 	@Override
-	public boolean addAll(int index, Collection<? extends T> c) {
+	public boolean addAll(int index, Collection<? extends E> c) {
 		throw unsupportedOperationException("Object is read-only.");
 	}
 
@@ -167,22 +167,22 @@ public class UnmodifiableArray<T> implements List<T> {
 	}
 
 	@Override
-	public T get(int index) {
+	public E get(int index) {
 		return reversed ? array[length-index-1] : array[index];
 	}
 
 	@Override
-	public T set(int index, T element) {
+	public E set(int index, E element) {
 		throw unsupportedOperationException("Object is read-only.");
 	}
 
 	@Override
-	public void add(int index, T element) {
+	public void add(int index, E element) {
 		throw unsupportedOperationException("Object is read-only.");
 	}
 
 	@Override
-	public T remove(int index) {
+	public E remove(int index) {
 		throw unsupportedOperationException("Object is read-only.");
 	}
 
@@ -190,7 +190,7 @@ public class UnmodifiableArray<T> implements List<T> {
 	public int indexOf(Object o) {
 		for (int i = 0; i < length; i++) {
 			int j = reversed ? length-i-1 : i;
-			T t = array[j];
+			E t = array[j];
 			if ((o == t) || (o != null && o.equals(t)))
 				return j;
 		}
@@ -201,7 +201,7 @@ public class UnmodifiableArray<T> implements List<T> {
 	public int lastIndexOf(Object o) {
 		for (int i = length-1; i >= 0; i--) {
 			int j = reversed ? length-i-1 : i;
-			T t = array[j];
+			E t = array[j];
 			if ((o == t) || (o != null && o.equals(t)))
 				return j;
 		}
@@ -209,22 +209,38 @@ public class UnmodifiableArray<T> implements List<T> {
 	}
 
 	@Override
-	public ListIterator<T> listIterator() {
+	public ListIterator<E> listIterator() {
 		throw unsupportedOperationException("Object is read-only.");
 	}
 
 	@Override
-	public ListIterator<T> listIterator(int index) {
+	public ListIterator<E> listIterator(int index) {
 		throw unsupportedOperationException("Object is read-only.");
 	}
 
 	@Override
-	public List<T> subList(int fromIndex, int toIndex) {
+	public List<E> subList(int fromIndex, int toIndex) {
 		if (reversed) {
-			List<T> l = Arrays.asList(array);
+			List<E> l = Arrays.asList(array);
 			Collections.reverse(l);
 			return l.subList(fromIndex, toIndex);
 		}
 		return Arrays.asList(array).subList(fromIndex, toIndex);
 	}
+
+	@Override
+	public String toString() {
+		if (array.length == 0)
+			return "[]";
+
+		StringBuilder sb = new StringBuilder();
+		sb.append('[');
+		for (int i = 0; i < array.length; i++) {
+			if (i != 0)
+				sb.append(',').append(' ');
+			sb.append(array[i] == this ? "(this Collection)" : array[i]);
+		}
+		sb.append(']');
+		return sb.toString();
+	}
 }
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserSet.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserSet.java
index 1112ed3..2498ca8 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserSet.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserSet.java
@@ -117,12 +117,22 @@ public final class ParserSet {
 	}
 
 	/**
-	 * Instantiates a new clean-slate {@link Builder} object.
+	 * Static creator.
 	 *
-	 * @return A new {@link Builder} object.
+	 * @param beanStore The bean store to use for creating beans.
+	 * @return A new builder for this object.
+	 */
+	public static Builder create(BeanStore beanStore) {
+		return new Builder(beanStore);
+	}
+
+	/**
+	 * Static creator.
+	 *
+	 * @return A new builder for this object.
 	 */
 	public static Builder create() {
-		return new Builder();
+		return new Builder(BeanStore.INSTANCE);
 	}
 
 	//-----------------------------------------------------------------------------------------------------------------
@@ -140,9 +150,11 @@ public final class ParserSet {
 
 		/**
 		 * Create an empty parser group builder.
+		 *
+		 * @param beanStore The bean store to use for creating beans.
 		 */
-		protected Builder() {
-			super(ParserSet.class);
+		protected Builder(BeanStore beanStore) {
+			super(ParserSet.class, beanStore);
 			this.entries = AList.create();
 		}
 
@@ -152,7 +164,7 @@ public final class ParserSet {
 		 * @param copyFrom The parser group that we're copying settings and parsers from.
 		 */
 		protected Builder(ParserSet copyFrom) {
-			super(copyFrom.getClass());
+			super(copyFrom.getClass(), BeanStore.INSTANCE);
 			this.entries = AList.create().append(asList(copyFrom.entries));
 		}
 
@@ -190,7 +202,11 @@ public final class ParserSet {
 			return new ParserSet(this);
 		}
 
-		@Override /* BeanBuilder */
+		/**
+		 * Makes a copy of this builder.
+		 *
+		 * @return A new copy of this builder.
+		 */
 		public Builder copy() {
 			return new Builder(this);
 		}
@@ -436,24 +452,12 @@ public final class ParserSet {
 		// <FluentSetters>
 
 		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
-		public Builder beanStore(BeanStore value) {
-			super.beanStore(value);
-			return this;
-		}
-
-		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
 		public Builder impl(Object value) {
 			super.impl(value);
 			return this;
 		}
 
 		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
-		public Builder outer(Object value) {
-			super.outer(value);
-			return this;
-		}
-
-		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
 		public Builder type(Class<?> value) {
 			super.type(value);
 			return this;
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/AnnotationInfo.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/AnnotationInfo.java
index 7857df0..042f2e0 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/AnnotationInfo.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/AnnotationInfo.java
@@ -58,8 +58,8 @@ public class AnnotationInfo<T extends Annotation> {
 
 	private static int getRank(Object a) {
 		ClassInfo ci = ClassInfo.ofc(a);
-		MethodInfo mi = ci.getPublicMethod("rank");
-		if (mi != null && mi.hasReturnType(int.class)) {
+		MethodInfo mi = ci.getPublicMethod(x -> x.hasName("rank") && x.hasNoParams() && x.hasReturnType(int.class));
+		if (mi != null) {
 			try {
 				return (int)mi.invoke(a);
 			} catch (ExecutableException e) {
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ClassInfo.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ClassInfo.java
index e205ed5..8ced4bf 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ClassInfo.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ClassInfo.java
@@ -18,12 +18,14 @@ import static org.apache.juneau.assertions.Assertions.*;
 import static org.apache.juneau.internal.ThrowableUtils.*;
 import static org.apache.juneau.internal.ObjectUtils.*;
 import static org.apache.juneau.reflect.ReflectionFilters.*;
+import static java.util.Arrays.*;
 
 import java.lang.annotation.*;
 import java.lang.reflect.*;
 import java.util.*;
 import java.util.concurrent.*;
 import java.util.function.*;
+import java.util.stream.*;
 
 import org.apache.juneau.*;
 import org.apache.juneau.annotation.*;
@@ -72,7 +74,7 @@ public final class ClassInfo {
 	private ClassInfo[] interfaces, declaredInterfaces, parents, allParents;
 	private MethodInfo[] publicMethods, declaredMethods, allMethods, allMethodsParentFirst;
 	private MethodInfo repeatedAnnotationMethod;
-	private ConstructorInfo[] publicConstructors, declaredConstructors;
+	private ConstructorInfo[] publicConstructors, protectedConstructors, declaredConstructors;
 	private FieldInfo[] publicFields, declaredFields, allFields, allFieldsParentFirst;
 	private int dim = -1;
 	private ClassInfo componentType;
@@ -433,87 +435,122 @@ public final class ClassInfo {
 	}
 
 	/**
-	 * Returns the public method with the specified method name and argument types.
+	 * Returns all methods declared on this class.
 	 *
-	 * @param name The method name (e.g. <js>"toString"</js>).
-	 * @param args The exact argument types.
 	 * @return
-	 *  The public method with the specified method name and argument types, or <jk>null</jk> if not found.
+	 * 	All methods declared on this class.
+	 * 	<br>Results are ordered alphabetically.
 	 */
-	public MethodInfo getPublicMethod(String name, Class<?>...args) {
-		for (MethodInfo mi : _getPublicMethods())
-			if (mi.hasName(name) && mi.hasParamTypes(args))
-				return mi;
-		return null;
+	public List<MethodInfo> getDeclaredMethods() {
+		return new UnmodifiableArray<>(_getDeclaredMethods());
 	}
 
 	/**
-	 * Returns the public method with the specified method name and fuzzy argument types.
+	 * Returns all declared methods on this class and all parent classes.
 	 *
-	 * @param name The method name (e.g. <js>"toString"</js>).
-	 * @param args The fuzzy argument types.
 	 * @return
-	 *  The public method with the specified method name and argument types, or <jk>null</jk> if not found.
+	 * 	All declared methods on this class and all parent classes.
+	 * 	<br>Results are ordered child-to-parent, and then alphabetically per class.
 	 */
-	public MethodInfo getPublicMethodFuzzy(String name, Object...args) {
-		Class<?>[] ac = ClassUtils.getClasses(args);
+	public List<MethodInfo> getAllMethods() {
+		return new UnmodifiableArray<>(_getAllMethods());
+	}
+
+	/**
+	 * Returns the public method that matches the specified predicate.
+	 *
+	 * @param predicate The predicate.
+	 * @return The first matching method, or <jk>null</jk> if no methods matched.
+	 */
+	public final MethodInfo getPublicMethod(Predicate<MethodInfo> predicate) {
 		for (MethodInfo mi : _getPublicMethods())
-			if (mi.hasName(name) && mi.argsOnlyOfType(ac))
+			if (predicate.test(mi))
 				return mi;
 		return null;
 	}
 
 	/**
-	 * Returns the method with the specified method name and argument types.
+	 * Returns the declared method that matches the specified predicate.
 	 *
-	 * @param name The method name (e.g. <js>"toString"</js>).
-	 * @param args The exact argument types.
-	 * @return
-	 *  The method with the specified method name and argument types, or <jk>null</jk> if not found.
+	 * @param predicate The predicate.
+	 * @return The first matching method, or <jk>null</jk> if no methods matched.
 	 */
-	public MethodInfo getMethod(String name, Class<?>...args) {
-		for (MethodInfo mi : _getAllMethods())
-			if (mi.hasName(name) && mi.hasParamTypes(args))
+	public MethodInfo getDeclaredMethod(Predicate<MethodInfo> predicate) {
+		for (MethodInfo mi : _getDeclaredMethods())
+			if (predicate.test(mi))
 				return mi;
 		return null;
 	}
 
 	/**
-	 * Returns the method with the specified method name and fuzzy argument types.
+	 * Returns the method that matches the specified predicate.
 	 *
-	 * @param name The method name (e.g. <js>"toString"</js>).
-	 * @param args The exact argument types.
-	 * @return
-	 *  The method with the specified method name and argument types, or <jk>null</jk> if not found.
+	 * @param predicate The predicate.
+	 * @return The first matching method, or <jk>null</jk> if no methods matched.
 	 */
-	public MethodInfo getMethodFuzzy(String name, Object...args) {
-		Class<?>[] ac = ClassUtils.getClasses(args);
+	public MethodInfo getMethod(Predicate<MethodInfo> predicate) {
 		for (MethodInfo mi : _getAllMethods())
-			if (mi.hasName(name) && mi.argsOnlyOfType(ac))
+			if (predicate.test(mi))
 				return mi;
 		return null;
 	}
 
 	/**
-	 * Returns all methods declared on this class.
+	 * Returns the public method that matches the specified predicate.
 	 *
-	 * @return
-	 * 	All methods declared on this class.
-	 * 	<br>Results are ordered alphabetically.
+	 * @param predicate The predicate.
+	 * @param consumer The consumer of the matching predicate.
+	 * @return This object.
 	 */
-	public List<MethodInfo> getDeclaredMethods() {
-		return new UnmodifiableArray<>(_getDeclaredMethods());
+	public final ClassInfo getPublicMethods(Predicate<MethodInfo> predicate, Consumer<MethodInfo> consumer) {
+		for (MethodInfo mi : _getPublicMethods())
+			if (predicate.test(mi))
+				consumer.accept(mi);
+		return this;
 	}
 
 	/**
-	 * Returns all declared methods on this class and all parent classes.
+	 * Returns the declared method that matches the specified predicate.
 	 *
+	 * @param predicate The predicate.
+	 * @param consumer The consumer of the matching predicate.
+	 * @return This object.
+	 */
+	public final ClassInfo getDeclaredMethods(Predicate<MethodInfo> predicate, Consumer<MethodInfo> consumer) {
+		for (MethodInfo mi : _getDeclaredMethods())
+			if (predicate.test(mi))
+				consumer.accept(mi);
+		return this;
+	}
+
+	/**
+	 * Returns the method that matches the specified predicate.
+	 *
+	 * @param predicate The predicate.
+	 * @param consumer The consumer of the matching predicate.
+	 * @return This object.
+	 */
+	public final ClassInfo getMethods(Predicate<MethodInfo> predicate, Consumer<MethodInfo> consumer) {
+		for (MethodInfo mi : _getAllMethods())
+			if (predicate.test(mi))
+				consumer.accept(mi);
+		return this;
+	}
+
+	/**
+	 * Returns the method with the specified method name and fuzzy argument types.
+	 *
+	 * @param name The method name (e.g. <js>"toString"</js>).
+	 * @param args The exact argument types.
 	 * @return
-	 * 	All declared methods on this class and all parent classes.
-	 * 	<br>Results are ordered child-to-parent, and then alphabetically per class.
+	 *  The method with the specified method name and argument types, or <jk>null</jk> if not found.
 	 */
-	public List<MethodInfo> getAllMethods() {
-		return new UnmodifiableArray<>(_getAllMethods());
+	public MethodInfo getMethodFuzzy(String name, Object...args) {
+		Class<?>[] ac = ClassUtils.getClasses(args);
+		for (MethodInfo mi : _getAllMethods())
+			if (mi.hasName(name) && mi.argsOnlyOfType(ac))
+				return mi;
+		return null;
 	}
 
 	/**
@@ -575,7 +612,8 @@ public final class ClassInfo {
 	}
 
 	private List<MethodInfo> _appendDeclaredMethods(List<MethodInfo> l) {
-		l.addAll(getDeclaredMethods());
+		for (MethodInfo mi : _getDeclaredMethods())
+			l.add(mi);
 		return l;
 	}
 
@@ -584,136 +622,6 @@ public final class ClassInfo {
 	//-----------------------------------------------------------------------------------------------------------------
 
 	/**
-	 * Find the public static creator method on this class.
-	 *
-	 * <p>
-	 * Looks for the following method names:
-	 * <ul>
-	 * 	<li><c>create</c>
-	 * 	<li><c>from</c>
-	 * 	<li><c>fromValue</c>
-	 * 	<li><c>parse</c>
-	 * 	<li><c>valueOf</c>
-	 * 	<li><c>fromX</c>
-	 * 	<li><c>forX</c>
-	 * 	<li><c>parseX</c>
-	 * </ul>
-	 *
-	 * @param ic The argument type.
-	 * @param additionalNames Additional method names to check for.
-	 * @return The static method, or <jk>null</jk> if it couldn't be found.
-	 */
-	public MethodInfo getStaticCreateMethod(Class<?> ic, String...additionalNames) {
-		if (c != null) {
-			for (MethodInfo m : getPublicMethods()) {
-				if (m.isAll(STATIC, PUBLIC, NOT_DEPRECATED) && m.hasReturnType(c) && m.hasParamTypes(ic)) {
-					String n = m.getSimpleName(), cn = ic.getSimpleName();
-					if (
-						isOneOf(n, "create","from","fromValue","parse","valueOf")
-						|| isOneOf(n, additionalNames)
-						|| (n.startsWith("from") && n.substring(4).equals(cn))
-						|| (n.startsWith("for") && n.substring(3).equals(cn))
-						|| (n.startsWith("parse") && n.substring(5).equals(cn))
-						) {
-						return m;
-					}
-				}
-			}
-		}
-		return null;
-	}
-
-	/**
-	 * Find the public static creator method on this class.
-	 *
-	 * <p>
-	 * Must have the following signature where T is the exact outer class.
-	 * <p class='bcode w800'>
-	 * 	public static T create(...);
-	 * </p>
-	 *
-	 * <p>
-	 * Must be able to take in all arguments specified in any order.
-	 *
-	 * @param args The arguments to pass to the create method.
-	 * @return The static method, or <jk>null</jk> if it couldn't be found.
-	 */
-	public MethodInfo getStaticCreator(Object...args) {
-		if (c != null) {
-			Class<?>[] argTypes = ClassUtils.getClasses(args);
-			for (MethodInfo m : getPublicMethods()) {
-				if (m.isAll(STATIC, PUBLIC, NOT_DEPRECATED) && m.hasReturnType(c) && (m.getSimpleName().equals("create") || m.getSimpleName().equals("getInstance")) && m.hasMatchingParamTypes(argTypes))
-					return m;
-			}
-		}
-		return null;
-	}
-
-	/**
-	 * Find the public static creator method on this class.
-	 *
-	 * <p>
-	 * Must have the following signature where T is the exact outer class.
-	 * <p class='bcode w800'>
-	 * 	public static T create(...);
-	 * </p>
-	 *
-	 * <p>
-	 * Returned method can take in arguments in any order if they match.  The method is guaranteed to not require additional
-	 * arguments not specified.
-	 *
-	 * @param args The arguments to pass to the create method.
-	 * @return The static method, or <jk>null</jk> if it couldn't be found.
-	 */
-	public MethodInfo getStaticCreatorFuzzy(Object...args) {
-		int bestCount = -1;
-		MethodInfo bestMatch = null;
-		if (c != null) {
-			Class<?>[] argTypes = ClassUtils.getClasses(args);
-			for (MethodInfo m : getPublicMethods()) {
-				String sn = m.getSimpleName();
-				if (m.isAll(STATIC, PUBLIC, NOT_DEPRECATED) && m.hasReturnType(c) && (sn.equals("create") || sn.equals("getInstance"))) {
-					int mn = m.fuzzyArgsMatch(argTypes);
-					if (mn > bestCount) {
-						bestCount = mn;
-						bestMatch = m;
-					}
-				}
-			}
-		}
-		return bestMatch;
-	}
-
-	/**
-	 * Find the public static method with the specified name and args.
-	 *
-	 * @param name The method name.
-	 * @param rt The method return type.
-	 * @param args The method arguments
-	 * @return The method, or <jk>null</jk> if it couldn't be found.
-	 */
-	public MethodInfo getStaticPublicMethod(String name, Class<?> rt, Class<?>...args) {
-		if (c != null)
-			for (MethodInfo m : getPublicMethods())
-				if (m.isAll(STATIC, PUBLIC, NOT_DEPRECATED) && name.equals(m.getSimpleName()) && m.hasReturnType(rt) && m.hasParamTypes(args))
-					return m;
-		return null;
-	}
-
-	/**
-	 * Find the public static method with the specified name and args.
-	 *
-	 * @param name The method name.
-	 * @param rt The method return type.
-	 * @param args The method arguments
-	 * @return The method, or <jk>null</jk> if it couldn't be found.
-	 */
-	public Method getStaticPublicMethodInner(String name, Class<?> rt, Class<?>...args) {
-		MethodInfo mi = getStaticPublicMethod(name, rt, args);
-		return mi == null ? null : mi.inner();
-	}
-
-	/**
 	 * Returns the <c>public static Builder create()</c> method on this class.
 	 *
 	 * @return The <c>public static Builder create()</c> method on this class, or <jk>null</jk> if it doesn't exist.
@@ -763,6 +671,33 @@ public final class ClassInfo {
 	}
 
 	/**
+	 * Returns all the public constructors defined on this class.
+	 *
+	 * @return All public constructors defined on this class.
+	 */
+	public Stream<ConstructorInfo> publicConstructors() {
+		return stream(_getPublicConstructors());
+	}
+
+	/**
+	 * Returns all the public constructors defined on this class.
+	 *
+	 * @return All public constructors defined on this class.
+	 */
+	public List<ConstructorInfo> getProtectedConstructors() {
+		return new UnmodifiableArray<>(_getProtectedConstructors());
+	}
+
+	/**
+	 * Returns all the public constructors defined on this class.
+	 *
+	 * @return All public constructors defined on this class.
+	 */
+	public Stream<ConstructorInfo> protectedConstructors() {
+		return stream(_getProtectedConstructors());
+	}
+
+	/**
 	 * Returns the public constructor with the specified argument types.
 	 *
 	 * @param args The exact argument types.
@@ -896,6 +831,18 @@ public final class ClassInfo {
 		return publicConstructors;
 	}
 
+	private ConstructorInfo[] _getProtectedConstructors() {
+		if (protectedConstructors == null) {
+			Constructor<?>[] cc = c == null ? new Constructor[0] : c.getDeclaredConstructors();
+			List<ConstructorInfo> l = new ArrayList<>(cc.length);
+			for (Constructor<?> ccc : cc)
+				if (Modifier.isProtected(ccc.getModifiers()))
+					l.add(ConstructorInfo.of(this, ccc));
+			l.sort(null);
+			protectedConstructors = l.toArray(new ConstructorInfo[l.size()]);
+		}
+		return protectedConstructors;
+	}
 	private ConstructorInfo[] _getDeclaredConstructors() {
 		if (declaredConstructors == null) {
 			Constructor<?>[] cc = c == null ? new Constructor[0] : c.getDeclaredConstructors();
@@ -2145,6 +2092,24 @@ public final class ClassInfo {
 	}
 
 	/**
+	 * Returns <jk>true</jk> if this type can be used as a parameter for the specified object.
+	 *
+	 * @param child The argument to check.
+	 * @return <jk>true</jk> if this type can be used as a parameter for the specified object.
+	 */
+	public boolean canAcceptArg(Object child) {
+		if (c == null || child == null)
+			return false;
+		if (c.isInstance(child))
+			return true;
+		if (this.isPrimitive() || child.getClass().isPrimitive()) {
+			return this.getWrapperIfPrimitive().isAssignableFrom(of(child).getWrapperIfPrimitive());
+		}
+		return false;
+	}
+
+
+	/**
 	 * Same as {@link #isParentOfFuzzyPrimitives(Class)} but takes in a {@link ClassInfo}.
 	 *
 	 * @param child The child class.
@@ -2251,6 +2216,16 @@ public final class ClassInfo {
 	}
 
 	/**
+	 * Performs a predicate check on this class.
+	 *
+	 * @param test The test to perform.
+	 * @return <jk>true</jk> if the predicate test passes.
+	 */
+	public boolean is(Predicate<Class<?>> test) {
+		return test.test(c);
+	}
+
+	/**
 	 * Checks for equality with the specified class.
 	 *
 	 * @param c The class to check equality with.
@@ -2371,7 +2346,7 @@ public final class ClassInfo {
 	public boolean isRepeatedAnnotation() {
 		if (isRepeatedAnnotation == null) {
 			boolean b = false;
-			MethodInfo mi = getMethod("value");
+			MethodInfo mi = getPublicMethod(x -> x.hasName("value"));
 			if (mi != null) {
 				ClassInfo rt = mi.getReturnType();
 				if (rt.isArray()) {
@@ -2400,7 +2375,7 @@ public final class ClassInfo {
 	public MethodInfo getRepeatedAnnotationMethod() {
 		if (isRepeatedAnnotation()) {
 			if (repeatedAnnotationMethod == null)
-				repeatedAnnotationMethod = getMethod("value");
+				repeatedAnnotationMethod = getPublicMethod(x -> x.hasName("value"));
 			return repeatedAnnotationMethod;
 		}
 		return null;
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ConstructorInfo.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ConstructorInfo.java
index 03db4af..6cfece0 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ConstructorInfo.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ConstructorInfo.java
@@ -16,6 +16,7 @@ import static org.apache.juneau.internal.CollectionUtils.*;
 
 import java.lang.annotation.*;
 import java.lang.reflect.*;
+import java.util.function.*;
 
 import org.apache.juneau.*;
 import org.apache.juneau.internal.*;
@@ -129,6 +130,32 @@ public final class ConstructorInfo extends ExecutableInfo implements Comparable<
 	//-----------------------------------------------------------------------------------------------------------------
 
 	/**
+	 * Returns <jk>true</jk> if this constructor passes the specified predicate.
+	 *
+	 * @param predicate The predicate.
+	 * @return <jk>true</jk> if this constructor passes the specified predicate.
+	 */
+	public boolean matches(Predicate<ConstructorInfo> predicate) {
+		return predicate.test(this);
+	}
+
+	/**
+	 * Returns <jk>true</jk> if this constructor can accept the specified arguments in the specified order.
+	 *
+	 * @param args The arguments to check.
+	 * @return <jk>true</jk> if this constructor can accept the specified arguments in the specified order.
+	 */
+	public boolean canAccept(Object...args) {
+		Class<?>[] pt = c.getParameterTypes();
+		if (pt.length != args.length)
+			return false;
+		for (int i = 0; i < pt.length; i++)
+			if (! pt[i].isInstance(args[i]))
+				return false;
+		return true;
+	}
+
+	/**
 	 * Shortcut for calling the new-instance method on the underlying constructor.
 	 *
 	 * @param args the arguments used for the method call.
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ExecutableInfo.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ExecutableInfo.java
index eb93a2a..f9d0f48 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ExecutableInfo.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ExecutableInfo.java
@@ -249,8 +249,19 @@ public abstract class ExecutableInfo {
 			// Note that due to a bug involving Enum constructors, getGenericParameterTypes() may
 			// always return an empty array.  This appears to be fixed in Java 8 b75.
 			Type[] ptt = _getRawGenericParamTypes();
-			if (ptt.length != ptc.length)
-				ptt = ptc;
+			if (ptt.length != ptc.length) {
+				// Bug in javac: generic type array excludes enclosing instance parameter
+				// for inner classes with at least one generic constructor parameter.
+				if (ptt.length + 1 == ptc.length) {
+					Type[] ptt2 = new Type[ptc.length];
+					ptt2[0] = ptc[0];
+					for (int i = 0; i < ptt.length; i++)
+						ptt2[i+1] = ptt[i];
+					ptt = ptt2;
+				} else {
+					ptt = ptc;
+				}
+			}
 			ClassInfo[] l = new ClassInfo[ptc.length];
 			for (int i = 0; i < ptc.length; i++)
 				l[i] = ClassInfo.of(ptc[i], ptt[i]);
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/MethodInfo.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/MethodInfo.java
index f41076e..3826136 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/MethodInfo.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/MethodInfo.java
@@ -105,6 +105,52 @@ public final class MethodInfo extends ExecutableInfo implements Comparable<Metho
 	//-----------------------------------------------------------------------------------------------------------------
 
 	/**
+	 * Returns <jk>true</jk> if this method passes the specified predicate.
+	 *
+	 * @param predicate The predicate.
+	 * @return <jk>true</jk> if this method passes the specified predicate.
+	 */
+	public boolean matches(Predicate<MethodInfo> predicate) {
+		return predicate.test(this);
+	}
+
+	/**
+	 * Returns <jk>true</jk> if this constructor can accept the specified arguments in the specified order.
+	 *
+	 * @param args The arguments to check.
+	 * @return <jk>true</jk> if this constructor can accept the specified arguments in the specified order.
+	 */
+	public boolean canAccept(Object...args) {
+		Class<?>[] pt = m.getParameterTypes();
+		if (pt.length != args.length)
+			return false;
+		for (int i = 0; i < pt.length; i++)
+			if (! pt[i].isInstance(args[i]))
+				return false;
+		return true;
+	}
+
+	/**
+	 * Returns the number of matching arguments for this method.
+	 *
+	 * @param args The arguments to check.
+	 * @return the number of matching arguments for this method.
+	 */
+	public int canAcceptFuzzy(Object...args) {
+		int matches = 0;
+		outer: for (ClassInfo pi : getParamTypes()) {
+			for (Object a : args) {
+				if (pi.canAcceptArg(a)) {
+					matches++;
+					continue outer;
+				}
+			}
+			return -1;
+		}
+		return matches;
+	}
+
+	/**
 	 * Finds all declared methods with the same name and arguments on all superclasses and interfaces.
 	 *
 	 * @return
@@ -191,7 +237,7 @@ public final class MethodInfo extends ExecutableInfo implements Comparable<Metho
 	public final <T extends Annotation> T getLastAnnotation(Class<T> a, MetaProvider mp) {
 		if (a == null)
 			return null;
-		for (Method m2 : getMatching()) {
+		for (Method m2 : _getMatching()) {
 			T t = last(mp.getAnnotations(a, m2));
 			if (t != null)
 				return t;
@@ -210,6 +256,16 @@ public final class MethodInfo extends ExecutableInfo implements Comparable<Metho
 	}
 
 	/**
+	 * Returns <jk>true</jk> if the specified annotation is not present on this method.
+	 *
+	 * @param a The annotation to check for.
+	 * @return <jk>true</jk> if the specified annotation is not present on this method.
+	 */
+	public final boolean hasNoAnnotation(Class<? extends Annotation> a) {
+		return getLastAnnotation(a) == null;
+	}
+
+	/**
 	 * Returns <jk>true</jk> if at least one of the specified annotation is present on this method.
 	 *
 	 * @param a The annotation to check for.
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/Mutaters.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/Mutaters.java
index f4b1995..fcc6bd0 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/Mutaters.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/Mutaters.java
@@ -12,6 +12,7 @@
 // ***************************************************************************************************************************
 package org.apache.juneau.reflect;
 
+import static org.apache.juneau.internal.StringUtils.*;
 import static org.apache.juneau.internal.ThrowableUtils.*;
 import static org.apache.juneau.reflect.ReflectFlags.*;
 
@@ -160,9 +161,15 @@ public class Mutaters {
 
 		if (ic == String.class) {
 			Class<?> oc2 = oci.hasPrimitiveWrapper() ? oci.getPrimitiveWrapper() : oc;
-			ClassInfo oc2i = ClassInfo.of(oc2);
+			ClassInfo oc2i = ClassInfo.ofc(oc2);
 
-			final MethodInfo createMethod = oc2i.getStaticCreateMethod(ic, "forName");
+			final MethodInfo createMethod = oc2i.getPublicMethod(
+				x -> x.isStatic()
+				&& x.isNotDeprecated()
+				&& x.hasReturnType(oc2)
+				&& x.hasParamTypes(ic)
+				&& (x.hasName("forName") || isStaticCreateMethodName(x, ic))
+			);
 
 			if (oc2.isEnum() && createMethod == null) {
 				return new Mutater<String,Object>() {
@@ -186,7 +193,14 @@ public class Mutaters {
 				};
 			}
 		} else {
-			MethodInfo createMethod = oci.getStaticCreateMethod(ic);
+			MethodInfo createMethod = oci.getPublicMethod(
+				x -> x.isStatic()
+				&& x.isNotDeprecated()
+				&& x.hasReturnType(oc)
+				&& x.hasParamTypes(ic)
+				&& isStaticCreateMethodName(x, ic)
+			);
+
 			if (createMethod != null) {
 				Method cm = createMethod.inner();
 				return new Mutater() {
@@ -236,6 +250,14 @@ public class Mutaters {
 		return NULL;
 	}
 
+	private static boolean isStaticCreateMethodName(MethodInfo mi, Class<?> ic) {
+		String n = mi.getSimpleName(), cn = ic.getSimpleName();
+		return isOneOf(n, "create","from","fromValue","parse","valueOf")
+			|| (n.startsWith("from") && n.substring(4).equals(cn))
+			|| (n.startsWith("for") && n.substring(3).equals(cn))
+			|| (n.startsWith("parse") && n.substring(5).equals(cn));
+	}
+
 	/**
 	 * Constructs a new instance of the specified class from the specified string.
 	 *
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ParamInfo.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ParamInfo.java
index df30ab3..4e21d03 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ParamInfo.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/reflect/ParamInfo.java
@@ -274,6 +274,16 @@ public final class ParamInfo {
 		return null;
 	}
 
+	/**
+	 * Returns <jk>true</jk> if this parameter can accept the specified value.
+	 *
+	 * @param value The value to check.
+	 * @return <jk>true</jk> if this parameter can accept the specified value.
+	 */
+	public boolean canAccept(Object value) {
+		return getParameterType().isInstance(value);
+	}
+
 	@Override
 	public String toString() {
 		return (eInfo.getSimpleName()) + "[" + index + "]";
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/SerializerSet.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/SerializerSet.java
index 8c78b6d..080a90f 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/SerializerSet.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/SerializerSet.java
@@ -116,12 +116,22 @@ public final class SerializerSet {
 	}
 
 	/**
-	 * Instantiates a new clean-slate {@link Builder} object.
+	 * Static creator.
 	 *
-	 * @return A new {@link Builder} object.
+	 * @param beanStore The bean store to use for creating beans.
+	 * @return A new builder for this object.
+	 */
+	public static Builder create(BeanStore beanStore) {
+		return new Builder(beanStore);
+	}
+
+	/**
+	 * Static creator.
+	 *
+	 * @return A new builder for this object.
 	 */
 	public static Builder create() {
-		return new Builder();
+		return new Builder(BeanStore.INSTANCE);
 	}
 
 	//-----------------------------------------------------------------------------------------------------------------
@@ -139,9 +149,11 @@ public final class SerializerSet {
 
 		/**
 		 * Create an empty serializer group builder.
+		 *
+		 * @param beanStore The bean store to use for creating beans.
 		 */
-		protected Builder() {
-			super(SerializerSet.class);
+		protected Builder(BeanStore beanStore) {
+			super(SerializerSet.class, beanStore);
 			this.entries = AList.create();
 		}
 
@@ -189,7 +201,11 @@ public final class SerializerSet {
 			return new SerializerSet(this);
 		}
 
-		@Override /* BeanBuilder */
+		/**
+		 * Makes a copy of this builder.
+		 *
+		 * @return A new copy of this builder.
+		 */
 		public Builder copy() {
 			return new Builder(this);
 		}
@@ -432,24 +448,12 @@ public final class SerializerSet {
 		// <FluentSetters>
 
 		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
-		public Builder beanStore(BeanStore value) {
-			super.beanStore(value);
-			return this;
-		}
-
-		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
 		public Builder impl(Object value) {
 			super.impl(value);
 			return this;
 		}
 
 		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
-		public Builder outer(Object value) {
-			super.outer(value);
-			return this;
-		}
-
-		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
 		public Builder type(Class<?> value) {
 			super.type(value);
 			return this;
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/svl/VarResolver.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/svl/VarResolver.java
index ca0ae65..71a50e7 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/svl/VarResolver.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/svl/VarResolver.java
@@ -116,9 +116,8 @@ public class VarResolver {
 		 * Constructor.
 		 */
 		protected Builder() {
-			super(VarResolver.class);
+			super(VarResolver.class, BeanStore.create().build());
 			vars = VarList.create();
-			beanStore(BeanStore.create().build());
 		}
 
 		/**
@@ -127,19 +126,8 @@ public class VarResolver {
 		 * @param copyFrom The bean to copy from.
 		 */
 		protected Builder(VarResolver copyFrom) {
-			super(copyFrom.getClass());
+			super(copyFrom.getClass(), copyFrom.beanStore);
 			vars = VarList.of(copyFrom.vars);
-			beanStore(copyFrom.beanStore.copy().build());
-		}
-
-		/**
-		 * Copy constructor.
-		 *
-		 * @param copyFrom The builder to copy from.
-		 */
-		protected Builder(Builder copyFrom) {
-			super(copyFrom);
-			vars = copyFrom.vars.copy();
 		}
 
 		@Override /* BeanBuilder */
@@ -147,11 +135,6 @@ public class VarResolver {
 			return new VarResolver(this);
 		}
 
-		@Override /* BeanBuilder */
-		public Builder copy() {
-			return new Builder(this);
-		}
-
 		//-------------------------------------------------------------------------------------------------------------
 		// Properties
 		//-------------------------------------------------------------------------------------------------------------
@@ -235,31 +218,19 @@ public class VarResolver {
 		 * @return This object .
 		 */
 		public <T> Builder bean(Class<T> c, T value) {
-			beanStore().get().addBean(c, value);
+			beanStore().addBean(c, value);
 			return this;
 		}
 
 		// <FluentSetters>
 
 		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
-		public Builder beanStore(BeanStore value) {
-			super.beanStore(value);
-			return this;
-		}
-
-		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
 		public Builder impl(Object value) {
 			super.impl(value);
 			return this;
 		}
 
 		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
-		public Builder outer(Object value) {
-			super.outer(value);
-			return this;
-		}
-
-		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
 		public Builder type(Class<?> value) {
 			super.type(value);
 			return this;
@@ -282,19 +253,19 @@ public class VarResolver {
 	 * @param builder The builder for this object.
 	 */
 	protected VarResolver(Builder builder) {
-		this.vars = builder.vars.stream().map(x -> toVar(builder.beanStore().get(),x)).toArray(Var[]::new);
+		this.vars = builder.vars.stream().map(x -> toVar(builder.beanStore(),x)).toArray(Var[]::new);
 
 		Map<String,Var> m = new ConcurrentSkipListMap<>();
 		for (Var v : vars)
 			m.put(v.getName(), v);
 
 		this.varMap = AMap.unmodifiable(m);
-		this.beanStore = BeanStore.of(builder.beanStore().get());
+		this.beanStore = BeanStore.of(builder.beanStore());
 	}
 
 	private static Var toVar(BeanStore bs, Object o) {
 		if (o instanceof Class)
-			return bs.creator(Var.class).type((Class<?>)o).run();
+			return bs.createBean(Var.class).type((Class<?>)o).run();
 		return (Var)o;
 	}
 
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/swap/SurrogateSwap.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/swap/SurrogateSwap.java
index 3a0c917..1002b86 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/swap/SurrogateSwap.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/swap/SurrogateSwap.java
@@ -13,6 +13,7 @@
 package org.apache.juneau.swap;
 
 import static org.apache.juneau.internal.ClassUtils.*;
+import static java.util.Optional.*;
 
 import java.lang.reflect.*;
 import java.util.*;
@@ -72,12 +73,11 @@ public class SurrogateSwap<T,F> extends ObjectSwap<T,F> {
 				Class<?> pt = cc.getRawParamType(0);
 				if (! pt.equals(c.getDeclaringClass())) {
 					// Find the unswap method if there is one.
-					Method unswapMethod = null;
-					for (MethodInfo m : ci.getPublicMethods()) {
-						if (m.getReturnType().is(pt) && m.isPublic())
-						unswapMethod = m.inner();
-					}
-
+					Method unswapMethod = ofNullable(
+						ci.getPublicMethod(
+							x -> x.hasReturnType(pt)
+						)
+					).map(x -> x.inner()).orElse(null);
 					l.add(new SurrogateSwap(pt, cc.inner(), unswapMethod));
 				}
 			}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/swaps/TemporalSwap.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/swaps/TemporalSwap.java
index b876685..c57588a 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/swaps/TemporalSwap.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/swaps/TemporalSwap.java
@@ -334,9 +334,16 @@ public class TemporalSwap extends StringSwap<Temporal> {
 	private static Method findParseMethod(Class<? extends Temporal> c) throws ExecutableException {
 		Method m = FROM_METHODS.get(c);
 		if (m == null) {
-			m = ClassInfo.of(c).getStaticPublicMethodInner("from", c, TemporalAccessor.class);
-			if (m == null)
+			MethodInfo mi = ClassInfo.ofc(c).getPublicMethod(
+				x -> x.isStatic()
+				&& x.isNotDeprecated()
+				&& x.hasName("from")
+				&& x.hasReturnType(c)
+				&& x.hasParamTypes(TemporalAccessor.class)
+			);
+			if (mi == null)
 				throw new ExecutableException("Parse method not found on temporal class ''{0}''", c.getSimpleName());
+			m = mi.inner();
 			FROM_METHODS.put(c, m);
 		}
 		return m;
diff --git a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClient.java b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClient.java
index 47110d2..0366bc9 100644
--- a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClient.java
+++ b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClient.java
@@ -3609,7 +3609,7 @@ public class RestClient extends BeanContextable implements HttpClient, Closeable
 		 * @see #callHandler()
 		 */
 		protected BeanCreator<RestCallHandler> createCallHandler() {
-			return BeanCreator.of(RestCallHandler.class).type(BasicRestCallHandler.class).store(beanStore);
+			return beanStore.createBean(RestCallHandler.class).type(BasicRestCallHandler.class);
 		}
 
 		/**
@@ -8078,7 +8078,7 @@ public class RestClient extends BeanContextable implements HttpClient, Closeable
 		HttpPartSerializer x = partSerializers.get(c);
 		if (x == null) {
 			try {
-				x = beanStore.creator(c).run();
+				x = beanStore.createBean(c).run();
 			} catch (ExecutableException e) {
 				throw runtimeException(e);
 			}
@@ -8097,7 +8097,7 @@ public class RestClient extends BeanContextable implements HttpClient, Closeable
 		HttpPartParser x = partParsers.get(c);
 		if (x == null) {
 			try {
-				x = beanStore.creator(c).run();
+				x = beanStore.createBean(c).run();
 			} catch (ExecutableException e) {
 				throw runtimeException(e);
 			}
diff --git a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/remote/RemoteMeta.java b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/remote/RemoteMeta.java
index 1d63080..bd2bb1a 100644
--- a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/remote/RemoteMeta.java
+++ b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/remote/RemoteMeta.java
@@ -80,8 +80,11 @@ public class RemoteMeta {
 			headersBuilder.append(stringHeader(versionHeader, clientVersion));
 
 		AMap<Method,RemoteOperationMeta> operations = AMap.create();
-		for (MethodInfo m : ci.getPublicMethods())
-			operations.put(m.inner(), new RemoteOperationMeta(path, m.inner(), "GET"));
+		String path2 = path;
+		ci.getPublicMethods(
+			x -> true, 
+			x -> operations.put(x.inner(), new RemoteOperationMeta(path2, x.inner(), "GET"))
+		);
 
 		this.operations = operations.unmodifiable();
 		this.headers = headersBuilder.build();
diff --git a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/remote/RemoteOperationArg.java b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/remote/RemoteOperationArg.java
index 4931f92..92f414f 100644
--- a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/remote/RemoteOperationArg.java
+++ b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/remote/RemoteOperationArg.java
@@ -42,7 +42,7 @@ public final class RemoteOperationArg {
 	RemoteOperationArg(int index, HttpPartType partType, HttpPartSchema schema) {
 		this.index = index;
 		this.partType = partType;
-		this.serializer = ofNullable(BeanCreator.of(schema.getSerializer()).run());
+		this.serializer = ofNullable(BeanStore.INSTANCE.createBean(schema.getSerializer()).run());
 		this.schema = schema;
 	}
 
diff --git a/juneau-rest/juneau-rest-server-springboot/src/main/java/org/apache/juneau/rest/springboot/SpringBeanStore.java b/juneau-rest/juneau-rest-server-springboot/src/main/java/org/apache/juneau/rest/springboot/SpringBeanStore.java
index 34f2aa7..59c7346 100644
--- a/juneau-rest/juneau-rest-server-springboot/src/main/java/org/apache/juneau/rest/springboot/SpringBeanStore.java
+++ b/juneau-rest/juneau-rest-server-springboot/src/main/java/org/apache/juneau/rest/springboot/SpringBeanStore.java
@@ -13,8 +13,9 @@
 package org.apache.juneau.rest.springboot;
 
 import java.util.*;
+import java.util.stream.*;
 
-import org.apache.juneau.cp.BeanStore;
+import org.apache.juneau.cp.*;
 import org.springframework.context.*;
 
 /**
@@ -42,9 +43,9 @@ public class SpringBeanStore extends BeanStore {
 	}
 
 	@Override
-	public <T> Optional<T> getBean(String name, Class<T> c) {
+	public <T> Optional<T> getBean(Class<T> c, String name) {
 		try {
-			Optional<T> o = super.getBean(name, c);
+			Optional<T> o = super.getBean(c, name);
 			if (o.isPresent())
 				return o;
 			if (appContext.isPresent()) {
@@ -57,4 +58,18 @@ public class SpringBeanStore extends BeanStore {
 		}
 		return Optional.empty();
 	}
+
+	@SuppressWarnings("unchecked")
+	@Override
+	public <T> Stream<BeanStoreEntry<T>> stream(Class<T> c)  {
+		try {
+			Stream<BeanStoreEntry<T>> o = super.stream(c);
+			if (appContext.isPresent())
+				o = Stream.concat(o, appContext.get().getBeansOfType(c).entrySet().stream().map(x -> BeanStoreEntry.create(c, ()->x.getValue(), x.getKey())));
+			return o;
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+		return Collections.emptyList().stream().map(x -> (BeanStoreEntry<T>)x);
+	}
 }
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestChildren.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestChildren.java
index 8da3b91..eb0f914 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestChildren.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestChildren.java
@@ -48,12 +48,13 @@ public class RestChildren {
 	}
 
 	/**
-	 * Creates a new builder for this object.
+	 * Static creator.
 	 *
+	 * @param beanStore The bean store to use for creating beans.
 	 * @return A new builder for this object.
 	 */
-	public static Builder create() {
-		return new Builder();
+	public static Builder create(BeanStore beanStore) {
+		return new Builder(beanStore);
 	}
 
 	//-----------------------------------------------------------------------------------------------------------------
@@ -70,20 +71,12 @@ public class RestChildren {
 
 		/**
 		 * Constructor.
-		 */
-		protected Builder() {
-			super(RestChildren.class);
-			list = AList.create();
-		}
-
-		/**
-		 * Copy constructor.
 		 *
-		 * @param copyFrom The builder being copied.
+		 * @param beanStore The bean store to use for creating beans.
 		 */
-		protected Builder(Builder copyFrom) {
-			super(copyFrom);
-			list = AList.of(copyFrom.list);
+		protected Builder(BeanStore beanStore) {
+			super(RestChildren.class, beanStore);
+			list = AList.create();
 		}
 
 		@Override /* BeanBuilder */
@@ -91,11 +84,6 @@ public class RestChildren {
 			return new RestChildren(this);
 		}
 
-		@Override /* BeanBuilder */
-		public Builder copy() {
-			return new Builder(this);
-		}
-
 		//-------------------------------------------------------------------------------------------------------------
 		// Properties
 		//-------------------------------------------------------------------------------------------------------------
@@ -114,24 +102,12 @@ public class RestChildren {
 		// <FluentSetters>
 
 		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
-		public Builder beanStore(BeanStore value) {
-			super.beanStore(value);
-			return this;
-		}
-
-		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
 		public Builder impl(Object value) {
 			super.impl(value);
 			return this;
 		}
 
 		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
-		public Builder outer(Object value) {
-			super.outer(value);
-			return this;
-		}
-
-		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
 		public Builder type(Class<?> value) {
 			super.type(value);
 			return this;
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
index cd62d1b..550ab8c 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
@@ -40,7 +40,6 @@ import java.util.concurrent.*;
 import java.util.concurrent.atomic.*;
 import java.util.function.*;
 import java.util.logging.*;
-import java.util.stream.*;
 
 import javax.servlet.*;
 import javax.servlet.http.*;
@@ -188,7 +187,7 @@ public class RestContext extends Context {
 			.addBean(Class.class, resourceClass)
 			.addBean(RestContext.class, parentContext)
 			.addBean(ServletConfig.class, servletConfig)
-			.creator(Builder.class)
+			.createBean(Builder.class)
 			.type(v.get())
 			.run();
 	}
@@ -313,7 +312,7 @@ public class RestContext extends Context {
 		@Override /* BeanContext.Builder */
 		public RestContext build() {
 			try {
-				return BeanCreator.of(RestContext.class).outer(resource.get()).store(beanStore()).builder(this).type(getType().orElse(RestContext.class)).run();
+				return beanStore().createBean(RestContext.class).type(getType().orElse(RestContext.class)).builder(RestContext.Builder.class, this).run();
 			} catch (Exception e) {
 				throw new InternalServerError(e, "Could not instantiate RestContext.");
 			}
@@ -342,10 +341,12 @@ public class RestContext extends Context {
 				.addBean(Builder.class, this)
 				.addBean(ServletConfig.class, ofNullable(inner).orElse(this))
 				.addBean(ServletContext.class, ofNullable(inner).orElse(this).getServletContext());
-			BeanStore bs = beanStore;
 
-			if (rootBeanStore == null)
-				rootBeanStore = beanStore.copy().build();
+			if (rootBeanStore == null) {
+				rootBeanStore = beanStore;
+				beanStore = BeanStore.of(rootBeanStore, r.get());
+			}
+			BeanStore bs = beanStore;
 
 			varResolver = createVarResolver(bs, rc);
 			beanStore.add(VarResolver.class, varResolver.build());
@@ -383,14 +384,10 @@ public class RestContext extends Context {
 			}
 
 			for (MethodInfo m : map.values()) {
-				List<ParamInfo> params = m.getParams();
-
-				List<ClassInfo> missing = beanStore.getMissingParamTypes(params);
-				if (! missing.isEmpty())
-					throw servletException("Could not call @RestHook(INIT) method {0}.{1}.  Could not find prerequisites: {2}.", m.getDeclaringClass().getSimpleName(), m.getSignature(), missing.stream().map(x->x.getSimpleName()).collect(Collectors.joining(",")));
-
+				if (! beanStore.hasAllParams(m))
+					throw servletException("Could not call @RestHook(INIT) method {0}.{1}.  Could not find prerequisites: {2}.", m.getDeclaringClass().getSimpleName(), m.getSignature(), beanStore.getMissingParams(m));
 				try {
-					m.invoke(r, beanStore.getParams(params));
+					m.invoke(r, beanStore.getParams(m));
 				} catch (Exception e) {
 					throw servletException(e, "Exception thrown from @RestHook(INIT) method {0}.{1}.", m.getDeclaringClass().getSimpleName(), m.getSignature());
 				}
@@ -602,13 +599,13 @@ public class RestContext extends Context {
 
 			// Replace with builder from:  public [static] BeanStore.Builder createBeanStore(<args>)
 			v.get().build()
-				.beanCreateMethodFinder(BeanStore.Builder.class)
+				.createMethodFinder(BeanStore.Builder.class)
 				.find("createBeanStore")
 				.run(x -> v.set(x));
 
 			// Replace with bean from:  public [static] BeanStore createBeanStore(<args>)
 			v.get().build()
-				.beanCreateMethodFinder(BeanStore.class)
+				.createMethodFinder(BeanStore.class)
 				.find("createBeanStore")
 				.run(x -> v.get().impl(x));
 
@@ -714,29 +711,23 @@ public class RestContext extends Context {
 					.defaultVars()
 					.vars(createVars(beanStore, resourceClass))
 					.vars(FileVar.class)
-					.bean(FileFinder.class, FileFinder.create().cp(resourceClass,null,true).build())
+					.bean(FileFinder.class, FileFinder.create(beanStore).cp(resourceClass,null,true).build())
 			);
 
-			// Replace with builder from bean store.
-			beanStore
-				.getBean(VarResolver.Builder.class)
-				.map(y -> y.copy())
-				.ifPresent(x -> v.set(x));
-
 			// Replace with bean from bean store.
-			beanStore
+			rootBeanStore
 				.getBean(VarResolver.class)
 				.ifPresent(x -> v.get().impl(x));
 
 			// Replace with builder from:  public [static] VarResolver.Builder createVarResolver(<args>)
 			beanStore
-				.beanCreateMethodFinder(VarResolver.Builder.class)
+				.createMethodFinder(VarResolver.Builder.class)
 				.find("createVarResolver")
 				.run(x -> v.set(x));
 
 			// Replace with bean from:  public [static] VarResolver createVarResolver(<args>)
 			beanStore
-				.beanCreateMethodFinder(VarResolver.class)
+				.createMethodFinder(VarResolver.class)
 				.addBean(VarResolver.Builder.class, v.get())
 				.find("createVarResolver")
 				.run(x -> v.get().impl(x));
@@ -797,7 +788,7 @@ public class RestContext extends Context {
 
 			// Replace with bean from:  public [static] VarList createVars(<args>)
 			beanStore
-				.beanCreateMethodFinder(VarList.class)
+				.createMethodFinder(VarList.class)
 				.addBean(VarList.class, v.get())
 				.find("createVars")
 				.run(x -> v.set(x));
@@ -913,7 +904,7 @@ public class RestContext extends Context {
 
 			// Replace with bean from:  public [static] Config createConfig(<args>)
 			beanStore
-				.beanCreateMethodFinder(Config.class)
+				.createMethodFinder(Config.class)
 				.addBean(Config.class, v.get())
 				.find("createConfig")
 				.run(x -> v.set(x));
@@ -1011,7 +1002,7 @@ public class RestContext extends Context {
 
 			// Replace with bean from:  public [static] Logger createLogger(<args>)
 			beanStore
-				.beanCreateMethodFinder(Logger.class)
+				.createMethodFinder(Logger.class)
 				.addBean(Logger.class, v.get())
 				.find("createLogger")
 				.run(x -> v.set(x));
@@ -1088,8 +1079,7 @@ public class RestContext extends Context {
 			// Default value.
 			Value<ThrownStore.Builder> v = Value.of(
 				ThrownStore
-					.create()
-					.beanStore(beanStore)
+					.create(beanStore)
 					.impl(parent == null ? null : parent.getThrownStore())
 			);
 
@@ -1098,27 +1088,21 @@ public class RestContext extends Context {
 				.get(ThrownStore.class)
 				.ifPresent(x -> v.get().type(x));
 
-			// Replace with builder from bean store.
-			beanStore
-				.getBean(ThrownStore.Builder.class)
-				.map(x -> x.copy())
-				.ifPresent(x->v.set(x));
-
 			// Replace with bean from bean store.
-			beanStore
+			rootBeanStore
 				.getBean(ThrownStore.class)
 				.ifPresent(x->v.get().impl(x));
 
 			// Replace with builder from:  public [static] ThrownStore.Builder createThrownStore(<args>)
 			beanStore
-				.beanCreateMethodFinder(ThrownStore.Builder.class)
+				.createMethodFinder(ThrownStore.Builder.class)
 				.addBean(ThrownStore.Builder.class, v.get())
 				.find("createThrownStore")
 				.run(x -> v.set(x));
 
 			// Replace with bean from:  public [static] ThrownStore createThrownStore(<args>)
 			beanStore
-				.beanCreateMethodFinder(ThrownStore.class)
+				.createMethodFinder(ThrownStore.class)
 				.addBean(ThrownStore.Builder.class, v.get())
 				.find("createThrownStore")
 				.run(x -> v.get().impl(x));
@@ -1199,8 +1183,7 @@ public class RestContext extends Context {
 			// Default value.
 			Value<EncoderSet.Builder> v = Value.of(
 				EncoderSet
-					.create()
-					.beanStore(beanStore)
+					.create(beanStore)
 					.add(IdentityEncoder.INSTANCE)
 			);
 
@@ -1209,27 +1192,21 @@ public class RestContext extends Context {
 				.get(EncoderSet.class)
 				.ifPresent(x -> v.get().type(x));
 
-			// Replace with builder from bean store.
-			beanStore
-				.getBean(EncoderSet.Builder.class)
-				.map(x -> x.copy())
-				.ifPresent(x->v.set(x));
-
 			// Replace with bean from bean store.
-			beanStore
+			rootBeanStore
 				.getBean(EncoderSet.class)
 				.ifPresent(x->v.get().impl(x));
 
 			// Replace with builder from:  public [static] EncoderSet.Builder createEncoders(<args>)
 			beanStore
-				.beanCreateMethodFinder(EncoderSet.Builder.class)
+				.createMethodFinder(EncoderSet.Builder.class)
 				.addBean(EncoderSet.Builder.class, v.get())
 				.find("createEncoders")
 				.run(x -> v.set(x));
 
 			// Replace with bean from:  public [static] EncoderSet createEncoders(<args>)
 			beanStore
-				.beanCreateMethodFinder(EncoderSet.class)
+				.createMethodFinder(EncoderSet.class)
 				.addBean(EncoderSet.Builder.class, v.get())
 				.find("createEncoders")
 				.run(x -> v.get().impl(x));
@@ -1289,8 +1266,7 @@ public class RestContext extends Context {
 			// Default value.
 			Value<SerializerSet.Builder> v = Value.of(
 				SerializerSet
-					.create()
-					.beanStore(beanStore)
+					.create(beanStore)
 			);
 
 			// Specify the implementation class if its set as a default.
@@ -1298,27 +1274,21 @@ public class RestContext extends Context {
 				.get(SerializerSet.class)
 				.ifPresent(x -> v.get().type(x));
 
-			// Replace with builder from bean store.
-			beanStore
-				.getBean(SerializerSet.Builder.class)
-				.map(x -> x.copy())
-				.ifPresent(x->v.set(x));
-
 			// Replace with bean from bean store.
-			beanStore
+			rootBeanStore
 				.getBean(SerializerSet.class)
 				.ifPresent(x->v.get().impl(x));
 
 			// Replace with builder from:  public [static] SerializerSet.Builder createSerializers(<args>)
 			beanStore
-				.beanCreateMethodFinder(SerializerSet.Builder.class)
+				.createMethodFinder(SerializerSet.Builder.class)
 				.addBean(SerializerSet.Builder.class, v.get())
 				.find("createSerializers")
 				.run(x -> v.set(x));
 
 			// Replace with bean from:  public [static] SerializerSet createSerializers(<args>)
 			beanStore
-				.beanCreateMethodFinder(SerializerSet.class)
+				.createMethodFinder(SerializerSet.class)
 				.addBean(SerializerSet.Builder.class, v.get())
 				.find("createSerializers")
 				.run(x -> v.get().impl(x));
@@ -1378,8 +1348,7 @@ public class RestContext extends Context {
 			// Default value.
 			Value<ParserSet.Builder> v = Value.of(
 				ParserSet
-					.create()
-					.beanStore(beanStore)
+					.create(beanStore)
 			);
 
 			// Specify the implementation class if its set as a default.
@@ -1387,27 +1356,21 @@ public class RestContext extends Context {
 				.get(ParserSet.class)
 				.ifPresent(x -> v.get().type(x));
 
-			// Replace with builder from bean store.
-			beanStore
-				.getBean(ParserSet.Builder.class)
-				.map(x -> x.copy())
-				.ifPresent(x->v.set(x));
-
 			// Replace with bean from bean store.
-			beanStore
+			rootBeanStore
 				.getBean(ParserSet.class)
 				.ifPresent(x->v.get().impl(x));
 
 			// Replace with builder from:  public [static] ParserSet.Builder createParsers(<args>)
 			beanStore
-				.beanCreateMethodFinder(ParserSet.Builder.class)
+				.createMethodFinder(ParserSet.Builder.class)
 				.addBean(ParserSet.Builder.class, v.get())
 				.find("createParsers")
 				.run(x -> v.set(x));
 
 			// Replace with bean from:  public [static] ParserSet createParsers(<args>)
 			beanStore
-				.beanCreateMethodFinder(ParserSet.class)
+				.createMethodFinder(ParserSet.class)
 				.addBean(ParserSet.Builder.class, v.get())
 				.find("createParsers")
 				.run(x -> v.get().impl(x));
@@ -1466,8 +1429,7 @@ public class RestContext extends Context {
 			// Default value.
 			Value<MethodExecStore.Builder> v = Value.of(
 				MethodExecStore
-					.create()
-					.beanStore(beanStore)
+					.create(beanStore)
 			);
 
 			// Specify the implementation class if its set as a default.
@@ -1475,27 +1437,21 @@ public class RestContext extends Context {
 				.get(MethodExecStore.class)
 				.ifPresent(x -> v.get().type(x));
 
-			// Replace with builder from bean store.
-			beanStore
-				.getBean(MethodExecStore.Builder.class)
-				.map(x -> x.copy())
-				.ifPresent(x->v.set(x));
-
 			// Replace with bean from bean store.
-			beanStore
+			rootBeanStore
 				.getBean(MethodExecStore.class)
 				.ifPresent(x->v.get().impl(x));
 
 			// Replace with builder from:  public [static] MethodExecStore.Builder createThrownStore(<args>)
 			beanStore
-				.beanCreateMethodFinder(MethodExecStore.Builder.class)
+				.createMethodFinder(MethodExecStore.Builder.class)
 				.addBean(MethodExecStore.Builder.class, v.get())
 				.find("createMethodExecStore")
 				.run(x -> v.set(x));
 
 			// Replace with bean from:  public [static] MethodExecStore createThrownStore(<args>)
 			beanStore
-				.beanCreateMethodFinder(MethodExecStore.class)
+				.createMethodFinder(MethodExecStore.class)
 				.addBean(MethodExecStore.Builder.class, v.get())
 				.find("createMethodExecStore")
 				.run(x -> v.get().impl(x));
@@ -1630,26 +1586,20 @@ public class RestContext extends Context {
 				.create(resourceClass)
 			);
 
-			// Replace with builder from bean store.
-			beanStore
-				.getBean(Messages.Builder.class)
-				.map(x -> x.copy())
-				.ifPresent(x->v.set(x));
-
 			// Replace with bean from bean store.
-			beanStore
+			rootBeanStore
 				.getBean(Messages.class)
 				.ifPresent(x->v.get().impl(x));
 
 			// Replace with builder from:  public [static] Messages.Builder createMessages(<args>)
 			beanStore
-				.beanCreateMethodFinder(Messages.Builder.class)
+				.createMethodFinder(Messages.Builder.class)
 				.find("createMessages")
 				.run(x -> v.set(x));
 
 			// Replace with bean from:  public [static] Messages createMessages(<args>)
 			beanStore
-				.beanCreateMethodFinder(Messages.class)
+				.createMethodFinder(Messages.class)
 				.addBean(Messages.Builder.class, v.get())
 				.find("createMessages")
 				.run(x -> v.get().impl(x));
@@ -1808,8 +1758,7 @@ public class RestContext extends Context {
 			// Default value.
 			Value<ResponseProcessorList.Builder> v = Value.of(
 				 ResponseProcessorList
-				 	.create()
-				 	.beanStore(beanStore)
+				 	.create(beanStore)
 				 	.add(
 						ReaderProcessor.class,
 						InputStreamProcessor.class,
@@ -1823,27 +1772,21 @@ public class RestContext extends Context {
 					)
 			);
 
-			// Replace with builder from bean store.
-			beanStore
-				.getBean(ResponseProcessorList.Builder.class)
-				.map(x -> x.copy())
-				.ifPresent(x -> v.set(x));
-
 			// Replace with bean from bean store.
-			beanStore
+			rootBeanStore
 				.getBean(ResponseProcessorList.class)
 				.ifPresent(x -> v.get().impl(x));
 
 			// Replace with builder from:  public [static] ResponseProcessorList.Builder createResponseProcessors(<args>)
 			beanStore
-				.beanCreateMethodFinder(ResponseProcessorList.Builder.class)
+				.createMethodFinder(ResponseProcessorList.Builder.class)
 				.addBean(ResponseProcessorList.Builder.class, v.get())
 				.find("createResponseProcessors")
 				.run(x -> v.set(x));
 
 			// Replace with bean from:  public [static] ResponseProcessorList createResponseProcessors(<args>)
 			beanStore
-				.beanCreateMethodFinder(ResponseProcessorList.class)
+				.createMethodFinder(ResponseProcessorList.class)
 				.addBean(ResponseProcessorList.Builder.class, v.get())
 				.find("createResponseProcessors")
 				.run(x -> v.get().impl(x));
@@ -1984,16 +1927,15 @@ public class RestContext extends Context {
 			// Default value.
 			Value<RestLogger.Builder> v = Value.of(
 				RestLogger
-					.create()
-					.beanStore(beanStore)
+					.create(beanStore)
 					.normalRules(  // Rules when debugging is not enabled.
-						RestLoggerRule.create()  // Log 500+ errors with status-line and header information.
+						RestLoggerRule.create(beanStore)  // Log 500+ errors with status-line and header information.
 							.statusFilter(a -> a >= 500)
 							.level(SEVERE)
 							.requestDetail(HEADER)
 							.responseDetail(HEADER)
 							.build(),
-						RestLoggerRule.create()  // Log 400-500 errors with just status-line information.
+						RestLoggerRule.create(beanStore)  // Log 400-500 errors with just status-line information.
 							.statusFilter(a -> a >= 400)
 							.level(WARNING)
 							.requestDetail(STATUS_LINE)
@@ -2001,7 +1943,7 @@ public class RestContext extends Context {
 							.build()
 					)
 					.debugRules(  // Rules when debugging is enabled.
-						RestLoggerRule.create()  // Log everything with full details.
+						RestLoggerRule.create(beanStore)  // Log everything with full details.
 							.level(SEVERE)
 							.requestDetail(ENTITY)
 							.responseDetail(ENTITY)
@@ -2009,14 +1951,8 @@ public class RestContext extends Context {
 					)
 			);
 
-			// Replace with builder from bean store.
-			beanStore
-				.getBean(RestLogger.Builder.class)
-				.map(x -> x.copy())
-				.ifPresent(x-> v.set(x));
-
 			// Replace with bean from bean store.
-			beanStore
+			rootBeanStore
 				.getBean(RestLogger.class)
 				.ifPresent(x-> v.get().impl(x));
 
@@ -2031,14 +1967,14 @@ public class RestContext extends Context {
 
 			// Replace with builder from:  public [static] RestLogger.Builder createCallLogger(<args>)
 			beanStore
-				.beanCreateMethodFinder(RestLogger.Builder.class)
+				.createMethodFinder(RestLogger.Builder.class)
 				.addBean(RestLogger.Builder.class, v.get())
 				.find("createCallLogger")
 				.run(x -> v.set(x));
 
 			// Replace with bean from:  public [static] RestLogger createCallLogger(<args>)
 			beanStore
-				.beanCreateMethodFinder(RestLogger.class)
+				.createMethodFinder(RestLogger.class)
 				.addBean(RestLogger.Builder.class, v.get())
 				.find("createCallLogger")
 				.run(x -> v.get().impl(x));
@@ -2126,20 +2062,20 @@ public class RestContext extends Context {
 				.ifPresent(x -> v.set(x));
 
 			// Replace with bean from bean store.
-			beanStore
+			rootBeanStore
 				.getBean(BeanContext.class)
 				.ifPresent(x -> v.get().impl(x));
 
 			// Replace with builder from:  public [static] BeanContext.Builder createBeanContext(<args>)
 			beanStore
-				.beanCreateMethodFinder(BeanContext.Builder.class)
+				.createMethodFinder(BeanContext.Builder.class)
 				.addBean(BeanContext.Builder.class, v.get())
 				.find("createBeanContext")
 				.run(x -> v.set(x));
 
 			// Replace with builder from:  public [static] BeanContext createBeanContext(<args>)
 			beanStore
-				.beanCreateMethodFinder(BeanContext.class)
+				.createMethodFinder(BeanContext.class)
 				.addBean(BeanContext.Builder.class, v.get())
 				.find("createBeanContext")
 				.run(x -> v.get().impl(x));
@@ -2229,7 +2165,7 @@ public class RestContext extends Context {
 				.ifPresent(x -> v.set(x));
 
 			// Replace with bean from bean store.
-			beanStore
+			rootBeanStore
 				.getBean(HttpPartSerializer.class)
 				.ifPresent(x -> v.get().impl(x));
 
@@ -2244,14 +2180,14 @@ public class RestContext extends Context {
 
 			// Replace with builder from:  public [static] HttpPartSerializer.Creator createPartSerializer(<args>)
 			beanStore
-				.beanCreateMethodFinder(HttpPartSerializer.Creator.class)
+				.createMethodFinder(HttpPartSerializer.Creator.class)
 				.addBean(HttpPartSerializer.Creator.class, v.get())
 				.find("createPartSerializer")
 				.run(x -> v.set(x));
 
 			// Replace with bean from:  public [static] HttpPartSerializer createPartSerializer(<args>)
 			beanStore
-				.beanCreateMethodFinder(HttpPartSerializer.class)
+				.createMethodFinder(HttpPartSerializer.class)
 				.addBean(HttpPartSerializer.Creator.class, v.get())
 				.find("createPartSerializer")
 				.run(x -> v.get().impl(x));
@@ -2341,7 +2277,7 @@ public class RestContext extends Context {
 				.ifPresent(x -> v.set(x));
 
 			// Replace with bean from bean store.
-			beanStore
+			rootBeanStore
 				.getBean(HttpPartParser.class)
 				.ifPresent(x -> v.get().impl(x));
 
@@ -2356,14 +2292,14 @@ public class RestContext extends Context {
 
 			// Replace with builder from:  public [static] HttpPartParser.Creator createPartParser(<args>)
 			beanStore
-				.beanCreateMethodFinder(HttpPartParser.Creator.class)
+				.createMethodFinder(HttpPartParser.Creator.class)
 				.addBean(HttpPartParser.Creator.class, v.get())
 				.find("createPartParser")
 				.run(x -> v.set(x));
 
 			// Replace with bean from:  public [static] HttpPartParser createPartParser(<args>)
 			beanStore
-				.beanCreateMethodFinder(HttpPartParser.class)
+				.createMethodFinder(HttpPartParser.class)
 				.addBean(HttpPartParser.Creator.class, v.get())
 				.find("createPartParser")
 				.run(x -> v.get().impl(x));
@@ -2445,20 +2381,20 @@ public class RestContext extends Context {
 				.ifPresent(x -> v.set(x));
 
 			// Replace with bean from bean store.
-			beanStore
+			rootBeanStore
 				.getBean(JsonSchemaGenerator.class)
 				.ifPresent(x -> v.get().impl(x));
 
 			// Replace with builder from:  public [static] JsonSchemaGeneratorBuilder createJsonSchemaGenerator(<args>)
 			beanStore
-				.beanCreateMethodFinder(JsonSchemaGenerator.Builder.class)
+				.createMethodFinder(JsonSchemaGenerator.Builder.class)
 				.addBean(JsonSchemaGenerator.Builder.class, v.get())
 				.find("createJsonSchemaGenerator")
 				.run(x -> v.set(x));
 
 			// Replace with bean from:  public [static] JsonSchemaGenerator createJsonSchemaGenerator(<args>)
 			beanStore
-				.beanCreateMethodFinder(JsonSchemaGenerator.class)
+				.createMethodFinder(JsonSchemaGenerator.class)
 				.addBean(JsonSchemaGenerator.Builder.class, v.get())
 				.find("createJsonSchemaGenerator")
 				.run(x -> v.get().impl(x));
@@ -2635,8 +2571,7 @@ public class RestContext extends Context {
 			// Default value.
 			Value<FileFinder.Builder> v = Value.of(
 				FileFinder
-					.create()
-					.beanStore(beanStore)
+					.create(beanStore)
 					.dir("static")
 					.dir("htdocs")
 					.cp(resourceClass, "htdocs", true)
@@ -2645,14 +2580,8 @@ public class RestContext extends Context {
 					.exclude("(?i).*\\.(class|properties)")
 			);
 
-			// Replace with builder from bean store.
-			beanStore
-				.getBean(FileFinder.Builder.class)
-				.map(x -> x.copy())
-				.ifPresent(x -> v.set(x));
-
 			// Replace with bean from bean store.
-			beanStore
+			rootBeanStore
 				.getBean(FileFinder.class)
 				.ifPresent(x -> v.get().impl(x));
 
@@ -2667,14 +2596,14 @@ public class RestContext extends Context {
 
 			// Replace with builder from:  public [static] FileFinder.Builder createFileFinder(<args>)
 			beanStore
-				.beanCreateMethodFinder(FileFinder.Builder.class)
+				.createMethodFinder(FileFinder.Builder.class)
 				.addBean(FileFinder.Builder.class, v.get())
 				.find("createFileFinder")
 				.run(x -> v.set(x));
 
 			// Replace with bean from:  public [static] FileFinder createFileFinder(<args>)
 			beanStore
-				.beanCreateMethodFinder(FileFinder.class)
+				.createMethodFinder(FileFinder.class)
 				.addBean(FileFinder.Builder.class, v.get())
 				.find("createFileFinder")
 				.run(x -> v.get().impl(x));
@@ -2752,8 +2681,7 @@ public class RestContext extends Context {
 		 * 		Constructs a builder with default settings:
 		 * 		<p class='bcode w800'>
 		 * 	StaticFiles
-		 * 		.<jsm>create</jsm>()
-		 * 		.{@link org.apache.juneau.rest.staticfile.StaticFiles.Builder#beanStore(BeanStore) beanStore}(<jv>beanStore</jv>)  <jc>// Allow injected beans in constructor.</jc>
+		 * 		.<jsm>create</jsm>(<jv>beanStore</jv>)
 		 * 		.{@link org.apache.juneau.rest.staticfile.StaticFiles.Builder#type(Class) type}({@link BasicStaticFiles}.<jk>class</jk>)
 		 * 		.{@link org.apache.juneau.rest.staticfile.StaticFiles.Builder#dir(String) dir}(<js>"static"</js>)  <jc>// Look in working /static directory.</jc>
 		 * 		.{@link org.apache.juneau.rest.staticfile.StaticFiles.Builder#dir(String) dir}(<js>"htdocs"</js>)  <jc>// Look in working /htdocs directory.</jc>
@@ -2823,8 +2751,7 @@ public class RestContext extends Context {
 			// Default value.
 			Value<StaticFiles.Builder> v = Value.of(
 				StaticFiles
-					.create()
-					.beanStore(beanStore)
+					.create(beanStore)
 					.type(BasicStaticFiles.class)
 					.dir("static")
 					.dir("htdocs")
@@ -2835,14 +2762,8 @@ public class RestContext extends Context {
 					.headers(cacheControl("max-age=86400, public"))
 			);
 
-			// Replace with builder from bean store.
-			beanStore
-				.getBean(StaticFiles.Builder.class)
-				.map(x -> x.copy())
-				.ifPresent(x -> v.set(x));
-
 			// Replace with bean from bean store.
-			beanStore
+			rootBeanStore
 				.getBean(StaticFiles.class)
 				.ifPresent(x -> v.get().impl(x));
 
@@ -2857,14 +2778,14 @@ public class RestContext extends Context {
 
 			// Replace with builder from:  public [static] StaticFiles.Builder createStaticFiles(<args>)
 			beanStore
-				.beanCreateMethodFinder(StaticFiles.Builder.class)
+				.createMethodFinder(StaticFiles.Builder.class)
 				.addBean(StaticFiles.Builder.class, v.get())
 				.find("createStaticFiles")
 				.run(x -> v.set(x));
 
 			// Replace with bean from:  public [static] StaticFiles createStaticFiles(<args>)
 			beanStore
-				.beanCreateMethodFinder(StaticFiles.class)
+				.createMethodFinder(StaticFiles.class)
 				.addBean(StaticFiles.Builder.class, v.get())
 				.find("createStaticFiles")
 				.run(x -> v.get().impl(x));
@@ -3016,27 +2937,21 @@ public class RestContext extends Context {
 				HeaderList.create()
 			);
 
-			// Replace with builder from bean store.
-			beanStore
-				.getBean("RestContext.defaultRequestHeaders", HeaderList.Builder.class)
-				.map(x -> x.copy())
-				.ifPresent(x -> v.set(x));
-
 			// Replace with bean from bean store.
-			beanStore
-				.getBean("RestContext.defaultRequestHeaders", HeaderList.class)
+			rootBeanStore
+				.getBean(HeaderList.class, "RestContext.defaultRequestHeaders")
 				.ifPresent(x -> v.get().impl(x));
 
 			// Replace with builder from:  public [static] HeaderList.Builder createDefaultRequestHeaders(<args>)
 			beanStore
-				.beanCreateMethodFinder(HeaderList.Builder.class)
+				.createMethodFinder(HeaderList.Builder.class)
 				.addBean(HeaderList.Builder.class, v.get())
 				.find("createDefaultRequestHeaders")
 				.run(x -> v.set(x));
 
 			// Replace with bean from:  public [static] HeaderList createDefaultRequestHeaders(<args>)
 			beanStore
-				.beanCreateMethodFinder(HeaderList.class)
+				.createMethodFinder(HeaderList.class)
 				.addBean(HeaderList.Builder.class, v.get())
 				.find("createDefaultRequestHeaders")
 				.run(x -> v.get().impl(x));
@@ -3154,27 +3069,21 @@ public class RestContext extends Context {
 				HeaderList.create()
 			);
 
-			// Replace with builder from bean store.
-			beanStore
-				.getBean("RestContext.defaultResponseHeaders", HeaderList.Builder.class)
-				.map(x -> x.copy())
-				.ifPresent(x -> v.set(x));
-
 			// Replace with bean from bean store.
-			beanStore
-				.getBean("RestContext.defaultResponseHeaders", HeaderList.class)
+			rootBeanStore
+				.getBean(HeaderList.class, "RestContext.defaultResponseHeaders")
 				.ifPresent(x -> v.get().impl(x));
 
 			// Replace with builder from:  public [static] HeaderList.Builder createDefaultResponseHeaders(<args>)
 			beanStore
-				.beanCreateMethodFinder(HeaderList.Builder.class)
+				.createMethodFinder(HeaderList.Builder.class)
 				.addBean(HeaderList.Builder.class, v.get())
 				.find("createDefaultResponseHeaders")
 				.run(x -> v.set(x));
 
 			// Replace with bean from:  public [static] HeaderList createDefaultResponseHeaders(<args>)
 			beanStore
-				.beanCreateMethodFinder(HeaderList.class)
+				.createMethodFinder(HeaderList.class)
 				.addBean(HeaderList.Builder.class, v.get())
 				.find("createDefaultResponseHeaders")
 				.run(x -> v.get().impl(x));
@@ -3289,26 +3198,20 @@ public class RestContext extends Context {
 				NamedAttributeList.create()
 			);
 
-			// Replace with bean from bean store.
-			beanStore
-				.getBean("RestContext.defaultRequestAttributes", NamedAttributeList.Builder.class)
-				.map(x -> x.copy())
-				.ifPresent(x -> v.set(x));
-
-			beanStore
-				.getBean("RestContext.defaultRequestAttributes", NamedAttributeList.class)
+			rootBeanStore
+				.getBean(NamedAttributeList.class, "RestContext.defaultRequestAttributes")
 				.ifPresent(x -> v.get().impl(x));
 
 			// Replace with bean from:  public [static] NamedAttributeList.Builder createDefaultRequestAttributes(<args>)
 			beanStore
-				.beanCreateMethodFinder(NamedAttributeList.Builder.class)
+				.createMethodFinder(NamedAttributeList.Builder.class)
 				.addBean(NamedAttributeList.Builder.class, v.get())
 				.find("createDefaultRequestAttributes")
 				.run(x -> v.set(x));
 
 			// Replace with bean from:  public [static] NamedAttributeList createDefaultRequestAttributes(<args>)
 			beanStore
-				.beanCreateMethodFinder(NamedAttributeList.class)
+				.createMethodFinder(NamedAttributeList.class)
 				.addBean(NamedAttributeList.Builder.class, v.get())
 				.find("createDefaultRequestAttributes")
 				.run(x -> v.get().impl(x));
@@ -3455,7 +3358,8 @@ public class RestContext extends Context {
 			// Default value.
 			Value<RestOpArgList.Builder> v = Value.of(
 				RestOpArgList
-					.of(
+					.create(beanStore)
+					.add(
 						AttributeArg.class,
 						BodyArg.class,
 						FormDataArg.class,
@@ -3485,27 +3389,21 @@ public class RestContext extends Context {
 					)
 			);
 
-			// Replace with builder from bean store.
-			beanStore
-				.getBean("RestContext.restOpArgs", RestOpArgList.Builder.class)
-				.map(x -> x.copy())
-				.ifPresent(x -> v.set(x));
-
 			// Replace with bean from bean store.
-			beanStore
-				.getBean("RestContext.restOpArgs", RestOpArgList.class)
+			rootBeanStore
+				.getBean(RestOpArgList.class)
 				.ifPresent(x -> v.get().impl(x));
 
 			// Replace with builder from:  public [static] RestOpArgList.Builder createRestOpArgs(<args>)
 			beanStore
-				.beanCreateMethodFinder(RestOpArgList.Builder.class)
+				.createMethodFinder(RestOpArgList.Builder.class)
 				.addBean(RestOpArgList.Builder.class, v.get())
 				.find("createRestOpArgs")
 				.run(x -> v.set(x));
 
 			// Replace with bean from:  public [static] RestOpArgList createRestOpArgs(<args>)
 			beanStore
-				.beanCreateMethodFinder(RestOpArgList.class)
+				.createMethodFinder(RestOpArgList.class)
 				.addBean(RestOpArgList.Builder.class, v.get())
 				.find("createRestOpArgs")
 				.run(x -> v.get().impl(x));
@@ -3629,8 +3527,7 @@ public class RestContext extends Context {
 			// Default value.
 			Value<DebugEnablement.Builder> v = Value.of(
 				DebugEnablement
-					.create()
-					.beanStore(beanStore)
+					.create(beanStore)
 			);
 
 			// Default debug enablement if not overridden at class/method level.
@@ -3638,24 +3535,19 @@ public class RestContext extends Context {
 			v.get().defaultEnable(debugDefault);
 
 			// Gather @RestOp(debug) settings.
-			for (MethodInfo mi : ClassInfo.ofProxy(resource.get()).getPublicMethods()) {
-				mi
+			ClassInfo.ofProxy(resource.get()).getPublicMethods(
+				x -> true,
+				x -> x
 					.getAnnotationGroupList(RestOp.class)
 					.getValues(String.class, "debug")
 					.stream()
 					.filter(y->!y.isEmpty())
 					.findFirst()
-					.ifPresent(x -> v.get().enable(Enablement.fromString(x), mi.getFullName()));
-			}
-
-			// Replace with builder from bean store.
-			beanStore
-				.getBean(DebugEnablement.Builder.class)
-				.map(x -> x.copy())
-				.ifPresent(x -> v.set(x));
+					.ifPresent(x2 -> v.get().enable(Enablement.fromString(x2), x.getFullName()))
+			);
 
 			// Replace with bean from bean store.
-			beanStore
+			rootBeanStore
 				.getBean(DebugEnablement.class)
 				.ifPresent(x -> v.get().impl(x));
 
@@ -3670,14 +3562,14 @@ public class RestContext extends Context {
 
 			// Replace with builder from:  public [static] DebugEnablement.Builder createDebugEnablement(<args>)
 			beanStore
-				.beanCreateMethodFinder(DebugEnablement.Builder.class)
+				.createMethodFinder(DebugEnablement.Builder.class)
 				.addBean(DebugEnablement.Builder.class, v.get())
 				.find("createDebugEnablement")
 				.run(x -> v.set(x));
 
 			// Replace with bean from:  public [static] DebugEnablement createDebugEnablement(<args>)
 			beanStore
-				.beanCreateMethodFinder(DebugEnablement.class)
+				.createMethodFinder(DebugEnablement.class)
 				.addBean(DebugEnablement.Builder.class, v.get())
 				.find("createDebugEnablement")
 				.run(x -> v.get().impl(x));
@@ -3740,7 +3632,7 @@ public class RestContext extends Context {
 
 			// Replace with bean from:  public [static] MethodList createStartCallMethods(<args>)
 			beanStore
-				.beanCreateMethodFinder(MethodList.class)
+				.createMethodFinder(MethodList.class)
 				.addBean(MethodList.class, v.get())
 				.find("createStartCallMethods")
 				.run(x -> v.set(x));
@@ -3803,7 +3695,7 @@ public class RestContext extends Context {
 
 			// Replace with bean from:  public [static] MethodList createEndCallMethods(<args>)
 			beanStore
-				.beanCreateMethodFinder(MethodList.class)
+				.createMethodFinder(MethodList.class)
 				.addBean(MethodList.class, v.get())
 				.find("createEndCallMethods")
 				.run(x -> v.set(x));
@@ -3866,7 +3758,7 @@ public class RestContext extends Context {
 
 			// Replace with bean from:  public [static] MethodList createPostInitMethods(<args>)
 			beanStore
-				.beanCreateMethodFinder(MethodList.class)
+				.createMethodFinder(MethodList.class)
 				.addBean(MethodList.class, v.get())
 				.find("createPostInitMethods")
 				.run(x -> v.set(x));
@@ -3929,7 +3821,7 @@ public class RestContext extends Context {
 
 			// Replace with bean from:  public [static] MethodList createPostInitChildFirstMethods(<args>)
 			beanStore
-				.beanCreateMethodFinder(MethodList.class)
+				.createMethodFinder(MethodList.class)
 				.addBean(MethodList.class, v.get())
 				.find("createPostInitChildFirstMethods")
 				.run(x -> v.set(x));
@@ -3992,7 +3884,7 @@ public class RestContext extends Context {
 
 			// Replace with bean from:  public [static] MethodList createDestroyMethods(<args>)
 			beanStore
-				.beanCreateMethodFinder(MethodList.class)
+				.createMethodFinder(MethodList.class)
 				.addBean(MethodList.class, v.get())
 				.find("createDestroyMethods")
 				.run(x -> v.set(x));
@@ -4058,7 +3950,7 @@ public class RestContext extends Context {
 
 			// Replace with bean from:  public [static] MethodList createPreCallMethods(<args>)
 			beanStore
-				.beanCreateMethodFinder(MethodList.class)
+				.createMethodFinder(MethodList.class)
 				.addBean(MethodList.class, v.get())
 				.find("createPreCallMethods")
 				.run(x -> v.set(x));
@@ -4124,7 +4016,7 @@ public class RestContext extends Context {
 
 			// Replace with bean from:  public [static] MethodList createPostCallMethods(<args>)
 			beanStore
-				.beanCreateMethodFinder(MethodList.class)
+				.createMethodFinder(MethodList.class)
 				.addBean(MethodList.class, v.get())
 				.find("createPostCallMethods")
 				.run(x -> v.set(x));
@@ -4167,7 +4059,7 @@ public class RestContext extends Context {
 
 			// Default value.
 			Value<RestOperations.Builder> v = Value.of(
-				RestOperations.create()
+				RestOperations.create(beanStore)
 			);
 
 			ClassInfo rci = ClassInfo.of(resource.get());
@@ -4223,14 +4115,14 @@ public class RestContext extends Context {
 
 			// Replace with builder from:  public [static] RestOperations.Builder createRestOperations(<args>)
 			beanStore
-				.beanCreateMethodFinder(RestOperations.Builder.class)
+				.createMethodFinder(RestOperations.Builder.class)
 				.addBean(RestOperations.Builder.class, v.get())
 				.find("createRestOperations")
 				.run(x -> v.set(x));
 
 			// Replace with bean from:  public [static] RestOperations createRestOperations(<args>)
 			beanStore
-				.beanCreateMethodFinder(RestOperations.class)
+				.createMethodFinder(RestOperations.class)
 				.addBean(RestOperations.Builder.class, v.get())
 				.find("createRestOperations")
 				.run(x -> v.get().impl(x));
@@ -4271,8 +4163,7 @@ public class RestContext extends Context {
 			// Default value.
 			Value<RestChildren.Builder> v = Value.of(
 				RestChildren
-					.create()
-					.beanStore(beanStore)
+					.create(beanStore)
 					.type(childrenClass)
 				);
 
@@ -4299,7 +4190,7 @@ public class RestContext extends Context {
 					if (beanStore.getBean(oc).isPresent()) {
 						so = ()->beanStore.getBean(oc).get();  // If we resolved via injection, always get it this way.
 					} else {
-						Object o2 = beanStore.creator(oc).builder(cb).outer(resource).run();
+						Object o2 = beanStore.createBean(oc).builder(RestContext.Builder.class, cb).run();
 						so = ()->o2;
 					}
 				} else {
@@ -4312,7 +4203,10 @@ public class RestContext extends Context {
 
 				RestContext cc = cb.init(so).build();
 
-				MethodInfo mi = ClassInfo.of(o).getMethod("setContext", RestContext.class);
+				MethodInfo mi = ClassInfo.ofc(o).getPublicMethod(
+					x -> x.hasName("setContext")
+					&& x.hasParamTypes(RestContext.class)
+				);
 				if (mi != null)
 					mi.accessible().invoke(o, cc);
 
@@ -4321,14 +4215,14 @@ public class RestContext extends Context {
 
 			// Replace with builder from:  public [static] RestChildren.Builder createRestChildren(<args>)
 			beanStore
-				.beanCreateMethodFinder(RestChildren.Builder.class)
+				.createMethodFinder(RestChildren.Builder.class)
 				.addBean(RestChildren.Builder.class, v.get())
 				.find("createRestChildren")
 				.run(x -> v.set(x));
 
 			// Replace with bean from:  public [static] RestChildren createRestChildren(<args>)
 			beanStore
-				.beanCreateMethodFinder(RestChildren.class)
+				.createMethodFinder(RestChildren.class)
 				.addBean(RestChildren.Builder.class, v.get())
 				.find("createRestChildren")
 				.run(x -> v.get().impl(x));
@@ -4412,8 +4306,7 @@ public class RestContext extends Context {
 			// Default value.
 			Value<SwaggerProvider.Builder> v = Value.of(
 				SwaggerProvider
-					.create()
-					.beanStore(beanStore)
+					.create(beanStore)
 					.varResolver(()->beanStore.getBean(VarResolver.class).orElseThrow(()->runtimeException("VarResolver bean not found.")))
 					.fileFinder(()->beanStore.getBean(FileFinder.class).orElseThrow(()->runtimeException("FileFinder bean not found.")))
 					.messages(()->beanStore.getBean(Messages.class).orElseThrow(()->runtimeException("Messages bean not found.")))
@@ -4421,13 +4314,7 @@ public class RestContext extends Context {
 			);
 
 			// Replace with builder from bean store.
-			beanStore
-				.getBean(SwaggerProvider.Builder.class)
-				.map(x -> x.copy())
-				.ifPresent(x -> v.set(x));
-
-			// Replace with builder from bean store.
-			beanStore
+			rootBeanStore
 				.getBean(SwaggerProvider.class)
 				.ifPresent(x -> v.get().impl(x));
 
@@ -4437,14 +4324,14 @@ public class RestContext extends Context {
 
 			// Replace with builder from:  public [static] SwaggerProvider.Builder createSwaggerProvider(<args>)
 			beanStore
-				.beanCreateMethodFinder(SwaggerProvider.Builder.class)
+				.createMethodFinder(SwaggerProvider.Builder.class)
 				.addBean(SwaggerProvider.Builder.class, v.get())
 				.find("createSwaggerProvider")
 				.run(x -> v.set(x));
 
 			// Replace with bean from:  public [static] SwaggerProvider createSwaggerProvider(<args>)
 			beanStore
-				.beanCreateMethodFinder(SwaggerProvider.class)
+				.createMethodFinder(SwaggerProvider.class)
 				.addBean(SwaggerProvider.Builder.class, v.get())
 				.find("createSwaggerProvider")
 				.run(x -> v.get().impl(x));
@@ -6058,15 +5945,15 @@ public class RestContext extends Context {
 			varResolver = bs.add(VarResolver.class, builder.varResolver().bean(Messages.class, messages).build());
 			config = bs.add(Config.class, builder.config().resolving(varResolver.createSession()));
 			responseProcessors = bs.add(ResponseProcessor[].class, builder.responseProcessors().build().toArray());
-			callLogger = bs.add(RestLogger.class, builder.callLogger().beanStore(beanStore).loggerOnce(logger).thrownStoreOnce(thrownStore).build());
+			callLogger = bs.add(RestLogger.class, builder.callLogger().loggerOnce(logger).thrownStoreOnce(thrownStore).build());
 			partSerializer = bs.add(HttpPartSerializer.class, builder.partSerializer().create());
 			partParser = bs.add(HttpPartParser.class, builder.partParser().create());
 			jsonSchemaGenerator = bs.add(JsonSchemaGenerator.class, builder.jsonSchemaGenerator().build());
 			fileFinder = bs.add(FileFinder.class, builder.fileFinder().build());
 			staticFiles = bs.add(StaticFiles.class, builder.staticFiles().build());
-			defaultRequestHeaders = bs.add("RestContext.defaultRequestHeaders", builder.defaultRequestHeaders().build());
-			defaultResponseHeaders = bs.add("RestContext.defaultResponseHeaders", builder.defaultResponseHeaders().build());
-			defaultRequestAttributes = bs.add("RestContext.defaultRequestAttributes", builder.defaultRequestAttributes().build());
+			defaultRequestHeaders = bs.add(HeaderList.class, builder.defaultRequestHeaders().build(), "RestContext.defaultRequestHeaders");
+			defaultResponseHeaders = bs.add(HeaderList.class, builder.defaultResponseHeaders().build(), "RestContext.defaultResponseHeaders");
+			defaultRequestAttributes = bs.add(NamedAttributeList.class, builder.defaultRequestAttributes().build(), "RestContext.defaultRequestAttributes");
 			restOpArgs = builder.restOpArgs().build().asArray();
 			debugEnablement = builder.debugEnablement().build();
 			startCallMethods = builder.startCallMethods().stream().map(this::toMethodInvoker).toArray(MethodInvoker[]::new);
@@ -6793,7 +6680,7 @@ public class RestContext extends Context {
 			beanStore.addBean(ParamInfo.class, pi);
 			for (Class<? extends RestOpArg> c : restOpArgs) {
 				try {
-					ra[i] = beanStore.creator(RestOpArg.class).type(c).run();
+					ra[i] = beanStore.createBean(RestOpArg.class).type(c).run();
 					if (ra[i] != null)
 						break;
 				} catch (ExecutableException e) {
@@ -7196,7 +7083,10 @@ public class RestContext extends Context {
 		if (initialized.get())
 			return this;
 		Object resource = getResource();
-		MethodInfo mi = ClassInfo.of(getResource()).getMethod("setContext", RestContext.class);
+		MethodInfo mi = ClassInfo.ofc(getResource()).getPublicMethod(
+			x -> x.hasName("setContext")
+			&& x.hasParamTypes(RestContext.class)
+		);
 		if (mi != null) {
 			try {
 				mi.accessible().invoke(resource, this);
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestOpContext.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestOpContext.java
index a575882..7711e91 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestOpContext.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestOpContext.java
@@ -154,7 +154,7 @@ public class RestOpContext extends Context implements Comparable<RestOpContext>
 		@Override /* BeanContext.Builder */
 		public RestOpContext build() {
 			try {
-				return BeanCreator.of(RestOpContext.class).type(getType().orElse(getDefaultImplClass())).store(beanStore).builder(this).run();
+				return beanStore.createBean(RestOpContext.class).type(getType().orElse(getDefaultImplClass())).builder(RestOpContext.Builder.class, this).run();
 			} catch (Exception e) {
 				throw toHttpException(e, InternalServerError.class);
 			}
@@ -904,8 +904,7 @@ public class RestOpContext extends Context implements Comparable<RestOpContext>
 			// Default value.
 			Value<RestConverterList.Builder> v = Value.of(
 				RestConverterList
-					.create()
-					.beanStore(beanStore)
+					.create(beanStore)
 			);
 
 			// Specify the implementation class if its set as a default.
@@ -913,12 +912,6 @@ public class RestOpContext extends Context implements Comparable<RestOpContext>
 				.get(RestConverterList.class)
 				.ifPresent(x -> v.get().type(x));
 
-			// Replace with builder from bean store.
-			beanStore
-				.getBean(RestConverterList.Builder.class)
-				.map(x -> x.copy())
-				.ifPresent(x->v.set(x));
-
 			// Replace with bean from bean store.
 			beanStore
 				.getBean(RestConverterList.class)
@@ -926,14 +919,14 @@ public class RestOpContext extends Context implements Comparable<RestOpContext>
 
 			// Replace with builder from:  public [static] RestConverterList.Builder createConverters(<args>)
 			beanStore
-				.beanCreateMethodFinder(RestConverterList.Builder.class)
+				.createMethodFinder(RestConverterList.Builder.class)
 				.addBean(RestConverterList.Builder.class, v.get())
 				.find("createConverters")
 				.run(x -> v.set(x));
 
 			// Replace with bean from:  public [static] RestConverterList createConverters(<args>)
 			beanStore
-				.beanCreateMethodFinder(RestConverterList.class)
+				.createMethodFinder(RestConverterList.class)
 				.addBean(RestConverterList.Builder.class, v.get())
 				.find("createConverters")
 				.run(x -> v.get().impl(x));
@@ -1013,8 +1006,7 @@ public class RestOpContext extends Context implements Comparable<RestOpContext>
 			// Default value.
 			Value<RestGuardList.Builder> v = Value.of(
 				RestGuardList
-					.create()
-					.beanStore(beanStore)
+					.create(beanStore)
 			);
 
 			// Specify the implementation class if its set as a default.
@@ -1022,12 +1014,6 @@ public class RestOpContext extends Context implements Comparable<RestOpContext>
 				.get(RestGuardList.class)
 				.ifPresent(x -> v.get().type(x));
 
-			// Replace with builder from bean store.
-			beanStore
-				.getBean(RestGuardList.Builder.class)
-				.map(x -> x.copy())
-				.ifPresent(x->v.set(x));
-
 			// Replace with bean from bean store.
 			beanStore
 				.getBean(RestGuardList.class)
@@ -1035,14 +1021,14 @@ public class RestOpContext extends Context implements Comparable<RestOpContext>
 
 			// Replace with builder from:  public [static] RestGuardList.Builder createGuards(<args>)
 			beanStore
-				.beanCreateMethodFinder(RestGuardList.Builder.class)
+				.createMethodFinder(RestGuardList.Builder.class)
 				.addBean(RestGuardList.Builder.class, v.get())
 				.find("createGuards")
 				.run(x -> v.set(x));
 
 			// Replace with bean from:  public [static] RestGuardList createGuards(<args>)
 			beanStore
-				.beanCreateMethodFinder(RestGuardList.class)
+				.createMethodFinder(RestGuardList.class)
 				.addBean(RestGuardList.Builder.class, v.get())
 				.find("createGuards")
 				.run(x -> v.get().impl(x));
@@ -1163,8 +1149,7 @@ public class RestOpContext extends Context implements Comparable<RestOpContext>
 			// Default value.
 			Value<RestMatcherList.Builder> v = Value.of(
 				RestMatcherList
-					.create()
-					.beanStore(beanStore)
+					.create(beanStore)
 			);
 
 			// Specify the implementation class if its set as a default.
@@ -1172,12 +1157,6 @@ public class RestOpContext extends Context implements Comparable<RestOpContext>
 				.get(RestMatcherList.class)
 				.ifPresent(x -> v.get().type(x));
 
-			// Replace with builder from bean store.
-			beanStore
-				.getBean(RestMatcherList.Builder.class)
-				.map(x -> x.copy())
-				.ifPresent(x->v.set(x));
-
 			// Replace with bean from bean store.
 			beanStore
 				.getBean(RestMatcherList.class)
@@ -1185,14 +1164,14 @@ public class RestOpContext extends Context implements Comparable<RestOpContext>
 
 			// Replace with builder from:  public [static] RestMatcherList.Builder createMatchers(<args>)
 			beanStore
-				.beanCreateMethodFinder(RestMatcherList.Builder.class)
+				.createMethodFinder(RestMatcherList.Builder.class)
 				.addBean(RestMatcherList.Builder.class, v.get())
 				.find("createMatchers")
 				.run(x -> v.set(x));
 
 			// Replace with bean from:  public [static] RestMatcherList createMatchers(<args>)
 			beanStore
-				.beanCreateMethodFinder(RestMatcherList.class)
+				.createMethodFinder(RestMatcherList.class)
 				.addBean(RestMatcherList.Builder.class, v.get())
 				.find("createMatchers")
 				.run(x -> v.get().impl(x));
@@ -2266,7 +2245,7 @@ public class RestOpContext extends Context implements Comparable<RestOpContext>
 			if (builder.debug == null)
 				debug = context.getDebugEnablement();
 			else
-				debug = DebugEnablement.create().enable(builder.debug, "*").build();
+				debug = DebugEnablement.create(context.getRootBeanStore()).enable(builder.debug, "*").build();
 
 			mi = MethodInfo.of(method).accessible();
 			Object r = context.getResource();
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestOperations.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestOperations.java
index 9473f04..ea3e362 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestOperations.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestOperations.java
@@ -47,12 +47,13 @@ public class RestOperations {
 	}
 
 	/**
-	 * Creates a new builder.
+	 * Static creator.
 	 *
-	 * @return A new builder.
+	 * @param beanStore The bean store to use for creating beans.
+	 * @return A new builder for this object.
 	 */
-	public static Builder create() {
-		return new Builder();
+	public static Builder create(BeanStore beanStore) {
+		return new Builder(beanStore);
 	}
 
 	//-----------------------------------------------------------------------------------------------------------------
@@ -70,34 +71,20 @@ public class RestOperations {
 
 		/**
 		 * Constructor.
+		 *
+		 * @param beanStore The bean store to use for creating beans.
 		 */
-		protected Builder() {
-			super(RestOperations.class);
+		protected Builder(BeanStore beanStore) {
+			super(RestOperations.class, beanStore);
 			map = new TreeMap<>();
 			set = ASet.of();
 		}
 
-		/**
-		 * Copy constructor.
-		 *
-		 * @param copyFrom The builder being copied.
-		 */
-		protected Builder(Builder copyFrom) {
-			super(copyFrom);
-			map = new TreeMap<>(copyFrom.map);
-			set = ASet.of(copyFrom.set);
-		}
-
 		@Override /* BeanBuilder */
 		protected RestOperations buildDefault() {
 			return new RestOperations(this);
 		}
 
-		@Override /* BeanBuilder */
-		public Builder copy() {
-			return new Builder(this);
-		}
-
 		//-------------------------------------------------------------------------------------------------------------
 		// Properties
 		//-------------------------------------------------------------------------------------------------------------
@@ -131,24 +118,12 @@ public class RestOperations {
 		// <FluentSetters>
 
 		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
-		public Builder beanStore(BeanStore value) {
-			super.beanStore(value);
-			return this;
-		}
-
-		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
 		public Builder impl(Object value) {
 			super.impl(value);
 			return this;
 		}
 
 		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
-		public Builder outer(Object value) {
-			super.outer(value);
-			return this;
-		}
-
-		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
 		public Builder type(Class<?> value) {
 			super.type(value);
 			return this;
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/RestOpArgList.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/RestOpArgList.java
index 5259a69..a48ce04 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/RestOpArgList.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/arg/RestOpArgList.java
@@ -38,21 +38,11 @@ public class RestOpArgList {
 	/**
 	 * Static creator.
 	 *
-	 * @return An empty list.
+	 * @param beanStore The bean store to use for creating beans.
+	 * @return A new builder for this object.
 	 */
-	public static Builder create() {
-		return new Builder();
-	}
-
-	/**
-	 * Static creator.
-	 *
-	 * @param values The initial contents of the list.
-	 * @return A list initialized with the specified values.
-	 */
-	@SafeVarargs
-	public static Builder of(Class<? extends RestOpArg>...values) {
-		return new Builder().add(values);
+	public static Builder create(BeanStore beanStore) {
+		return new Builder(beanStore);
 	}
 
 	//-----------------------------------------------------------------------------------------------------------------
@@ -69,20 +59,12 @@ public class RestOpArgList {
 
 		/**
 		 * Constructor.
-		 */
-		protected Builder() {
-			super(RestOpArgList.class);
-			entries = AList.create();
-		}
-
-		/**
-		 * Copy constructor.
 		 *
-		 * @param copyFrom The builder being copied.
+		 * @param beanStore The bean store to use for creating beans.
 		 */
-		protected Builder(Builder copyFrom) {
-			super(copyFrom);
-			entries = AList.of(copyFrom.entries);
+		protected Builder(BeanStore beanStore) {
+			super(RestOpArgList.class, beanStore);
+			entries = AList.create();
 		}
 
 		@Override /* BeanBuilder */
@@ -90,11 +72,6 @@ public class RestOpArgList {
 			return new RestOpArgList(this);
 		}
 
-		@Override /* BeanBuilder */
-		public Builder copy() {
-			return new Builder(this);
-		}
-
 		//-------------------------------------------------------------------------------------------------------------
 		// Properties
 		//-------------------------------------------------------------------------------------------------------------
@@ -114,24 +91,12 @@ public class RestOpArgList {
 		// <FluentSetters>
 
 		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
-		public Builder beanStore(BeanStore value) {
-			super.beanStore(value);
-			return this;
-		}
-
-		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
 		public Builder impl(Object value) {
 			super.impl(value);
 			return this;
 		}
 
 		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
-		public Builder outer(Object value) {
-			super.outer(value);
-			return this;
-		}
-
-		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
 		public Builder type(Class<?> value) {
 			super.type(value);
 			return this;
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/converter/RestConverterList.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/converter/RestConverterList.java
index d5fdb5a..14537c6 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/converter/RestConverterList.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/converter/RestConverterList.java
@@ -34,10 +34,11 @@ public class RestConverterList {
 	/**
 	 * Static creator.
 	 *
-	 * @return An empty list.
+	 * @param beanStore The bean store to use for creating beans.
+	 * @return A new builder for this object.
 	 */
-	public static Builder create() {
-		return new Builder();
+	public static Builder create(BeanStore beanStore) {
+		return new Builder(beanStore);
 	}
 
 	//-----------------------------------------------------------------------------------------------------------------
@@ -54,20 +55,12 @@ public class RestConverterList {
 
 		/**
 		 * Create an empty builder.
-		 */
-		protected Builder() {
-			super(RestConverterList.class);
-			this.entries = AList.create();
-		}
-
-		/**
-		 * Copy constructor.
 		 *
-		 * @param copyFrom The builder being copied.
+		 * @param beanStore The bean store to use for creating beans.
 		 */
-		protected Builder(Builder copyFrom) {
-			super(copyFrom);
-			entries = AList.of(copyFrom.entries);
+		protected Builder(BeanStore beanStore) {
+			super(RestConverterList.class, beanStore);
+			this.entries = AList.create();
 		}
 
 		@Override /* BeanBuilder */
@@ -75,11 +68,6 @@ public class RestConverterList {
 			return new RestConverterList(this);
 		}
 
-		@Override /* BeanBuilder */
-		public Builder copy() {
-			return new Builder(this);
-		}
-
 		//-------------------------------------------------------------------------------------------------------------
 		// Properties
 		//-------------------------------------------------------------------------------------------------------------
@@ -93,7 +81,7 @@ public class RestConverterList {
 		@SuppressWarnings("unchecked")
 		public Builder append(Class<? extends RestConverter>...values) {
 			for (Class<? extends RestConverter> v : values)
-				entries.append(BeanCreator.of(RestConverter.class).type(v));
+				entries.append(beanStore().createBean(RestConverter.class).type(v));
 			return this;
 		}
 
@@ -105,31 +93,19 @@ public class RestConverterList {
 		 */
 		public Builder append(RestConverter...values) {
 			for (RestConverter v : values)
-				entries.append(BeanCreator.of(RestConverter.class).impl(v));
+				entries.append(beanStore().createBean(RestConverter.class).impl(v));
 			return this;
 		}
 
 		// <FluentSetters>
 
 		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
-		public Builder beanStore(BeanStore value) {
-			super.beanStore(value);
-			return this;
-		}
-
-		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
 		public Builder impl(Object value) {
 			super.impl(value);
 			return this;
 		}
 
 		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
-		public Builder outer(Object value) {
-			super.outer(value);
-			return this;
-		}
-
-		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
 		public Builder type(Class<?> value) {
 			super.type(value);
 			return this;
@@ -150,13 +126,11 @@ public class RestConverterList {
 	 * @param builder The builder containing the contents for this list.
 	 */
 	protected RestConverterList(Builder builder) {
-		BeanStore bs = builder.beanStore().orElse(BeanStore.INSTANCE);
-		builder.entries.stream().forEach(x -> x.store(bs));
 		entries =
 			builder
 				.entries
 				.stream()
-				.map(x -> x.store(bs).run())
+				.map(x -> x.run())
 				.toArray(RestConverter[]::new);
 	}
 
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/debug/DebugEnablement.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/debug/DebugEnablement.java
index 318c185..18191f0 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/debug/DebugEnablement.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/debug/DebugEnablement.java
@@ -46,12 +46,13 @@ public interface DebugEnablement {
 	public abstract class Null implements DebugEnablement {};
 
 	/**
-	 * Creator.
+	 * Static creator.
 	 *
+	 * @param beanStore The bean store to use for creating beans.
 	 * @return A new builder for this object.
 	 */
-	public static Builder create() {
-		return new Builder();
+	public static Builder create(BeanStore beanStore) {
+		return new Builder(beanStore);
 	}
 
 	//-----------------------------------------------------------------------------------------------------------------
@@ -66,27 +67,18 @@ public interface DebugEnablement {
 		ReflectionMap.Builder<Enablement> mapBuilder;
 		Enablement defaultEnablement = NEVER;
 		Predicate<HttpServletRequest> conditionalPredicate;
-		BeanCreator<DebugEnablement> creator = BeanCreator.of(DebugEnablement.class).type(BasicDebugEnablement.class).builder(this);
+		BeanCreator<DebugEnablement> creator;
 
 		/**
 		 * Constructor.
+		 *
+		 * @param beanStore The bean store to use for creating beans.
 		 */
-		protected Builder() {
+		protected Builder(BeanStore beanStore) {
 			mapBuilder = ReflectionMap.create(Enablement.class);
 			defaultEnablement = NEVER;
 			conditionalPredicate = x -> "true".equalsIgnoreCase(x.getHeader("Debug"));
-		}
-
-		/**
-		 * Copy constructor.
-		 *
-		 * @param copyFrom The builder being copied.
-		 */
-		protected Builder(Builder copyFrom) {
-			mapBuilder = copyFrom.mapBuilder.copy();
-			creator = copyFrom.creator.copy();
-			defaultEnablement = copyFrom.defaultEnablement;
-			conditionalPredicate = copyFrom.conditionalPredicate;
+			creator = beanStore.createBean(DebugEnablement.class).type(BasicDebugEnablement.class).builder(Builder.class, this);
 		}
 
 		/**
@@ -107,17 +99,6 @@ public interface DebugEnablement {
 		}
 
 		/**
-		 * Specifies the bean store to use for instantiating the {@link DebugEnablement} object.
-		 *
-		 * @param value The new value for this setting.
-		 * @return  This object.
-		 */
-		public Builder beanStore(BeanStore value) {
-			creator.store(value);
-			return this;
-		}
-
-		/**
 		 * Specifies a subclass of {@link DebugEnablement} to create when the {@link #build()} method is called.
 		 *
 		 * @param value The new value for this setting.
@@ -227,15 +208,6 @@ public interface DebugEnablement {
 			conditionalPredicate = value;
 			return this;
 		}
-
-		/**
-		 * Creates a copy of this builder.
-		 *
-		 * @return A copy of this builder.
-		 */
-		public Builder copy() {
-			return new Builder(this);
-		}
 	}
 
 	//-----------------------------------------------------------------------------------------------------------------
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/guard/RestGuardList.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/guard/RestGuardList.java
index f9c321c..7fe16a7 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/guard/RestGuardList.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/guard/RestGuardList.java
@@ -34,10 +34,11 @@ public class RestGuardList {
 	/**
 	 * Static creator.
 	 *
-	 * @return An empty list.
+	 * @param beanStore The bean store to use for creating beans.
+	 * @return A new builder for this object.
 	 */
-	public static Builder create() {
-		return new Builder();
+	public static Builder create(BeanStore beanStore) {
+		return new Builder(beanStore);
 	}
 
 	//-----------------------------------------------------------------------------------------------------------------
@@ -54,20 +55,12 @@ public class RestGuardList {
 
 		/**
 		 * Constructor.
-		 */
-		protected Builder() {
-			super(RestGuardList.class);
-			entries = AList.create();
-		}
-
-		/**
-		 * Copy constructor.
 		 *
-		 * @param copyFrom The builder being copied.
+		 * @param beanStore The bean store to use for creating beans.
 		 */
-		protected Builder(Builder copyFrom) {
-			super(copyFrom);
-			entries = AList.of(copyFrom.entries);
+		protected Builder(BeanStore beanStore) {
+			super(RestGuardList.class, beanStore);
+			entries = AList.create();
 		}
 
 		@Override /* BeanBuilder */
@@ -75,11 +68,6 @@ public class RestGuardList {
 			return new RestGuardList(this);
 		}
 
-		@Override /* BeanBuilder */
-		public Builder copy() {
-			return new Builder(this);
-		}
-
 		//-------------------------------------------------------------------------------------------------------------
 		// Properties
 		//-------------------------------------------------------------------------------------------------------------
@@ -93,7 +81,7 @@ public class RestGuardList {
 		@SuppressWarnings("unchecked")
 		public Builder append(Class<? extends RestGuard>...values) {
 			for (Class<? extends RestGuard> v : values)
-				entries.append(BeanCreator.of(RestGuard.class).type(v));
+				entries.append(beanStore().createBean(RestGuard.class).type(v));
 			return this;
 		}
 
@@ -105,31 +93,19 @@ public class RestGuardList {
 		 */
 		public Builder append(RestGuard...values) {
 			for (RestGuard v : values)
-				entries.append(BeanCreator.of(RestGuard.class).impl(v));
+				entries.append(beanStore().createBean(RestGuard.class).impl(v));
 			return this;
 		}
 
 		// <FluentSetters>
 
 		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
-		public Builder beanStore(BeanStore value) {
-			super.beanStore(value);
-			return this;
-		}
-
-		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
 		public Builder impl(Object value) {
 			super.impl(value);
 			return this;
 		}
 
 		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
-		public Builder outer(Object value) {
-			super.outer(value);
-			return this;
-		}
-
-		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
 		public Builder type(Class<?> value) {
 			super.type(value);
 			return this;
@@ -150,12 +126,11 @@ public class RestGuardList {
 	 * @param builder The builder containing the contents for this list.
 	 */
 	protected RestGuardList(Builder builder) {
-		BeanStore bs = builder.beanStore().orElse(BeanStore.INSTANCE);
 		entries =
 			builder
 				.entries
 				.stream()
-				.map(x -> x.store(bs).run())
+				.map(x -> x.run())
 				.toArray(RestGuard[]::new);
 	}
 
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/httppart/NamedAttributeList.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/httppart/NamedAttributeList.java
index fdda7c8..e8f147a 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/httppart/NamedAttributeList.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/httppart/NamedAttributeList.java
@@ -67,7 +67,7 @@ public class NamedAttributeList {
 		 * Constructor.
 		 */
 		protected Builder() {
-			super(NamedAttributeList.class);
+			super(NamedAttributeList.class, BeanStore.INSTANCE);
 			entries = new LinkedHashMap<>();
 		}
 
@@ -86,7 +86,11 @@ public class NamedAttributeList {
 			return new NamedAttributeList(this);
 		}
 
-		@Override /* BeanBuilder */
+		/**
+		 * Creates a copy of this builder.
+		 *
+		 * @return A new copy of this builder.
+		 */
 		public Builder copy() {
 			return new Builder(this);
 		}
@@ -110,24 +114,12 @@ public class NamedAttributeList {
 		// <FluentSetters>
 
 		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
-		public Builder beanStore(BeanStore value) {
-			super.beanStore(value);
-			return this;
-		}
-
-		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
 		public Builder impl(Object value) {
 			super.impl(value);
 			return this;
 		}
 
 		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
-		public Builder outer(Object value) {
-			super.outer(value);
-			return this;
-		}
-
-		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
 		public Builder type(Class<?> value) {
 			super.type(value);
 			return this;
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/BasicDisabledRestLogger.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/BasicDisabledRestLogger.java
index fa10c66..25c4b04 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/BasicDisabledRestLogger.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/BasicDisabledRestLogger.java
@@ -30,6 +30,6 @@ public class BasicDisabledRestLogger extends BasicRestLogger {
 	 * @param context The context of the resource object.
 	 */
 	public BasicDisabledRestLogger(RestContext context) {
-		super(RestLogger.create().disabled());
+		super(RestLogger.create(context.getBeanStore()).disabled());
 	}
 }
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/BasicRestLogger.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/BasicRestLogger.java
index e3ff6c8..43e1755 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/BasicRestLogger.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/BasicRestLogger.java
@@ -23,6 +23,7 @@ import java.util.logging.*;
 import javax.servlet.http.*;
 
 import org.apache.juneau.*;
+import org.apache.juneau.cp.*;
 import org.apache.juneau.internal.*;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.rest.stats.*;
@@ -87,7 +88,7 @@ import org.apache.juneau.rest.util.*;
  */
 public class BasicRestLogger implements RestLogger {
 
-	private static final RestLoggerRule DEFAULT_RULE = RestLoggerRule.create().build();
+	private static final RestLoggerRule DEFAULT_RULE = RestLoggerRule.create(BeanStore.INSTANCE).build();
 
 	private final Logger logger;
 	private final ThrownStore thrownStore;
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/BasicTestCaptureRestLogger.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/BasicTestCaptureRestLogger.java
index 7d113b4..130cc18 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/BasicTestCaptureRestLogger.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/BasicTestCaptureRestLogger.java
@@ -19,6 +19,7 @@ import java.util.concurrent.atomic.*;
 import java.util.logging.*;
 
 import org.apache.juneau.assertions.*;
+import org.apache.juneau.cp.*;
 
 /**
  *
@@ -93,15 +94,16 @@ public class BasicTestCaptureRestLogger extends BasicRestLogger {
 	}
 
 	private static RestLogger.Builder builder() {
-		return RestLogger.create()
+		BeanStore bs = BeanStore.INSTANCE;
+		return RestLogger.create(bs)
 			.normalRules(  // Rules when debugging is not enabled.
-				RestLoggerRule.create()  // Log 500+ errors with status-line and header information.
+				RestLoggerRule.create(bs)  // Log 500+ errors with status-line and header information.
 					.statusFilter(x -> x >= 500)
 					.level(SEVERE)
 					.requestDetail(HEADER)
 					.responseDetail(HEADER)
 					.build(),
-				RestLoggerRule.create()  // Log 400-500 errors with just status-line information.
+				RestLoggerRule.create(bs)  // Log 400-500 errors with just status-line information.
 					.statusFilter(x -> x >= 400)
 					.level(WARNING)
 					.requestDetail(STATUS_LINE)
@@ -109,7 +111,7 @@ public class BasicTestCaptureRestLogger extends BasicRestLogger {
 					.build()
 			)
 			.debugRules(  // Rules when debugging is enabled.
-				RestLoggerRule.create()  // Log everything with full details.
+				RestLoggerRule.create(bs)  // Log everything with full details.
 					.level(SEVERE)
 					.requestDetail(ENTITY)
 					.responseDetail(ENTITY)
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/BasicTestRestLogger.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/BasicTestRestLogger.java
index 3a624e3..761d6e2 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/BasicTestRestLogger.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/BasicTestRestLogger.java
@@ -19,6 +19,7 @@ import static org.apache.juneau.rest.logging.RestLoggingDetail.*;
 
 import javax.servlet.http.*;
 
+import org.apache.juneau.cp.*;
 import org.apache.juneau.rest.*;
 
 /**
@@ -60,9 +61,10 @@ public class BasicTestRestLogger extends BasicRestLogger {
 	}
 
 	private static RestLogger.Builder builder() {
-		return RestLogger.create()
+		BeanStore bs = BeanStore.INSTANCE;
+		return RestLogger.create(bs)
 			.normalRules(  // Rules when debugging is not enabled.
-				RestLoggerRule.create()  // Log 500+ errors with status-line and header information.
+				RestLoggerRule.create(bs)  // Log 500+ errors with status-line and header information.
 					.statusFilter(x -> x >= 400)
 					.level(SEVERE)
 					.requestDetail(HEADER)
@@ -71,7 +73,7 @@ public class BasicTestRestLogger extends BasicRestLogger {
 					.enabledTest(x -> ! isNoTrace(x))  // Only log if it's not a no-trace request.
 					.logStackTrace()
 					.build(),
-				RestLoggerRule.create()  // Log 400-500 errors with just status-line information.
+				RestLoggerRule.create(bs)  // Log 400-500 errors with just status-line information.
 					.statusFilter(x -> x >= 400)
 					.level(WARNING)
 					.requestDetail(STATUS_LINE)
@@ -82,7 +84,7 @@ public class BasicTestRestLogger extends BasicRestLogger {
 					.build()
 			)
 			.debugRules(  // Rules when debugging is enabled.
-				RestLoggerRule.create()  // Log everything with full details.
+				RestLoggerRule.create(bs)  // Log everything with full details.
 					.level(SEVERE)
 					.requestDetail(ENTITY)
 					.responseDetail(ENTITY)
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/RestLogger.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/RestLogger.java
index 0dc97e0..0216be5 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/RestLogger.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/RestLogger.java
@@ -135,12 +135,13 @@ public interface RestLogger {
 	public static final String SP_level = "juneau.restLogger.level";
 
 	/**
-	 * Creates a new builder for this object.
+	 * Static creator.
 	 *
+	 * @param beanStore The bean store to use for creating beans.
 	 * @return A new builder for this object.
 	 */
-	public static Builder create() {
-		return new Builder();
+	public static Builder create(BeanStore beanStore) {
+		return new Builder(beanStore);
 	}
 
 	//-----------------------------------------------------------------------------------------------------------------
@@ -163,9 +164,11 @@ public interface RestLogger {
 
 		/**
 		 * Constructor.
+		 *
+		 * @param beanStore The bean store to use for creating beans.
 		 */
-		protected Builder() {
-			super(BasicRestLogger.class);
+		protected Builder(BeanStore beanStore) {
+			super(BasicRestLogger.class, beanStore);
 			logger = Logger.getLogger(env(SP_logger, "global"));
 			enabled = env(SP_enabled, ALWAYS);
 			enabledTest = x -> false;
@@ -174,24 +177,6 @@ public interface RestLogger {
 			level = env(SP_level).map(Level::parse).orElse(OFF);
 		}
 
-		/**
-		 * Copy constuctor.
-		 *
-		 * @param copyFrom The builder to copy.
-		 */
-		protected Builder(Builder copyFrom) {
-			super(copyFrom);
-			logger = copyFrom.logger;
-			thrownStore = copyFrom.thrownStore;
-			normalRules = AList.<RestLoggerRule>create().append(copyFrom.normalRules);
-			debugRules = AList.<RestLoggerRule>create().append(copyFrom.debugRules);
-			enabled = copyFrom.enabled;
-			enabledTest = copyFrom.enabledTest;
-			requestDetail = copyFrom.requestDetail;
-			responseDetail = copyFrom.responseDetail;
-			level = copyFrom.level;
-		}
-
 		@Override /* BeanBuilder */
 		protected RestLogger buildDefault() {
 			return new BasicRestLogger(this);
@@ -199,12 +184,7 @@ public interface RestLogger {
 
 		@Override /* BeanBuilder */
 		protected BeanCreator<? extends RestLogger> creator() {
-			return super.creator().findSingleton();
-		}
-
-		@Override /* BeanBuilder */
-		public Builder copy() {
-			return new Builder(this);
+			return super.creator();
 		}
 
 		//-------------------------------------------------------------------------------------------------------------
@@ -491,24 +471,12 @@ public interface RestLogger {
 		// <FluentSetters>
 
 		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
-		public Builder beanStore(BeanStore value) {
-			super.beanStore(value);
-			return this;
-		}
-
-		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
 		public Builder impl(Object value) {
 			super.impl(value);
 			return this;
 		}
 
 		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
-		public Builder outer(Object value) {
-			super.outer(value);
-			return this;
-		}
-
-		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
 		public Builder type(Class<?> value) {
 			super.type(value);
 			return this;
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/RestLoggerRule.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/RestLoggerRule.java
index 32c36cd..fdde7eb 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/RestLoggerRule.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/logging/RestLoggerRule.java
@@ -38,12 +38,13 @@ public class RestLoggerRule {
 	//-----------------------------------------------------------------------------------------------------------------
 
 	/**
-	 * Creates a new builder for this object.
+	 * Static creator.
 	 *
+	 * @param beanStore The bean store to use for creating beans.
 	 * @return A new builder for this object.
 	 */
-	public static Builder create() {
-		return new Builder();
+	public static Builder create(BeanStore beanStore) {
+		return new Builder(beanStore);
 	}
 
 	//-----------------------------------------------------------------------------------------------------------------
@@ -68,28 +69,11 @@ public class RestLoggerRule {
 
 		/**
 		 * Constructor.
-		 */
-		protected Builder() {
-			super(RestLoggerRule.class);
-		}
-
-		/**
-		 * Copy constructor.
 		 *
-		 * @param copyFrom The builder being copied.
+		 * @param beanStore The bean store to use for creating beans.
 		 */
-		protected Builder(Builder copyFrom) {
-			super(copyFrom);
-			statusFilter = copyFrom.statusFilter;
-			requestFilter = copyFrom.requestFilter;
-			responseFilter = copyFrom.responseFilter;
-			exceptionFilter = copyFrom.exceptionFilter;
-			enabled = copyFrom.enabled;
-			enabledTest = copyFrom.enabledTest;
-			level = copyFrom.level;
-			requestDetail = copyFrom.requestDetail;
-			responseDetail = copyFrom.responseDetail;
-			logStackTrace = copyFrom.logStackTrace;
+		protected Builder(BeanStore beanStore) {
+			super(RestLoggerRule.class, beanStore);
 		}
 
 		@Override /* BeanBuilder */
@@ -97,11 +81,6 @@ public class RestLoggerRule {
 			return new RestLoggerRule(this);
 		}
 
-		@Override /* BeanBuilder */
-		public Builder copy() {
-			return new Builder(this);
-		}
-
 		//-------------------------------------------------------------------------------------------------------------
 		// Properties
 		//-------------------------------------------------------------------------------------------------------------
@@ -334,24 +313,12 @@ public class RestLoggerRule {
 		// <FluentSetters>
 
 		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
-		public Builder beanStore(BeanStore value) {
-			super.beanStore(value);
-			return this;
-		}
-
-		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
 		public Builder impl(Object value) {
 			super.impl(value);
 			return this;
 		}
 
 		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
-		public Builder outer(Object value) {
-			super.outer(value);
-			return this;
-		}
-
-		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
 		public Builder type(Class<?> value) {
 			super.type(value);
 			return this;
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/matcher/RestMatcherList.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/matcher/RestMatcherList.java
index cb9e106..587906b 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/matcher/RestMatcherList.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/matcher/RestMatcherList.java
@@ -38,10 +38,11 @@ public class RestMatcherList {
 	/**
 	 * Static creator.
 	 *
-	 * @return An empty list.
+	 * @param beanStore The bean store to use for creating beans.
+	 * @return A new builder for this object.
 	 */
-	public static Builder create() {
-		return new Builder();
+	public static Builder create(BeanStore beanStore) {
+		return new Builder(beanStore);
 	}
 
 	//-----------------------------------------------------------------------------------------------------------------
@@ -58,20 +59,12 @@ public class RestMatcherList {
 
 		/**
 		 * Constructor.
-		 */
-		protected Builder() {
-			super(RestMatcherList.class);
-			entries = AList.create();
-		}
-
-		/**
-		 * Copy constructor.
 		 *
-		 * @param copyFrom The builder being copied.
+		 * @param beanStore The bean store to use for creating beans.
 		 */
-		protected Builder(Builder copyFrom) {
-			super(copyFrom);
-			entries = AList.of(copyFrom.entries);
+		protected Builder(BeanStore beanStore) {
+			super(RestMatcherList.class, beanStore);
+			entries = AList.create();
 		}
 
 		@Override /* BeanBuilder */
@@ -79,11 +72,6 @@ public class RestMatcherList {
 			return new RestMatcherList(this);
 		}
 
-		@Override /* BeanBuilder */
-		public Builder copy() {
-			return new Builder(this);
-		}
-
 		//-------------------------------------------------------------------------------------------------------------
 		// Properties
 		//-------------------------------------------------------------------------------------------------------------
@@ -97,7 +85,7 @@ public class RestMatcherList {
 		@SuppressWarnings("unchecked")
 		public Builder append(Class<? extends RestMatcher>...values) {
 			for (Class<? extends RestMatcher> v : values)
-				entries.append(BeanCreator.of(RestMatcher.class).type(v));
+				entries.append(beanStore().createBean(RestMatcher.class).type(v));
 			return this;
 		}
 
@@ -109,31 +97,19 @@ public class RestMatcherList {
 		 */
 		public Builder append(RestMatcher...values) {
 			for (RestMatcher v : values)
-				entries.append(BeanCreator.of(RestMatcher.class).impl(v));
+				entries.append(beanStore().createBean(RestMatcher.class).impl(v));
 			return this;
 		}
 
 		// <FluentSetters>
 
 		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
-		public Builder beanStore(BeanStore value) {
-			super.beanStore(value);
-			return this;
-		}
-
-		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
 		public Builder impl(Object value) {
 			super.impl(value);
 			return this;
 		}
 
 		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
-		public Builder outer(Object value) {
-			super.outer(value);
-			return this;
-		}
-
-		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
 		public Builder type(Class<?> value) {
 			super.type(value);
 			return this;
@@ -155,12 +131,11 @@ public class RestMatcherList {
 	 * @param builder The builder containing the contents for this list.
 	 */
 	protected RestMatcherList(Builder builder) {
-		BeanStore bs = builder.beanStore().orElse(BeanStore.INSTANCE);
 		List<RestMatcher> l =
 			builder
 				.entries
 				.stream()
-				.map(x -> x.store(bs).run())
+				.map(x -> x.run())
 				.collect(toList());
 		optionalEntries = l.stream().filter(x -> ! x.required()).toArray(RestMatcher[]::new);
 		requiredEntries = l.stream().filter(x -> x.required()).toArray(RestMatcher[]::new);
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/processor/ResponseProcessorList.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/processor/ResponseProcessorList.java
index 3ac49f6..335175e 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/processor/ResponseProcessorList.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/processor/ResponseProcessorList.java
@@ -40,10 +40,11 @@ public class ResponseProcessorList {
 	/**
 	 * Static creator.
 	 *
-	 * @return An empty list.
+	 * @param beanStore The bean store to use for creating beans.
+	 * @return A new builder for this object.
 	 */
-	public static Builder create() {
-		return new Builder();
+	public static Builder create(BeanStore beanStore) {
+		return new Builder(beanStore);
 	}
 
 	//-----------------------------------------------------------------------------------------------------------------
@@ -60,20 +61,12 @@ public class ResponseProcessorList {
 
 		/**
 		 * Constructor.
-		 */
-		protected Builder() {
-			super(ResponseProcessorList.class);
-			this.entries = AList.create();
-		}
-
-		/**
-		 * Copy constructor.
 		 *
-		 * @param copyFrom The builder to copy.
+		 * @param beanStore The bean store to use for creating beans.
 		 */
-		protected Builder(Builder copyFrom) {
-			super(copyFrom);
-			this.entries = AList.create().append(copyFrom.entries);
+		protected Builder(BeanStore beanStore) {
+			super(ResponseProcessorList.class, beanStore);
+			this.entries = AList.create();
 		}
 
 		@Override /* BeanBuilder */
@@ -81,11 +74,6 @@ public class ResponseProcessorList {
 			return new ResponseProcessorList(this);
 		}
 
-		@Override /* BeanBuilder */
-		public Builder copy() {
-			return new Builder(this);
-		}
-
 		//-------------------------------------------------------------------------------------------------------------
 		// Properties
 		//-------------------------------------------------------------------------------------------------------------
@@ -116,24 +104,12 @@ public class ResponseProcessorList {
 		// <FluentSetters>
 
 		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
-		public Builder beanStore(BeanStore value) {
-			super.beanStore(value);
-			return this;
-		}
-
-		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
 		public Builder impl(Object value) {
 			super.impl(value);
 			return this;
 		}
 
 		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
-		public Builder outer(Object value) {
-			super.outer(value);
-			return this;
-		}
-
-		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
 		public Builder type(Class<?> value) {
 			super.type(value);
 			return this;
@@ -154,7 +130,7 @@ public class ResponseProcessorList {
 	 * @param builder The builder containing the contents for this list.
 	 */
 	protected ResponseProcessorList(Builder builder) {
-		BeanStore bs = builder.beanStore().orElse(BeanStore.INSTANCE);
+		BeanStore bs = builder.beanStore();
 		entries =
 			builder
 				.entries
@@ -167,7 +143,7 @@ public class ResponseProcessorList {
 		if (o instanceof ResponseProcessor)
 			return (ResponseProcessor)o;
 		try {
-			return bs.creator(ResponseProcessor.class).type((Class<?>)o).run();
+			return bs.createBean(ResponseProcessor.class).type((Class<?>)o).run();
 		} catch (ExecutableException e) {
 			throw new ConfigException(e, "Could not instantiate class {0}", o);
 		}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/servlet/RestObject.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/servlet/RestObject.java
index 39371b0..d8d549f 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/servlet/RestObject.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/servlet/RestObject.java
@@ -39,7 +39,7 @@ import org.apache.juneau.rest.matcher.*;
  * but you want this resource to be deployed as a child instead.
  *
  * <ul class='seealso'>
- * 	<li class='link'>{@doc jrs.BasicRestServlet}
+ * 	<li class='link'>{@doc jrs.AnnotatedClasses}
  * 	<li class='extlink'>{@source}
  * </ul>
  */
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/staticfile/BasicStaticFiles.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/staticfile/BasicStaticFiles.java
index 49e09bf..75db577 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/staticfile/BasicStaticFiles.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/staticfile/BasicStaticFiles.java
@@ -50,11 +50,12 @@ public class BasicStaticFiles implements StaticFiles {
 
 	/**
 	 * Creates a new builder for this object.
-	 *
+	 * 
+	 * @param beanStore The bean store to use for creating beans.
 	 * @return A new builder for this object.
 	 */
-	public static StaticFiles.Builder create() {
-		return new StaticFiles.Builder();
+	public static StaticFiles.Builder create(BeanStore beanStore) {
+		return new StaticFiles.Builder(beanStore);
 	}
 
 	/**
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/staticfile/StaticFiles.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/staticfile/StaticFiles.java
index 437c216..78c2a5f 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/staticfile/StaticFiles.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/staticfile/StaticFiles.java
@@ -43,12 +43,13 @@ public interface StaticFiles extends FileFinder {
 	public abstract class Null implements StaticFiles {}
 
 	/**
-	 * Creates a new builder for this object.
+	 * Static creator.
 	 *
+	 * @param beanStore The bean store to use for creating beans.
 	 * @return A new builder for this object.
 	 */
-	public static Builder create() {
-		return new Builder();
+	public static Builder create(BeanStore beanStore) {
+		return new Builder(beanStore);
 	}
 
 	//-----------------------------------------------------------------------------------------------------------------
@@ -67,35 +68,21 @@ public interface StaticFiles extends FileFinder {
 
 		/**
 		 * Constructor.
+		 *
+		 * @param beanStore The bean store to use for creating beans.
 		 */
-		protected Builder() {
-			super(BasicStaticFiles.class);
+		protected Builder(BeanStore beanStore) {
+			super(BasicStaticFiles.class, beanStore);
 			headers = AList.create();
-			fileFinder = FileFinder.create();
+			fileFinder = FileFinder.create(beanStore);
 			mimeTypes = new ExtendedMimetypesFileTypeMap();
 		}
 
-		/**
-		 * Copy constructor.
-		 *
-		 * @param copyFrom The builder being copied.
-		 */
-		protected Builder(Builder copyFrom) {
-			super(copyFrom);
-			headers = AList.of(copyFrom.headers);
-			mimeTypes = copyFrom.mimeTypes;
-		}
-
 		@Override /* BeanBuilder */
 		protected StaticFiles buildDefault() {
 			return new BasicStaticFiles(this);
 		}
 
-		@Override /* BeanBuilder */
-		public Builder copy() {
-			return new Builder(this);
-		}
-
 		//-------------------------------------------------------------------------------------------------------------
 		// Properties
 		//-------------------------------------------------------------------------------------------------------------
@@ -220,24 +207,12 @@ public interface StaticFiles extends FileFinder {
 		// <FluentSetters>
 
 		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
-		public Builder beanStore(BeanStore value) {
-			super.beanStore(value);
-			return this;
-		}
-
-		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
 		public Builder impl(Object value) {
 			super.impl(value);
 			return this;
 		}
 
 		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
-		public Builder outer(Object value) {
-			super.outer(value);
-			return this;
-		}
-
-		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
 		public Builder type(Class<?> value) {
 			super.type(value);
 			return this;
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/stats/MethodExecStats.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/stats/MethodExecStats.java
index cf75f02..b7a8d9c 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/stats/MethodExecStats.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/stats/MethodExecStats.java
@@ -42,10 +42,11 @@ public class MethodExecStats {
 	/**
 	 * Static creator.
 	 *
+	 * @param beanStore The bean store to use for creating beans.
 	 * @return A new builder for this object.
 	 */
-	public static Builder create() {
-		return new Builder();
+	public static Builder create(BeanStore beanStore) {
+		return new Builder(beanStore);
 	}
 
 	//-----------------------------------------------------------------------------------------------------------------
@@ -63,20 +64,11 @@ public class MethodExecStats {
 
 		/**
 		 * Constructor.
-		 */
-		protected Builder() {
-			super(MethodExecStats.class);
-		}
-
-		/**
-		 * Copy constructor.
 		 *
-		 * @param copyFrom The builder being copied.
+		 * @param beanStore The bean store to use for creating beans.
 		 */
-		protected Builder(Builder copyFrom) {
-			super(copyFrom);
-			method = copyFrom.method;
-			thrownStore = copyFrom.thrownStore;
+		protected Builder(BeanStore beanStore) {
+			super(MethodExecStats.class, beanStore);
 		}
 
 		@Override /* BeanBuilder */
@@ -84,11 +76,6 @@ public class MethodExecStats {
 			return new MethodExecStats(this);
 		}
 
-		@Override /* BeanBuilder */
-		public Builder copy() {
-			return new Builder(this);
-		}
-
 		//-------------------------------------------------------------------------------------------------------------
 		// Properties
 		//-------------------------------------------------------------------------------------------------------------
@@ -120,24 +107,12 @@ public class MethodExecStats {
 		// <FluentSetters>
 
 		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
-		public Builder beanStore(BeanStore value) {
-			super.beanStore(value);
-			return this;
-		}
-
-		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
 		public Builder impl(Object value) {
 			super.impl(value);
 			return this;
 		}
 
 		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
-		public Builder outer(Object value) {
-			super.outer(value);
-			return this;
-		}
-
-		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
 		public Builder type(Class<?> value) {
 			super.type(value);
 			return this;
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/stats/MethodExecStore.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/stats/MethodExecStore.java
index 8b2d629..3771f3a 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/stats/MethodExecStore.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/stats/MethodExecStore.java
@@ -40,12 +40,22 @@ public class MethodExecStore {
 	//-----------------------------------------------------------------------------------------------------------------
 
 	/**
-	 * Creates a new builder for this object.
+	 * Static creator.
+	 *
+	 * @param beanStore The bean store to use for creating beans.
+	 * @return A new builder for this object.
+	 */
+	public static Builder create(BeanStore beanStore) {
+		return new Builder(beanStore);
+	}
+
+	/**
+	 * Static creator.
 	 *
 	 * @return A new builder for this object.
 	 */
 	public static Builder create() {
-		return new Builder();
+		return new Builder(BeanStore.INSTANCE);
 	}
 
 	//-----------------------------------------------------------------------------------------------------------------
@@ -63,20 +73,11 @@ public class MethodExecStore {
 
 		/**
 		 * Constructor.
-		 */
-		protected Builder() {
-			super(MethodExecStore.class);
-		}
-
-		/**
-		 * Copy constructor.
 		 *
-		 * @param copyFrom The builder to copy.
+		 * @param beanStore The bean store to use for creating beans.
 		 */
-		protected Builder(Builder copyFrom) {
-			super(copyFrom);
-			thrownStore = copyFrom.thrownStore;
-			statsImplClass = copyFrom.statsImplClass;
+		protected Builder(BeanStore beanStore) {
+			super(MethodExecStore.class, beanStore);
 		}
 
 		@Override /* BeanBuilder */
@@ -84,11 +85,6 @@ public class MethodExecStore {
 			return new MethodExecStore(this);
 		}
 
-		@Override /* BeanBuilder */
-		public Builder copy() {
-			return new Builder(this);
-		}
-
 		//-------------------------------------------------------------------------------------------------------------
 		// Properties
 		//-------------------------------------------------------------------------------------------------------------
@@ -136,24 +132,12 @@ public class MethodExecStore {
 		// <FluentSetters>
 
 		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
-		public Builder beanStore(BeanStore value) {
-			super.beanStore(value);
-			return this;
-		}
-
-		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
 		public Builder impl(Object value) {
 			super.impl(value);
 			return this;
 		}
 
 		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
-		public Builder outer(Object value) {
-			super.outer(value);
-			return this;
-		}
-
-		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
 		public Builder type(Class<?> value) {
 			super.type(value);
 			return this;
@@ -177,7 +161,7 @@ public class MethodExecStore {
 	 * @param builder The store to use for storing thrown exception statistics.
 	 */
 	protected MethodExecStore(Builder builder) {
-		this.beanStore = builder.beanStore().orElseGet(()->BeanStore.create().build());
+		this.beanStore = builder.beanStore();
 		this.thrownStore = ofNullable(builder.thrownStore).orElse(beanStore.getBean(ThrownStore.class).orElseGet(ThrownStore::new));
 		this.statsImplClass = builder.statsImplClass;
 	}
@@ -195,11 +179,10 @@ public class MethodExecStore {
 		MethodExecStats stats = db.get(m);
 		if (stats == null) {
 			stats = MethodExecStats
-				.create()
-				.beanStore(beanStore)
+				.create(beanStore)
 				.type(statsImplClass)
 				.method(m)
-				.thrownStore(ThrownStore.create().parent(thrownStore).build())
+				.thrownStore(ThrownStore.create(beanStore).parent(thrownStore).build())
 				.build();
 			db.putIfAbsent(m, stats);
 			stats = db.get(m);
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/stats/MethodInvoker.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/stats/MethodInvoker.java
index 25cd4ad..0973405 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/stats/MethodInvoker.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/stats/MethodInvoker.java
@@ -15,8 +15,6 @@ package org.apache.juneau.rest.stats;
 import static org.apache.juneau.internal.ThrowableUtils.*;
 
 import java.lang.reflect.*;
-import java.util.*;
-import java.util.stream.*;
 
 import org.apache.juneau.cp.*;
 import org.apache.juneau.reflect.*;
@@ -85,11 +83,9 @@ public class MethodInvoker {
 	 * @throws InvocationTargetException If method threw an exception.
 	 */
 	public Object invoke(BeanStore beanStore, Object o) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
-		List<ClassInfo> missing;
-		missing = beanStore.getMissingParamTypes(m.getParams());
-		if (missing.isEmpty())
-			return invoke(o, beanStore.getParams(m.getParams()));
-		throw illegalArgumentException("Could not find prerequisites to invoke method ''{0}'': {1}", getFullName(), missing.stream().map(x->x.getSimpleName()).collect(Collectors.joining(",")));
+		if (beanStore.hasAllParams(m))
+			return invoke(o, beanStore.getParams(m));
+		throw illegalArgumentException("Could not find prerequisites to invoke method ''{0}'': {1}", getFullName(), beanStore.getMissingParams(m));
 	}
 
 	/**
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/stats/ThrownStats.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/stats/ThrownStats.java
index 86681b8..0b610bf 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/stats/ThrownStats.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/stats/ThrownStats.java
@@ -39,10 +39,11 @@ public class ThrownStats implements Cloneable {
 	/**
 	 * Static creator.
 	 *
+	 * @param beanStore The bean store to use for creating beans.
 	 * @return A new builder for this object.
 	 */
-	public static Builder create() {
-		return new Builder();
+	public static Builder create(BeanStore beanStore) {
+		return new Builder(beanStore);
 	}
 
 	//-----------------------------------------------------------------------------------------------------------------
@@ -55,35 +56,31 @@ public class ThrownStats implements Cloneable {
 	@FluentSetters
 	public static class Builder {
 
+		final BeanStore beanStore;
 		Throwable throwable;
 		long hash;
 		List<String> stackTrace;
 		ThrownStats causedBy;
 
-		BeanCreator<ThrownStats> creator = BeanCreator.of(ThrownStats.class).builder(this);
+		BeanCreator<ThrownStats> creator;
 
 		/**
-		 * Create a new {@link ThrownStats} using this builder.
+		 * Constructor.
 		 *
-		 * @return A new {@link ThrownStats}
+		 * @param beanStore The bean store to use for creating beans.
 		 */
-		public ThrownStats build() {
-			return creator.run();
+		protected Builder(BeanStore beanStore) {
+			this.beanStore = beanStore;
+			this.creator = beanStore.createBean(ThrownStats.class).builder(Builder.class, this);
 		}
 
 		/**
-		 * Specifies the bean store to use for instantiating the {@link ThrownStats} object.
-		 *
-		 * <p>
-		 * Can be used to instantiate {@link ThrownStats} implementations with injected constructor argument beans.
+		 * Create a new {@link ThrownStats} using this builder.
 		 *
-		 * @param value The new value for this setting.
-		 * @return This object.
+		 * @return A new {@link ThrownStats}
 		 */
-		@FluentSetter
-		public Builder beanStore(BeanStore value) {
-			creator.store(value);
-			return this;
+		public ThrownStats build() {
+			return creator.run();
 		}
 
 		/**
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/stats/ThrownStore.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/stats/ThrownStore.java
index 032d980..cc8a42e 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/stats/ThrownStore.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/stats/ThrownStore.java
@@ -49,10 +49,20 @@ public class ThrownStore {
 	/**
 	 * Static creator.
 	 *
+	 * @param beanStore The bean store to use for creating beans.
+	 * @return A new builder for this object.
+	 */
+	public static Builder create(BeanStore beanStore) {
+		return new Builder(beanStore);
+	}
+
+	/**
+	 * Static creator.
+	 *
 	 * @return A new builder for this object.
 	 */
 	public static Builder create() {
-		return new Builder();
+		return new Builder(BeanStore.INSTANCE);
 	}
 
 	//-----------------------------------------------------------------------------------------------------------------
@@ -71,21 +81,11 @@ public class ThrownStore {
 
 		/**
 		 * Constructor.
-		 */
-		protected Builder() {
-			super(ThrownStore.class);
-		}
-
-		/**
-		 * Copy constructor.
 		 *
-		 * @param copyFrom The builder to copy.
+		 * @param beanStore The bean store to use for creating beans.
 		 */
-		protected Builder(Builder copyFrom) {
-			super(copyFrom);
-			parent = copyFrom.parent;
-			statsImplClass = copyFrom.statsImplClass;
-			ignoreClasses = copyFrom.ignoreClasses == null ? null : ASet.of(copyFrom.ignoreClasses);
+		protected Builder(BeanStore beanStore) {
+			super(ThrownStore.class, beanStore);
 		}
 
 		@Override /* BeanBuilder */
@@ -93,11 +93,6 @@ public class ThrownStore {
 			return new ThrownStore(this);
 		}
 
-		@Override /* BeanBuilder */
-		public Builder copy() {
-			return new Builder(this);
-		}
-
 		//-------------------------------------------------------------------------------------------------------------
 		// Properties
 		//-------------------------------------------------------------------------------------------------------------
@@ -145,24 +140,12 @@ public class ThrownStore {
 		// <FluentSetters>
 
 		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
-		public Builder beanStore(BeanStore value) {
-			super.beanStore(value);
-			return this;
-		}
-
-		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
 		public Builder impl(Object value) {
 			super.impl(value);
 			return this;
 		}
 
 		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
-		public Builder outer(Object value) {
-			super.outer(value);
-			return this;
-		}
-
-		@Override /* GENERATED - org.apache.juneau.BeanBuilder */
 		public Builder type(Class<?> value) {
 			super.type(value);
 			return this;
@@ -185,7 +168,7 @@ public class ThrownStore {
 	 * Constructor.
 	 */
 	public ThrownStore() {
-		this(create());
+		this(create(BeanStore.INSTANCE));
 	}
 
 	/**
@@ -195,7 +178,7 @@ public class ThrownStore {
 	 */
 	public ThrownStore(Builder builder) {
 		this.parent = ofNullable(builder.parent);
-		this.beanStore = builder.beanStore().orElseGet(()->BeanStore.create().build());
+		this.beanStore = builder.beanStore();
 
 		this.statsImplClass = firstNonNull(builder.statsImplClass, parent.isPresent() ? parent.get().statsImplClass : null, null);
 
@@ -340,8 +323,7 @@ public class ThrownStore {
 		ThrownStats stc = db.get(hash);
 		if (stc == null) {
 			stc = ThrownStats
-				.create()
-				.beanStore(beanStore)
+				.create(beanStore)
 				.type(statsImplClass)
 				.throwable(t)
 				.hash(hash)
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/swagger/BasicSwaggerProvider.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/swagger/BasicSwaggerProvider.java
index 4f8d91f..91b4d8f 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/swagger/BasicSwaggerProvider.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/swagger/BasicSwaggerProvider.java
@@ -36,6 +36,7 @@ public class BasicSwaggerProvider implements SwaggerProvider {
 	private final JsonSchemaGenerator js;
 	private final Messages messages;
 	private final FileFinder fileFinder;
+	private final BeanStore beanStore;
 
 	/**
 	 * Constructor.
@@ -43,9 +44,9 @@ public class BasicSwaggerProvider implements SwaggerProvider {
 	 * @param builder The builder containing the settings for this Swagger provider.
 	 */
 	public BasicSwaggerProvider(SwaggerProvider.Builder builder) {
-		BeanStore bs = builder.beanStore;
-		this.vr = builder.varResolver().orElse(bs.getBean(VarResolver.class).orElse(VarResolver.DEFAULT));
-		this.js = builder.jsonSchemaGenerator().orElse(bs.getBean(JsonSchemaGenerator.class).orElse(JsonSchemaGenerator.DEFAULT));
+		this.beanStore = builder.beanStore;
+		this.vr = builder.varResolver().orElse(beanStore.getBean(VarResolver.class).orElse(VarResolver.DEFAULT));
+		this.js = builder.jsonSchemaGenerator().orElse(beanStore.getBean(JsonSchemaGenerator.class).orElse(JsonSchemaGenerator.DEFAULT));
 		this.messages = builder.messages().orElse(null);
 		this.fileFinder = builder.fileFinder().orElse(null);
 	}
@@ -65,7 +66,7 @@ public class BasicSwaggerProvider implements SwaggerProvider {
 	public Swagger getSwagger(RestContext context, Locale locale) throws Exception {
 
 		Class<?> c = context.getResourceClass();
-		FileFinder ff = fileFinder != null ? fileFinder : FileFinder.create().cp(c,null,false).build();
+		FileFinder ff = fileFinder != null ? fileFinder : FileFinder.create(beanStore).cp(c,null,false).build();
 		Messages mb = messages != null ? messages.forLocale(locale) : Messages.create(c).build().forLocale(locale);
 		VarResolverSession vrs = vr.createSession().bean(Messages.class, mb);
 		BasicSwaggerProviderSession session = new BasicSwaggerProviderSession(context, locale, ff, messages, vrs, js.getSession());
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/swagger/SwaggerProvider.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/swagger/SwaggerProvider.java
index 38256f6..685c067 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/swagger/SwaggerProvider.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/swagger/SwaggerProvider.java
@@ -49,12 +49,13 @@ public interface SwaggerProvider {
 	public abstract class Null implements SwaggerProvider {};
 
 	/**
-	 * Creator.
+	 * Static creator.
 	 *
+	 * @param beanStore The bean store to use for creating beans.
 	 * @return A new builder for this object.
 	 */
-	public static Builder create() {
-		return new Builder();
+	public static Builder create(BeanStore beanStore) {
+		return new Builder(beanStore);
 	}
 
 	//-----------------------------------------------------------------------------------------------------------------
@@ -66,32 +67,24 @@ public interface SwaggerProvider {
 	 */
 	public class Builder {
 
-		BeanStore beanStore;
+		final BeanStore beanStore;
 		Class<?> resourceClass;
 		Supplier<VarResolver> varResolver;
 		Supplier<JsonSchemaGenerator> jsonSchemaGenerator;
 		Supplier<Messages> messages;
 		Supplier<FileFinder> fileFinder;
-		BeanCreator<SwaggerProvider> creator = BeanCreator.of(SwaggerProvider.class).type(BasicSwaggerProvider.class).builder(this);
+		BeanCreator<SwaggerProvider> creator;
 
 		/**
 		 * Constructor.
-		 */
-		protected Builder() {}
-
-		/**
-		 * Copy constructor.
 		 *
-		 * @param copyFrom The builder being copied.
+		 * @param beanStore The bean store to use for creating beans.
 		 */
-		protected Builder(Builder copyFrom) {
-			resourceClass = copyFrom.resourceClass;
-			varResolver = copyFrom.varResolver;
-			jsonSchemaGenerator = copyFrom.jsonSchemaGenerator;
-			messages = copyFrom.messages;
-			fileFinder = copyFrom.fileFinder;
-			creator = copyFrom.creator.copy();
+		protected Builder(BeanStore beanStore) {
+			this.beanStore = beanStore;
+			this.creator = beanStore.createBean(SwaggerProvider.class).type(BasicSwaggerProvider.class).builder(Builder.class, this);
 		}
+
 		/**
 		 * Creates a new {@link SwaggerProvider} object from this builder.
 		 *
@@ -155,18 +148,6 @@ public interface SwaggerProvider {
 		}
 
 		/**
-		 * Specifies the bean store to use for instantiating the {@link SwaggerProvider} object.
-		 *
-		 * @param value The new value for this setting.
-		 * @return  This object.
-		 */
-		public Builder beanStore(BeanStore value) {
-			creator.store(value);
-			beanStore = value;
-			return this;
-		}
-
-		/**
 		 * Specifies a subclass of {@link SwaggerProvider} to create when the {@link #build()} method is called.
 		 *
 		 * @param value The new value for this setting.
@@ -231,15 +212,6 @@ public interface SwaggerProvider {
 			creator.impl(value);
 			return this;
 		}
-
-		/**
-		 * Creates a copy of this builder.
-		 *
-		 * @return A copy of this builder.
-		 */
-		public Builder copy() {
-			return new Builder(this);
-		}
 	}
 
 	//-----------------------------------------------------------------------------------------------------------------
diff --git a/juneau-utest/src/test/java/org/apache/juneau/assertions/Assertions_Test.java b/juneau-utest/src/test/java/org/apache/juneau/assertions/Assertions_Test.java
index 88c171a..e967879 100644
--- a/juneau-utest/src/test/java/org/apache/juneau/assertions/Assertions_Test.java
+++ b/juneau-utest/src/test/java/org/apache/juneau/assertions/Assertions_Test.java
@@ -91,8 +91,8 @@ public class Assertions_Test {
 
 	@Test
 	public void a10_assertStream() throws Exception {
-		assertStream(inputStream("foo")).asString().is("foo");
-		assertStream((InputStream)null).asString().isNull();
+		assertBytes(inputStream("foo")).asString().is("foo");
+		assertBytes((InputStream)null).asString().isNull();
 	}
 
 	@Test
diff --git a/juneau-utest/src/test/java/org/apache/juneau/cp/BeanCreator_Test.java b/juneau-utest/src/test/java/org/apache/juneau/cp/BeanCreator_Test.java
deleted file mode 100644
index c89f24a..0000000
--- a/juneau-utest/src/test/java/org/apache/juneau/cp/BeanCreator_Test.java
+++ /dev/null
@@ -1,419 +0,0 @@
-// ***************************************************************************************************************************
-// * 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.cp;
-
-import static org.apache.juneau.assertions.Assertions.*;
-import static org.junit.runners.MethodSorters.*;
-
-import java.util.*;
-
-import javax.inject.*;
-
-import static org.apache.juneau.cp.BeanCreator.*;
-
-import org.apache.juneau.annotation.*;
-import org.junit.*;
-
-@FixMethodOrder(NAME_ASCENDING)
-public class BeanCreator_Test {
-
-	//-----------------------------------------------------------------------------------------------------------------
-	// Basic tests.
-	//-----------------------------------------------------------------------------------------------------------------
-
-	public static class A1 {}
-
-	@Test
-	public void a01_basic() {
-		assertObject(of(A1.class).run()).isNotNull();
-		assertObject(of(null).run()).isNull();
-	}
-
-	public class A2 {}
-
-	@Test
-	public void a02_outer() {
-		BeanCreator_Test outer = new BeanCreator_Test();
-		assertObject(of(A2.class).outer(outer).run()).isNotNull();
-	}
-
-	//-----------------------------------------------------------------------------------------------------------------
-	// Static creators.
-	//-----------------------------------------------------------------------------------------------------------------
-
-	public static class B1 {
-		public String a;
-		public static B1 create() {
-			B1 x = new B1();
-			x.a = "foo";
-			return x;
-		}
-	}
-
-	@Test
-	public void b01_staticCreator_create() {
-		assertString(of(B1.class).run().a).is("foo");
-
-	}
-
-	public static abstract class B2 {
-		public String a;
-		public static B2 getInstance() {
-			B2 x = new B2(){};
-			x.a = "foo";
-			return x;
-		}
-	}
-
-	@Test
-	public void b02_staticCreator_getInstance() {
-		assertString(of(B2.class).run().a).is("foo");
-	}
-
-	public static class B3a {
-		public String a;
-		public static B3a getFoo() {
-			B3a x = new B3a();
-			x.a = "foo";
-			return x;
-		}
-		protected static B3a create() {
-			B3a x = new B3a();
-			x.a = "foo";
-			return x;
-		}
-		public static B3a create(String foo) {
-			B3a x = new B3a();
-			x.a = "foo";
-			return x;
-		}
-		@Deprecated protected static B3a getInstance() {
-			B3a x = new B3a();
-			x.a = "foo";
-			return x;
-		}
-		protected B3a() {
-			a = "bar";
-		}
-	}
-
-	public static class B3b {
-		public String a;
-		public B3b create() {
-			B3b x = new B3b();
-			x.a = "foo";
-			return x;
-		}
-		@BeanIgnore public static B3b getInstance() {
-			B3b x = new B3b();
-			x.a = "foo";
-			return x;
-		}
-		protected B3b() {
-			a = "bar";
-		}
-	}
-
-	public static class B3c {
-		public String a;
-		public static String create() {
-			return null;
-		}
-		protected B3c() {
-			a = "bar";
-		}
-	}
-
-	@Test
-	public void b03_staticCreator_invalidSignatures() {
-		BeanStore bs = BeanStore.INSTANCE;
-		assertString(bs.creator(B3a.class).run().a).is("bar");
-		assertString(bs.creator(B3b.class).run().a).is("bar");
-		assertString(bs.creator(B3c.class).run().a).is("bar");
-	}
-
-	public static class B4 {
-		public String a;
-		public static B4 create() {
-			B4 x = new B4();
-			x.a = "foo";
-			return x;
-		}
-		public static B4 create(Integer i, String s) {
-			B4 x = new B4();
-			x.a = i.toString() + s;
-			return x;
-		}
-		public static B4 create(Integer i) {
-			B4 x = new B4();
-			x.a = i.toString();
-			return x;
-		}
-		protected B4() {
-			a = "bar";
-		}
-	}
-
-	@Test
-	public void b04_staticCreator_withBeans() {
-		BeanStore bs = BeanStore.create().build();
-		assertString(bs.creator(B4.class).run().a).is("foo");
-		bs.add(Integer.class, 1);
-		assertString(bs.creator(B4.class).run().a).is("1");
-		bs.add(String.class, "x");
-		assertString(bs.creator(B4.class).run().a).is("1x");
-		bs.add(Integer.class, null);
-		assertString(bs.creator(B4.class).run().a).is("foo");
-	}
-
-	public static class B5 {
-		public String a;
-		public static B5 create() {
-			return new B5("foo");
-		}
-		protected B5(String s) {
-			a = s;
-		}
-	}
-
-	@Test
-	public void b05_staticCreator_ignoredWithBuilder() {
-		assertString(of(B5.class).builder("bar").run().a).is("bar");
-	}
-
-	public static class B6 {
-		public String a = "foo";
-		public static B6 create(Optional<String> s) {
-			B6 x = new B6();
-			x.a = s.orElse(null);
-			return x;
-		}
-	}
-
-	@Test
-	public void b06_staticCreator_withOptional() {
-		BeanStore bs = BeanStore.create().build();
-		assertString(bs.creator(B6.class).run().a).isNull();
-		bs.add(String.class, "bar");
-		assertString(bs.creator(B6.class).run().a).is("bar");
-	}
-
-	public static class B7 {
-		public String a = "foo";
-		public static B7 create(Optional<String> s, Integer i) {
-			B7 x = new B7();
-			x.a = s.orElse(null) + "," + i;
-			return x;
-		}
-		private B7() {}
-	}
-
-	@Test
-	public void b07_staticCreator_missingPrereqs() {
-		BeanStore bs = BeanStore.create().build();
-		assertThrown(()->bs.creator(B7.class).run()).message().is("Could not instantiate class org.apache.juneau.cp.BeanCreator_Test$B7: Static creator found but could not find prerequisites: Integer.");
-		bs.add(Integer.class, 1);
-		assertString(bs.creator(B7.class).run().a).is("null,1");
-		bs.add(String.class, "bar");
-		assertString(bs.creator(B7.class).run().a).is("bar,1");
-	}
-	//-----------------------------------------------------------------------------------------------------------------
-	// Invalid types.
-	//-----------------------------------------------------------------------------------------------------------------
-
-	public static abstract class C1 {
-		public C1() {}
-	}
-
-	public interface C2 {}
-
-	@Test
-	public void c01_staticCreator_withBeans() {
-		assertThrown(()->of(C1.class).run()).message().is("Could not instantiate class "+C1.class.getName()+": Class is abstract.");
-		assertThrown(()->of(C2.class).run()).message().is("Could not instantiate class "+C2.class.getName()+": Class is an interface.");
-	}
-
-	//-----------------------------------------------------------------------------------------------------------------
-	// Constructors.
-	//-----------------------------------------------------------------------------------------------------------------
-
-	public static class D1 {
-		public String a;
-		public D1(String s) {
-			a = "s="+s;
-		}
-		public D1(Integer i) {
-			a = "i="+i;
-		}
-		public D1(String s, Integer i) {
-			a = "s="+s+",i="+i;
-		}
-	}
-
-	@Test
-	public void d01_constructors_public() {
-		BeanStore bs = BeanStore.create().build();
-		assertThrown(()->bs.creator(D1.class).run()).message().is("Could not instantiate class "+D1.class.getName()+": Public constructor found but could not find prerequisites: Integer or Integer,String or String.");
-		bs.add(String.class, "foo");
-		assertString(bs.creator(D1.class).run().a).is("s=foo");
-		bs.add(Integer.class, 1);
-		assertString(bs.creator(D1.class).run().a).is("s=foo,i=1");
-		bs.removeBean(String.class);
-		assertString(bs.creator(D1.class).run().a).is("i=1");
-	}
-
-	public static class D2 {
-		public String a;
-		protected D2(String s) {
-			a = "s="+s;
-		}
-		protected D2(Integer i) {
-			a = "i="+i;
-		}
-		protected D2(String s, Integer i) {
-			a = "s="+s+",i="+i;
-		}
-	}
-
-	@Test
-	public void d02_constructors_protected() {
-		BeanStore bs = BeanStore.create().build();
-		assertThrown(()->bs.creator(D2.class).run()).message().is("Could not instantiate class "+D2.class.getName()+": Protected constructor found but could not find prerequisites: Integer or Integer,String or String.");
-		bs.add(String.class, "foo");
-		assertString(bs.creator(D2.class).run().a).is("s=foo");
-		bs.add(Integer.class, 1);
-		assertString(bs.creator(D2.class).run().a).is("s=foo,i=1");
-		bs.removeBean(String.class);
-		assertString(bs.creator(D2.class).run().a).is("i=1");
-	}
-
-	public static class D3 {
-		public String a;
-		public D3(String s) {
-			a = "s="+s;
-		}
-		protected D3(String s, Integer i) {
-			a = "s="+s+",i="+i;
-		}
-	}
-
-	@Test
-	public void d03_constructors_publicOverProtected() {
-		BeanStore bs = BeanStore.create().build();
-		assertThrown(()->bs.creator(D3.class).run()).message().is("Could not instantiate class "+D3.class.getName()+": Public constructor found but could not find prerequisites: String.");
-		bs.add(String.class, "foo");
-		bs.add(Integer.class, 1);
-		assertString(bs.creator(D3.class).run().a).is("s=foo");
-	}
-
-	public static class D4 {
-		private D4() {}
-	}
-
-	@Test
-	public void d04_constructors_private() {
-		assertThrown(()->of(D4.class).run()).message().is("Could not instantiate class "+D4.class.getName()+": No public/protected constructors found.");
-	}
-
-	public static class D5 {
-		public String a;
-		public D5(@Named("foo") Object o) {
-			a = o.toString();
-		}
-		public D5(@Named("foo") Object o, Integer i) {
-			a = o.toString() + "," + i;
-		}
-	}
-
-	@Test
-	public void d05_constructors_namedBean() {
-		BeanStore bs = BeanStore.create().build();
-		assertThrown(()->bs.creator(D5.class).run()).message().is("Could not instantiate class "+D5.class.getName()+": Public constructor found but could not find prerequisites: Integer,foo or foo.");
-		bs.add("foo", "bar");
-		assertString(bs.creator(D5.class).run().a).is("bar");
-	}
-
-	public class D6 {
-		public String a;
-		public D6(@Named("foo") Object o) {
-			a = o.toString();
-		}
-		public D6(@Named("foo") Object o, Integer i) {
-			a = o.toString() + "," + i;
-		}
-	}
-
-	@Test
-	public void d06_constructors_namedBean_withOuter() {
-		BeanStore bs = BeanStore.create().build();
-		Object outer = new BeanCreator_Test();
-		assertThrown(()->bs.creator(D6.class).outer(outer).run()).message().is("Could not instantiate class "+D6.class.getName()+": Public constructor found but could not find prerequisites: Integer,foo or foo.");
-		bs.add("foo", "bar");
-		assertString(bs.creator(D6.class).outer(outer).run().a).is("bar");
-	}
-
-	//-----------------------------------------------------------------------------------------------------------------
-	// Builders.
-	//-----------------------------------------------------------------------------------------------------------------
-
-	public static class E1 {
-		public String a;
-
-		public static Builder create() {
-			return new Builder();
-		}
-
-		public static class Builder {
-			public String b;
-		}
-
-		protected E1(Builder b) {
-			a = b.b;
-		}
-	}
-
-	@Test
-	public void e01_builders() {
-		BeanStore bs = BeanStore.create().build();
-		E1.Builder b = E1.create();
-		b.b = "foo";
-		assertString(bs.creator(E1.class).builder(b).run().a).is("foo");
-	}
-
-	public static class E2 {
-		public String a;
-		public static Builder create() {
-			return new Builder();
-		}
-		public static class Builder {
-			public String b;
-		}
-		protected E2(Builder b, Integer i) {
-			a = b.b;
-		}
-		protected E2(Integer i) {
-		}
-		E2(String s) {
-		}
-		protected E2(Builder b) {
-			a = b.b;
-		}
-	}
-
-	@Test
-	public void e02_builders_inherent() {
-		BeanStore bs = BeanStore.create().build();
-		assertString(bs.creator(E2.class).run().a).isNull();
-		assertThrown(()->bs.creator(E2.class).builder(true).run()).message().is("Could not instantiate class "+E2.class.getName()+": Protected constructor found but could not find prerequisites: Builder or Builder,Integer or Integer.");
-	}
-}
diff --git a/juneau-utest/src/test/java/org/apache/juneau/cp/BeanStore_Test.java b/juneau-utest/src/test/java/org/apache/juneau/cp/BeanStore_Test.java
index 39f2650..86d0991 100644
--- a/juneau-utest/src/test/java/org/apache/juneau/cp/BeanStore_Test.java
+++ b/juneau-utest/src/test/java/org/apache/juneau/cp/BeanStore_Test.java
@@ -13,189 +13,1043 @@
 package org.apache.juneau.cp;
 
 import static org.apache.juneau.assertions.Assertions.*;
+import static org.apache.juneau.internal.ObjectUtils.*;
+import static org.junit.Assert.*;
 import static org.junit.runners.MethodSorters.*;
 
 import java.util.*;
+import java.util.function.*;
 
 import javax.inject.*;
 
 import org.apache.juneau.annotation.*;
+import org.apache.juneau.reflect.*;
 import org.junit.*;
 
 @FixMethodOrder(NAME_ASCENDING)
 public class BeanStore_Test {
 
-	private static final String CNAME = BeanStore_Test.class.getName();
-
 	//-----------------------------------------------------------------------------------------------------------------
-	// Basic tests.
+	// Basic tests
 	//-----------------------------------------------------------------------------------------------------------------
 
-	public static class A {}
+	public static class A1 {}
+	public static class A2 {}
+
+	public static String A1n = A1.class.getSimpleName();
+
+	public static class A3 extends BeanStore {
+		protected A3(Builder builder) {
+			super(builder);
+		}
+	}
+
+	private static A1 a1a = new A1(), a1b = new A1(), a1c = new A1(), a1d = new A1(), a1e = new A1();
+	private static A2 a2a = new A2();
+
+	@Test
+	public void a00_dummy() {
+		new BeanStore.Null();
+	}
+
+	@Test
+	public void a01_builderCopyConstructor() {
+		BeanStore b1p = BeanStore.create().readOnly().threadSafe().build();
+		BeanStore b1c = BeanStore.create().parent(b1p).build();
+		assertString(b1c.toString()).is("{parent:{readOnly:true,threadSafe:true}}");
+	}
 
 	@Test
-	public void a01_addBean() {
-		BeanStore bs = new BeanStore();
-		assertBoolean(bs.hasBean(A.class)).isFalse();
-		assertOptional(bs.getBean(A.class)).isNull();
-		bs.addBean(A.class, new A());
-		assertBoolean(bs.hasBean(A.class)).isTrue();
-		assertOptional(bs.getBean(A.class)).exists();
-		bs = BeanStore.of(bs);
-		assertBoolean(bs.hasBean(A.class)).isTrue();
-		assertOptional(bs.getBean(A.class)).exists();
+	public void a02_readOnly() {
+		BeanStore b1p = BeanStore.create().readOnly().build();
+		BeanStore b1c = BeanStore.create().parent(b1p).build();
+		BeanStore b2p = BeanStore.create().readOnly().threadSafe().build();
+		BeanStore b2c = BeanStore.create().parent(b1p).threadSafe().build();
+
+		for (BeanStore b : array(b1p, b2p)) {
+			assertThrown(()->b.add(A1.class, a1a)).message().is("Method cannot be used because BeanStore is read-only.");
+			assertThrown(()->b.add(A1.class, a1a, "foo")).message().is("Method cannot be used because BeanStore is read-only.");
+			assertThrown(()->b.addBean(A1.class, a1a)).message().is("Method cannot be used because BeanStore is read-only.");
+			assertThrown(()->b.addBean(A1.class, a1a, "foo")).message().is("Method cannot be used because BeanStore is read-only.");
+			assertThrown(()->b.addSupplier(A1.class, ()->a1a)).message().is("Method cannot be used because BeanStore is read-only.");
+			assertThrown(()->b.addSupplier(A1.class, ()->a1a, "foo")).message().is("Method cannot be used because BeanStore is read-only.");
+			assertThrown(()->b.clear()).message().is("Method cannot be used because BeanStore is read-only.");
+			assertThrown(()->b.removeBean(A1.class)).message().is("Method cannot be used because BeanStore is read-only.");
+			assertThrown(()->b.removeBean(A1.class, "foo")).message().is("Method cannot be used because BeanStore is read-only.");
+		}
+
+		for (BeanStore b : array(b1c, b2c)) {
+			b.add(A1.class, a1a);
+			b.add(A1.class, a1a, "foo");
+			b.addBean(A1.class, a1a);
+			b.addBean(A1.class, a1a, "foo");
+			b.addSupplier(A1.class, ()->a1a);
+			b.addSupplier(A1.class, ()->a1a, "foo");
+			b.clear();
+			b.removeBean(A1.class);
+			b.removeBean(A1.class, "foo");
+		}
+	}
+
+	@Test
+	public void a04_addBean() {
+		BeanStore b1p = BeanStore.create().build();
+		BeanStore b1c = BeanStore.of(b1p);
+		BeanStore b2p = BeanStore.create().threadSafe().build();
+		BeanStore b2c = BeanStore.create().threadSafe().parent(b2p).build();
+
+		for (BeanStore b : array(b1p, b1c, b2p, b2c)) {
+			assertBoolean(b.hasBean(A1.class)).isFalse();
+			assertOptional(b.getBean(A1.class)).isNull();
+		}
+
+		b1p.addBean(A1.class, a1a);
+		b2p.addBean(A1.class, a1a);
+		for (BeanStore b : array(b1p, b1c, b2p, b2c)) {
+			assertBoolean(b.hasBean(A1.class)).isTrue();
+			assertOptional(b.getBean(A1.class)).is(a1a);
+		}
+
+		b1p.clear();
+		b2p.clear();
+		for (BeanStore b : array(b1p, b1c, b2p, b2c)) {
+			assertBoolean(b.hasBean(A1.class)).isFalse();
+			assertOptional(b.getBean(A1.class)).isNull();
+		}
+
+		b1p.addBean(A1.class, null);
+		b2p.addBean(A1.class, null);
+		for (BeanStore b : array(b1p, b1c, b2p, b2c)) {
+			assertBoolean(b.hasBean(A1.class)).isTrue();
+			assertOptional(b.getBean(A1.class)).isNull();
+		}
+
+		b1p.clear().addSupplier(A1.class, ()->a1a);
+		b2p.clear().addSupplier(A1.class, ()->a1a);
+		for (BeanStore b : array(b1p, b1c, b2p, b2c)) {
+			assertBoolean(b.hasBean(A1.class)).isTrue();
+			assertOptional(b.getBean(A1.class)).is(a1a);
+		}
+
+		b1p.add(A1.class, a1b);
+		b2p.add(A1.class, a1b);
+		for (BeanStore b : array(b1p, b1c, b2p, b2c)) {
+			assertBoolean(b.hasBean(A1.class)).isTrue();
+			assertOptional(b.getBean(A1.class)).is(a1b);
+			assertList(b.stream(A1.class).map(BeanStoreEntry::get)).has(a1b,a1a);
+		}
+
+		b1c.add(A2.class, a2a);
+		b2c.add(A2.class, a2a);
+		for (BeanStore b : array(b1p, b2p)) {
+			assertBoolean(b.hasBean(A2.class)).isFalse();
+			assertOptional(b.getBean(A2.class)).isNull();
+			assertList(b.stream(A2.class)).isEmpty();
+		}
+		for (BeanStore b : array(b1c, b2c)) {
+			assertBoolean(b.hasBean(A2.class)).isTrue();
+			assertOptional(b.getBean(A2.class)).is(a2a);
+			assertList(b.stream(A2.class).map(BeanStoreEntry::get)).has(a2a);
+		}
+
+		assertString(b1p.toString()).is("{entries:[{type:'A1',bean:'"+identity(a1b)+"'},{type:'A1',bean:'"+identity(a1a)+"'}]}");
+		assertString(b1c.toString()).is("{entries:[{type:'A2',bean:'"+identity(a2a)+"'}],parent:{entries:[{type:'A1',bean:'"+identity(a1b)+"'},{type:'A1',bean:'"+identity(a1a)+"'}]}}");
+		assertString(b2p.toString()).is("{entries:[{type:'A1',bean:'"+identity(a1b)+"'},{type:'A1',bean:'"+identity(a1a)+"'}],threadSafe:true}");
+		assertString(b2c.toString()).is("{entries:[{type:'A2',bean:'"+identity(a2a)+"'}],parent:{entries:[{type:'A1',bean:'"+identity(a1b)+"'},{type:'A1',bean:'"+identity(a1a)+"'}],threadSafe:true},threadSafe:true}");
+
+		b1p.removeBean(A1.class);
+		b1c.clear().addBean(A1.class, a1a);
+		b2p.removeBean(A1.class);
+		b2c.clear().addBean(A1.class, a1a);
+
+		for (BeanStore b : array(b1p, b2p)) {
+			assertBoolean(b.hasBean(A1.class)).isFalse();
+			assertOptional(b.getBean(A1.class)).isNull();
+			assertList(b.stream(A1.class)).isEmpty();
+		}
+		for (BeanStore b : array(b1c, b2c)) {
+			assertBoolean(b.hasBean(A1.class)).isTrue();
+			assertOptional(b.getBean(A1.class)).is(a1a);
+			assertList(b.stream(A1.class).map(BeanStoreEntry::get)).has(a1a);
+		}
+
+		b1c.removeBean(A1.class);
+		b2c.removeBean(A1.class);
+		for (BeanStore b : array(b1p, b1c, b2p, b2c)) {
+			assertBoolean(b.hasBean(A1.class)).isFalse();
+			assertOptional(b.getBean(A1.class)).isNull();
+			assertList(b.stream(A1.class)).isEmpty();
+		}
+	}
+
+	@Test
+	public void a05_addNamedBeans() {
+		BeanStore b1p = BeanStore.create().build();
+		BeanStore b1c = BeanStore.of(b1p);
+		BeanStore b2p = BeanStore.create().threadSafe().build();
+		BeanStore b2c = BeanStore.create().threadSafe().parent(b2p).build();
+
+		for (BeanStore b : array(b1p, b2p)) {
+			b.addBean(A1.class, a1a).addBean(A1.class, a1b, "foo").addBean(A1.class, a1c, "bar").addBean(A1.class, a1d, "bar").addBean(A2.class, a2a, "foo");
+		}
+		for (BeanStore b : array(b1c, b2c)) {
+			b.addBean(A1.class, a1e);
+		}
+
+		for (BeanStore b : array(b1p, b2p)) {
+			assertList(b.stream(A1.class).map(BeanStoreEntry::get)).has(a1d,a1c,a1b,a1a);
+		}
+		for (BeanStore b : array(b1c, b2c)) {
+			assertList(b.stream(A1.class).map(BeanStoreEntry::get)).has(a1e,a1d,a1c,a1b,a1a);
+		}
+
+		for (BeanStore b : array(b1p, b1c, b2p, b2c)) {
+			assertOptional(b.getBean(A1.class, "foo")).is(a1b);
+			assertOptional(b.getBean(A1.class, "bar")).is(a1d);
+			assertOptional(b.getBean(A1.class, "baz")).isNull();
+		}
+		for (BeanStore b : array(b1p, b2p)) {
+			assertOptional(b.getBean(A1.class, null)).is(a1a);
+		}
+		for (BeanStore b : array(b1c, b2c)) {
+			assertOptional(b.getBean(A1.class, null)).is(a1e);
+		}
 	}
 
 	//-----------------------------------------------------------------------------------------------------------------
-	// Create bean via method.
+	// Parameter matching
 	//-----------------------------------------------------------------------------------------------------------------
 
-	public static class E {
-		public A a;
+	public static class B1 {
+		A1 a1;
+		Optional<A2> a2;
+		BeanStore a3;
+
+		public B1(A1 a1, Optional<A2> a2, BeanStore a3) {
+			this.a1 = a1;
+			this.a2 = a2;
+			this.a3 = a3;
+		}
+
+		public B1(@Named("foo") A1 a1, @Named("bar") Optional<A2> a2) {
+			this.a1 = a1;
+			this.a2 = a2;
+		}
+
+		public void m1(A1 a1, Optional<A2> a2, BeanStore a3) {
+			this.a1 = a1;
+			this.a2 = a2;
+			this.a3 = a3;
+		}
+
+		public void m2(@Named("foo") A1 a1, @Named("bar") Optional<A2> a2) {
+			this.a1 = a1;
+			this.a2 = a2;
+			this.a3 = null;
+		}
+
+		public static B1 m3(A1 a1, Optional<A2> a2, BeanStore a3) {
+			return new B1(a1, a2, a3);
+		}
 	}
 
-	public static class E1 {
+	@Test
+	public void b01_getParams() {
+
+		Predicate<Object> pEmptyOptional = x -> !((Optional<?>)x).isPresent();
+		Predicate<Object> pIsBeanStore = x -> x instanceof BeanStore;
+		Predicate<Object> pNull = x -> x == null;
+		Predicate<Object> pA1a = x -> x==a1a;
+		Predicate<Object> pA2a = x -> ((Optional<?>)x).get()==a2a;
+
+		B1 outer = new B1(null, null, null);
+
+		BeanStore b1p = BeanStore.create().outer(outer).build();
+		BeanStore b1c = BeanStore.create().outer(outer).parent(b1p).build();
+		BeanStore b2p = BeanStore.create().outer(outer).threadSafe().build();
+		BeanStore b2c = BeanStore.create().outer(outer).parent(b1p).threadSafe().build();
+
+		ClassInfo ci = ClassInfo.of(B1.class);
+		ConstructorInfo c1 = ci.getPublicConstructor(A1.class, Optional.class, BeanStore.class);
+		ConstructorInfo c2 = ci.getPublicConstructor(A1.class, Optional.class);
+		MethodInfo m1 = ci.getPublicMethod(x-> x.hasName("m1"));
+		MethodInfo m2 = ci.getPublicMethod(x-> x.hasName("m2"));
+		MethodInfo m3 = ci.getPublicMethod(x-> x.hasName("m3"));
+
+		for (BeanStore b : array(b1p, b1c, b2p, b2c)) {
+			for (ExecutableInfo e : array(c1, m1, m3)) {
+				assertString(b.getMissingParams(e)).is(A1n);
+				assertBoolean(b.hasAllParams(e)).isFalse();
+			}
+			for (ExecutableInfo e : array(c2, m2)) {
+				assertString(b.getMissingParams(e)).is(A1n+"@foo");
+				assertBoolean(b.hasAllParams(e)).isFalse();
+			}
+		}
+
+		for (BeanStore b : array(b1p, b1c, b2p, b2c)) {
+			assertArray(b.getParams(c1)).is(pNull, pEmptyOptional, pIsBeanStore);
+			assertArray(b.getParams(c2)).is(pNull, pEmptyOptional);
+			assertArray(b.getParams(m1)).is(pNull, pEmptyOptional, pIsBeanStore);
+			assertArray(b.getParams(m2)).is(pNull, pEmptyOptional);
+			assertArray(b.getParams(m3)).is(pNull, pEmptyOptional, pIsBeanStore);
+		}
+
+		b1p.add(A1.class, a1a);
+		b2p.add(A1.class, a1a);
+		for (BeanStore b : array(b1p, b1c, b2p, b2c)) {
+			assertString(b.getMissingParams(c1)).isNull();
+			assertString(b.getMissingParams(c2)).is(A1n+"@foo");
+			assertString(b.getMissingParams(m1)).isNull();
+			assertString(b.getMissingParams(m2)).is(A1n+"@foo");
+			assertString(b.getMissingParams(m3)).isNull();
+			assertBoolean(b.hasAllParams(c1)).isTrue();
+			assertBoolean(b.hasAllParams(c2)).isFalse();
+			assertBoolean(b.hasAllParams(m1)).isTrue();
+			assertBoolean(b.hasAllParams(m2)).isFalse();
+			assertBoolean(b.hasAllParams(m3)).isTrue();
+			assertArray(b.getParams(c1)).is(pA1a, pEmptyOptional, pIsBeanStore);
+			assertArray(b.getParams(c2)).is(pNull, pEmptyOptional);
+			assertArray(b.getParams(m1)).is(pA1a, pEmptyOptional, pIsBeanStore);
+			assertArray(b.getParams(m2)).is(pNull, pEmptyOptional);
+			assertArray(b.getParams(m3)).is(pA1a, pEmptyOptional, pIsBeanStore);
+		}
+
+		b1p.add(A1.class, a1a, "foo");
+		b2p.add(A1.class, a1a, "foo");
+		for (BeanStore b : array(b1p, b1c, b2p, b2c)) {
+			for (ExecutableInfo e : array(c1, c2, m1, m2, m3)) {
+				assertString(b.getMissingParams(e)).isNull();
+				assertBoolean(b.hasAllParams(e)).isTrue();
+			}
+			assertArray(b.getParams(c1)).is(pA1a, pEmptyOptional, pIsBeanStore);
+			assertArray(b.getParams(c2)).is(pA1a, pEmptyOptional);
+			assertArray(b.getParams(m1)).is(pA1a, pEmptyOptional, pIsBeanStore);
+			assertArray(b.getParams(m2)).is(pA1a, pEmptyOptional);
+			assertArray(b.getParams(m3)).is(pA1a, pEmptyOptional, pIsBeanStore);
+		}
+
+		b1p.add(A1.class, a1b, "bar");
+		b2p.add(A1.class, a1b, "bar");
+		for (BeanStore b : array(b1p, b1c, b2p, b2c)) {
+			for (ExecutableInfo e : array(c1, c2, m1, m2, m3)) {
+				assertString(b.getMissingParams(e)).isNull();
+				assertBoolean(b.hasAllParams(e)).isTrue();
+			}
+			assertArray(b.getParams(c1)).is(pA1a, pEmptyOptional, pIsBeanStore);
+			assertArray(b.getParams(c2)).is(pA1a, pEmptyOptional);
+			assertArray(b.getParams(m1)).is(pA1a, pEmptyOptional, pIsBeanStore);
+			assertArray(b.getParams(m2)).is(pA1a, pEmptyOptional);
+			assertArray(b.getParams(m3)).is(pA1a, pEmptyOptional, pIsBeanStore);
+		}
+
+		b1p.add(A2.class, a2a, "bar");
+		b2p.add(A2.class, a2a, "bar");
+		for (BeanStore b : array(b1p, b1c, b2p, b2c)) {
+			for (ExecutableInfo e : array(c1, c2, m1, m2, m3)) {
+				assertString(b.getMissingParams(e)).isNull();
+				assertBoolean(b.hasAllParams(e)).isTrue();
+			}
+			assertArray(b.getParams(c1)).is(pA1a, pEmptyOptional, pIsBeanStore);
+			assertArray(b.getParams(c2)).is(pA1a, pA2a);
+			assertArray(b.getParams(m1)).is(pA1a, pEmptyOptional, pIsBeanStore);
+			assertArray(b.getParams(m2)).is(pA1a, pA2a);
+			assertArray(b.getParams(m3)).is(pA1a, pEmptyOptional, pIsBeanStore);
+		}
+
+		b1p.add(A2.class, a2a, null);
+		b2p.add(A2.class, a2a, null);
+		for (BeanStore b : array(b1p, b1c, b2p, b2c)) {
+			for (ExecutableInfo e : array(c1, c2, m1, m2, m3)) {
+				assertString(b.getMissingParams(e)).isNull();
+				assertBoolean(b.hasAllParams(e)).isTrue();
+			}
+			assertArray(b.getParams(c1)).is(pA1a, pA2a, pIsBeanStore);
+			assertArray(b.getParams(c2)).is(pA1a, pA2a);
+			assertArray(b.getParams(m1)).is(pA1a, pA2a, pIsBeanStore);
+			assertArray(b.getParams(m2)).is(pA1a, pA2a);
+			assertArray(b.getParams(m3)).is(pA1a, pA2a, pIsBeanStore);
+		}
+	}
+
+	public class B2 {
+		A1 a1;
+		Optional<A2> a2;
+		BeanStore a3;
+
+		public B2(A1 a1, Optional<A2> a2, BeanStore a3) {
+			this.a1 = a1;
+			this.a2 = a2;
+			this.a3 = a3;
+		}
+
+		public B2(@Named("foo") A1 a1, @Named("bar") Optional<A2> a2) {
+			this.a1 = a1;
+			this.a2 = a2;
+		}
+	}
+
+	@Test
+	public void b02_getParams_innerClass() {
+
+		Predicate<Object> pEmptyOptional = x -> !((Optional<?>)x).isPresent();
+		Predicate<Object> pIsBeanStore = x -> x instanceof BeanStore;
+		Predicate<Object> pNull = x -> x == null;
+		Predicate<Object> pThis = x -> x == this;
+		Predicate<Object> pA1a = x -> x==a1a;
+		Predicate<Object> pA2a = x -> ((Optional<?>)x).get()==a2a;
+
+		BeanStore b1p = BeanStore.create().outer(this).build();
+		BeanStore b1c = BeanStore.create().outer(this).parent(b1p).build();
+		BeanStore b2p = BeanStore.create().outer(this).threadSafe().build();
+		BeanStore b2c = BeanStore.create().outer(this).parent(b1p).threadSafe().build();
 
-		public E createA1() {
-			return new E();
+		ClassInfo ci = ClassInfo.of(B2.class);
+		ConstructorInfo c1 = ci.getPublicConstructor(BeanStore_Test.class, A1.class, Optional.class, BeanStore.class);
+		ConstructorInfo c2 = ci.getPublicConstructor(BeanStore_Test.class, A1.class, Optional.class);
+
+		for (BeanStore b : array(b1p, b1c, b2p, b2c)) {
+			assertString(b.getMissingParams(c1)).is(A1n);
+			assertString(b.getMissingParams(c2)).is(A1n+"@foo");
+			assertBoolean(b.hasAllParams(c1)).isFalse();
+			assertBoolean(b.hasAllParams(c2)).isFalse();
 		}
-		public A createA2() {
-			return new A();
+
+		for (BeanStore b : array(b1p, b1c, b2p, b2c)) {
+			assertArray(b.getParams(c1)).is(pThis, pNull, pEmptyOptional, pIsBeanStore);
+			assertArray(b.getParams(c2)).is(pThis, pNull, pEmptyOptional);
 		}
-		protected A createA3() {
-			return new A();
+
+		b1p.add(A1.class, a1a);
+		b2p.add(A1.class, a1a);
+		for (BeanStore b : array(b1p, b1c, b2p, b2c)) {
+			assertString(b.getMissingParams(c1)).isNull();
+			assertString(b.getMissingParams(c2)).is(A1n+"@foo");
+			assertBoolean(b.hasAllParams(c1)).isTrue();
+			assertBoolean(b.hasAllParams(c2)).isFalse();
+			assertArray(b.getParams(c1)).is(pThis, pA1a, pEmptyOptional, pIsBeanStore);
+			assertArray(b.getParams(c2)).is(pThis, pNull, pEmptyOptional);
 		}
-		@Deprecated
-		public A createA4() {
-			return new A();
+
+		b1p.add(A1.class, a1a, "foo");
+		b2p.add(A1.class, a1a, "foo");
+		for (BeanStore b : array(b1p, b1c, b2p, b2c)) {
+			for (ExecutableInfo e : array(c1, c2)) {
+				assertString(b.getMissingParams(e)).isNull();
+				assertBoolean(b.hasAllParams(e)).isTrue();
+			}
+			assertArray(b.getParams(c1)).is(pThis, pA1a, pEmptyOptional, pIsBeanStore);
+			assertArray(b.getParams(c2)).is(pThis, pA1a, pEmptyOptional);
 		}
-		@BeanIgnore
-		public A createA5() {
-			return new A();
+
+		b1p.add(A1.class, a1b, "bar");
+		b2p.add(A1.class, a1b, "bar");
+		for (BeanStore b : array(b1p, b1c, b2p, b2c)) {
+			for (ExecutableInfo e : array(c1, c2)) {
+				assertString(b.getMissingParams(e)).isNull();
+				assertBoolean(b.hasAllParams(e)).isTrue();
+			}
+			assertArray(b.getParams(c1)).is(pThis, pA1a, pEmptyOptional, pIsBeanStore);
+			assertArray(b.getParams(c2)).is(pThis, pA1a, pEmptyOptional);
 		}
-		public E createA6() {
-			return null;
+
+		b1p.add(A2.class, a2a, "bar");
+		b2p.add(A2.class, a2a, "bar");
+		for (BeanStore b : array(b1p, b1c, b2p, b2c)) {
+			for (ExecutableInfo e : array(c1, c2)) {
+				assertString(b.getMissingParams(e)).isNull();
+				assertBoolean(b.hasAllParams(e)).isTrue();
+			}
+			assertArray(b.getParams(c1)).is(pThis, pA1a, pEmptyOptional, pIsBeanStore);
+			assertArray(b.getParams(c2)).is(pThis, pA1a, pA2a);
 		}
-		public E createA7() {
-			throw new RuntimeException("foo");
... 2110 lines suppressed ...