Respect MediaType charset in Jackson converters
Before this commit, AbstractJackson2HttpMessageConverter and subclasses did not check media type encoding in the canRead and canWrite methods. As a result, the converter reported that it can write (for instance) "application/json;charset=ISO-8859-1", but in practice wrote the default charset (UTF-8). This commit fixes that bug. See: gh-25076
This commit is contained in:
@@ -21,7 +21,11 @@ import java.lang.reflect.Type;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonEncoding;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
@@ -68,6 +72,8 @@ import org.springframework.util.TypeUtils;
|
||||
*/
|
||||
public abstract class AbstractJackson2HttpMessageConverter extends AbstractGenericHttpMessageConverter<Object> {
|
||||
|
||||
private static final Map<String, JsonEncoding> ENCODINGS = jsonEncodings();
|
||||
|
||||
/**
|
||||
* The default charset used by the converter.
|
||||
*/
|
||||
@@ -167,6 +173,14 @@ public abstract class AbstractJackson2HttpMessageConverter extends AbstractGener
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canRead(@Nullable MediaType mediaType) {
|
||||
if (!super.canRead(mediaType)) {
|
||||
return false;
|
||||
}
|
||||
return checkEncoding(mediaType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType) {
|
||||
if (!canWrite(mediaType)) {
|
||||
@@ -180,6 +194,14 @@ public abstract class AbstractJackson2HttpMessageConverter extends AbstractGener
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canWrite(@Nullable MediaType mediaType) {
|
||||
if (!super.canWrite(mediaType)) {
|
||||
return false;
|
||||
}
|
||||
return checkEncoding(mediaType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether to log the given exception coming from a
|
||||
* {@link ObjectMapper#canDeserialize} / {@link ObjectMapper#canSerialize} check.
|
||||
@@ -211,6 +233,14 @@ public abstract class AbstractJackson2HttpMessageConverter extends AbstractGener
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkEncoding(@Nullable MediaType mediaType) {
|
||||
if (mediaType != null && mediaType.getCharset() != null) {
|
||||
Charset charset = mediaType.getCharset();
|
||||
return ENCODINGS.containsKey(charset.name());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object readInternal(Class<?> clazz, HttpInputMessage inputMessage)
|
||||
throws IOException, HttpMessageNotReadableException {
|
||||
@@ -333,10 +363,9 @@ public abstract class AbstractJackson2HttpMessageConverter extends AbstractGener
|
||||
protected JsonEncoding getJsonEncoding(@Nullable MediaType contentType) {
|
||||
if (contentType != null && contentType.getCharset() != null) {
|
||||
Charset charset = contentType.getCharset();
|
||||
for (JsonEncoding encoding : JsonEncoding.values()) {
|
||||
if (charset.name().equals(encoding.getJavaName())) {
|
||||
return encoding;
|
||||
}
|
||||
JsonEncoding encoding = ENCODINGS.get(charset.name());
|
||||
if (encoding != null) {
|
||||
return encoding;
|
||||
}
|
||||
}
|
||||
return JsonEncoding.UTF8;
|
||||
@@ -359,4 +388,9 @@ public abstract class AbstractJackson2HttpMessageConverter extends AbstractGener
|
||||
return super.getContentLength(object, contentType);
|
||||
}
|
||||
|
||||
private static Map<String, JsonEncoding> jsonEncodings() {
|
||||
return EnumSet.allOf(JsonEncoding.class).stream()
|
||||
.collect(Collectors.toMap(JsonEncoding::getJavaName, Function.identity()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user