diff --git a/core/src/main/java/feign/FeignException.java b/core/src/main/java/feign/FeignException.java index c158aeb2..9d471410 100644 --- a/core/src/main/java/feign/FeignException.java +++ b/core/src/main/java/feign/FeignException.java @@ -19,8 +19,6 @@ import static java.lang.String.format; import java.io.IOException; -import feign.codec.StringDecoder; - /** * Origin exception type for all Http Apis. */ @@ -29,14 +27,11 @@ public class FeignException extends RuntimeException { return new FeignException(format("%s %s %s", cause.getMessage(), request.method(), request.url(), 0), cause); } - private static final StringDecoder toString = new StringDecoder(); - public static FeignException errorStatus(String methodKey, Response response) { String message = format("status %s reading %s", response.status(), methodKey); try { if (response.body() != null) { - String body = toString.decode(response, String.class).toString(); - response = Response.create(response.status(), response.reason(), response.headers(), body); + String body = Util.toString(response.body().asReader()); message += "; content:\n" + body; } } catch (IOException ignored) { // NOPMD diff --git a/core/src/main/java/feign/Util.java b/core/src/main/java/feign/Util.java index 289f60f7..412b10f6 100644 --- a/core/src/main/java/feign/Util.java +++ b/core/src/main/java/feign/Util.java @@ -17,10 +17,12 @@ package feign; import java.io.Closeable; import java.io.IOException; +import java.io.Reader; import java.lang.reflect.Array; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.lang.reflect.WildcardType; +import java.nio.CharBuffer; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Collection; @@ -163,4 +165,24 @@ public class Util { } return types[types.length - 1]; } + + private static final int BUF_SIZE = 0x800; // 2K chars (4K bytes) + + public static String toString(Reader reader) throws IOException { + if (reader == null) { + return null; + } + try { + StringBuilder to = new StringBuilder(); + CharBuffer buf = CharBuffer.allocate(BUF_SIZE); + while (reader.read(buf) != -1) { + buf.flip(); + to.append(buf); + buf.clear(); + } + return to.toString(); + } finally { + ensureClosed(reader); + } + } } diff --git a/core/src/main/java/feign/codec/Decoder.java b/core/src/main/java/feign/codec/Decoder.java index 1a7865ca..54f078fc 100644 --- a/core/src/main/java/feign/codec/Decoder.java +++ b/core/src/main/java/feign/codec/Decoder.java @@ -17,6 +17,7 @@ package feign.codec; import feign.FeignException; import feign.Response; +import feign.Util; import java.io.IOException; import java.lang.reflect.Type; @@ -74,16 +75,18 @@ public interface Decoder { * signatures. */ public class Default implements Decoder { - private final StringDecoder stringDecoder = new StringDecoder(); - @Override public Object decode(Response response, Type type) throws IOException { if (Response.class.equals(type)) { - return response; - } else if (String.class.equals(type)) { - return stringDecoder.decode(response, type); + String bodyString = null; + if (response.body() != null) { + bodyString = Util.toString(response.body().asReader()); + } + return Response.create(response.status(), response.reason(), response.headers(), bodyString); } else if (void.class.equals(type) || response.body() == null) { return null; + } else if (String.class.equals(type)) { + return Util.toString(response.body().asReader()); } throw new DecodeException(format("%s is not a type supported by this decoder.", type)); } diff --git a/core/src/main/java/feign/codec/StringDecoder.java b/core/src/main/java/feign/codec/StringDecoder.java index 93f66eac..03c1b1d3 100644 --- a/core/src/main/java/feign/codec/StringDecoder.java +++ b/core/src/main/java/feign/codec/StringDecoder.java @@ -16,38 +16,21 @@ package feign.codec; import feign.Response; +import feign.Util; import java.io.IOException; -import java.io.Reader; import java.lang.reflect.Type; -import java.nio.CharBuffer; - -import static feign.Util.ensureClosed; /** * Adapted from {@code com.google.common.io.CharStreams.toString()}. */ public class StringDecoder implements Decoder { - private static final int BUF_SIZE = 0x800; // 2K chars (4K bytes) - @Override public Object decode(Response response, Type type) throws IOException { Response.Body body = response.body(); if (body == null) { return null; } - Reader from = body.asReader(); - try { - StringBuilder to = new StringBuilder(); - CharBuffer buf = CharBuffer.allocate(BUF_SIZE); - while (from.read(buf) != -1) { - buf.flip(); - to.append(buf); - buf.clear(); - } - return to.toString(); - } finally { - ensureClosed(from); - } + return Util.toString(body.asReader()); } } diff --git a/core/src/test/java/feign/codec/DefaultDecoderTest.java b/core/src/test/java/feign/codec/DefaultDecoderTest.java index d02f8a24..9442d760 100644 --- a/core/src/test/java/feign/codec/DefaultDecoderTest.java +++ b/core/src/test/java/feign/codec/DefaultDecoderTest.java @@ -15,11 +15,12 @@ */ package feign.codec; -import feign.FeignException; import feign.Response; +import feign.Util; import org.testng.annotations.Test; import org.w3c.dom.Document; +import java.io.StringReader; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -38,19 +39,19 @@ public class DefaultDecoderTest { @Test public void testDecodesToResponse() throws Exception { Response response = knownResponse(); Object decodedObject = decoder.decode(response, Response.class); - assertEquals(decodedObject.getClass(), Response.class, ""); + assertEquals(decodedObject.getClass(), Response.class); Response decodedResponse = (Response) decodedObject; assertEquals(decodedResponse.status(), response.status()); assertEquals(decodedResponse.reason(), response.reason()); assertEquals(decodedResponse.headers(), response.headers()); - assertEquals(decodedResponse.body().toString(), response.body().toString()); + assertEquals(Util.toString(decodedResponse.body().asReader()), "response body"); } @Test public void testDecodesToString() throws Exception { Response response = knownResponse(); Object decodedObject = decoder.decode(response, String.class); assertEquals(decodedObject.getClass(), String.class); - assertEquals(decodedObject.toString(), response.body().toString()); + assertEquals(decodedObject.toString(), "response body"); } @Test public void testDecodesNullBodyToNull() throws Exception { @@ -63,9 +64,11 @@ public class DefaultDecoderTest { } private Response knownResponse() { + String content = "response body"; + StringReader reader = new StringReader(content); Map> headers = new HashMap>(); headers.put("Content-Type", Collections.singleton("text/plain")); - return Response.create(200, "OK", headers, "response body"); + return Response.create(200, "OK", headers, reader, content.length()); } private Response nullBodyResponse() {