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/23 14:44:49 UTC

[juneau] branch master updated: JUNEAU-232

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 c44d2fb  JUNEAU-232
c44d2fb is described below

commit c44d2fb36d77d8ee76ed11fd45b2d72ae0b99e67
Author: JamesBognar <ja...@salesforce.com>
AuthorDate: Sat May 23 10:44:32 2020 -0400

    JUNEAU-232
    
    BEAN_isIgnoreUnknownNullBeanProperties doesn't always work correctly.
---
 .../org/apache/juneau/jena/RdfParserSession.java   |   4 +-
 .../main/java/org/apache/juneau/BeanContext.java   |   3 +-
 .../java/org/apache/juneau/BeanContextBuilder.java |   3 +-
 .../org/apache/juneau/html/HtmlParserSession.java  |   3 +-
 .../org/apache/juneau/json/JsonParserSession.java  |   3 +-
 .../juneau/msgpack/MsgPackParserSession.java       |   2 +-
 .../org/apache/juneau/parser/ParserSession.java    |  10 +-
 .../org/apache/juneau/uon/UonParserSession.java    |   5 +-
 .../urlencoding/UrlEncodingParserSession.java      |   5 +-
 .../org/apache/juneau/xml/XmlParserSession.java    |  17 +-
 .../juneau/rest/test/client/RestClientTest.java    |  50 ++++-
 .../apache/juneau/rest/client2/RestClientTest.java | 249 +++++++++++++++------
 .../org/apache/juneau/rest/client2/RestClient.java |   2 +-
 .../apache/juneau/rest/client2/RestRequest.java    |   2 +-
 .../apache/juneau/rest/client2/RestResponse.java   |  15 ++
 .../juneau/rest/client2/RestResponseBody.java      |  58 ++---
 16 files changed, 290 insertions(+), 141 deletions(-)

diff --git a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfParserSession.java b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfParserSession.java
index 65c58fb..b71c6b5 100644
--- a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfParserSession.java
+++ b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfParserSession.java
@@ -202,7 +202,9 @@ public class RdfParserSession extends ReaderParserSession {
 					}
 				}
 			} else if (! (p.equals(pRoot) || p.equals(pType))) {
-				onUnknownProperty(key, m);
+				RDFNode o = st.getObject();
+				Object value = parseAnything(object(), o, m.getBean(false), null);
+				onUnknownProperty(key, m, value);
 			}
 			setCurrentProperty(null);
 		}
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 5375f66..15db6b3 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
@@ -1567,8 +1567,7 @@ public class BeanContext extends Context implements MetaProvider {
 	 * <h5 class='section'>Description:</h5>
 	 *
 	 * <p>
-	 * When enabled, methods and fields marked as <jk>transient</jk> or annotated with {@link java.beans.Transient}
-	 * will be ignored as bean properties.
+	 * When enabled, methods and fields marked as <jk>transient</jk> will be ignored as bean properties.
 	 *
 	 * <h5 class='section'>Example:</h5>
 	 * <p class='bcode w800'>
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContextBuilder.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContextBuilder.java
index f33cd5e..51d946f 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContextBuilder.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContextBuilder.java
@@ -2292,8 +2292,7 @@ public class BeanContextBuilder extends ContextBuilder {
 	 * <i><l>BeanContext</l> configuration property:</i>  Ignore transient fields.
 	 *
 	 * <p>
-	 * When enabled, methods and fields marked as <jk>transient</jk> or annotated with {@link java.beans.Transient}
-	 * will be ignored as bean properties.
+	 * When enabled, methods and fields marked as <jk>transient</jk> will be ignored as bean properties.
 	 *
 	 * <h5 class='section'>Example:</h5>
 	 * <p class='bcode w800'>
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlParserSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlParserSession.java
index b549fc4..bdd0e7f 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlParserSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlParserSession.java
@@ -515,8 +515,7 @@ public final class HtmlParserSession extends XmlParserSession {
 				nextTag(r, TD);
 				BeanPropertyMeta pMeta = m.getPropertyMeta(key);
 				if (pMeta == null) {
-					onUnknownProperty(key, m);
-					parseAnything(object(), r, null, false, null);
+					onUnknownProperty(key, m, parseAnything(object(), r, null, false, null));
 				} else {
 					ClassMeta<?> cm = pMeta.getClassMeta();
 					Object value = parseAnything(cm, r, m.getBean(false), false, pMeta);
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonParserSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonParserSession.java
index 3b056b2..d4d85d9 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonParserSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonParserSession.java
@@ -513,9 +513,8 @@ public final class JsonParserSession extends ReaderParserSession {
 							BeanPropertyMeta pMeta = m.getPropertyMeta(currAttr);
 							setCurrentProperty(pMeta);
 							if (pMeta == null) {
-								onUnknownProperty(currAttr, m);
+								onUnknownProperty(currAttr, m, parseAnything(object(), r.unread(), m.getBean(false), null));
 								unmark();
-								parseAnything(object(), r.unread(), m.getBean(false), null); // Read content anyway to ignore it
 							} else {
 								unmark();
 								ClassMeta<?> cm = pMeta.getClassMeta();
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/msgpack/MsgPackParserSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/msgpack/MsgPackParserSession.java
index 7ae1e7c..c9c619b 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/msgpack/MsgPackParserSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/msgpack/MsgPackParserSession.java
@@ -133,7 +133,7 @@ public final class MsgPackParserSession extends InputStreamParserSession {
 							if (pName.equals(getBeanTypePropertyName(eType)))
 								parseAnything(string(), is, null, null);
 							else
-								onUnknownProperty(pName, m);
+								onUnknownProperty(pName, m, parseAnything(string(), is, null, null));
 						} else {
 							ClassMeta<?> cm = bpm.getClassMeta();
 							Object value = parseAnything(cm, is, m.getBean(false), bpm);
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserSession.java
index b2f588e..9e64b19 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserSession.java
@@ -316,18 +316,20 @@ public abstract class ParserSession extends BeanSession {
 	 *
 	 * @param propertyName The unknown bean property name.
 	 * @param beanMap The bean that doesn't have the expected property.
+	 * @param value The parsed value.
 	 * @throws ParseException
 	 * 	Automatically thrown if {@link BeanContext#BEAN_ignoreUnknownBeanProperties} setting on this parser is
 	 * 	<jk>false</jk>
 	 * @param <T> The class type of the bean map that doesn't have the expected property.
 	 */
-	protected final <T> void onUnknownProperty(String propertyName, BeanMap<T> beanMap) throws ParseException {
+	protected final <T> void onUnknownProperty(String propertyName, BeanMap<T> beanMap, Object value) throws ParseException {
 		if (propertyName.equals(getBeanTypePropertyName(beanMap.getClassMeta())))
 			return;
 		if (! isIgnoreUnknownBeanProperties())
-			throw new ParseException(this,
-				"Unknown property ''{0}'' encountered while trying to parse into class ''{1}''", propertyName,
-				beanMap.getClassMeta());
+			if (value != null || ! isIgnoreUnknownNullBeanProperties())
+				throw new ParseException(this,
+					"Unknown property ''{0}'' encountered while trying to parse into class ''{1}''", propertyName,
+					beanMap.getClassMeta());
 		if (listener != null)
 			listener.onUnknownBeanProperty(this, propertyName, beanMap.getClassMeta().getInnerClass(), beanMap.getBean());
 	}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/uon/UonParserSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/uon/UonParserSession.java
index dbfc4de..f432e31 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/uon/UonParserSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/uon/UonParserSession.java
@@ -539,7 +539,7 @@ public class UonParserSession extends ReaderParserSession implements HttpPartPar
 							if (! currAttr.equals(getBeanTypePropertyName(m.getClassMeta()))) {
 								BeanPropertyMeta pMeta = m.getPropertyMeta(currAttr);
 								if (pMeta == null) {
-									onUnknownProperty(currAttr, m);
+									onUnknownProperty(currAttr, m, null);
 									unmark();
 								} else {
 									unmark();
@@ -559,9 +559,8 @@ public class UonParserSession extends ReaderParserSession implements HttpPartPar
 							if (! currAttr.equals(getBeanTypePropertyName(m.getClassMeta()))) {
 								BeanPropertyMeta pMeta = m.getPropertyMeta(currAttr);
 								if (pMeta == null) {
-									onUnknownProperty(currAttr, m);
+									onUnknownProperty(currAttr, m, parseAnything(object(), r.unread(), m.getBean(false), false, null));
 									unmark();
-									parseAnything(object(), r.unread(), m.getBean(false), false, null); // Read content anyway to ignore it
 								} else {
 									unmark();
 									setCurrentProperty(pMeta);
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/urlencoding/UrlEncodingParserSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/urlencoding/UrlEncodingParserSession.java
index eb3b487..72ed9c9 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/urlencoding/UrlEncodingParserSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/urlencoding/UrlEncodingParserSession.java
@@ -289,7 +289,7 @@ public class UrlEncodingParserSession extends UonParserSession {
 							if (! currAttr.equals(getBeanTypePropertyName(m.getClassMeta()))) {
 								BeanPropertyMeta pMeta = m.getPropertyMeta(currAttr);
 								if (pMeta == null) {
-									onUnknownProperty(currAttr, m);
+									onUnknownProperty(currAttr, m, null);
 									unmark();
 								} else {
 									unmark();
@@ -315,9 +315,8 @@ public class UrlEncodingParserSession extends UonParserSession {
 							if (! currAttr.equals(getBeanTypePropertyName(m.getClassMeta()))) {
 								BeanPropertyMeta pMeta = m.getPropertyMeta(currAttr);
 								if (pMeta == null) {
-									onUnknownProperty(currAttr, m);
+									onUnknownProperty(currAttr, m, parseAnything(object(), r.unread(), m.getBean(false), true, null));
 									unmark();
-									parseAnything(object(), r.unread(), m.getBean(false), true, null); // Read content anyway to ignore it
 								} else {
 									unmark();
 									setCurrentProperty(pMeta);
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlParserSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlParserSession.java
index c4fce6b..3a623c1 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlParserSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlParserSession.java
@@ -495,7 +495,7 @@ public class XmlParserSession extends ReaderParserSession {
 					if (xmlMeta.getAttrsProperty() != null) {
 						xmlMeta.getAttrsProperty().add(m, key, key, val);
 					} else if (ns == null) {
-						onUnknownProperty(key, m);
+						onUnknownProperty(key, m, val);
 					}
 				} else {
 					try {
@@ -581,8 +581,8 @@ public class XmlParserSession extends ReaderParserSession {
 						currAttr = getElementName(r);
 					BeanPropertyMeta pMeta = xmlMeta.getPropertyMeta(currAttr);
 					if (pMeta == null) {
-						onUnknownProperty(currAttr, m);
-						skipCurrentTag(r);
+						Object value = parseAnything(object(), currAttr, r, m.getBean(false), false, null);
+						onUnknownProperty(currAttr, m, value);
 					} else {
 						setCurrentProperty(pMeta);
 						XmlFormat xf = getXmlBeanPropertyMeta(pMeta).getXmlFormat();
@@ -637,17 +637,6 @@ public class XmlParserSession extends ReaderParserSession {
 		return m;
 	}
 
-	private static void skipCurrentTag(XmlReader r) throws XMLStreamException {
-		int depth = 1;
-		do {
-			int event = r.next();
-			if (event == START_ELEMENT)
-				depth++;
-			else if (event == END_ELEMENT)
-				depth--;
-		} while (depth > 0);
-	}
-
 	private boolean isSpecialAttr(String key) {
 		return key.equals(getBeanTypePropertyName(null)) || key.equals(getNamePropertyName());
 	}
diff --git a/juneau-microservice/juneau-microservice-ftest/src/test/java/org/apache/juneau/rest/test/client/RestClientTest.java b/juneau-microservice/juneau-microservice-ftest/src/test/java/org/apache/juneau/rest/test/client/RestClientTest.java
index 17779fe..1e8cdbe 100644
--- a/juneau-microservice/juneau-microservice-ftest/src/test/java/org/apache/juneau/rest/test/client/RestClientTest.java
+++ b/juneau-microservice/juneau-microservice-ftest/src/test/java/org/apache/juneau/rest/test/client/RestClientTest.java
@@ -36,12 +36,20 @@ public class RestClientTest extends RestTestcase {
 
 		Mutable<Integer> rc = new Mutable<>();
 		Mutable<String> r = new Mutable<>();
-		c.post(URL, new StringEntity("xxxSUCCESSxxx")).run().getStatusCode(rc).getBody().cache().assertContains("SUCCESS").getBody().asString(r);
+		c.post(URL, new StringEntity("xxxSUCCESSxxx"))
+			.run()
+			.getStatusCode(rc)
+			.cacheBody()
+			.getBody().assertContains("SUCCESS")
+			.getBody().asString(r);
 		assertEquals("xxxSUCCESSxxx", r.get());
 		assertEquals(200, rc.get().intValue());
 
 		try {
-			c.post(URL, new StringEntity("xxxFAILURExxx")).run().getBody().assertContains("SUCCESS");
+			c.post(URL, new StringEntity("xxxFAILURExxx"))
+				.run()
+				.getBody()
+				.assertContains("SUCCESS");
 			fail();
 		} catch (AssertionError e) {
 			assertTrue(e.getLocalizedMessage().contains("Response did not have the expected substring for body."));
@@ -57,12 +65,20 @@ public class RestClientTest extends RestTestcase {
 
 		Mutable<Integer> rc = new Mutable<>();
 		Mutable<String> r = new Mutable<>();
-		c.post(URL, new StringEntity("xxxSUCCESSxxx")).run().getStatusCode(rc).getBody().cache().assertValue(x -> ! x.contains("FAILURE")).getBody().asString(r);
+		c.post(URL, new StringEntity("xxxSUCCESSxxx"))
+			.run()
+			.getStatusCode(rc)
+			.cacheBody()
+			.getBody().assertValue(x -> ! x.contains("FAILURE"))
+			.getBody().asString(r);
 		assertEquals("xxxSUCCESSxxx", r.get());
 		assertEquals(200, rc.get().intValue());
 
 		try {
-			c.post(URL, new StringEntity("xxxFAILURExxx")).run().getBody().assertValue(x -> ! x.contains("FAILURE"));
+			c.post(URL, new StringEntity("xxxFAILURExxx"))
+				.run()
+				.getBody()
+				.assertValue(x -> ! x.contains("FAILURE"));
 			fail();
 		} catch (AssertionError e) {
 			assertTrue(e.getLocalizedMessage().contains("Response did not have the expected value for body."));
@@ -75,7 +91,11 @@ public class RestClientTest extends RestTestcase {
 	@Test
 	public void testCaptureResponse() throws Exception {
 		RestClient c = TestMicroservice.DEFAULT_CLIENT;
-		RestResponse r = c.post(URL, new StringEntity("xxx")).run().getBody().cache().toResponse();
+		RestResponse r = c
+			.post(URL, new StringEntity("xxx"))
+			.run()
+			.cacheBody()
+			.getBody().toResponse();
 
 		assertEquals("xxx", r.getBody().asString());
 		assertEquals("xxx", r.getBody().asString());
@@ -87,7 +107,7 @@ public class RestClientTest extends RestTestcase {
 			r.getBody().asString();
 			fail();
 		} catch (IllegalStateException e) {
-			assertEquals("Method cannot be called.  Response has already been consumed.", e.getLocalizedMessage());
+			assertEquals("Method cannot be called.  Response has already been consumed.  Consider using the RestResponse.cacheBody() method.", e.getLocalizedMessage());
 		}
 	}
 
@@ -100,12 +120,20 @@ public class RestClientTest extends RestTestcase {
 		String r;
 
 		Mutable<Matcher> m = Mutable.create();
-		r = c.post(URL, new StringEntity("x=1,y=2")).run().getBody().cache().asMatcher(m, "x=(\\d+),y=(\\S+)").getBody().asString();
+		r = c.post(URL, new StringEntity("x=1,y=2"))
+			.run()
+			.cacheBody()
+			.getBody().asMatcher(m, "x=(\\d+),y=(\\S+)")
+			.getBody().asString();
 		assertEquals("x=1,y=2", r);
 		assertTrue(m.get().matches());
 		assertObjectEquals("['x=1,y=2','1','2']", m.get().toMatchResult());
 
-		r = c.post(URL, new StringEntity("x=1,y=2\nx=3,y=4")).run().getBody().cache().asMatcher(m, "x=(\\d+),y=(\\S+)").getBody().asString();
+		r = c.post(URL, new StringEntity("x=1,y=2\nx=3,y=4"))
+			.run()
+			.cacheBody()
+			.getBody().asMatcher(m, "x=(\\d+),y=(\\S+)")
+			.getBody().asString();
 		assertEquals("x=1,y=2\nx=3,y=4", r);
 		assertTrue(m.get().find());
 		assertObjectEquals("['x=1,y=2','1','2']", m.get().toMatchResult());
@@ -116,7 +144,11 @@ public class RestClientTest extends RestTestcase {
 		assertFalse(m.get().find());
 
 		Mutable<Matcher> m2 = Mutable.create();
-		c.post(URL, new StringEntity("x=1,y=2")).run().getBody().cache().asMatcher(m, "x=(\\d+),y=(\\S+)").getBody().asMatcher(m2, "x=(\\d+),y=(\\S+)");
+		c.post(URL, new StringEntity("x=1,y=2"))
+			.run()
+			.cacheBody()
+			.getBody().asMatcher(m, "x=(\\d+),y=(\\S+)")
+			.getBody().asMatcher(m2, "x=(\\d+),y=(\\S+)");
 		assertTrue(m.get().matches());
 		assertTrue(m2.get().matches());
 		assertObjectEquals("['x=1,y=2','1','2']", m.get().toMatchResult());
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 b724e11..1f15acb 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
@@ -30,6 +30,7 @@ import org.apache.http.client.methods.*;
 import org.apache.http.impl.client.*;
 import org.apache.http.protocol.*;
 import org.apache.juneau.*;
+import org.apache.juneau.Visibility;
 import org.apache.juneau.annotation.*;
 import org.apache.juneau.collections.*;
 import org.apache.juneau.http.*;
@@ -1834,8 +1835,8 @@ public class RestClientTest {
 		Bean b = rc
 			.post("/echoBody", bean)
 			.run()
-			.getBody().cache()
-			.assertValue("<object><f>1</f></object>")
+			.cacheBody()
+			.getBody().assertValue("<object><f>1</f></object>")
 			.getBody().as(Bean.class);
 
 		assertEqualObjects(b, bean);
@@ -1851,15 +1852,15 @@ public class RestClientTest {
 		rc
 			.post("/echoBody", bean)
 			.run()
-			.getBody().cache().assertValue("{f:1}");
+			.getBody().assertValue("{f:1}");
 
 		Bean b = rc
 			.post("/echoBody", bean)
 			.accept("text/xml")
 			.contentType("text/xml")
 			.run()
-			.getBody().cache()
-			.assertValue("<object><f>1</f></object>")
+			.cacheBody()
+			.getBody().assertValue("<object><f>1</f></object>")
 			.getBody().as(Bean.class);
 		assertEqualObjects(b, bean);
 
@@ -1868,7 +1869,8 @@ public class RestClientTest {
 			.accept("text/json")
 			.contentType("text/json")
 			.run()
-			.getBody().cache().assertValue("{\"f\":1}")
+			.cacheBody()
+			.getBody().assertValue("{\"f\":1}")
 			.getBody().as(Bean.class);
 		assertEqualObjects(b, bean);
 	}
@@ -1884,7 +1886,8 @@ public class RestClientTest {
 		Bean b = rc
 			.post("/echoBody", bean)
 			.run()
-			.getBody().cache().assertValue("<object><f>1</f></object>")
+			.cacheBody()
+			.getBody().assertValue("<object><f>1</f></object>")
 			.getBody().as(Bean.class);
 
 		assertEqualObjects(b, bean);
@@ -1901,7 +1904,8 @@ public class RestClientTest {
 		Bean b = rc
 			.post("/echoBody", bean)
 			.run()
-			.getBody().cache().assertValue("<object><f>1</f></object>")
+			.cacheBody()
+			.getBody().assertValue("<object><f>1</f></object>")
 			.getBody().as(Bean.class);
 
 		assertEqualObjects(b, bean);
@@ -1919,14 +1923,15 @@ public class RestClientTest {
 		rc
 			.post("/echoBody", bean)
 			.run()
-			.getBody().cache().assertValue("{f:1}");
+			.getBody().assertValue("{f:1}");
 
 		Bean b = rc
 			.post("/echoBody", bean)
 			.accept("text/xml")
 			.contentType("text/xml")
 			.run()
-			.getBody().cache().assertValue("<object><f>1</f></object>")
+			.cacheBody()
+			.getBody().assertValue("<object><f>1</f></object>")
 			.getBody().as(Bean.class);
 		assertEqualObjects(b, bean);
 
@@ -1935,7 +1940,8 @@ public class RestClientTest {
 			.accept("text/json")
 			.contentType("text/json")
 			.run()
-			.getBody().cache().assertValue("{\"f\":1}")
+			.cacheBody()
+			.getBody().assertValue("{\"f\":1}")
 			.getBody().as(Bean.class);
 		assertEqualObjects(b, bean);
 	}
@@ -1951,14 +1957,15 @@ public class RestClientTest {
 		rc
 			.post("/echoBody", bean)
 			.run()
-			.getBody().cache().assertValue("{f:1}");
+			.getBody().assertValue("{f:1}");
 
 		Bean b = rc
 			.post("/echoBody", bean)
 			.accept("text/xml")
 			.contentType("text/xml")
 			.run()
-			.getBody().cache().assertValue("<object><f>1</f></object>")
+			.cacheBody()
+			.getBody().assertValue("<object><f>1</f></object>")
 			.getBody().as(Bean.class);
 		assertEqualObjects(b, bean);
 
@@ -1967,7 +1974,8 @@ public class RestClientTest {
 			.accept("text/json")
 			.contentType("text/json")
 			.run()
-			.getBody().cache().assertValue("{\"f\":1}")
+			.cacheBody()
+			.getBody().assertValue("{\"f\":1}")
 			.getBody().as(Bean.class);
 		assertEqualObjects(b, bean);
 	}
@@ -2117,7 +2125,7 @@ public class RestClientTest {
 				.post("/echoBody", l1)
 				.run();
 		} catch (RestCallException e) {
-			assertTrue(e.getCause().getCause().getMessage().startsWith("Recursion occurred"));
+			assertTrue(e.getCause(SerializeException.class).getMessage().startsWith("Recursion occurred"));
 		}
 	}
 
@@ -2620,7 +2628,8 @@ public class RestClientTest {
 			.post("/test", new O2(1))
 			.header("X", new O2(1))
 			.run()
-			.getBody().cache().assertValue("1")
+			.cacheBody()
+			.getBody().assertValue("1")
 			.getHeader("X").assertValue("1")
 		;
 		assertEquals(1, rr.getBody().as(O2.class).f);
@@ -2654,7 +2663,8 @@ public class RestClientTest {
 			.post("/test", new O9().init())
 			.header("X", new O9().init())
 			.run()
-			.getBody().cache().assertValue("{f1:1,f2:2}")
+			.cacheBody()
+			.getBody().assertValue("{f1:1,f2:2}")
 			.getHeader("X").assertValue("f1=1,f2=2")
 		;
 		assertEquals(2, rr.getBody().as(O9.class).f2);
@@ -2703,7 +2713,8 @@ public class RestClientTest {
 			.post("/test", new O10().init())
 			.header("X", new O10().init())
 			.run()
-			.getBody().cache().assertValue("{f1:1}")
+			.cacheBody()
+			.getBody().assertValue("{f1:1}")
 			.getHeader("X").assertValue("f1=1")
 		;
 		assertEquals(0, rr.getBody().as(O10.class).f2);
@@ -2717,7 +2728,8 @@ public class RestClientTest {
 			.post("/test", new O10().init())
 			.header("X", new O10().init())
 			.run()
-			.getBody().cache().assertValue("{f1:1}")
+			.cacheBody()
+			.getBody().assertValue("{f1:1}")
 			.getHeader("X").assertValue("f1=1")
 		;
 		assertEquals(0, rr.getBody().as(O10.class).f2);
@@ -2731,7 +2743,8 @@ public class RestClientTest {
 			.post("/test", new O10().init())
 			.header("X", new O10().init())
 			.run()
-			.getBody().cache().assertValue("{f1:1}")
+			.cacheBody()
+			.getBody().assertValue("{f1:1}")
 			.getHeader("X").assertValue("f1=1")
 		;
 		assertEquals(0, rr.getBody().as(O10.class).f2);
@@ -2745,13 +2758,13 @@ public class RestClientTest {
 			.post("/test", new O10().init())
 			.header("X", new O10().init())
 			.run()
-			.getBody().cache().assertValue("{f1:1}")
+			.cacheBody()
+			.getBody().assertValue("{f1:1}")
 			.getHeader("X").assertValue("f1=1")
 		;
 		assertEquals(0, rr.getBody().as(O10.class).f2);
 		assertEquals(0, rr.getHeader("X").as(O10.class).f2);
 
-
 		rr = MockRestClient
 			.create(O2R.class)
 			.interfaces(O10I.class)
@@ -2760,7 +2773,8 @@ public class RestClientTest {
 			.post("/test", new O10().init())
 			.header("X", new O10().init())
 			.run()
-			.getBody().cache().assertValue("{f3:3}")
+			.cacheBody()
+			.getBody().assertValue("{f3:3}")
 			.getHeader("X").assertValue("f3=3")
 		;
 		assertEquals(3, rr.getBody().as(O10.class).f3);
@@ -2805,7 +2819,8 @@ public class RestClientTest {
 			.post("/test", new O18().init())
 			.header("X", new O18().init())
 			.run()
-			.getBody().cache().assertValue("{f1:1,f2:2}")
+			.cacheBody()
+			.getBody().assertValue("{f1:1,f2:2}")
 			.getHeader("X").assertValue("f1=1,f2=2")
 		;
 		assertEquals(2, rr.getBody().as(O18.class).f2);
@@ -2834,7 +2849,7 @@ public class RestClientTest {
 			.post("/test", new O21("1"))
 			.header("X", new O21("1"))
 			.run()
-			.getBody().cache().assertValue("{f1:'1'}")
+			.getBody().assertValue("{f1:'1'}")
 			.getHeader("X").assertValue("f1=1")
 		;
 		MockRestClient
@@ -2845,7 +2860,7 @@ public class RestClientTest {
 			.post("/test", new O21("1"))
 			.header("X", new O21("1"))
 			.run()
-			.getBody().cache().assertValue("'1'")
+			.getBody().assertValue("'1'")
 			.getHeader("X").assertValue("1")
 		;
 	}
@@ -2859,7 +2874,7 @@ public class RestClientTest {
 			.post("/test", new O21("1"))
 			.header("X", new O21("1"))
 			.run()
-			.getBody().cache().assertValue("{f1:'1'}")
+			.getBody().assertValue("{f1:'1'}")
 			.getHeader("X").assertValue("f1=1")
 		;
 		MockRestClient
@@ -2870,7 +2885,7 @@ public class RestClientTest {
 			.post("/test", new O21("1"))
 			.header("X", new O21("1"))
 			.run()
-			.getBody().cache().assertValue("'1'")
+			.getBody().assertValue("'1'")
 			.getHeader("X").assertValue("1")
 		;
 	}
@@ -2909,7 +2924,7 @@ public class RestClientTest {
 			.post("/test", new O25().init())
 			.header("X", new O25().init())
 			.run()
-			.getBody().cache().assertValue("{f1:1,f2:2}")
+			.getBody().assertValue("{f1:1,f2:2}")
 			.getHeader("X").assertValue("f1=1,f2=2")
 		;
 		MockRestClient
@@ -2920,7 +2935,7 @@ public class RestClientTest {
 			.post("/test", new O25().init())
 			.header("X", new O25().init())
 			.run()
-			.getBody().cache().assertValue("{f1:1}")
+			.getBody().assertValue("{f1:1}")
 			.getHeader("X").assertValue("f1=1")
 		;
 	}
@@ -2935,7 +2950,7 @@ public class RestClientTest {
 			.post("/test", new O25().init())
 			.header("X", new O25().init())
 			.run()
-			.getBody().cache().assertValue("{f2:2}")
+			.getBody().assertValue("{f2:2}")
 			.getHeader("X").assertValue("f2=2")
 		;
 		MockRestClient
@@ -2946,7 +2961,7 @@ public class RestClientTest {
 			.post("/test", new O25().init())
 			.header("X", new O25().init())
 			.run()
-			.getBody().cache().assertValue("{f2:2}")
+			.getBody().assertValue("{f2:2}")
 			.getHeader("X").assertValue("f2=2")
 		;
 		MockRestClient
@@ -2957,7 +2972,7 @@ public class RestClientTest {
 			.post("/test", new O25().init())
 			.header("X", new O25().init())
 			.run()
-			.getBody().cache().assertValue("{f2:2}")
+			.getBody().assertValue("{f2:2}")
 			.getHeader("X").assertValue("f2=2")
 		;
 		MockRestClient
@@ -2968,7 +2983,7 @@ public class RestClientTest {
 			.post("/test", new O25().init())
 			.header("X", new O25().init())
 			.run()
-			.getBody().cache().assertValue("{f2:2}")
+			.getBody().assertValue("{f2:2}")
 			.getHeader("X").assertValue("f2=2")
 		;
 	}
@@ -2985,7 +3000,8 @@ public class RestClientTest {
 			.post("/test", new O25().init())
 			.header("X", new O25().init())
 			.run()
-			.getBody().cache().assertValue("{f1:1,f2:2}")
+			.cacheBody()
+			.getBody().assertValue("{f1:1,f2:2}")
 			.getHeader("X").assertValue("f1=1,f2=2")
 		;
 		assertEquals("1/0", rr.getBody().as(O25.class).toString());
@@ -2999,7 +3015,8 @@ public class RestClientTest {
 			.post("/test", new O25().init())
 			.header("X", new O25().init())
 			.run()
-			.getBody().cache().assertValue("{f1:1,f2:2}")
+			.cacheBody()
+			.getBody().assertValue("{f1:1,f2:2}")
 			.getHeader("X").assertValue("f1=1,f2=2")
 		;
 		assertEquals("1/0", rr.getBody().as(O25.class).toString());
@@ -3013,7 +3030,8 @@ public class RestClientTest {
 			.post("/test", new O25().init())
 			.header("X", new O25().init())
 			.run()
-			.getBody().cache().assertValue("{f1:1,f2:2}")
+			.cacheBody()
+			.getBody().assertValue("{f1:1,f2:2}")
 			.getHeader("X").assertValue("f1=1,f2=2")
 		;
 		assertEquals("1/0", rr.getBody().as(O25.class).toString());
@@ -3032,7 +3050,8 @@ public class RestClientTest {
 			.post("/test", new O25().init())
 			.header("X", new O25().init())
 			.run()
-			.getBody().cache().assertValue("{f1:1}")
+			.cacheBody()
+			.getBody().assertValue("{f1:1}")
 			.getHeader("X").assertValue("f1=1")
 		;
 		assertEquals("1/0", rr.getBody().as(O25.class).toString());
@@ -3046,7 +3065,8 @@ public class RestClientTest {
 			.post("/test", new O25().init())
 			.header("X", new O25().init())
 			.run()
-			.getBody().cache().assertValue("{f1:1}")
+			.cacheBody()
+			.getBody().assertValue("{f1:1}")
 			.getHeader("X").assertValue("f1=1")
 		;
 		assertEquals("1/0", rr.getBody().as(O25.class).toString());
@@ -3060,7 +3080,8 @@ public class RestClientTest {
 			.post("/test", new O25().init())
 			.header("X", new O25().init())
 			.run()
-			.getBody().cache().assertValue("{f1:1}")
+			.cacheBody()
+			.getBody().assertValue("{f1:1}")
 			.getHeader("X").assertValue("f1=1")
 		;
 		assertEquals("1/0", rr.getBody().as(O25.class).toString());
@@ -3077,7 +3098,7 @@ public class RestClientTest {
 			.post("/test", new O25().init())
 			.header("X", new O25().init())
 			.run()
-			.getBody().cache().assertValue("{f2:2}")
+			.getBody().assertValue("{f2:2}")
 			.getHeader("X").assertValue("f2=2")
 		;
 		MockRestClient
@@ -3088,7 +3109,7 @@ public class RestClientTest {
 			.post("/test", new O25().init())
 			.header("X", new O25().init())
 			.run()
-			.getBody().cache().assertValue("{f2:2}")
+			.getBody().assertValue("{f2:2}")
 			.getHeader("X").assertValue("f2=2")
 		;
 		MockRestClient
@@ -3099,7 +3120,7 @@ public class RestClientTest {
 			.post("/test", new O25().init())
 			.header("X", new O25().init())
 			.run()
-			.getBody().cache().assertValue("{f2:2}")
+			.getBody().assertValue("{f2:2}")
 			.getHeader("X").assertValue("f2=2")
 		;
 		MockRestClient
@@ -3110,7 +3131,7 @@ public class RestClientTest {
 			.post("/test", new O25().init())
 			.header("X", new O25().init())
 			.run()
-			.getBody().cache().assertValue("{f2:2}")
+			.getBody().assertValue("{f2:2}")
 			.getHeader("X").assertValue("f2=2")
 		;
 	}
@@ -3178,7 +3199,8 @@ public class RestClientTest {
 			.build()
 			.post("/echoBody", new O33a().init())
 			.run()
-			.getBody().cache().assertContains("{_type:'foo',foo:'1'}")
+			.cacheBody()
+			.getBody().assertContains("{_type:'foo',foo:'1'}")
 			.getBody().as(Object.class);
 		;
 		assertTrue(o instanceof O33a);
@@ -3193,7 +3215,8 @@ public class RestClientTest {
 			.build()
 			.post("/echoBody", m)
 			.run()
-			.getBody().cache().assertValue("{x:{_type:'foo',foo:'1'},y:{_type:'bar',foo:'2'}}")
+			.cacheBody()
+			.getBody().assertValue("{x:{_type:'foo',foo:'1'},y:{_type:'bar',foo:'2'}}")
 			.getBody().as(OMap.class);
 		;
 		assertTrue(m.get("x") instanceof O33a);
@@ -3208,34 +3231,126 @@ public class RestClientTest {
 			.build()
 			.post("/echoBody", new O33c().init())
 			.run()
-			.getBody().cache().assertValue("{foo:{_type:'foo',foo:'1'}}")
+			.cacheBody()
+			.getBody().assertValue("{foo:{_type:'foo',foo:'1'}}")
 			.getBody().as(O33c.class);
 		;
 		assertTrue(o33c.foo instanceof O33a);
 	}
 
+	public static class O34 {
+		private String foo;
+		public String getFoo() {
+			return foo;
+		}
+		public O34 init() {
+			foo = "foo";
+			return this;
+		}
+	}
 
+	@Test
+	public void o034_beanContext_dontIgnorePropertiesWithoutSetters() throws Exception {
+		O34 x = MockRestClient
+			.create(A.class)
+			.simpleJson()
+			.build()
+			.post("/echoBody", new O34().init())
+			.run()
+			.cacheBody()
+			.getBody().assertContains("{foo:'foo'}")
+			.getBody().as(O34.class);
+		;
+		assertNull(x.foo);
 
-//
-//	@Test
-//	public void o0_beanContext_() throws Exception {
-//	}
-//	@Override /* GENERATED - BeanContextBuilder */
-//	public MockRestClient dontIgnorePropertiesWithoutSetters() {
-//		super.dontIgnorePropertiesWithoutSetters();
-//		return this;
-//	}
-//
-//	@Test
-//	public void o0_beanContext_() throws Exception {
-//	}
-//	@Override /* GENERATED - BeanContextBuilder */
-//	public MockRestClient dontIgnoreTransientFields() {
-//		super.dontIgnoreTransientFields();
-//		return this;
-//	}
-//
-//	@Test
+		try {
+			MockRestClient
+				.create(A.class)
+				.simpleJson()
+				.dontIgnorePropertiesWithoutSetters()
+				.build()
+				.post("/echoBody", new O34().init())
+				.run()
+				.cacheBody()
+				.getBody().assertContains("{foo:'foo'}")
+				.getBody().as(O34.class);
+		} catch (RestCallException e) {
+			assertTrue(e.getCause(BeanRuntimeException.class).getMessage().contains("Setter or public field not defined"));
+		}
+	}
+
+	public static class O35 {
+		public String foo;
+		public transient String bar;
+
+		public O35 init() {
+			foo = "1";
+			bar = "2";
+			return this;
+		}
+	}
+
+	@Test
+	public void o035_beanContext_dontIgnoreTransientFields() throws Exception {
+		O35 x = MockRestClient
+			.create(A.class)
+			.simpleJson()
+			.build()
+			.post("/echoBody", new O35().init())
+			.run()
+			.cacheBody()
+			.getBody().assertContains("{foo:'1'}")
+			.getBody().as(O35.class);
+		;
+		assertNull(x.bar);
+
+		x = MockRestClient
+			.create(A.class)
+			.simpleJson()
+			.dontIgnoreTransientFields()
+			.build()
+			.post("/echoBody", new O35().init())
+			.run()
+			.cacheBody()
+			.getBody().assertContains("{bar:'2',foo:'1'}")
+			.getBody().as(O35.class);
+		assertEquals("2", x.bar);
+	}
+
+	public static class O36 {
+		public String foo;
+	}
+
+	@Test
+	public void o036_beanContext_dontIgnoreUnknownNullBeanProperties() throws Exception {
+		MockRestClient
+			.create(A.class)
+			.simpleJson()
+			.build()
+			.post("/echoBody", new StringReader("{foo:'1',bar:null}"))
+			.run()
+			.cacheBody()
+			.getBody().assertContains("{foo:'1',bar:null}")
+			.getBody().as(O36.class);
+		;
+
+		try {
+			MockRestClient
+				.create(A.class)
+				.simpleJson()
+				.dontIgnoreUnknownNullBeanProperties()
+				.build()
+				.post("/echoBody", new StringReader("{foo:'1',bar:null}"))
+				.run()
+				.cacheBody()
+				.getBody().assertContains("{foo:'1',bar:null}")
+				.getBody().as(O34.class);
+		} catch (RestCallException e) {
+			assertTrue(e.getCause(ParseException.class).getMessage().contains("Unknown property 'bar'"));
+		}
+	}
+
+	//	@Test
 //	public void o0_beanContext_() throws Exception {
 //	}
 //	@Override /* GENERATED - BeanContextBuilder */
diff --git a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestClient.java b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestClient.java
index fd264bd..fee442d 100644
--- a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestClient.java
+++ b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestClient.java
@@ -717,7 +717,7 @@ import org.apache.http.client.CookieStore;
  * </p>
  *
  * <p class='w900'>
- * The response body can only be consumed once.  However, the {@link RestResponseBody#cache()} method is provided
+ * The response body can only be consumed once.  However, the {@link RestResponse#cacheBody()} and {@link RestResponseBody#cache()} methods are provided
  * to cache the response body in memory so that you can perform several operations against it.
  *
  * <h5 class='figure'>Examples:</h5>
diff --git a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestRequest.java b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestRequest.java
index 25e7a42..c37bf77 100644
--- a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestRequest.java
+++ b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestRequest.java
@@ -2329,7 +2329,7 @@ public final class RestRequest extends BeanSession implements HttpUriRequest, Co
 			}
 
 			if (client.logRequests == DetailLevel.FULL)
-				response.getBody().cache();
+				response.cacheBody();
 
 			for (RestCallInterceptor rci : interceptors)
 				rci.onConnect(this, response);
diff --git a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestResponse.java b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestResponse.java
index 0d8444b..9a3e720 100644
--- a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestResponse.java
+++ b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestResponse.java
@@ -234,6 +234,21 @@ public final class RestResponse implements HttpResponse {
 		return responseBody;
 	}
 
+	/**
+	 * Caches the response body so that it can be read as a stream multiple times.
+	 *
+	 * This is equivalent to calling the following:
+	 * <p class='bcode w800'>
+	 * 	getBody().cache();
+	 * </p>
+	 *
+	 * @return The body of the response.
+	 */
+	public RestResponse cacheBody() {
+		responseBody.cache();
+		return this;
+	}
+
 	@SuppressWarnings("unchecked")
 	<T> T as(ResponseBeanMeta rbm) throws RestCallException {
 		try {
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 62a31aa..32177e7 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
@@ -240,7 +240,7 @@ public class RestResponseBody implements HttpEntity {
 			}
 
 			if (isConsumed && ! entity.isRepeatable())
-				throw new IllegalStateException("Method cannot be called.  Response has already been consumed.");
+				throw new IllegalStateException("Method cannot be called.  Response has already been consumed.  Consider using the RestResponse.cacheBody() method.");
 
 			HttpEntity e = response.asHttpResponse().getEntity();
 			InputStream is = e == null ? new ByteArrayInputStream(new byte[0]) : e.getContent();
@@ -523,7 +523,7 @@ public class RestResponseBody implements HttpEntity {
 	 * 			<li class='jc'>{@link StreamResource} - Returns access as an input stream wrapped in a stream resource.
 	 * 		</ul>
 	 * 	<li>
-	 *		If {@link #cache()} has been called, this method can be can be called multiple times and/or combined with
+	 *		If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with
 	 *		other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
 	 *		with an inner {@link IllegalStateException} will be thrown.
 	 * 	<li>
@@ -568,7 +568,7 @@ public class RestResponseBody implements HttpEntity {
 	 *
 	 * <ul class='notes'>
 	 * 	<li>
-	 *		If {@link #cache()} has been called, this method can be can be called multiple times and/or combined with
+	 *		If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with
 	 *		other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
 	 *		with an inner {@link IllegalStateException} will be thrown.
 	 * 	<li>
@@ -632,7 +632,7 @@ public class RestResponseBody implements HttpEntity {
 	 * 			<li class='jc'>{@link StreamResource} - Returns access as an input stream wrapped in a stream resource.
 	 * 		</ul>
 	 * 	<li>
-	 *		If {@link #cache()} has been called, this method can be can be called multiple times and/or combined with
+	 *		If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with
 	 *		other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
 	 *		with an inner {@link IllegalStateException} will be thrown.
 	 * 	<li>
@@ -670,7 +670,7 @@ public class RestResponseBody implements HttpEntity {
 	 *
 	 * <ul class='notes'>
 	 * 	<li>
-	 *		If {@link #cache()} has been called, this method can be can be called multiple times and/or combined with
+	 *		If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with
 	 *		other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
 	 *		with an inner {@link IllegalStateException} will be thrown.
 	 * 	<li>
@@ -724,7 +724,7 @@ public class RestResponseBody implements HttpEntity {
 	 *
 	 * <ul class='notes'>
 	 * 	<li>
-	 *		If {@link #cache()} has been called, this method can be can be called multiple times and/or combined with
+	 *		If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with
 	 *		other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
 	 *		with an inner {@link IllegalStateException} will be thrown.
 	 * 	<li>
@@ -849,7 +849,7 @@ public class RestResponseBody implements HttpEntity {
 	 *
 	 * <ul class='notes'>
 	 * 	<li>
-	 *		If {@link #cache()} has been called, this method can be can be called multiple times and/or combined with
+	 *		If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with
 	 *		other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
 	 *		with an inner {@link IllegalStateException} will be thrown.
 	 * 	<li>
@@ -878,7 +878,7 @@ public class RestResponseBody implements HttpEntity {
 	 *
 	 * <ul class='notes'>
 	 * 	<li>
-	 *		If {@link #cache()} has been called, this method can be can be called multiple times and/or combined with
+	 *		If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with
 	 *		other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
 	 *		with an inner {@link IllegalStateException} will be thrown.
 	 * 	<li>
@@ -909,7 +909,7 @@ public class RestResponseBody implements HttpEntity {
 	 *
 	 * <ul class='notes'>
 	 * 	<li>
-	 *		If {@link #cache()} has been called, this method can be can be called multiple times and/or combined with
+	 *		If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with
 	 *		other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
 	 *		with an inner {@link IllegalStateException} will be thrown.
 	 * 	<li>
@@ -935,7 +935,7 @@ public class RestResponseBody implements HttpEntity {
 	 *
 	 * <ul class='notes'>
 	 * 	<li>
-	 *		If {@link #cache()} has been called, this method can be can be called multiple times and/or combined with
+	 *		If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with
 	 *		other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
 	 *		with an inner {@link IllegalStateException} will be thrown.
 	 * 	<li>
@@ -968,7 +968,7 @@ public class RestResponseBody implements HttpEntity {
 	 *
 	 * <ul class='notes'>
 	 * 	<li>
-	 *		If {@link #cache()} has been called, this method can be can be called multiple times and/or combined with
+	 *		If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with
 	 *		other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
 	 *		with an inner {@link IllegalStateException} will be thrown.
 	 * 	<li>
@@ -996,7 +996,7 @@ public class RestResponseBody implements HttpEntity {
 	 *
 	 * <ul class='notes'>
 	 * 	<li>
-	 *		If {@link #cache()} has been called, this method can be can be called multiple times and/or combined with
+	 *		If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with
 	 *		other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
 	 *		with an inner {@link IllegalStateException} will be thrown.
 	 * 	<li>
@@ -1035,7 +1035,7 @@ public class RestResponseBody implements HttpEntity {
 	 *
 	 * <ul class='notes'>
 	 * 	<li>
-	 *		If {@link #cache()} has been called, this method can be can be called multiple times and/or combined with
+	 *		If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with
 	 *		other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
 	 *		with an inner {@link IllegalStateException} will be thrown.
 	 * 	<li>
@@ -1071,7 +1071,7 @@ public class RestResponseBody implements HttpEntity {
 	 * 	<li>
 	 * 		If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed.
 	 *  <li>
-	 *		If {@link #cache()} has been called, this method can be can be called multiple times and/or combined with
+	 *		If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with
 	 *		other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
 	 *		with an inner {@link IllegalStateException} will be thrown.
 	 * 	<li>
@@ -1101,7 +1101,7 @@ public class RestResponseBody implements HttpEntity {
 	 * 	<li>
 	 * 		If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed.
 	 *  <li>
-	 *		If {@link #cache()} has been called, this method can be can be called multiple times and/or combined with
+	 *		If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with
 	 *		other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
 	 *		with an inner {@link IllegalStateException} will be thrown.
 	 * 	<li>
@@ -1127,7 +1127,7 @@ public class RestResponseBody implements HttpEntity {
 	 * 	<li>
 	 * 		If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed.
 	 *  <li>
-	 *		If {@link #cache()} has been called, this method can be can be called multiple times and/or combined with
+	 *		If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with
 	 *		other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
 	 *		with an inner {@link IllegalStateException} will be thrown.
 	 * 	<li>
@@ -1158,7 +1158,7 @@ public class RestResponseBody implements HttpEntity {
 	 * 	<li>
 	 * 		If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed.
 	 *  <li>
-	 *		If {@link #cache()} has been called, this method can be can be called multiple times and/or combined with
+	 *		If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with
 	 *		other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
 	 *		with an inner {@link IllegalStateException} will be thrown.
 	 * 	<li>
@@ -1301,7 +1301,7 @@ public class RestResponseBody implements HttpEntity {
 	 * 	<li>
 	 * 		If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed.
 	 *  <li>
-	 *		If {@link #cache()} has been called, this method can be can be called multiple times and/or combined with
+	 *		If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with
 	 *		other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
 	 *		with an inner {@link IllegalStateException} will be thrown.
 	 * 	<li>
@@ -1338,7 +1338,7 @@ public class RestResponseBody implements HttpEntity {
 	 * 	<li>
 	 * 		If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed.
 	 *  <li>
-	 *		If {@link #cache()} has been called, this method can be can be called multiple times and/or combined with
+	 *		If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with
 	 *		other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
 	 *		with an inner {@link IllegalStateException} will be thrown.
 	 * 	<li>
@@ -1375,7 +1375,7 @@ public class RestResponseBody implements HttpEntity {
 	 * 	<li>
 	 * 		If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed.
 	 *  <li>
-	 *		If {@link #cache()} has been called, this method can be can be called multiple times and/or combined with
+	 *		If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with
 	 *		other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
 	 *		with an inner {@link IllegalStateException} will be thrown.
 	 * 	<li>
@@ -1412,7 +1412,7 @@ public class RestResponseBody implements HttpEntity {
 	 * 	<li>
 	 * 		If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed.
 	 *  <li>
-	 *		If {@link #cache()} has been called, this method can be can be called multiple times and/or combined with
+	 *		If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with
 	 *		other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
 	 *		with an inner {@link IllegalStateException} will be thrown.
 	 * 	<li>
@@ -1449,7 +1449,7 @@ public class RestResponseBody implements HttpEntity {
 	 * 	<li>
 	 * 		If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed.
 	 *  <li>
-	 *		If {@link #cache()} has been called, this method can be can be called multiple times and/or combined with
+	 *		If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with
 	 *		other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
 	 *		with an inner {@link IllegalStateException} will be thrown.
 	 * 	<li>
@@ -1487,7 +1487,7 @@ public class RestResponseBody implements HttpEntity {
 	 * 	<li>
 	 * 		If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed.
 	 *  <li>
-	 *		If {@link #cache()} has been called, this method can be can be called multiple times and/or combined with
+	 *		If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with
 	 *		other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
 	 *		with an inner {@link IllegalStateException} will be thrown.
 	 * 	<li>
@@ -1534,7 +1534,7 @@ public class RestResponseBody implements HttpEntity {
 	 * 	<li>
 	 * 		If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed.
 	 *  <li>
-	 *		If {@link #cache()} has been called, this method can be can be called multiple times and/or combined with
+	 *		If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with
 	 *		other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
 	 *		with an inner {@link IllegalStateException} will be thrown.
 	 * 	<li>
@@ -1577,7 +1577,7 @@ public class RestResponseBody implements HttpEntity {
 	 * 	<li>
 	 * 		If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed.
 	 *  <li>
-	 *		If {@link #cache()} has been called, this method can be can be called multiple times and/or combined with
+	 *		If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with
 	 *		other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
 	 *		with an inner {@link IllegalStateException} will be thrown.
 	 * 	<li>
@@ -1622,7 +1622,7 @@ public class RestResponseBody implements HttpEntity {
 	 * 	<li>
 	 * 		If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed.
 	 *  <li>
-	 *		If {@link #cache()} has been called, this method can be can be called multiple times and/or combined with
+	 *		If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with
 	 *		other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
 	 *		with an inner {@link IllegalStateException} will be thrown.
 	 * 	<li>
@@ -1657,7 +1657,7 @@ public class RestResponseBody implements HttpEntity {
 	 * 	<li>
 	 * 		If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed.
 	 *  <li>
-	 *		If {@link #cache()} has been called, this method can be can be called multiple times and/or combined with
+	 *		If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with
 	 *		other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
 	 *		with an inner {@link IllegalStateException} will be thrown.
 	 * 	<li>
@@ -1689,7 +1689,7 @@ public class RestResponseBody implements HttpEntity {
 	 * 	<li>
 	 * 		If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed.
 	 *  <li>
-	 *		If {@link #cache()} has been called, this method can be can be called multiple times and/or combined with
+	 *		If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with
 	 *		other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
 	 *		with an inner {@link IllegalStateException} will be thrown.
 	 * 	<li>
@@ -1727,7 +1727,7 @@ public class RestResponseBody implements HttpEntity {
 	 * 	<li>
 	 * 		If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed.
 	 *  <li>
-	 *		If {@link #cache()} has been called, this method can be can be called multiple times and/or combined with
+	 *		If {@link #cache()} or {@link RestResponse#cacheBody()} has been called, this method can be can be called multiple times and/or combined with
 	 *		other methods that retrieve the content of the response.  Otherwise a {@link RestCallException}
 	 *		with an inner {@link IllegalStateException} will be thrown.
 	 * 	<li>