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 2020/05/12 20:12:35 UTC

[juneau] branch master updated: JUNEAU-227

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 c3fa242  JUNEAU-227
c3fa242 is described below

commit c3fa242de1bab2f0c8bb61ed863ec877f6713792
Author: JamesBognar <ja...@salesforce.com>
AuthorDate: Tue May 12 16:12:17 2020 -0400

    JUNEAU-227
    
    BEAN_methodVisibility and BEAN_constructorVisibility doesn't affect swap
    methods
---
 .../main/java/org/apache/juneau/BeanContext.java   |   8 +-
 .../src/main/java/org/apache/juneau/ClassMeta.java |   9 +
 .../juneau/oapi/OpenApiSerializerSession.java      |  16 +-
 .../org/apache/juneau/transform/AutoListSwap.java  |  23 +-
 .../org/apache/juneau/transform/AutoMapSwap.java   |  23 +-
 .../apache/juneau/transform/AutoNumberSwap.java    |  26 +-
 .../apache/juneau/transform/AutoObjectSwap.java    |  23 +-
 .../java/org/apache/juneau/transform/PojoSwap.java |   1 -
 juneau-doc/docs/ReleaseNotes/8.1.4.html            |   2 +
 .../apache/juneau/rest/client2/RestClientTest.java | 277 +++++++++++++++------
 .../juneau/rest/client2/RestCallException.java     |   2 +-
 .../juneau/rest/client2/RestClientBuilder.java     |  47 ++++
 .../juneau/rest/client2/RestResponseBody.java      |  11 +-
 .../apache/juneau/rest/mock2/MockRestClient.java   |  36 ++-
 14 files changed, 368 insertions(+), 136 deletions(-)

diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java
index 5198d2b..f028963 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java
@@ -3752,7 +3752,7 @@ public class BeanContext extends Context implements MetaProvider {
 	 * @return
 	 * 	Classes are not considered beans unless they meet the minimum visibility requirements.
 	 */
-	protected final Visibility getBeanClassVisibility() {
+	public final Visibility getBeanClassVisibility() {
 		return beanClassVisibility;
 	}
 
@@ -3763,7 +3763,7 @@ public class BeanContext extends Context implements MetaProvider {
 	 * @return
 	 * 	Only look for constructors with this specified minimum visibility.
 	 */
-	protected final Visibility getBeanConstructorVisibility() {
+	public final Visibility getBeanConstructorVisibility() {
 		return beanConstructorVisibility;
 	}
 
@@ -3786,7 +3786,7 @@ public class BeanContext extends Context implements MetaProvider {
 	 * @return
 	 * 	Only look for bean fields with this specified minimum visibility.
 	 */
-	protected final Visibility getBeanFieldVisibility() {
+	public final Visibility getBeanFieldVisibility() {
 		return beanFieldVisibility;
 	}
 
@@ -3821,7 +3821,7 @@ public class BeanContext extends Context implements MetaProvider {
 	 * @return
 	 * 	Only look for bean methods with this specified minimum visibility.
 	 */
-	protected final Visibility getBeanMethodVisibility() {
+	public final Visibility getBeanMethodVisibility() {
 		return beanMethodVisibility;
 	}
 
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 13eac61..06afe22 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
@@ -1339,6 +1339,15 @@ public final class ClassMeta<T> implements Type {
 	}
 
 	/**
+	 * Returns <jk>true</jk> if this class is a {@link Date} or {@link Calendar} or {@link Temporal}.
+	 *
+	 * @return <jk>true</jk> if this class is a {@link Date} or {@link Calendar} or {@link Temporal}.
+	 */
+	public boolean isDateOrCalendarOrTemporal() {
+		return cc == DATE || info.isChildOf(Temporal.class);
+	}
+
+	/**
 	 * Returns <jk>true</jk> if this class is a {@link Date}.
 	 *
 	 * @return <jk>true</jk> if this class is a {@link Date}.
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/oapi/OpenApiSerializerSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/oapi/OpenApiSerializerSession.java
index 8dbf800..19f9429 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/oapi/OpenApiSerializerSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/oapi/OpenApiSerializerSession.java
@@ -27,6 +27,7 @@ import org.apache.juneau.collections.*;
 import org.apache.juneau.httppart.*;
 import org.apache.juneau.internal.*;
 import org.apache.juneau.serializer.*;
+import org.apache.juneau.transform.*;
 import org.apache.juneau.transforms.*;
 import org.apache.juneau.uon.*;
 
@@ -93,11 +94,24 @@ public class OpenApiSerializerSession extends UonSerializerSession {
 	@Override /* PartSerializer */
 	public String serialize(HttpPartType partType, HttpPartSchema schema, Object value) throws SerializeException, SchemaValidationException {
 
-		schema = ObjectUtils.firstNonNull(schema, DEFAULT_SCHEMA);
 		ClassMeta<?> type = getClassMetaForObject(value);
 		if (type == null)
 			type = object();
 
+		// Swap if necessary
+		PojoSwap swap = type.getPojoSwap(this);
+		if (swap != null && ! type.isDateOrCalendarOrTemporal()) {
+			value = swap(swap, value);
+			type = swap.getSwapClassMeta(this);
+
+			// If the getSwapClass() method returns Object, we need to figure out
+			// the actual type now.
+			if (type.isObject())
+				type = getClassMetaForObject(value);
+		}
+
+		schema = ObjectUtils.firstNonNull(schema, DEFAULT_SCHEMA);
+
 		HttpPartDataType t = schema.getType(type);
 
 		HttpPartFormat f = schema.getFormat(type);
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoListSwap.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoListSwap.java
index 8da2941..83425c1 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoListSwap.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoListSwap.java
@@ -93,20 +93,20 @@ public class AutoListSwap<T> extends PojoSwap<T,List<?>> {
 			return null;
 
 		// Find swap() method if present.
-		for (MethodInfo m : ci.getPublicMethods()) {
+		for (MethodInfo m : ci.getAllMethods()) {
 			if (isSwapMethod(bc, m)) {
 
 				ClassInfo rt = m.getReturnType();
 
-				for (MethodInfo m2 : ci.getPublicMethods())
+				for (MethodInfo m2 : ci.getAllMethods())
 					if (isUnswapMethod(bc, m2, ci, rt))
-						return new AutoListSwap(ci, m, m2, null);
+						return new AutoListSwap(bc, ci, m, m2, null);
 
-				for (ConstructorInfo cs : ci.getPublicConstructors())
+				for (ConstructorInfo cs : ci.getDeclaredConstructors())
 					if (isUnswapConstructor(bc, cs, rt))
-						return new AutoListSwap(ci, m, null, cs);
+						return new AutoListSwap(bc, ci, m, null, cs);
 
-				return new AutoListSwap(ci, m, null, null);
+				return new AutoListSwap(bc, ci, m, null, null);
 			}
 		}
 
@@ -123,6 +123,7 @@ public class AutoListSwap<T> extends PojoSwap<T,List<?>> {
 		return
 			mi.isNotDeprecated()
 			&& mi.isNotStatic()
+			&& mi.isVisible(bc.getBeanMethodVisibility())
 			&& mi.hasName(SWAP_METHOD_NAMES)
 			&& mi.hasReturnTypeParent(List.class)
 			&& mi.hasFuzzyParamTypes(BeanSession.class)
@@ -133,6 +134,7 @@ public class AutoListSwap<T> extends PojoSwap<T,List<?>> {
 		return
 			mi.isNotDeprecated()
 			&& mi.isStatic()
+			&& mi.isVisible(bc.getBeanMethodVisibility())
 			&& mi.hasName(UNSWAP_METHOD_NAMES)
 			&& mi.hasFuzzyParamTypes(BeanSession.class, rt.inner())
 			&& mi.hasReturnTypeParent(ci)
@@ -142,6 +144,7 @@ public class AutoListSwap<T> extends PojoSwap<T,List<?>> {
 	private static boolean isUnswapConstructor(BeanContext bc, ConstructorInfo cs, ClassInfo rt) {
 		return
 			cs.isNotDeprecated()
+			&& cs.isVisible(bc.getBeanConstructorVisibility())
 			&& cs.hasMatchingParamTypes(rt)
 			&& ! bc.hasAnnotation(BeanIgnore.class, cs);
 	}
@@ -151,11 +154,11 @@ public class AutoListSwap<T> extends PojoSwap<T,List<?>> {
 	private final Method swapMethod, unswapMethod;
 	private final Constructor<?> unswapConstructor;
 
-	private AutoListSwap(ClassInfo ci, MethodInfo swapMethod, MethodInfo unswapMethod, ConstructorInfo unswapConstructor) {
+	private AutoListSwap(BeanContext bc, ClassInfo ci, MethodInfo swapMethod, MethodInfo unswapMethod, ConstructorInfo unswapConstructor) {
 		super(ci.inner(), swapMethod.getReturnType().inner());
-		this.swapMethod = swapMethod.inner();
-		this.unswapMethod = unswapMethod == null ? null : unswapMethod.inner();
-		this.unswapConstructor = unswapConstructor == null ? null : unswapConstructor.inner();
+		this.swapMethod = bc.getBeanMethodVisibility().transform(swapMethod.inner());
+		this.unswapMethod = unswapMethod == null ? null : bc.getBeanMethodVisibility().transform(unswapMethod.inner());
+		this.unswapConstructor = unswapConstructor == null ? null : bc.getBeanConstructorVisibility().transform(unswapConstructor.inner());
 	}
 
 	@Override /* PojoSwap */
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoMapSwap.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoMapSwap.java
index f803d4f..d5e16ef 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoMapSwap.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoMapSwap.java
@@ -92,20 +92,20 @@ public class AutoMapSwap<T> extends PojoSwap<T,Map<?,?>> {
 			return null;
 
 		// Find swap() method if present.
-		for (MethodInfo m : ci.getPublicMethods()) {
+		for (MethodInfo m : ci.getAllMethods()) {
 			if (isSwapMethod(bc, m)) {
 
 				ClassInfo rt = m.getReturnType();
 
-				for (MethodInfo m2 : ci.getPublicMethods())
+				for (MethodInfo m2 : ci.getAllMethods())
 					if (isUnswapMethod(bc, m2, ci, rt))
-						return new AutoMapSwap(ci, m, m2, null);
+						return new AutoMapSwap(bc, ci, m, m2, null);
 
-				for (ConstructorInfo cs : ci.getPublicConstructors())
+				for (ConstructorInfo cs : ci.getDeclaredConstructors())
 					if (isUnswapConstructor(bc, cs, rt))
-						return new AutoMapSwap(ci, m, null, cs);
+						return new AutoMapSwap(bc, ci, m, null, cs);
 
-				return new AutoMapSwap(ci, m, null, null);
+				return new AutoMapSwap(bc, ci, m, null, null);
 			}
 		}
 
@@ -122,6 +122,7 @@ public class AutoMapSwap<T> extends PojoSwap<T,Map<?,?>> {
 		return
 			mi.isNotDeprecated()
 			&& mi.isNotStatic()
+			&& mi.isVisible(bc.getBeanMethodVisibility())
 			&& mi.hasName(SWAP_METHOD_NAMES)
 			&& mi.hasReturnTypeParent(Map.class)
 			&& mi.hasFuzzyParamTypes(BeanSession.class)
@@ -132,6 +133,7 @@ public class AutoMapSwap<T> extends PojoSwap<T,Map<?,?>> {
 		return
 			mi.isNotDeprecated()
 			&& mi.isStatic()
+			&& mi.isVisible(bc.getBeanMethodVisibility())
 			&& mi.hasName(UNSWAP_METHOD_NAMES)
 			&& mi.hasFuzzyParamTypes(BeanSession.class, rt.inner())
 			&& mi.hasReturnTypeParent(ci)
@@ -141,6 +143,7 @@ public class AutoMapSwap<T> extends PojoSwap<T,Map<?,?>> {
 	private static boolean isUnswapConstructor(BeanContext bc, ConstructorInfo cs, ClassInfo rt) {
 		return
 			cs.isNotDeprecated()
+			&& cs.isVisible(bc.getBeanConstructorVisibility())
 			&& cs.hasMatchingParamTypes(rt)
 			&& ! bc.hasAnnotation(BeanIgnore.class, cs);
 	}
@@ -150,11 +153,11 @@ public class AutoMapSwap<T> extends PojoSwap<T,Map<?,?>> {
 	private final Method swapMethod, unswapMethod;
 	private final Constructor<?> unswapConstructor;
 
-	private AutoMapSwap(ClassInfo ci, MethodInfo swapMethod, MethodInfo unswapMethod, ConstructorInfo unswapConstructor) {
+	private AutoMapSwap(BeanContext bc, ClassInfo ci, MethodInfo swapMethod, MethodInfo unswapMethod, ConstructorInfo unswapConstructor) {
 		super(ci.inner(), swapMethod.inner().getReturnType());
-		this.swapMethod = swapMethod.inner();
-		this.unswapMethod = unswapMethod == null ? null : unswapMethod.inner();
-		this.unswapConstructor = unswapConstructor == null ? null : unswapConstructor.inner();
+		this.swapMethod = bc.getBeanMethodVisibility().transform(swapMethod.inner());
+		this.unswapMethod = unswapMethod == null ? null : bc.getBeanMethodVisibility().transform(unswapMethod.inner());
+		this.unswapConstructor = unswapConstructor == null ? null : bc.getBeanConstructorVisibility().transform(unswapConstructor.inner());
 	}
 
 	@Override /* PojoSwap */
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoNumberSwap.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoNumberSwap.java
index 5e4c6d9..c27e5af 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoNumberSwap.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoNumberSwap.java
@@ -116,20 +116,21 @@ public class AutoNumberSwap<T> extends PojoSwap<T,Number> {
 			return null;
 
 		// Find swap() method if present.
-		for (MethodInfo m : ci.getPublicMethods()) {
+		for (MethodInfo m : ci.getAllMethods()) {
+
 			if (isSwapMethod(bc, m)) {
 
 				ClassInfo rt = m.getReturnType();
 
-				for (MethodInfo m2 : ci.getPublicMethods())
+				for (MethodInfo m2 : ci.getAllMethods())
 					if (isUnswapMethod(bc, m2, ci, rt))
-						return new AutoNumberSwap(ci, m, m2, null);
+						return new AutoNumberSwap(bc, ci, m, m2, null);
 
-				for (ConstructorInfo cs : ci.getPublicConstructors())
+				for (ConstructorInfo cs : ci.getDeclaredConstructors())
 					if (isUnswapConstructor(bc, cs, rt))
-						return new AutoNumberSwap(ci, m, null, cs);
+						return new AutoNumberSwap(bc, ci, m, null, cs);
 
-				return new AutoNumberSwap(ci, m, null, null);
+				return new AutoNumberSwap(bc, ci, m, null, null);
 			}
 		}
 
@@ -149,6 +150,7 @@ public class AutoNumberSwap<T> extends PojoSwap<T,Number> {
 		return
 			mi.isNotDeprecated()
 			&& mi.isNotStatic()
+			&& mi.isVisible(bc.getBeanMethodVisibility())
 			&& (rt.isChildOf(Number.class) || (rt.isPrimitive() && rt.isAny(int.class, short.class, long.class, float.class, double.class, byte.class)))
 			&& mi.hasName(SWAP_METHOD_NAMES)
 			&& mi.hasFuzzyParamTypes(BeanSession.class)
@@ -159,6 +161,7 @@ public class AutoNumberSwap<T> extends PojoSwap<T,Number> {
 		return
 			mi.isNotDeprecated()
 			&& mi.isStatic()
+			&& mi.isVisible(bc.getBeanMethodVisibility())
 			&& mi.hasName(UNSWAP_METHOD_NAMES)
 			&& mi.hasFuzzyParamTypes(BeanSession.class, rt.inner())
 			&& mi.hasReturnTypeParent(ci)
@@ -168,6 +171,7 @@ public class AutoNumberSwap<T> extends PojoSwap<T,Number> {
 	private static boolean isUnswapConstructor(BeanContext bc, ConstructorInfo cs, ClassInfo rt) {
 		return
 			cs.isNotDeprecated()
+			&& cs.isVisible(bc.getBeanConstructorVisibility())
 			&& cs.hasMatchingParamTypes(rt)
 			&& ! bc.hasAnnotation(BeanIgnore.class, cs);
 	}
@@ -178,11 +182,11 @@ public class AutoNumberSwap<T> extends PojoSwap<T,Number> {
 	private final Constructor<?> unswapConstructor;
 	private final Class<?> unswapType;
 
-	private AutoNumberSwap(ClassInfo ci, MethodInfo swapMethod, MethodInfo unswapMethod, ConstructorInfo unswapConstructor) {
+	private AutoNumberSwap(BeanContext bc, ClassInfo ci, MethodInfo swapMethod, MethodInfo unswapMethod, ConstructorInfo unswapConstructor) {
 		super(ci.inner(), swapMethod.inner().getReturnType());
-		this.swapMethod = swapMethod.inner();
-		this.unswapMethod = unswapMethod == null ? null : unswapMethod.inner();
-		this.unswapConstructor = unswapConstructor == null ? null : unswapConstructor.inner();
+		this.swapMethod = bc.getBeanMethodVisibility().transform(swapMethod.inner());
+		this.unswapMethod = unswapMethod == null ? null : bc.getBeanMethodVisibility().transform(unswapMethod.inner());
+		this.unswapConstructor = unswapConstructor == null ? null : bc.getBeanConstructorVisibility().transform(unswapConstructor.inner());
 
 		Class<?> unswapType = null;
 		if (unswapMethod != null) {
@@ -209,6 +213,8 @@ public class AutoNumberSwap<T> extends PojoSwap<T,Number> {
 	@SuppressWarnings("unchecked")
 	@Override /* PojoSwap */
 	public T unswap(BeanSession session, Number o, ClassMeta<?> hint) throws ParseException {
+		if (unswapType == null)
+			throw new ParseException("No unparse methodology found for object.");
 		try {
 			Object o2 = ObjectUtils.toType(o, unswapType);
 			if (unswapMethod != null)
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoObjectSwap.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoObjectSwap.java
index 5330303..95b96b3 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoObjectSwap.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/AutoObjectSwap.java
@@ -95,20 +95,20 @@ public class AutoObjectSwap<T> extends PojoSwap<T,Object> {
 			return null;
 
 		// Find swap() method if present.
-		for (MethodInfo m : ci.getPublicMethods()) {
+		for (MethodInfo m : ci.getAllMethods()) {
 			if (isSwapMethod(bc, m)) {
 
 				ClassInfo rt = m.getReturnType();
 
-				for (MethodInfo m2 : ci.getPublicMethods())
+				for (MethodInfo m2 : ci.getAllMethods())
 					if (isUnswapMethod(bc, m2, ci, rt))
-						return new AutoObjectSwap(ci, m, m2, null);
+						return new AutoObjectSwap(bc, ci, m, m2, null);
 
-				for (ConstructorInfo cs : ci.getPublicConstructors())
+				for (ConstructorInfo cs : ci.getDeclaredConstructors())
 					if (isUnswapConstructor(bc, cs, rt))
-						return new AutoObjectSwap(ci, m, null, cs);
+						return new AutoObjectSwap(bc, ci, m, null, cs);
 
-				return new AutoObjectSwap(ci, m, null, null);
+				return new AutoObjectSwap(bc, ci, m, null, null);
 			}
 		}
 
@@ -125,6 +125,7 @@ public class AutoObjectSwap<T> extends PojoSwap<T,Object> {
 		return
 			mi.isNotDeprecated()
 			&& mi.isNotStatic()
+			&& mi.isVisible(bc.getBeanMethodVisibility())
 			&& mi.hasName(SWAP_METHOD_NAMES)
 			&& mi.hasFuzzyParamTypes(BeanSession.class)
 			&& ! bc.hasAnnotation(BeanIgnore.class, mi);
@@ -134,6 +135,7 @@ public class AutoObjectSwap<T> extends PojoSwap<T,Object> {
 		return
 			mi.isNotDeprecated()
 			&& mi.isStatic()
+			&& mi.isVisible(bc.getBeanMethodVisibility())
 			&& mi.hasName(UNSWAP_METHOD_NAMES)
 			&& mi.hasFuzzyParamTypes(BeanSession.class, rt.inner())
 			&& mi.hasReturnTypeParent(ci)
@@ -143,6 +145,7 @@ public class AutoObjectSwap<T> extends PojoSwap<T,Object> {
 	private static boolean isUnswapConstructor(BeanContext bc, ConstructorInfo cs, ClassInfo rt) {
 		return
 			cs.isNotDeprecated()
+			&& cs.isVisible(bc.getBeanConstructorVisibility())
 			&& cs.hasMatchingParamTypes(rt)
 			&& ! bc.hasAnnotation(BeanIgnore.class, cs);
 	}
@@ -152,11 +155,11 @@ public class AutoObjectSwap<T> extends PojoSwap<T,Object> {
 	private final Method swapMethod, unswapMethod;
 	private final Constructor<?> unswapConstructor;
 
-	private AutoObjectSwap(ClassInfo ci, MethodInfo swapMethod, MethodInfo unswapMethod, ConstructorInfo unswapConstructor) {
+	private AutoObjectSwap(BeanContext bc, ClassInfo ci, MethodInfo swapMethod, MethodInfo unswapMethod, ConstructorInfo unswapConstructor) {
 		super(ci.inner(), swapMethod.inner().getReturnType());
-		this.swapMethod = swapMethod.inner();
-		this.unswapMethod = unswapMethod == null ? null : unswapMethod.inner();
-		this.unswapConstructor = unswapConstructor == null ? null : unswapConstructor.inner();
+		this.swapMethod = bc.getBeanMethodVisibility().transform(swapMethod.inner());
+		this.unswapMethod = unswapMethod == null ? null : bc.getBeanMethodVisibility().transform(unswapMethod.inner());
+		this.unswapConstructor = unswapConstructor == null ? null : bc.getBeanConstructorVisibility().transform(unswapConstructor.inner());
 	}
 
 	@Override /* PojoSwap */
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/PojoSwap.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/PojoSwap.java
index 2d2d332..2f12167 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/PojoSwap.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/transform/PojoSwap.java
@@ -409,7 +409,6 @@ public abstract class PojoSwap<T,S> {
 		return swapClassInfo.isParentOf(o.getClass());
 	}
 
-
 	//-----------------------------------------------------------------------------------------------------------------
 	// Overridden methods
 	//-----------------------------------------------------------------------------------------------------------------
diff --git a/juneau-doc/docs/ReleaseNotes/8.1.4.html b/juneau-doc/docs/ReleaseNotes/8.1.4.html
index eddfcbb..24cd054 100644
--- a/juneau-doc/docs/ReleaseNotes/8.1.4.html
+++ b/juneau-doc/docs/ReleaseNotes/8.1.4.html
@@ -221,6 +221,8 @@
 		.build();
 		</p>
 	<li>
+		Fixes where the bean method/constructor visibility wasn't being used when finding swap methods and constructors.
+	<li>
 		HTML-Schema support is being deprecated due to low-use and difficulty in maintaining.  It will be removed in 9.0.
 	<li>
 		<c>JuneauLogger</c> class is being deprecated.  Improvements in logging in Java 8 make it obsolete.
diff --git a/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/RestClientTest.java b/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/RestClientTest.java
index f2713b3..cd95e95 100644
--- a/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/RestClientTest.java
+++ b/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/RestClientTest.java
@@ -2894,82 +2894,149 @@ public class RestClientTest {
 		assertEquals("BASE64", rc.parsers.getParser("octal/msgpack").toMap().getMap("InputStreamParser").getString("binaryFormat"));
 	}
 
-//	@Test
-//	public void m14_parser_paramFormat() throws Exception { fail(); }
-////	public RestClientBuilder paramFormat(String value) {
-//
-//	@Test
-//	public void m15_parser_paramFormatPlain() throws Exception { fail(); }
-////	public RestClientBuilder paramFormatPlain() {
-//
-//	//-----------------------------------------------------------------------------------------------------------------
-//	// Context properties
-//	//-----------------------------------------------------------------------------------------------------------------
-//
-//	@Test
-//	public void n01_context_addMap() throws Exception { fail(); }
-////	public RestClientBuilder add(Map<String,Object> properties) {
-//
-//	@Test
-//	public void n02_context_addToStringObject() throws Exception { fail(); }
-////	public RestClientBuilder addTo(String name, Object value) {
-//
-//	@Test
-//	public void n03_context_appendToStringObject() throws Exception { fail(); }
-////	public RestClientBuilder appendTo(String name, Object value) {
-//
-//	@Test
-//	public void n04_context_prependToStringObject() throws Exception { fail(); }
-////	public RestClientBuilder prependTo(String name, Object value) {
-//
-//	@Test
-//	public void n05_context_addToStringStringObject() throws Exception { fail(); }
-////	public RestClientBuilder addTo(String name, String key, Object value) {
-//
-//	@Test
-//	public void n06_context_apply() throws Exception { fail(); }
-////	public RestClientBuilder apply(PropertyStore copyFrom) {
-//
-//	@Test
-//	public void n07_context_applyAnnotationsClasses() throws Exception { fail(); }
-////	public RestClientBuilder applyAnnotations(java.lang.Class<?>...fromClasses) {
-//
-//	@Test
-//	public void n08_context_applyAnnotationsMethods() throws Exception { fail(); }
-////	public RestClientBuilder applyAnnotations(Method...fromMethods) {
-//
-//	@Test
-//	public void n09_context_applyAnnotationsAnnotationList() throws Exception { fail(); }
-////	public RestClientBuilder applyAnnotations(AnnotationList al, VarResolverSession r) {
-//
-//	@Test
-//	public void n10_context_removeFrom() throws Exception { fail(); }
-////	public RestClientBuilder removeFrom(String name, Object value) {
-//
-//	@Test
-//	public void n11_context_setMap() throws Exception { fail(); }
-////	public RestClientBuilder set(Map<String,Object> properties) {
-//
-//	@Test
-//	public void n12_context_setStringObject() throws Exception { fail(); }
-////	public RestClientBuilder set(String name, Object value) {
-//
-//	@Test
-//	public void n13_context_annotations() throws Exception { fail(); }
-////	public RestClientBuilder annotations(Annotation...values) {
-//
-//	//-----------------------------------------------------------------------------------------------------------------
-//	// BeanContext properties
-//	//-----------------------------------------------------------------------------------------------------------------
-//
-//	@Test
-//	public void o001_beanContext_beanClassVisibility() throws Exception { fail(); }
-////	public RestClientBuilder beanClassVisibility(Visibility value) {
-//
-//	@Test
-//	public void o002_beanContext_beanConstructorVisibility() throws Exception { fail(); }
-////	public RestClientBuilder beanConstructorVisibility(Visibility value) {
-//
+	//-----------------------------------------------------------------------------------------------------------------
+	// OpenApi properties
+	//-----------------------------------------------------------------------------------------------------------------
+
+	@Test
+	public void n01_openApi_oapiFormat() throws Exception {
+		MockRestClient
+			.create(A.class)
+			.oapiFormat(HttpPartFormat.UON)
+			.build()
+			.get("/checkQuery")
+			.query("Foo", "bar baz")
+			.run()
+			.getBody().assertValue("Foo=%27bar+baz%27");
+	}
+
+	@Test
+	public void n02_openApi_oapiCollectionFormat() throws Exception {
+		RestClient rc = MockRestClient
+			.create(A.class)
+			.oapiCollectionFormat(HttpPartCollectionFormat.PIPES)
+			.build();
+
+		rc.get("/checkQuery")
+			.query("Foo", new String[]{"bar","baz"})
+			.run()
+			.getBody().assertValue("Foo=bar%7Cbaz");
+
+		rc.post("/checkFormData")
+			.formData("Foo", new String[]{"bar","baz"})
+			.run()
+			.getBody().assertValue("Foo=bar%7Cbaz");
+
+		rc.get("/checkHeader")
+			.header("Check", "Foo")
+			.header("Foo", new String[]{"bar","baz"})
+			.accept("text/json+simple")
+			.run()
+			.getBody().assertValue("['bar|baz']");
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// BeanContext properties
+	//-----------------------------------------------------------------------------------------------------------------
+
+	protected static class O001 {
+		public int f = 1;
+
+		@Override
+		public String toString() {
+			return "O001";
+		}
+	}
+
+	@Test
+	public void o001_beanContext_beanClassVisibility() throws Exception {
+		RestClient rc1 = MockRestClient
+			.create(A.class)
+			.simpleJson()
+			.build();
+
+		RestClient rc2 = MockRestClient
+			.create(A.class)
+			.beanClassVisibility(Visibility.PROTECTED)
+			.simpleJson()
+			.build();
+
+		rc1.post("/echoBody", new O001())
+			.run()
+			.getBody().assertValue("'O001'");
+		rc2.post("/echoBody", new O001())
+			.run()
+			.getBody().assertValue("{f:1}");
+
+		rc1.get("/checkQuery")
+			.query("foo", new O001())
+			.run()
+			.getBody().assertValue("foo=O001");
+		rc2.get("/checkQuery")
+			.query("foo", new O001())
+			.run()
+			.getBody().assertValue("foo=f%3D1");
+
+		rc1.formPost("/checkFormData")
+			.formData("foo", new O001())
+			.run()
+			.getBody().assertValue("foo=O001");
+		rc2.formPost("/checkFormData")
+			.formData("foo", new O001())
+			.run()
+			.getBody().assertValue("foo=f%3D1");
+
+		rc1.get("/checkHeader")
+			.header("foo", new O001())
+			.header("Check", "foo")
+			.run()
+			.getBody().assertValue("['O001']");
+		rc2.get("/checkHeader")
+			.header("foo", new O001())
+			.header("Check", "foo")
+			.run()
+			.getBody().assertValue("['f=1']");
+	}
+
+	public static class O002 {
+		private int f;
+
+		protected O002(int f) {
+			this.f = f;
+		}
+
+		public int toInt() {
+			return f;
+		}
+	}
+
+	@Test
+	public void o002_beanContext_beanConstructorVisibility() throws Exception {
+		RestClient rc1 = MockRestClient
+			.create(A.class)
+			.simpleJson()
+			.build();
+
+		RestClient rc2 = MockRestClient
+			.create(A.class)
+			.beanConstructorVisibility(Visibility.PROTECTED)
+			.simpleJson()
+			.build();
+
+		try {
+			rc1.post("/echoBody", new O002(1))
+				.run()
+				.getBody().as(O002.class);
+				fail("Exception expected.");
+		} catch (RestCallException e) {
+			assertEquals("No unparse methodology found for object.", e.getMessage());
+		}
+
+		assertEquals(1, rc2.post("/echoBody", new O002(1))
+			.run()
+			.getBody().as(O002.class).f);
+	}
+
 //	@Test
 //	public void o003_beanContext_beanDictionaryClasses() throws Exception { fail(); }
 ////	public RestClientBuilder beanDictionary(java.lang.Class<?>...values) {
@@ -3369,4 +3436,62 @@ public class RestClientTest {
 //	@Test
 //	public void o102_beanContext_useJavaBeanIntrospectorBoolean() throws Exception { fail(); }
 ////	public RestClientBuilder useJavaBeanIntrospector(boolean value) {
+
+
+	//	//-----------------------------------------------------------------------------------------------------------------
+//	// Context properties
+//	//-----------------------------------------------------------------------------------------------------------------
+//
+//	@Test
+//	public void p01_context_addMap() throws Exception { fail(); }
+////	public RestClientBuilder add(Map<String,Object> properties) {
+//
+//	@Test
+//	public void p02_context_addToStringObject() throws Exception { fail(); }
+////	public RestClientBuilder addTo(String name, Object value) {
+//
+//	@Test
+//	public void p03_context_appendToStringObject() throws Exception { fail(); }
+////	public RestClientBuilder appendTo(String name, Object value) {
+//
+//	@Test
+//	public void p04_context_prependToStringObject() throws Exception { fail(); }
+////	public RestClientBuilder prependTo(String name, Object value) {
+//
+//	@Test
+//	public void p05_context_addToStringStringObject() throws Exception { fail(); }
+////	public RestClientBuilder addTo(String name, String key, Object value) {
+//
+//	@Test
+//	public void p06_context_apply() throws Exception { fail(); }
+////	public RestClientBuilder apply(PropertyStore copyFrom) {
+//
+//	@Test
+//	public void p07_context_applyAnnotationsClasses() throws Exception { fail(); }
+////	public RestClientBuilder applyAnnotations(java.lang.Class<?>...fromClasses) {
+//
+//	@Test
+//	public void p08_context_applyAnnotationsMethods() throws Exception { fail(); }
+////	public RestClientBuilder applyAnnotations(Method...fromMethods) {
+//
+//	@Test
+//	public void p09_context_applyAnnotationsAnnotationList() throws Exception { fail(); }
+////	public RestClientBuilder applyAnnotations(AnnotationList al, VarResolverSession r) {
+//
+//	@Test
+//	public void p10_context_removeFrom() throws Exception { fail(); }
+////	public RestClientBuilder removeFrom(String name, Object value) {
+//
+//	@Test
+//	public void p11_context_setMap() throws Exception { fail(); }
+////	public RestClientBuilder set(Map<String,Object> properties) {
+//
+//	@Test
+//	public void p12_context_setStringObject() throws Exception { fail(); }
+////	public RestClientBuilder set(String name, Object value) {
+//
+//	@Test
+//	public void p13_context_annotations() throws Exception { fail(); }
+////	public RestClientBuilder annotations(Annotation...values) {
+//
 }
diff --git a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestCallException.java b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestCallException.java
index 9cf4722..d94fc0a 100644
--- a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestCallException.java
+++ b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestCallException.java
@@ -259,7 +259,7 @@ public final class RestCallException extends HttpException {
 	private static String clean(String message) {
 
 		if (message == null)
-			return null;
+			return "";
 
 		boolean needsCleaning = false;
 		for (int i = 0; i < message.length() && !needsCleaning; i++)
diff --git a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestClientBuilder.java b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestClientBuilder.java
index 612f351..e0aabb9 100644
--- a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestClientBuilder.java
+++ b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestClientBuilder.java
@@ -20,6 +20,7 @@ import static org.apache.juneau.httppart.HttpPartType.*;
 import static org.apache.juneau.internal.StringUtils.*;
 import static org.apache.juneau.serializer.OutputStreamSerializer.*;
 import static org.apache.juneau.serializer.WriterSerializer.*;
+import static org.apache.juneau.oapi.OpenApiCommon.*;
 import static org.apache.juneau.uon.UonSerializer.*;
 
 import java.lang.annotation.*;
@@ -2802,7 +2803,50 @@ public class RestClientBuilder extends BeanContextBuilder {
 	}
 
 	/**
+	 * Configuration property:  Default OpenAPI format for HTTP parts.
+	 *
+	 * <p>
+	 * Specifies the format to use for HTTP parts when not otherwise specified via {@link org.apache.juneau.jsonschema.annotation.Schema#format()}.
+	 *
+	 * <ul class='seealso'>
+	 * 	<li class='jf'>{@link OpenApiCommon#OAPI_format}
+	 * </ul>
+	 *
+	 * @param value
+	 * 	The new value for this property.
+	 * 	<br>The default value is {@link HttpPartFormat#NO_FORMAT}.
+	 * @return This object (for method chaining).
+	 */
+	@ConfigurationProperty
+	public RestClientBuilder oapiFormat(HttpPartFormat value) {
+		return set(OAPI_format, value);
+	}
+
+	/**
+	 * Configuration property:  Default collection format for HTTP parts.
+	 *
+	 * <p>
+	 * Specifies the collection format to use for HTTP parts when not otherwise specified via {@link org.apache.juneau.jsonschema.annotation.Schema#collectionFormat()}.
+	 *
+	 * <ul class='seealso'>
+	 * 	<li class='jf'>{@link OpenApiCommon#OAPI_collectionFormat}
+	 * </ul>
+	 *
+	 * @param value
+	 * 	The new value for this property.
+	 * 	<br>The default value is {@link HttpPartCollectionFormat#NO_COLLECTION_FORMAT}.
+	 * @return This object (for method chaining).
+	 */
+	@ConfigurationProperty
+	public RestClientBuilder oapiCollectionFormat(HttpPartCollectionFormat value) {
+		return set(OAPI_collectionFormat, value);
+	}
+
+	/**
 	 * Configuration property:  Parameter format.
+	 * 
+	 * <p>
+	 * Specifies the format of parameters when using the {@link UrlEncodingSerializer} to serialize Form Posts.
 	 *
 	 * <ul class='seealso'>
 	 * 	<li class='jf'>{@link UonSerializer#UON_paramFormat}
@@ -2818,6 +2862,9 @@ public class RestClientBuilder extends BeanContextBuilder {
 
 	/**
 	 * Configuration property:  Parameter format.
+	 * 
+	 * <p>
+	 * Specifies the format of parameters when using the {@link UrlEncodingSerializer} to serialize Form Posts.
 	 *
 	 * <ul class='seealso'>
 	 * 	<li class='jf'>{@link UonSerializer#UON_paramFormat}
diff --git a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestResponseBody.java b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestResponseBody.java
index 723b662..cec732f 100644
--- a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestResponseBody.java
+++ b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestResponseBody.java
@@ -1591,8 +1591,17 @@ public class RestResponseBody implements HttpEntity {
 	public RestResponse assertContains(String...values) throws RestCallException, AssertionError {
 		String text = asString();
 		for (String substring : values)
-			if (! StringUtils.contains(text, substring))
+			if (! StringUtils.contains(text, substring)) {
+				if (substring.startsWith("x")) {
+					StringBuilder sb = new StringBuilder();
+					sb.append("Response did not have the expected substring for body.");
+					sb.append("\nExpected: [").append(substring.replaceAll("\\\\", "\\\\\\\\").replaceAll("\n", "\\\\n").replaceAll("\t", "\\\\t")).append("]");
+					sb.append("\nActual  : [").append(text.replaceAll("\\\\", "\\\\\\\\").replaceAll("\n", "\\\\n").replaceAll("\t", "\\\\t")).append("]");
+					System.err.println(sb);
+				}
 				throw new BasicAssertionError("Response did not have the expected substring for body.\n\tExpected=[{0}]\n\tBody=[{1}]", substring, text);
+
+			}
 		return response;
 	}
 
diff --git a/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock2/MockRestClient.java b/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock2/MockRestClient.java
index ba13a6e..e7ba129 100644
--- a/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock2/MockRestClient.java
+++ b/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock2/MockRestClient.java
@@ -1210,18 +1210,6 @@ public class MockRestClient extends RestClientBuilder {
 	}
 
 	@Override /* GENERATED - RestClientBuilder */
-	public MockRestClient parserListener(Class<? extends org.apache.juneau.parser.ParserListener> value) {
-		super.parserListener(value);
-		return this;
-	}
-
-	@Override /* GENERATED - RestClientBuilder */
-	public MockRestClient serializerListener(Class<? extends org.apache.juneau.serializer.SerializerListener> value) {
-		super.serializerListener(value);
-		return this;
-	}
-
-	@Override /* GENERATED - RestClientBuilder */
 	public MockRestClient logTo(Level level, Logger log) {
 		super.logTo(level, log);
 		return this;
@@ -1276,6 +1264,18 @@ public class MockRestClient extends RestClientBuilder {
 	}
 
 	@Override /* GENERATED - RestClientBuilder */
+	public MockRestClient oapiCollectionFormat(HttpPartCollectionFormat value) {
+		super.oapiCollectionFormat(value);
+		return this;
+	}
+
+	@Override /* GENERATED - RestClientBuilder */
+	public MockRestClient oapiFormat(HttpPartFormat value) {
+		super.oapiFormat(value);
+		return this;
+	}
+
+	@Override /* GENERATED - RestClientBuilder */
 	public MockRestClient openApi() {
 		super.openApi();
 		return this;
@@ -1312,6 +1312,12 @@ public class MockRestClient extends RestClientBuilder {
 	}
 
 	@Override /* GENERATED - RestClientBuilder */
+	public MockRestClient parserListener(Class<? extends org.apache.juneau.parser.ParserListener> value) {
+		super.parserListener(value);
+		return this;
+	}
+
+	@Override /* GENERATED - RestClientBuilder */
 	@SuppressWarnings("unchecked")
 	public MockRestClient parsers(java.lang.Class<? extends org.apache.juneau.parser.Parser>...value) {
 		super.parsers(value);
@@ -1433,6 +1439,12 @@ public class MockRestClient extends RestClientBuilder {
 	}
 
 	@Override /* GENERATED - RestClientBuilder */
+	public MockRestClient serializerListener(Class<? extends org.apache.juneau.serializer.SerializerListener> value) {
+		super.serializerListener(value);
+		return this;
+	}
+
+	@Override /* GENERATED - RestClientBuilder */
 	@SuppressWarnings("unchecked")
 	public MockRestClient serializers(java.lang.Class<? extends org.apache.juneau.serializer.Serializer>...value) {
 		super.serializers(value);