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 dc65ad4  RestClient tests
dc65ad4 is described below

commit dc65ad4c2bb215f5c8ed072838b1d54299c1df62
Author: JamesBognar <[email protected]>
AuthorDate: Sat Jul 4 11:57:45 2020 -0400

    RestClient tests
---
 .../apache/juneau/rest/client2/Remote_Test.java    | 113 +++++++++++----
 .../rest/client2/RestCallException_Test.java       |  83 +++++++++++
 .../juneau/rest/client2/RestClient_Query_Test.java |   2 +-
 .../client2/RestClient_Response_Body_Test.java     |   9 +-
 .../juneau/rest/client/remote/RemoteMeta.java      |   3 +-
 .../rest/client/remote/RemoteMethodMeta.java       |  43 +-----
 .../juneau/rest/client2/RestCallException.java     | 153 ++-------------------
 .../juneau/rest/client2/RestCallInterceptor.java   |  12 +-
 .../org/apache/juneau/rest/client2/RestClient.java |  33 +++--
 .../apache/juneau/rest/client2/RestRequest.java    |  43 +++---
 .../apache/juneau/rest/client2/RestResponse.java   |   4 +-
 .../juneau/rest/client2/RestResponseBody.java      |   6 +-
 .../juneau/rest/client2/RestResponseHeader.java    |   2 +-
 13 files changed, 251 insertions(+), 255 deletions(-)

diff --git 
a/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/Remote_Test.java
 
b/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/Remote_Test.java
index 79645ef..7b3834c 100644
--- 
a/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/Remote_Test.java
+++ 
b/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/Remote_Test.java
@@ -19,6 +19,7 @@ import java.util.concurrent.*;
 
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.annotation.*;
+import org.apache.juneau.rest.client.remote.*;
 import org.apache.juneau.rest.config.*;
 import org.apache.juneau.http.*;
 import org.apache.juneau.http.header.*;
@@ -61,7 +62,7 @@ public class Remote_Test {
 
        @Test
        public void a01_noPath() throws Exception {
-               A1 x = MockRestClient.build(A.class).getRemote(A1.class);
+               A1 x = plainRemote(A.class,A1.class);
                assertEquals("foo",x.x1());
                assertEquals("foo",x.x1a());
                assertEquals("foo",x.x1b());
@@ -76,7 +77,7 @@ public class Remote_Test {
 
        @Test
        public void a02_normalPath() throws Exception {
-               A2 x = MockRestClient.build(A.class).getRemote(A2.class);
+               A2 x = plainRemote(A.class,A2.class);
                assertEquals("foo",x.x2());
                assertEquals("foo",x.x2a());
                assertEquals("foo",x.x2b());
@@ -91,7 +92,7 @@ public class Remote_Test {
 
        @Test
        public void a03_normalPathWithSlashes() throws Exception {
-               A3 x = MockRestClient.build(A.class).getRemote(A3.class);
+               A3 x = plainRemote(A.class,A3.class);
                assertEquals("foo",x.x2());
                assertEquals("foo",x.x2a());
                assertEquals("foo",x.x2b());
@@ -106,7 +107,7 @@ public class Remote_Test {
 
        @Test
        public void a04_pathOnClient() throws Exception {
-               A4 x = 
MockRestClient.create(A.class).rootUrl("http://localhost/A";).build().getRemote(A4.class);
+               A4 x = plainRemote(A.class,A4.class,"http://localhost/A";);
                assertEquals("foo",x.x2());
                assertEquals("foo",x.x2a());
                assertEquals("foo",x.x2b());
@@ -121,7 +122,7 @@ public class Remote_Test {
 
        @Test
        public void a05_normalPath() throws Exception {
-               A5 x = MockRestClient.build(A.class).getRemote(A5.class);
+               A5 x = plainRemote(A.class,A5.class);
                assertEquals("foo",x.x3());
                assertEquals("foo",x.x3a());
                assertEquals("foo",x.x3b());
@@ -136,7 +137,7 @@ public class Remote_Test {
 
        @Test
        public void a06_normalPathWithSlashes() throws Exception {
-               A6 x = MockRestClient.build(A.class).getRemote(A6.class);
+               A6 x = plainRemote(A.class,A6.class);
                assertEquals("foo",x.x3());
                assertEquals("foo",x.x3a());
                assertEquals("foo",x.x3b());
@@ -151,7 +152,7 @@ public class Remote_Test {
 
        @Test
        public void a07_partialPath() throws Exception {
-               A7 x =  
MockRestClient.create(A.class).rootUrl("http://localhost/A";).build().getRemote(A7.class);
+               A7 x = plainRemote(A.class,A7.class,"http://localhost/A";);
                assertEquals("foo",x.x3());
                assertEquals("foo",x.x3a());
                assertEquals("foo",x.x3b());
@@ -166,7 +167,7 @@ public class Remote_Test {
 
        @Test
        public void a08_partialPathExtraSlashes() throws Exception {
-               A8 x = 
MockRestClient.create(A.class).rootUrl("http://localhost/A/";).build().getRemote(A8.class);
+               A8 x = plainRemote(A.class,A8.class,"http://localhost/A/";);
                assertEquals("foo",x.x3());
                assertEquals("foo",x.x3a());
                assertEquals("foo",x.x3b());
@@ -193,7 +194,7 @@ public class Remote_Test {
 
        @Test
        public void b01_noPath() throws Exception {
-               B1 x = 
MockRestClient.create(B.class).rootUrl("http://localhost/B";).build().getRemote(B1.class);
+               B1 x = plainRemote(B.class,B1.class,"http://localhost/B";);
                assertEquals("foo",x.x1());
                assertEquals("foo",x.x1a());
                assertEquals("foo",x.x1b());
@@ -208,7 +209,7 @@ public class Remote_Test {
 
        @Test
        public void b02_absolutePathOnClass() throws Exception {
-               B2 x = 
MockRestClient.create(B.class).rootUrl("http://localhost/B";).build().getRemote(B2.class);
+               B2 x = plainRemote(B.class,B2.class,"http://localhost/B";);
                assertEquals("foo",x.x1());
                assertEquals("foo",x.x1a());
                assertEquals("foo",x.x1b());
@@ -223,7 +224,7 @@ public class Remote_Test {
 
        @Test
        public void b03_absolutePathsOnMethods() throws Exception {
-               B3 x = 
MockRestClient.create(B.class).rootUrl("http://localhost/B";).build().getRemote(B3.class);
+               B3 x = plainRemote(B.class,B3.class,"http://localhost/B";);
                assertEquals("foo",x.x1());
                assertEquals("foo",x.x1a());
                assertEquals("foo",x.x1b());
@@ -248,13 +249,13 @@ public class Remote_Test {
 
        @Test
        public void c01_overriddenRootUrl() throws Exception {
-               C1 x = 
MockRestClient.create(C.class).json().build().getRemote(C1.class,"http://localhost/C1";);
+               C1 x = 
client(C.class).build().getRemote(C1.class,"http://localhost/C1";);
                assertEquals("foo",x.x1());
        }
 
        @Test
        public void c02_rootUriNotSpecified() throws Exception {
-               C1 x = 
MockRestClient.create(C.class).json().rootUrl("").build().getRemote(C1.class);
+               C1 x = client(C.class).rootUrl("").build().getRemote(C1.class);
                assertThrown(()->x.x1()).contains("Root URI has not been 
specified.");
        }
 
@@ -279,7 +280,7 @@ public class Remote_Test {
 
        @Test
        public void c03_methodNotAnnotated() throws Exception {
-               C3b x = 
MockRestClient.create(C3a.class).json().build().getRemote(C3b.class);
+               C3b x = remote(C3a.class,C3b.class);
                assertEquals("bar",x.x1());
                assertEquals("baz",x.getX2());
        }
@@ -318,7 +319,7 @@ public class Remote_Test {
 
        @Test
        public void c04_rethrownExceptions() throws Exception {
-               C4b x = 
MockRestClient.create(C4a.class).json().build().getRemote(C4b.class);
+               C4b x = remote(C4a.class,C4b.class);
                assertThrown(()->x.x1()).is("foo");
                assertThrown(()->x.x1a().get()).contains("foo");
                assertThrown(()->x.x1b().get()).contains("foo");
@@ -358,7 +359,7 @@ public class Remote_Test {
 
        @Test
        public void d01_statusReturnType() throws Exception {
-               D1a x = 
MockRestClient.create(D1.class).json().ignoreErrors().build().getRemote(D1a.class);
+               D1a x = 
client(D1.class).ignoreErrors().build().getRemote(D1a.class);
                assertEquals(202,x.x1());
                assertEquals(202,x.x2().intValue());
                assertEquals(true,x.x3());
@@ -392,7 +393,7 @@ public class Remote_Test {
 
        @Test
        public void d02_primitiveReturns() throws Exception {
-               D2a x = 
MockRestClient.create(D2.class).json().ignoreErrors().build().getRemote(D2a.class);
+               D2a x = 
client(D2.class).ignoreErrors().build().getRemote(D2a.class);
                assertEquals(0,x.x1());
                assertEquals(1,x.x2());
                assertNull(x.x1a());
@@ -421,14 +422,14 @@ public class Remote_Test {
 
        @Test
        public void e01_rrpcBasic() throws Exception {
-               E1 x = 
MockRestClient.create(E.class).rootUrl("http://localhost/proxy";).json().build().getRrpcInterface(E1.class);
+               E1 x = 
client(E.class).rootUrl("http://localhost/proxy";).build().getRrpcInterface(E1.class);
 
                assertEquals("foo",x.echo("foo"));
        }
 
        @Test
        public void e02_rrpc_noRootPath() throws Exception {
-               RestClient x = 
MockRestClient.create(E.class).rootUrl("").json().build();
+               RestClient x = client(E.class).rootUrl("").build();
                assertThrown(()->x.getRrpcInterface(E1.class)).contains("Root 
URI has not been specified.");
        }
 
@@ -439,7 +440,7 @@ public class Remote_Test {
 
        @Test
        public void e03_rrpc_noRestUrl() throws Exception {
-               E3 x = 
MockRestClient.create(E.class).rootUrl("http://localhost";).json().build().getRrpcInterface(E3.class);
+               E3 x = 
client(E.class).rootUrl("http://localhost";).build().getRrpcInterface(E3.class);
                assertEquals("foo",x.echo("foo"));
        }
 
@@ -450,7 +451,7 @@ public class Remote_Test {
 
        @Test
        public void e04_rrpc_fullPathOnRemotePath() throws Exception {
-               E4 x = 
MockRestClient.create(E.class).rootUrl("").json().build().getRrpcInterface(E4.class);
+               E4 x = 
client(E.class).rootUrl("").build().getRrpcInterface(E4.class);
                assertEquals("foo",x.echo("foo"));
        }
 
@@ -480,7 +481,7 @@ public class Remote_Test {
 
        @Test
        public void e05_rrpc_rethrownCheckedException() throws Exception {
-               RestClient x = MockRestClient.create(E5.class).json().build();
+               RestClient x = client(E5.class).build();
                
assertThrown(()->x.getRrpcInterface(E5b.class,"/proxy").echo("foo")).is("foobar");
        }
 
@@ -499,7 +500,7 @@ public class Remote_Test {
 
        @Test
        public void e06_rrpc_rethrownUncheckedException() throws Exception {
-               RestClient x = MockRestClient.create(E6.class).json().build();
+               RestClient x = client(E6.class).build();
                
assertThrown(()->x.getRrpcInterface(E5b.class,"/proxy").echo("foo")).contains("foobar");
        }
 
@@ -515,13 +516,13 @@ public class Remote_Test {
                }
        }
 
-       @Remote(headers="Foo:bar",headerSupplier=F2.class,version="1.2.3")
-       public static interface F1 {
+       @Remote(headers="Foo:bar",headerSupplier=F1b.class,version="1.2.3")
+       public static interface F1a {
                String[] getHeaders();
        }
 
-       public static class F2 extends HeaderSupplier {
-               public F2() {
+       public static class F1b extends HeaderSupplier {
+               public F1b() {
                        add(BasicHeader.of("Foo","baz"));
                        add(HeaderSupplier.of(BasicHeader.of("Foo",()->"qux")));
                }
@@ -529,9 +530,63 @@ public class Remote_Test {
 
        @Test
        public void f01_headers() throws Exception {
-               F1 x = 
MockRestClient.create(F.class).json().header("Check","Foo").build().getRemote(F1.class);
+               F1a x = 
client(F.class).header("Check","Foo").build().getRemote(F1a.class);
                
assertEquals("['bar','baz','qux']",SimpleJson.DEFAULT.toString(x.getHeaders()));
-               x = 
MockRestClient.create(F.class).json().header("Check","X-Client-Version").build().getRemote(F1.class);
+               x = 
client(F.class).header("Check","X-Client-Version").build().getRemote(F1a.class);
                
assertEquals("['1.2.3']",SimpleJson.DEFAULT.toString(x.getHeaders()));
        }
+
+       @Remote(headerSupplier=F2b.class)
+       public static interface F2a {
+               String[] getHeaders();
+       }
+
+       public static class F2b extends HeaderSupplier {
+               public F2b() {
+                       throw new NullPointerException("foo");
+               }
+       }
+
+       @Test
+       public void f02_headers_badSupplier() throws Exception {
+               
assertThrown(()->client(F.class).build().getRemote(F2a.class)).contains("foo");
+       }
+
+       
//-----------------------------------------------------------------------------------------------------------------
+       // Other
+       
//-----------------------------------------------------------------------------------------------------------------
+
+       @Rest
+       public static class G extends BasicRest {}
+
+       @Remote
+       public static interface G1 {
+               @RemoteMethod(method="FOO")
+               String[] getHeaders();
+       }
+
+       @Test
+       public void g01_badMethodName() throws Exception {
+               
assertThrown(()->client(G.class).header("Check","Foo").build().getRemote(G1.class)).isType(RemoteMetadataException.class).contains("Invalid
 value");
+       }
+
+       
//-----------------------------------------------------------------------------------------------------------------
+       // Helper methods.
+       
//-----------------------------------------------------------------------------------------------------------------
+
+       private static RestClientBuilder client(Class<?> c) {
+               return MockRestClient.create(c).simpleJson();
+       }
+
+       private static <T> T remote(Class<?> c, Class<T> r) {
+               return 
MockRestClient.create(c).simpleJson().build().getRemote(r);
+       }
+
+       private static <T> T plainRemote(Class<?> c, Class<T> r) {
+               return MockRestClient.create(c).build().getRemote(r);
+       }
+
+       private static <T> T plainRemote(Class<?> c, Class<T> r, String 
rootUrl) {
+               return 
MockRestClient.create(c).rootUrl(rootUrl).build().getRemote(r);
+       }
 }
diff --git 
a/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/RestCallException_Test.java
 
b/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/RestCallException_Test.java
new file mode 100644
index 0000000..e8d189d
--- /dev/null
+++ 
b/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/RestCallException_Test.java
@@ -0,0 +1,83 @@
+// 
***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                
                                              *
+// *                                                                           
                                              *
+// *  http://www.apache.org/licenses/LICENSE-2.0                               
                                              *
+// *                                                                           
                                              *
+// * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 
express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the 
License.                                              *
+// 
***************************************************************************************************************************
+package org.apache.juneau.rest.client2;
+
+import static org.apache.juneau.assertions.Assertions.*;
+import static org.junit.Assert.*;
+import static org.junit.runners.MethodSorters.*;
+
+import java.io.*;
+
+import org.apache.http.entity.*;
+import org.apache.juneau.marshall.*;
+import org.apache.juneau.parser.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+import org.apache.juneau.rest.mock2.*;
+import org.junit.*;
+
+@FixMethodOrder(NAME_ASCENDING)
+public class RestCallException_Test {
+
+       public static class ABean {
+               public int f;
+               static ABean get() {
+                       ABean x = new ABean();
+                       x.f = 1;
+                       return x;
+               }
+               @Override
+               public String toString() {
+                       return SimpleJson.DEFAULT.toString(this);
+               }
+       }
+
+       @Rest
+       public static class A extends BasicRest {
+               @RestMethod
+               public InputStream postEcho(InputStream is) {
+                       return is;
+               }
+       }
+
+       @Test
+       public void a01_basic() throws Exception {
+               try {
+                       client().build().get().run();
+                       fail();
+               } catch (RestCallException e) {
+                       assertInteger(e.getResponse().getStatusCode()).is(404);
+                       assertNull(e.getCause());
+               }
+
+               try {
+                       client().build().post("/echo",new 
StringEntity("{f:")).run().getBody().as(ABean.class);
+                       fail();
+               } catch (RestCallException e) {
+                       
assertThrowable(e.getCause(ParseException.class)).contains("Could not find 
'}'");
+               }
+
+               RestCallException e = new RestCallException(null, null, null);
+               assertNull(e.getServerExceptionMessage());
+               assertNull(e.getServerExceptionName());
+               assertEquals(0, e.getResponseCode());
+       }
+
+       
//-----------------------------------------------------------------------------------------------------------------
+       // Helper methods.
+       
//-----------------------------------------------------------------------------------------------------------------
+
+       private static RestClientBuilder client() {
+               return MockRestClient.create(A.class).simpleJson();
+       }
+}
diff --git 
a/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/RestClient_Query_Test.java
 
b/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/RestClient_Query_Test.java
index 0305db5..ed37eff 100644
--- 
a/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/RestClient_Query_Test.java
+++ 
b/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/RestClient_Query_Test.java
@@ -185,7 +185,7 @@ public class RestClient_Query_Test {
        @Test
        public void a12_queryCustom_Object() throws Exception {
                
client().build().get("/query").queryCustom("foo=bar").run().assertBody().contains("foo=bar");
-               assertThrown(()->client().build().get("").queryCustom(new 
A12())).is("foo");
+               assertThrown(()->client().build().get("").queryCustom(new 
A12())).contains("foo");
        }
 
        
//------------------------------------------------------------------------------------------------------------------
diff --git 
a/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/RestClient_Response_Body_Test.java
 
b/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/RestClient_Response_Body_Test.java
index 5c93413..7ad4e4e 100644
--- 
a/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/RestClient_Response_Body_Test.java
+++ 
b/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/RestClient_Response_Body_Test.java
@@ -95,6 +95,7 @@ public class RestClient_Response_Body_Test {
        @Test
        public void a01_basic() throws Exception {
                
client().build().post("/echo",bean).run().assertBody(ABean.class).json().is("{f:1}");
+               
client().build().post("/echo",bean).run().assertBodyBytes().string().is("{f:1}");
        }
 
        @Test
@@ -137,12 +138,8 @@ public class RestClient_Response_Body_Test {
 
                TestClient x2 = 
client().interceptors(rci).build(TestClient.class).entity(new 
StringEntity("{f:2}"));
                
assertThrown(()->x2.get("/bean").run().getBody().cache().asInputStream()).contains("foo");
-               is = x2.get("/bean").run().getBody().asInputStream();
-               assertStream(is).string().is("{f:2}");
-               is = x2.get("/bean").run().getBody().asInputStream();
-               is.close();
-               is = x2.get("/bean").run().getBody().asInputStream();
-               ((EofSensorInputStream)is).abortConnection();
+               
assertThrown(()->x2.get("/bean").run().getBody().asInputStream().close()).contains("foo");
+               
assertThrown(()->((EofSensorInputStream)x2.get("/bean").run().getBody().asInputStream()).abortConnection()).contains("foo");
        }
 
        @Test
diff --git 
a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/remote/RemoteMeta.java
 
b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/remote/RemoteMeta.java
index d7d1cd8..5139191 100644
--- 
a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/remote/RemoteMeta.java
+++ 
b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/remote/RemoteMeta.java
@@ -73,8 +73,7 @@ public class RemoteMeta {
 
                AMap<Method,RemoteMethodMeta> methods = AMap.of();
                for (MethodInfo m : ci.getPublicMethods())
-                       if (m.isPublic())
-                               methods.put(m.inner(), new 
RemoteMethodMeta(path, m.inner(), false, "GET"));
+                       methods.put(m.inner(), new RemoteMethodMeta(path, 
m.inner(), "GET"));
 
                this.methods = methods.unmodifiable();
        }
diff --git 
a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/remote/RemoteMethodMeta.java
 
b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/remote/RemoteMethodMeta.java
index 57b440a..0d7d335 100644
--- 
a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/remote/RemoteMethodMeta.java
+++ 
b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/remote/RemoteMethodMeta.java
@@ -39,12 +39,11 @@ import org.apache.juneau.reflect.*;
 public class RemoteMethodMeta {
 
        private final String httpMethod;
-       private final String fullPath, path;
+       private final String fullPath;
        private final RemoteMethodArg[] pathArgs, queryArgs, headerArgs, 
formDataArgs;
        private final RemoteMethodBeanArg[] requestArgs;
        private final RemoteMethodArg bodyArg;
        private final RemoteMethodReturn methodReturn;
-       private final Method method;
        private final Class<?>[] exceptions;
 
        /**
@@ -52,14 +51,11 @@ public class RemoteMethodMeta {
         *
         * @param parentPath The absolute URL of the REST interface backing the 
interface proxy.
         * @param m The Java method.
-        * @param useMethodSignatures If <jk>true</jk> then the default path 
for the method should be the full method signature.
         * @param defaultMethod The default HTTP method if not specified 
through annotation.
         */
-       public RemoteMethodMeta(final String parentPath, Method m, boolean 
useMethodSignatures, String defaultMethod) {
-               Builder b = new Builder(parentPath, m, useMethodSignatures, 
defaultMethod);
-               this.method = m;
+       public RemoteMethodMeta(final String parentPath, Method m, String 
defaultMethod) {
+               Builder b = new Builder(parentPath, m, defaultMethod);
                this.httpMethod = b.httpMethod;
-               this.path = b.path;
                this.fullPath = b.fullPath;
                this.pathArgs = b.pathArgs.toArray(new 
RemoteMethodArg[b.pathArgs.size()]);
                this.queryArgs = b.queryArgs.toArray(new 
RemoteMethodArg[b.queryArgs.size()]);
@@ -84,7 +80,7 @@ public class RemoteMethodMeta {
                RemoteMethodReturn methodReturn;
 
                @SuppressWarnings("deprecation")
-               Builder(String parentPath, Method m, boolean 
useMethodSignatures, String defaultMethod) {
+               Builder(String parentPath, Method m, String defaultMethod) {
 
                        MethodInfo mi = MethodInfo.of(m);
 
@@ -99,18 +95,16 @@ public class RemoteMethodMeta {
                        path = rm == null ? (orm == null ? "" : orm.path()) : 
rm.path();
 
                        if (path.isEmpty()) {
-                               path = HttpUtils.detectHttpPath(m, ! 
useMethodSignatures);
-                               if (useMethodSignatures)
-                                       path += 
HttpUtils.getMethodArgsSignature(m, true);
+                               path = HttpUtils.detectHttpPath(m, true);
                        }
                        if (httpMethod.isEmpty())
-                               httpMethod = HttpUtils.detectHttpMethod(m, ! 
useMethodSignatures, defaultMethod);
+                               httpMethod = HttpUtils.detectHttpMethod(m, 
true, defaultMethod);
 
                        path = trimSlashes(path);
 
                        if (! isOneOf(httpMethod, "DELETE", "GET", "POST", 
"PUT", "OPTIONS", "HEAD", "CONNECT", "TRACE", "PATCH"))
                                throw new RemoteMetadataException(m,
-                                       "Invalid value specified for 
@RemoteMethod(httpMethod) annotation.  Valid values are [DELTE,GET,POST,PUT].");
+                                       "Invalid value specified for 
@RemoteMethod(httpMethod) annotation.  Valid values are 
[DELTE,GET,POST,PUT,OPTIONS,HEAD,CONNECT,TRACE,PATCH].");
 
                        methodReturn = new RemoteMethodReturn(mi);
 
@@ -221,29 +215,6 @@ public class RemoteMethodMeta {
        }
 
        /**
-        * Returns the HTTP path of this method.
-        *
-        * @return
-        *      The HTTP path of this method relative to the parent interface.
-        *      <br>Never <jk>null</jk>.
-        *      <br>Never has leading or trailing slashes.
-        */
-       public String getPath() {
-               return path;
-       }
-
-       /**
-        * Returns the underlying Java method that this metadata is about.
-        *
-        * @return
-        *      The underlying Java method that this metadata is about.
-        *      <br>Never <jk>null</jk>.
-        */
-       public Method getJavaMethod() {
-               return method;
-       }
-
-       /**
         * Returns the exceptions thrown by this method.
         *
         * @return The exceptions thrown by this method.  Never <jk>null</jk>.
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 495a558..bbedd2a 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
@@ -12,13 +12,11 @@
 // 
***************************************************************************************************************************
 package org.apache.juneau.rest.client2;
 
-import java.io.*;
-import java.net.*;
+import static org.apache.juneau.internal.StringUtils.*;
+
 import java.text.*;
-import java.util.regex.*;
 
 import org.apache.http.*;
-import org.apache.http.client.*;
 import org.apache.juneau.internal.*;
 
 /**
@@ -28,107 +26,28 @@ public final class RestCallException extends HttpException 
{
 
        private static final long serialVersionUID = 1L;
 
-       private int responseCode;
-       private String response, responseStatusMessage;
-       HttpResponseException e;
-       private RestResponse restResponse;
-
-       private String serverExceptionName, serverExceptionMessage, 
serverExceptionTrace;
-
-       /**
-        * Converts the specified exception to a {@link RestCallException} by 
either casting or wrapping.
-        *
-        * @param e The exception to wrap.
-        * @return The casted or wrapped exception.
-        */
-       public static RestCallException create(Throwable e) {
-               if (e instanceof RestCallException)
-                       return (RestCallException)e;
-               return new RestCallException(e);
-       }
-
-       /**
-        * Constructor.
-        *
-        * @param message The {@link MessageFormat}-style message.
-        * @param args Optional {@link MessageFormat}-style arguments.
-        */
-       public RestCallException(String message, Object...args) {
-               super(format(message, args));
-       }
+       private RestResponse response;
 
        /**
         * Constructor.
         *
+        * @param response The HTTP response.  Can be <jk>null</jk>.
         * @param cause The cause of this exception.
         * @param message The {@link MessageFormat}-style message.
         * @param args Optional {@link MessageFormat}-style arguments.
         */
-       public RestCallException(Throwable cause, String message, 
Object...args) {
-               this(getMessage(cause, message, null), args);
-               initCause(cause);
-       }
-
-       /**
-        * Constructor.
-        *
-        * @param e The inner cause of the exception.
-        */
-       public RestCallException(Throwable e) {
-               super(clean(e.getLocalizedMessage()), e);
-               if (e instanceof FileNotFoundException) {
-                       responseCode = 404;
-               } else if (e.getMessage() != null) {
-                       Pattern p = Pattern.compile("[^\\d](\\d{3})[^\\d]");
-                       Matcher m = p.matcher(e.getMessage());
-                       if (m.find())
-                               responseCode = Integer.parseInt(m.group(1));
-               }
-               setStackTrace(e.getStackTrace());
-       }
-
-       /**
-        * Constructor.
-        *
-        * @param responseCode The response code.
-        * @param responseMsg The response message.
-        * @param method The HTTP method (for message purposes).
-        * @param url The HTTP URL (for message purposes).
-        * @param response The response from the server.
-        */
-       public RestCallException(int responseCode, String responseMsg, String 
method, URI url, String response) {
-               super(format("HTTP method ''{0}'' call to ''{1}'' caused 
response code ''{2}, {3}''.\nResponse: \n{4}", method, url, responseCode, 
responseMsg, response));
-               this.responseCode = responseCode;
-               this.responseStatusMessage = responseMsg;
+       public RestCallException(RestResponse response, Throwable cause, String 
message, Object...args) {
+               super(format(message,args),cause);
                this.response = response;
        }
 
        /**
-        * Sets the server-side exception details.
-        *
-        * @param exceptionName The <c>Exception-Name:</c> header specifying 
the full name of the exception.
-        * @param exceptionMessage
-        *      The <c>Exception-Message:</c> header specifying the message 
returned by {@link Throwable#getMessage()}.
-        * @param exceptionTrace The stack trace of the exception returned by 
{@link Throwable#printStackTrace()}.
-        * @return This object (for method chaining).
-        */
-       protected RestCallException setServerException(String exceptionName, 
String exceptionMessage, String exceptionTrace) {
-               if (exceptionName != null)
-                       serverExceptionName = exceptionName;
-               if (exceptionMessage != null)
-                       serverExceptionMessage = exceptionMessage;
-               if (exceptionTrace != null)
-                       serverExceptionTrace = exceptionTrace;
-               return this;
-       }
-
-       /**
         * Returns the value of the <js>"Exception-Name"</js> header on the 
response.
         *
         * @return The value of the <js>"Exception-Name"</js> header on the 
response, or <jk>null</jk> if not found.
         */
        public String getServerExceptionName() {
-               return serverExceptionName;
+               return response == null ? null : 
response.getStringHeader("Exception-Name", null);
        }
 
        /**
@@ -137,27 +56,7 @@ public final class RestCallException extends HttpException {
         * @return The value of the <js>"Exception-Message"</js> header on the 
response, or <jk>null</jk> if not found.
         */
        public String getServerExceptionMessage() {
-               return serverExceptionMessage;
-       }
-
-       /**
-        * Returns the value of the <js>"Exception-Trace"</js> header on the 
response.
-        *
-        * @return The value of the <js>"Exception-Trace"</js> header on the 
response, or <jk>null</jk> if not found.
-        */
-       public String getServerExceptionTrace() {
-               return serverExceptionTrace;
-       }
-
-       /**
-        * Sets the HTTP response object that caused this exception.
-        *
-        * @param restResponse The REST response object.
-        * @return This object (for method chaining).
-        */
-       protected RestCallException setRestResponse(RestResponse restResponse) {
-               this.restResponse = restResponse;
-               return this;
+               return response == null ? null : 
response.getStringHeader("Exception-Message", null);
        }
 
        /**
@@ -167,8 +66,8 @@ public final class RestCallException extends HttpException {
         *      The HTTP response object that caused this exception, or 
<jk>null</jk> if no response was created yet when the
         *      exception was thrown.
         */
-       public RestResponse getRestResponse() {
-               return this.restResponse;
+       public RestResponse getResponse() {
+               return this.response;
        }
 
        /**
@@ -177,25 +76,7 @@ public final class RestCallException extends HttpException {
         * @return The response status code.  If a connection could not be made 
at all, returns <c>0</c>.
         */
        public int getResponseCode() {
-               return responseCode;
-       }
-
-       /**
-        * Returns the HTTP response message body text.
-        *
-        * @return The response message body text.
-        */
-       public String getResponseMessage() {
-               return response;
-       }
-
-       /**
-        * Returns the response status message as a plain string.
-        *
-        * @return The response status message.
-        */
-       public String getResponseStatusMessage() {
-               return responseStatusMessage;
+               return response == null ? 0 : response.getStatusCode();
        }
 
        /**
@@ -213,14 +94,6 @@ public final class RestCallException extends HttpException {
        // Helper methods
        
//------------------------------------------------------------------------------------------------------------------
 
-       private static String getMessage(Throwable cause, String msg, String 
def) {
-               if (msg != null)
-                       return clean(msg);
-               if (cause != null)
-                       return clean(cause.getMessage());
-               return def;
-       }
-
        private static String format(String msg, Object...args) {
                if (args.length == 0)
                        return clean(msg);
@@ -229,9 +102,7 @@ public final class RestCallException extends HttpException {
 
        // HttpException has a bug involving ASCII control characters so just 
replace them with spaces.
        private static String clean(String message) {
-
-               if (message == null)
-                       return "";
+               message = emptyIfNull(message);
 
                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/RestCallInterceptor.java
 
b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestCallInterceptor.java
index 17cd144..dbaa1fa 100644
--- 
a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestCallInterceptor.java
+++ 
b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestCallInterceptor.java
@@ -53,7 +53,9 @@ public interface RestCallInterceptor {
         * copied from the client to the request object.
         *
         * @param req The HTTP request object.
-        * @throws Exception Any exception can be thrown.
+        * @throws Exception
+        *      Any exception can be thrown.
+        *      <br>If not a {@link RestCallException} or {@link 
RuntimeException}, will be wrapped in a {@link RestCallException}.
         */
        void onInit(RestRequest req) throws Exception;
 
@@ -62,7 +64,9 @@ public interface RestCallInterceptor {
         *
         * @param req The HTTP request object.
         * @param res The HTTP response object.
-        * @throws Exception Any exception can be thrown.
+        * @throws Exception
+        *      Any exception can be thrown.
+        *      <br>If not a {@link RestCallException} or {@link 
RuntimeException}, will be wrapped in a {@link RestCallException}.
         */
        void onConnect(RestRequest req, RestResponse res) throws Exception;
 
@@ -72,7 +76,9 @@ public interface RestCallInterceptor {
         * @param req The request object.
         * @param res The response object.
         * @throws RestCallException Error occurred during call.
-        * @throws Exception Any exception can be thrown.
+        * @throws Exception
+        *      Any exception can be thrown.
+        *      <br>If not a {@link RestCallException} or {@link 
RuntimeException}, will be wrapped in a {@link RestCallException}.
         */
        void onClose(RestRequest req, RestResponse res) throws Exception;
 }
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 31b7abe..2eb74ce 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
@@ -24,6 +24,7 @@ import java.lang.reflect.*;
 import java.lang.reflect.Proxy;
 import java.net.*;
 import java.net.URI;
+import java.nio.charset.*;
 import java.text.*;
 import java.util.*;
 import java.util.concurrent.*;
@@ -647,12 +648,12 @@ import org.apache.http.client.CookieStore;
  *     <ul>
  *             <li class='jm'><c>{@link RestResponseBody#asInputStream() 
asInputStream()} <jk>returns</jk> InputStream</c>
  *             <li class='jm'><c>{@link RestResponseBody#asReader() 
asReader()} <jk>returns</jk> Reader</c>
- *             <li class='jm'><c>{@link RestResponseBody#asReader(String) 
asReader(String)} <jk>returns</jk> Reader</c>
+ *             <li class='jm'><c>{@link RestResponseBody#asReader(Charset) 
asReader(Charset)} <jk>returns</jk> Reader</c>
  *             <li class='jm'><c>{@link RestResponseBody#pipeTo(OutputStream) 
pipeTo(OutputStream)} <jk>returns</jk> {@link RestResponse}</c>
  *             <li class='jm'><c>{@link RestResponseBody#pipeTo(Writer) 
pipeTo(Writer)} <jk>returns</jk> {@link RestResponse}</c>
- *             <li class='jm'><c>{@link RestResponseBody#pipeTo(Writer,String) 
pipeTo(Writer,String)} <jk>returns</jk> {@link RestResponse}</c>
+ *             <li class='jm'><c>{@link 
RestResponseBody#pipeTo(Writer,Charset) pipeTo(Writer,String)} <jk>returns</jk> 
{@link RestResponse}</c>
  *             <li class='jm'><c>{@link 
RestResponseBody#pipeTo(Writer,boolean) pipeTo(Writer,boolean)} 
<jk>returns</jk> {@link RestResponse}</c>
- *             <li class='jm'><c>{@link 
RestResponseBody#pipeTo(Writer,String,boolean) pipeTo(Writer,String,boolean)} 
<jk>returns</jk> {@link RestResponse}</c>
+ *             <li class='jm'><c>{@link 
RestResponseBody#pipeTo(Writer,Charset,boolean) pipeTo(Writer,String,boolean)} 
<jk>returns</jk> {@link RestResponse}</c>
  *             <li class='jm'><c>{@link RestResponseBody#as(Type,Type...) 
as(Type,Type...)} <jk>returns</jk> T</c>
  *             <li class='jm'><c>{@link 
RestResponseBody#as(Mutable,Type,Type...) as(Mutable&lt;T&gt;,Type,Type...)} 
<jk>returns</jk> {@link RestResponse}</c>
  *             <li class='jm'><c>{@link RestResponseBody#as(Class) 
as(Class&lt;T&gt;)} <jk>returns</jk> T</c>
@@ -2498,7 +2499,7 @@ public class RestClient extends BeanContext implements 
HttpClient, Closeable, Re
                        }
                        return req.body(new SerializedHttpEntity(body, 
urlEncodingSerializer, null, null));
                } catch (IOException e) {
-                       throw new RestCallException(e);
+                       throw new RestCallException(null, e, "Could not read 
form post body.");
                }
        }
 
@@ -2721,7 +2722,7 @@ public class RestClient extends BeanContext implements 
HttpClient, Closeable, Re
                }
 
                if (state != S05)
-                       throw new RestCallException("Invalid format for call 
string.  State=" + state);
+                       throw new RestCallException(null, null, "Invalid format 
for call string.  State={0}", state);
 
                try {
                        RestRequest req = request(method, uri, 
isNotEmpty(content));
@@ -2732,7 +2733,7 @@ public class RestClient extends BeanContext implements 
HttpClient, Closeable, Re
                                req.bodyString(content);
                        return req;
                } catch (ParseException e) {
-                       throw new RestCallException(e, "Invalid format for call 
string.");
+                       throw new RestCallException(null, e, "Invalid format 
for call string.");
                }
        }
 
@@ -2839,9 +2840,9 @@ public class RestClient extends BeanContext implements 
HttpClient, Closeable, Re
                        if (closedStack != null) {
                                e2 = new Exception("Creation stack:");
                                e2.setStackTrace(closedStack);
-                               throw new RestCallException(e2, 
"RestClient.close() has already been called.  This client cannot be reused.");
+                               throw new RestCallException(null, e2, 
"RestClient.close() has already been called.  This client cannot be reused.");
                        }
-                       throw new RestCallException("RestClient.close() has 
already been called.  This client cannot be reused.  Closed location stack 
trace can be displayed by setting the system property 
'org.apache.juneau.rest.client2.RestClient.trackCreation' to true.");
+                       throw new RestCallException(null, null, 
"RestClient.close() has already been called.  This client cannot be reused.  
Closed location stack trace can be displayed by setting the system property 
'org.apache.juneau.rest.client2.RestClient.trackCreation' to true.");
                }
 
                RestRequest req = createRequest(toURI(url, rootUrl), 
method.toUpperCase(Locale.ENGLISH), hasBody);
@@ -3127,7 +3128,7 @@ public class RestClient extends BeanContext implements 
HttpClient, Closeable, Re
                                else if (rt == Boolean.class || rt == 
boolean.class)
                                        ret = returnCode < 400;
                                else
-                                       throw new RestCallException("Invalid 
return type on method annotated with 
@RemoteMethod(returns=RemoteReturn.STATUS).  Only integer and booleans types 
are valid.");
+                                       throw new RestCallException(res, null, 
"Invalid return type on method annotated with 
@RemoteMethod(returns=RemoteReturn.STATUS).  Only integer and booleans types 
are valid.");
                        } else if (rmr.getReturnValue() == RemoteReturn.BEAN) {
                                rc.ignoreErrors();
                                res = rc.run();
@@ -3343,8 +3344,10 @@ public class RestClient extends BeanContext implements 
HttpClient, Closeable, Re
                try {
                        for (RestCallInterceptor rci : interceptors)
                                rci.onInit(req);
+               } catch (RuntimeException | RestCallException e) {
+                       throw e;
                } catch (Exception e) {
-                       throw RestCallException.create(e);
+                       throw new RestCallException(null, e, "Interceptor threw 
an exception on init.");
                }
        }
 
@@ -3369,8 +3372,10 @@ public class RestClient extends BeanContext implements 
HttpClient, Closeable, Re
                try {
                        for (RestCallInterceptor rci : interceptors)
                                rci.onConnect(req, res);
+               } catch (RuntimeException | RestCallException e) {
+                       throw e;
                } catch (Exception e) {
-                       throw RestCallException.create(e);
+                       throw new RestCallException(res, e, "Interceptor threw 
an exception on connect.");
                }
        }
 
@@ -3395,8 +3400,10 @@ public class RestClient extends BeanContext implements 
HttpClient, Closeable, Re
                try {
                        for (RestCallInterceptor rci : interceptors)
                                rci.onClose(req, res);
+               } catch (RuntimeException | RestCallException e) {
+                       throw e;
                } catch (Exception e) {
-                       throw RestCallException.create(e);
+                       throw new RestCallException(res, e, "Interceptor threw 
an exception on close.");
                }
        }
 
@@ -3662,7 +3669,7 @@ public class RestClient extends BeanContext implements 
HttpClient, Closeable, Re
                        s = fixUrl(s);
                        return new URI(s);
                } catch (URISyntaxException e) {
-                       throw new RestCallException(e, "Invalid URL 
encountered:  " + url);  // Shouldn't happen.
+                       throw new RestCallException(null, e, "Invalid URL 
encountered:  {0}", url);  // Shouldn't happen.
                }
        }
 
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 034bf1e..7c71a47 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
@@ -667,8 +667,10 @@ public class RestRequest extends BeanSession implements 
HttpUriRequest, Configur
                                this.interceptors.add(i);
                                i.onInit(this);
                        }
+               } catch (RuntimeException | RestCallException e) {
+                       throw e;
                } catch (Exception e) {
-                       throw RestCallException.create(e);
+                       throw new RestCallException(null, e, "Interceptor threw 
an exception on init.");
                }
 
                return this;
@@ -973,7 +975,7 @@ public class RestRequest extends BeanSession implements 
HttpUriRequest, Configur
                                for (Map.Entry<String,Object> e : 
toBeanMap(o).entrySet())
                                        
innerPath(serializedNameValuePair(e.getKey(), e.getValue(), PATH, 
partSerializer, null, null));
                        } else if (o != null) {
-                               throw new RestCallException("Invalid type 
passed to paths(): " + className(o));
+                               throw new RestCallException(null, null, 
"Invalid type passed to paths(): {0}", className(o));
                        }
                }
                return this;
@@ -1004,7 +1006,7 @@ public class RestRequest extends BeanSession implements 
HttpUriRequest, Configur
         */
        public RestRequest pathPairs(Object...pairs) throws RestCallException {
                if (pairs.length % 2 != 0)
-                       throw new RestCallException("Odd number of parameters 
passed into pathPairs()");
+                       throw new RestCallException(null, null, "Odd number of 
parameters passed into pathPairs()");
                for (int i = 0; i < pairs.length; i+=2)
                        paths(serializedNameValuePair(pairs[i], pairs[i+1], 
PATH, partSerializer, null, null));
                return this;
@@ -1034,7 +1036,7 @@ public class RestRequest extends BeanSession implements 
HttpUriRequest, Configur
                        for (Map.Entry<String,Object> p : 
toBeanMap(value).entrySet())
                                innerPath(serializedNameValuePair(p.getKey(), 
p.getValue(), PATH, serializer, schema, null));
                } else if (value != null) {
-                       throw new RestCallException("Invalid value type for 
path arg ''{0}'': {1}", name, className(value));
+                       throw new RestCallException(null, null, "Invalid value 
type for path arg ''{0}'': {1}", name, className(value));
                }
                return this;
        }
@@ -1044,7 +1046,7 @@ public class RestRequest extends BeanSession implements 
HttpUriRequest, Configur
                String name = param.getName(), value = param.getValue();
                String var = "{" + name + "}";
                if (path.indexOf(var) == -1 && ! name.equals("/*"))
-                       throw new RestCallException("Path variable {"+name+"} 
was not found in path.");
+                       throw new RestCallException(null, null, "Path variable 
{"+name+"} was not found in path.");
                String p = null;
                if (name.equals("/*"))
                        p = path.replaceAll("\\/\\*$", "/" + value);
@@ -1309,7 +1311,7 @@ public class RestRequest extends BeanSession implements 
HttpUriRequest, Configur
                                for (Map.Entry<String,Object> e : 
toBeanMap(o).entrySet())
                                        
l.add(serializedNameValuePair(e.getKey(), e.getValue(), QUERY, partSerializer, 
null, EnumSet.of(flag)));
                        } else if (o != null) {
-                               throw new RestCallException("Invalid type 
passed to queries(): " + className(o));
+                               throw new RestCallException(null, null, 
"Invalid type passed to queries(): {0}", className(o));
                        }
                }
                return innerQuery(EnumSet.of(flag), l);
@@ -1337,7 +1339,7 @@ public class RestRequest extends BeanSession implements 
HttpUriRequest, Configur
         */
        public RestRequest queryPairs(Object...pairs) throws RestCallException {
                if (pairs.length % 2 != 0)
-                       throw new RestCallException("Odd number of parameters 
passed into queryPairs()");
+                       throw new RestCallException(null, null, "Odd number of 
parameters passed into queryPairs()");
                for (int i = 0; i < pairs.length; i+=2)
                        queries(serializedNameValuePair(pairs[i], pairs[i+1], 
QUERY, partSerializer, null, null));
                return this;
@@ -1381,7 +1383,7 @@ public class RestRequest extends BeanSession implements 
HttpUriRequest, Configur
                                q = stringify(value);  // Works for 
NameValuePairs.
                        uriBuilder.setCustomQuery(q);
                } catch (IOException e) {
-                       throw new RestCallException(e);
+                       throw new RestCallException(null, e, "Could not read 
custom query.");
                }
                return this;
        }
@@ -1696,7 +1698,7 @@ public class RestRequest extends BeanSession implements 
HttpUriRequest, Configur
                                for (Map.Entry<String,Object> e : 
toBeanMap(o).entrySet())
                                        
l.add(serializedNameValuePair(e.getKey(), e.getValue(), FORMDATA, 
partSerializer, null, EnumSet.of(flag)));
                        } else if (o != null) {
-                               throw new RestCallException("Invalid type 
passed to formDatas(): " + className(o));
+                               throw new RestCallException(null, null, 
"Invalid type passed to formDatas(): {0}", className(o));
                        }
                }
                return innerFormData(EnumSet.of(flag), l);
@@ -1724,7 +1726,7 @@ public class RestRequest extends BeanSession implements 
HttpUriRequest, Configur
         */
        public RestRequest formDataPairs(Object...pairs) throws 
RestCallException {
                if (pairs.length % 2 != 0)
-                       throw new RestCallException("Odd number of parameters 
passed into formDataPairs()");
+                       throw new RestCallException(null, null, "Odd number of 
parameters passed into formDataPairs()");
                for (int i = 0; i < pairs.length; i+=2)
                        formDatas(serializedNameValuePair(pairs[i], pairs[i+1], 
FORMDATA, partSerializer, null, null));
                return this;
@@ -2207,7 +2209,7 @@ public class RestRequest extends BeanSession implements 
HttpUriRequest, Configur
                                for (Map.Entry<String,Object> e : 
toBeanMap(o).entrySet())
                                        l.add(serializedHeader(e.getKey(), 
e.getValue(), partSerializer, null, EnumSet.of(flag)));
                        } else if (o != null) {
-                               throw new RestCallException("Invalid type 
passed to headers(): " + className(o));
+                               throw new RestCallException(null, null, 
"Invalid type passed to headers(): {0}", className(o));
                        }
                }
                return innerHeaders(EnumSet.of(flag), l);
@@ -2236,7 +2238,7 @@ public class RestRequest extends BeanSession implements 
HttpUriRequest, Configur
        public RestRequest headerPairs(Object...pairs) throws RestCallException 
{
                List<Header> l = new ArrayList<>();
                if (pairs.length % 2 != 0)
-                       throw new RestCallException("Odd number of parameters 
passed into headerPairs()");
+                       throw new RestCallException(null, null, "Odd number of 
parameters passed into headerPairs()");
                for (int i = 0; i < pairs.length; i+=2)
                        l.add(serializedHeader(pairs[i], pairs[i+1], 
partSerializer, null, null));
                return innerHeaders(EnumSet.of(APPEND), l);
@@ -2269,7 +2271,7 @@ public class RestRequest extends BeanSession implements 
HttpUriRequest, Configur
                        for (Map.Entry<String,Object> e : 
toBeanMap(value).entrySet())
                                l.add(serializedHeader(e.getKey(), 
e.getValue(), serializer, schema, flags));
                } else if (value != null) {
-                       throw new RestCallException("Invalid value type for 
header arg ''{0}'': {1}", name, className(value));
+                       throw new RestCallException(null, null, "Invalid value 
type for header arg ''{0}'': {1}", name, className(value));
                }
 
                return innerHeaders(flags, l);
@@ -2792,7 +2794,7 @@ public class RestRequest extends BeanSession implements 
HttpUriRequest, Configur
         */
        public RestResponse run() throws RestCallException {
                if (response != null)
-                       throw new RestCallException("run() already called.");
+                       throw new RestCallException(response, null, "run() 
already called.");
 
                try {
                        HttpEntityEnclosingRequestBase request2 = request 
instanceof HttpEntityEnclosingRequestBase ? 
(HttpEntityEnclosingRequestBase)request : null;
@@ -2819,7 +2821,7 @@ public class RestRequest extends BeanSession implements 
HttpUriRequest, Configur
                        if (hasInput || formData != null) {
 
                                if (request2 == null)
-                                       throw new RestCallException(0, "Method 
does not support content entity.", getMethod(), getURI(), null);
+                                       throw new RestCallException(null, null, 
"Method does not support content entity.  Method={0}, URI={1}", getMethod(), 
getURI());
 
                                Object input2 = input;
 
@@ -2884,15 +2886,18 @@ public class RestRequest extends BeanSession implements 
HttpUriRequest, Configur
                        int sc = response.getStatusCode();
 
                        if (errorCodes.test(sc) && ! ignoreErrors) {
-                               throw new RestCallException(sc, 
response.getReasonPhrase(), method, getURI(), 
response.getBody().asAbbreviatedString(1000))
-                                       
.setServerException(response.getStringHeader("Exception-Name"), 
response.getStringHeader("Exception-Message"), 
response.getStringHeader("Exception-Trace"))
-                                       .setRestResponse(response);
+                               throw new RestCallException(response, null, 
"HTTP method ''{0}'' call to ''{1}'' caused response code ''{2}, 
{3}''.\nResponse: \n{4}",
+                                       method, getURI(), sc, 
response.getReasonPhrase(), response.getBody().asAbbreviatedString(1000));
                        }
 
+               } catch (RuntimeException | RestCallException e) {
+                       if (response != null)
+                               response.close();
+                       throw e;
                } catch (Exception e) {
                        if (response != null)
                                response.close();
-                       throw 
RestCallException.create(e).setRestResponse(response);
+                       throw new RestCallException(response, e, "Call 
failed.");
                }
 
                return 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 d449953..40a55d4 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
@@ -1036,8 +1036,10 @@ public class RestResponse implements HttpResponse {
                for (RestCallInterceptor r : request.interceptors) {
                        try {
                                r.onClose(request, this);
+                       } catch (RuntimeException | RestCallException e) {
+                               throw e;
                        } catch (Exception e) {
-                               throw RestCallException.create(e);
+                               throw new RestCallException(this, e, 
"Interceptor throw exception on close");
                        }
                }
                client.onClose(request, this);
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 4218c62..b6041a3 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
@@ -345,7 +345,7 @@ public class RestResponseBody implements HttpEntity {
                        try {
                                cache = IOUtils.readBytes(entity.getContent());
                        } catch (IOException e) {
-                               throw new RestCallException(e);
+                               throw new RestCallException(response, e, "Could 
not read response body.");
                        } finally {
                                response.close();
                        }
@@ -841,7 +841,7 @@ public class RestResponseBody implements HttpEntity {
 
                } catch (ParseException | IOException e) {
                        response.close();
-                       throw new RestCallException(e);
+                       throw new RestCallException(response, e, "Could not 
parse response body.");
                }
        }
 
@@ -1105,7 +1105,7 @@ public class RestResponseBody implements HttpEntity {
                        return read(r).toString();
                } catch (IOException e) {
                        response.close();
-                       throw new RestCallException(e);
+                       throw new RestCallException(response, e, "Could not 
read response body.");
                }
        }
 
diff --git 
a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestResponseHeader.java
 
b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestResponseHeader.java
index 5486d80..e7889a5 100644
--- 
a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestResponseHeader.java
+++ 
b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestResponseHeader.java
@@ -338,7 +338,7 @@ public class RestResponseHeader implements Header {
                try {
                        return parser.parse(HEADER, schema, asString(), type);
                } catch (ParseException e) {
-                       throw new RestCallException(e);
+                       throw new RestCallException(response, e, "Could not 
parse response header {0}.", getName());
                }
        }
 

Reply via email to