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:
Arjen Poutsma
2020-06-04 17:32:06 +02:00
parent 70a2219fac
commit d9c98801bc
4 changed files with 50 additions and 4 deletions

View File

@@ -22,7 +22,11 @@ import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
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;
@@ -69,6 +73,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()));
}
}