diff --git a/gson/src/main/java/feign/gson/GsonDecoder.java b/gson/src/main/java/feign/gson/GsonDecoder.java index 699c1d48ca..5fa6ee0369 100644 --- a/gson/src/main/java/feign/gson/GsonDecoder.java +++ b/gson/src/main/java/feign/gson/GsonDecoder.java @@ -15,7 +15,6 @@ */ package feign.gson; -import static feign.Util.UTF_8; import static feign.Util.ensureClosed; import com.google.gson.Gson; @@ -50,7 +49,7 @@ public GsonDecoder(Gson gson) { public Object decode(Response response, Type type) throws IOException { if (response.status() == 404 || response.status() == 204) return Util.emptyValueOf(type); if (response.body() == null) return null; - Reader reader = response.body().asReader(UTF_8); + Reader reader = response.body().asReader(response.charset()); try { return gson.fromJson(reader, type); } catch (JsonIOException e) { diff --git a/gson/src/test/java/feign/gson/GsonCodecTest.java b/gson/src/test/java/feign/gson/GsonCodecTest.java index 1ec47b8918..514c703995 100644 --- a/gson/src/test/java/feign/gson/GsonCodecTest.java +++ b/gson/src/test/java/feign/gson/GsonCodecTest.java @@ -29,7 +29,9 @@ import feign.Response; import feign.Util; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.LinkedHashMap; import java.util.LinkedList; @@ -76,6 +78,28 @@ void decodesMapObjectNumericalValuesAsInteger() throws Exception { new GsonDecoder().decode(response, new TypeToken>() {}.getType())); } + @Test + void decodesUsingResponseCharset() throws Exception { + Map expected = new LinkedHashMap<>(); + expected.put("name", "ÁÉÍÓÚ"); + + Map> headers = new LinkedHashMap<>(); + headers.put("Content-Type", Arrays.asList("application/json;charset=ISO-8859-1")); + + Response response = + Response.builder() + .status(200) + .reason("OK") + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .headers(headers) + .body("{\"name\":\"ÁÉÍÓÚ\"}".getBytes(StandardCharsets.ISO_8859_1)) + .build(); + assertThat(expected) + .isEqualTo( + new GsonDecoder().decode(response, new TypeToken>() {}.getType())); + } + @Test void encodesFormParams() { diff --git a/jackson/src/main/java/feign/jackson/JacksonIteratorDecoder.java b/jackson/src/main/java/feign/jackson/JacksonIteratorDecoder.java index 8474ddcec3..f65ba2ed19 100644 --- a/jackson/src/main/java/feign/jackson/JacksonIteratorDecoder.java +++ b/jackson/src/main/java/feign/jackson/JacksonIteratorDecoder.java @@ -15,7 +15,6 @@ */ package feign.jackson; -import static feign.Util.UTF_8; import static feign.Util.ensureClosed; import com.fasterxml.jackson.core.JsonParser; @@ -72,7 +71,7 @@ public final class JacksonIteratorDecoder implements Decoder { public Object decode(Response response, Type type) throws IOException { if (response.status() == 404 || response.status() == 204) return Util.emptyValueOf(type); if (response.body() == null) return null; - Reader reader = response.body().asReader(UTF_8); + Reader reader = response.body().asReader(response.charset()); if (!reader.markSupported()) { reader = new BufferedReader(reader, 1); } diff --git a/jackson/src/test/java/feign/jackson/JacksonIteratorTest.java b/jackson/src/test/java/feign/jackson/JacksonIteratorTest.java index 48bc1be058..c57d49ae69 100644 --- a/jackson/src/test/java/feign/jackson/JacksonIteratorTest.java +++ b/jackson/src/test/java/feign/jackson/JacksonIteratorTest.java @@ -21,6 +21,7 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType; import static org.junit.jupiter.api.Assertions.assertThrows; +import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import feign.Request; import feign.Request.HttpMethod; @@ -31,8 +32,16 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; import java.util.NoSuchElementException; import java.util.concurrent.atomic.AtomicBoolean; import org.junit.jupiter.api.Test; @@ -163,6 +172,29 @@ public void close() throws IOException { assertThat(closed.get()).isTrue(); } + @Test + void decodeUsesResponseCharset() throws IOException { + Map> headers = new HashMap<>(); + headers.put("Content-Type", Arrays.asList("application/json;charset=ISO-8859-1")); + + Response response = + Response.builder() + .status(200) + .reason("OK") + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .headers(headers) + .body("[{\"login\":\"ÁÉÍÓÚ\"}]".getBytes(StandardCharsets.ISO_8859_1)) + .build(); + Object decoded = + JacksonIteratorDecoder.create() + .decode(response, new TypeReference>() {}.getType()); + List users = new ArrayList<>(); + ((Iterator) decoded).forEachRemaining(users::add); + assertThat(users).hasSize(1); + assertThat((User) users.get(0)).containsEntry("login", "ÁÉÍÓÚ"); + } + static class User extends LinkedHashMap { private static final long serialVersionUID = 1L; diff --git a/jackson3/src/main/java/feign/jackson3/Jackson3IteratorDecoder.java b/jackson3/src/main/java/feign/jackson3/Jackson3IteratorDecoder.java index 9ba52fa593..53c0c0bfe0 100644 --- a/jackson3/src/main/java/feign/jackson3/Jackson3IteratorDecoder.java +++ b/jackson3/src/main/java/feign/jackson3/Jackson3IteratorDecoder.java @@ -15,7 +15,6 @@ */ package feign.jackson3; -import static feign.Util.UTF_8; import static feign.Util.ensureClosed; import feign.Response; @@ -75,7 +74,7 @@ public final class Jackson3IteratorDecoder implements Decoder { public Object decode(Response response, Type type) throws IOException { if (response.status() == 404 || response.status() == 204) return Util.emptyValueOf(type); if (response.body() == null) return null; - Reader reader = response.body().asReader(UTF_8); + Reader reader = response.body().asReader(response.charset()); if (!reader.markSupported()) { reader = new BufferedReader(reader, 1); } diff --git a/jackson3/src/test/java/feign/jackson3/Jackson3CodecTest.java b/jackson3/src/test/java/feign/jackson3/Jackson3CodecTest.java index d91683033c..525245e5d4 100644 --- a/jackson3/src/test/java/feign/jackson3/Jackson3CodecTest.java +++ b/jackson3/src/test/java/feign/jackson3/Jackson3CodecTest.java @@ -264,6 +264,38 @@ void decodesIterator() throws Exception { assertThat(asList((Iterator) decoded)).isEqualTo(zones); } + @Test + void decodesIteratorUsingResponseCharset() throws Exception { + Map> headers = new HashMap<>(); + headers.put("Content-Type", Arrays.asList("application/json;charset=ISO-8859-1")); + + Response response = + Response.builder() + .status(200) + .reason("OK") + .request( + Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8)) + .headers(headers) + .body( + new String( + "" // + + "[ {" + + System.lineSeparator() + + " \"name\" : \"denominator.io.\"," + + System.lineSeparator() + + " \"id\" : \"ÁÉÍÓÚÀÈÌÒÙÄËÏÖÜÑ\"" + + System.lineSeparator() + + "} ]") + .getBytes(StandardCharsets.ISO_8859_1)) + .build(); + Object decoded = + Jackson3IteratorDecoder.create() + .decode(response, new TypeReference>() {}.getType()); + List zones = asList((Iterator) decoded); + assertThat(zones).hasSize(1); + assertThat((Zone) zones.get(0)).containsEntry("id", "ÁÉÍÓÚÀÈÌÒÙÄËÏÖÜÑ"); + } + private List asList(Iterator iter) { final List copy = new ArrayList<>(); while (iter.hasNext()) {