Skip to content

Commit 7386ebc

Browse files
authored
Optimize DialogueFeignClient small response reader (#3114)
Avoid `InputStreamReader` / `HeapByteBuffer` overhead for small (less than 8KiB) inputs, see FasterXML/jackson-core#1081 and FasterXML/jackson-benchmarks#9 (comment) for benchmarks showing between 2x and 10x speedup handling deserialization of small values.
1 parent 1537545 commit 7386ebc

File tree

1 file changed

+29
-7
lines changed

1 file changed

+29
-7
lines changed

conjure-java-jaxrs-client/src/main/java/com/palantir/conjure/java/client/jaxrs/DialogueFeignClient.java

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@
5050
import java.io.InputStreamReader;
5151
import java.io.OutputStream;
5252
import java.io.Reader;
53-
import java.io.UnsupportedEncodingException;
53+
import java.io.SequenceInputStream;
54+
import java.io.StringReader;
5455
import java.net.URLDecoder;
5556
import java.nio.charset.StandardCharsets;
5657
import java.util.Collection;
@@ -143,11 +144,7 @@ private static boolean includeRequestHeader(String headerName) {
143144
}
144145

145146
private static String urlDecode(String input) {
146-
try {
147-
return URLDecoder.decode(input, "UTF-8");
148-
} catch (UnsupportedEncodingException e) {
149-
throw new SafeUncheckedIoException("Failed to decode path segment", e, UnsafeArg.of("encoded", input));
150-
}
147+
return URLDecoder.decode(input, StandardCharsets.UTF_8);
151148
}
152149

153150
private static Optional<RequestBody> requestBody(Request request) {
@@ -239,7 +236,32 @@ public InputStream asInputStream() {
239236

240237
@Override
241238
public Reader asReader() {
242-
return new InputStreamReader(asInputStream(), StandardCharsets.UTF_8);
239+
InputStream inputStream = asInputStream();
240+
Integer maybeLength = length();
241+
if (maybeLength != null) {
242+
int length = maybeLength;
243+
if (length < 8192) {
244+
// Avoid InputStreamReader / HeapByteBuffer overhead for small (less than 8KiB) inputs,
245+
// see https://github.com/FasterXML/jackson-core/pull/1081
246+
// try to read an extra byte to determine if more bytes were provided than actual content-length
247+
int toRead = length + 1;
248+
byte[] bytes = new byte[toRead];
249+
try {
250+
int read = inputStream.readNBytes(bytes, 0, toRead);
251+
if (read <= length) {
252+
// fully read input
253+
inputStream.close();
254+
return new StringReader(new String(bytes, 0, read, StandardCharsets.UTF_8));
255+
}
256+
// input was larger than provided content length, fallback to stream path
257+
inputStream = new SequenceInputStream(new ByteArrayInputStream(bytes), inputStream);
258+
} catch (IOException e) {
259+
throw new SafeUncheckedIoException(
260+
"Failed to read response body", e, SafeArg.of("length", maybeLength));
261+
}
262+
}
263+
}
264+
return new InputStreamReader(inputStream, StandardCharsets.UTF_8);
243265
}
244266

245267
@Override

0 commit comments

Comments
 (0)