Skip to content

Commit b79d6fc

Browse files
Use charset from response Content-Type header to decode (OpenFeign#1302)
* If charset is set in Content-type, we decode response using that charset * Java 8 compatibility * Format fix * Moving code to get charset to Response in order to be used by another decoders
1 parent 4cf1a54 commit b79d6fc

3 files changed

Lines changed: 53 additions & 5 deletions

File tree

core/src/main/java/feign/Response.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,25 @@ public Request request() {
175175
return request;
176176
}
177177

178+
public Charset charset() {
179+
180+
Collection<String> contentTypeHeaders = headers().get("Content-Type");
181+
182+
if (contentTypeHeaders != null) {
183+
for (String contentTypeHeader : contentTypeHeaders) {
184+
String[] contentTypeParmeters = contentTypeHeader.split(";");
185+
if (contentTypeParmeters.length > 1) {
186+
String[] charsetParts = contentTypeParmeters[1].split("=");
187+
if (charsetParts.length == 2 && "charset".equalsIgnoreCase(charsetParts[0].trim())) {
188+
return Charset.forName(charsetParts[1]);
189+
}
190+
}
191+
}
192+
}
193+
194+
return Util.UTF_8;
195+
}
196+
178197
@Override
179198
public String toString() {
180199
StringBuilder builder = new StringBuilder("HTTP/1.1 ").append(status);

jackson/src/main/java/feign/jackson/JacksonDecoder.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,17 @@
1313
*/
1414
package feign.jackson;
1515

16-
import com.fasterxml.jackson.databind.DeserializationFeature;
17-
import com.fasterxml.jackson.databind.Module;
18-
import com.fasterxml.jackson.databind.ObjectMapper;
19-
import com.fasterxml.jackson.databind.RuntimeJsonMappingException;
2016
import java.io.BufferedReader;
2117
import java.io.IOException;
2218
import java.io.Reader;
2319
import java.lang.reflect.Type;
20+
import java.nio.charset.Charset;
21+
import java.util.Collection;
2422
import java.util.Collections;
23+
import com.fasterxml.jackson.databind.DeserializationFeature;
24+
import com.fasterxml.jackson.databind.Module;
25+
import com.fasterxml.jackson.databind.ObjectMapper;
26+
import com.fasterxml.jackson.databind.RuntimeJsonMappingException;
2527
import feign.Response;
2628
import feign.Util;
2729
import feign.codec.Decoder;
@@ -47,7 +49,7 @@ public JacksonDecoder(ObjectMapper mapper) {
4749
public Object decode(Response response, Type type) throws IOException {
4850
if (response.body() == null)
4951
return null;
50-
Reader reader = response.body().asReader(Util.UTF_8);
52+
Reader reader = response.body().asReader(response.charset());
5153
if (!reader.markSupported()) {
5254
reader = new BufferedReader(reader, 1);
5355
}
@@ -66,4 +68,5 @@ public Object decode(Response response, Type type) throws IOException {
6668
throw e;
6769
}
6870
}
71+
6972
}

jackson/src/test/java/feign/jackson/JacksonCodecTest.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,12 @@
2828
import org.junit.Test;
2929
import java.io.Closeable;
3030
import java.io.IOException;
31+
import java.nio.charset.StandardCharsets;
3132
import java.util.ArrayList;
3233
import java.util.Arrays;
34+
import java.util.Collection;
3335
import java.util.Collections;
36+
import java.util.HashMap;
3437
import java.util.Iterator;
3538
import java.util.LinkedHashMap;
3639
import java.util.LinkedList;
@@ -169,6 +172,29 @@ public void customEncoder() {
169172
+ "} ]");
170173
}
171174

175+
@Test
176+
public void decoderCharset() throws IOException {
177+
Zone zone = new Zone("denominator.io.", "ÁÉÍÓÚÀÈÌÒÙÄËÏÖÜÑ");
178+
179+
Map<String, Collection<String>> headers = new HashMap<String, Collection<String>>();
180+
headers.put("Content-Type", Arrays.asList("application/json;charset=ISO-8859-1"));
181+
182+
Response response = Response.builder()
183+
.status(200)
184+
.reason("OK")
185+
.request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8))
186+
.headers(headers)
187+
.body(new String("" //
188+
+ "{" + System.lineSeparator()
189+
+ " \"name\" : \"DENOMINATOR.IO.\"," + System.lineSeparator()
190+
+ " \"id\" : \"ÁÉÍÓÚÀÈÌÒÙÄËÏÖÜÑ\"" + System.lineSeparator()
191+
+ "}").getBytes(StandardCharsets.ISO_8859_1))
192+
.build();
193+
assertEquals(zone.get("id"),
194+
((Zone) new JacksonDecoder().decode(response, new TypeReference<Zone>() {}.getType()))
195+
.get("id"));
196+
}
197+
172198
@Test
173199
public void decodesIterator() throws Exception {
174200
List<Zone> zones = new LinkedList<Zone>();

0 commit comments

Comments
 (0)