Skip to content

Commit

Permalink
Respect MimeType charset in Jackson codecs
Browse files Browse the repository at this point in the history
Before this commit, Jackson2CodecSupport and subclasses
did not check media type encoding in the supportsMimeType
method (called from canEncode/canDecode).
As a result, the encoder 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.

Closes: gh-25076
  • Loading branch information
poutsma committed Jun 5, 2020
1 parent d9c9880 commit f81b1de
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 2 deletions.
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -19,12 +19,18 @@
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

import com.fasterxml.jackson.annotation.JsonView;
import com.fasterxml.jackson.core.JsonEncoding;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.TypeFactory;
Expand Down Expand Up @@ -64,6 +70,9 @@ public abstract class Jackson2CodecSupport {
new MimeType("application", "json", StandardCharsets.UTF_8),
new MimeType("application", "*+json", StandardCharsets.UTF_8)));

private static final Map<String, JsonEncoding> ENCODINGS = jsonEncodings();



protected final Log logger = HttpLogging.forLogName(getClass());

Expand Down Expand Up @@ -96,7 +105,17 @@ protected List<MimeType> getMimeTypes() {


protected boolean supportsMimeType(@Nullable MimeType mimeType) {
return (mimeType == null || this.mimeTypes.stream().anyMatch(m -> m.isCompatibleWith(mimeType)));
if (mimeType == null) {
return true;
}
else if (this.mimeTypes.stream().noneMatch(m -> m.isCompatibleWith(mimeType))) {
return false;
}
else if (mimeType.getCharset() != null) {
Charset charset = mimeType.getCharset();
return ENCODINGS.containsKey(charset.name());
}
return true;
}

protected JavaType getJavaType(Type type, @Nullable Class<?> contextClass) {
Expand Down Expand Up @@ -125,4 +144,10 @@ protected MethodParameter getParameter(ResolvableType type) {
@Nullable
protected abstract <A extends Annotation> A getAnnotation(MethodParameter parameter, Class<A> annotType);

private static Map<String, JsonEncoding> jsonEncodings() {
return EnumSet.allOf(JsonEncoding.class).stream()
.collect(Collectors.toMap(JsonEncoding::getJavaName, Function.identity()));
}


}
Expand Up @@ -89,6 +89,11 @@ public void canDecode() {

assertFalse(decoder.canDecode(forClass(String.class), null));
assertFalse(decoder.canDecode(forClass(Pojo.class), APPLICATION_XML));
assertTrue(this.decoder.canDecode(forClass(Pojo.class),
new MediaType("application", "json", StandardCharsets.UTF_8)));
assertFalse(this.decoder.canDecode(forClass(Pojo.class),
new MediaType("application", "json", StandardCharsets.ISO_8859_1)));

}

@Test // SPR-15866
Expand Down
Expand Up @@ -71,6 +71,11 @@ public void canEncode() {
assertTrue(this.encoder.canEncode(pojoType, APPLICATION_STREAM_JSON));
assertTrue(this.encoder.canEncode(pojoType, null));

assertTrue(this.encoder.canEncode(ResolvableType.forClass(Pojo.class),
new MediaType("application", "json", StandardCharsets.UTF_8)));
assertFalse(this.encoder.canEncode(ResolvableType.forClass(Pojo.class),
new MediaType("application", "json", StandardCharsets.ISO_8859_1)));

// SPR-15464
assertTrue(this.encoder.canEncode(ResolvableType.NONE, null));

Expand Down
Expand Up @@ -16,6 +16,7 @@

package org.springframework.http.codec.json;

import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;

Expand Down Expand Up @@ -64,8 +65,14 @@ public void canDecode() {

assertFalse(decoder.canDecode(forClass(String.class), null));
assertFalse(decoder.canDecode(forClass(Pojo.class), APPLICATION_JSON));

assertTrue(this.decoder.canDecode(ResolvableType.forClass(Pojo.class),
new MimeType("application", "x-jackson-smile", StandardCharsets.UTF_8)));
assertFalse(this.decoder.canDecode(ResolvableType.forClass(Pojo.class),
new MimeType("application", "x-jackson-smile", StandardCharsets.ISO_8859_1)));
}


@Override
public void decode() {
Flux<DataBuffer> input = Flux.just(this.pojo1, this.pojo2)
Expand Down
Expand Up @@ -18,6 +18,7 @@

import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;

Expand Down Expand Up @@ -70,6 +71,11 @@ public void canEncode() {
assertTrue(this.encoder.canEncode(pojoType, STREAM_SMILE_MIME_TYPE));
assertTrue(this.encoder.canEncode(pojoType, null));

assertTrue(this.encoder.canEncode(ResolvableType.forClass(Pojo.class),
new MimeType("application", "x-jackson-smile", StandardCharsets.UTF_8)));
assertFalse(this.encoder.canEncode(ResolvableType.forClass(Pojo.class),
new MimeType("application", "x-jackson-smile", StandardCharsets.ISO_8859_1)));

// SPR-15464
assertTrue(this.encoder.canEncode(ResolvableType.NONE, null));
}
Expand Down

0 comments on commit f81b1de

Please sign in to comment.