Merge branch '5.2.x'

This commit is contained in:
Arjen Poutsma 2020-06-16 14:30:43 +02:00
commit 97aba77cc1
11 changed files with 113 additions and 100 deletions

View File

@ -69,10 +69,18 @@ public abstract class AbstractJackson2Encoder extends Jackson2CodecSupport imple
private static final Map<MediaType, byte[]> STREAM_SEPARATORS; private static final Map<MediaType, byte[]> STREAM_SEPARATORS;
private static final Map<Charset, JsonEncoding> ENCODINGS;
static { static {
STREAM_SEPARATORS = new HashMap<>(4); STREAM_SEPARATORS = new HashMap<>(4);
STREAM_SEPARATORS.put(MediaType.APPLICATION_STREAM_JSON, NEWLINE_SEPARATOR); STREAM_SEPARATORS.put(MediaType.APPLICATION_STREAM_JSON, NEWLINE_SEPARATOR);
STREAM_SEPARATORS.put(MediaType.parseMediaType("application/stream+x-jackson-smile"), new byte[0]); STREAM_SEPARATORS.put(MediaType.parseMediaType("application/stream+x-jackson-smile"), new byte[0]);
ENCODINGS = new HashMap<>(JsonEncoding.values().length);
for (JsonEncoding encoding : JsonEncoding.values()) {
Charset charset = Charset.forName(encoding.getJavaName());
ENCODINGS.put(charset, encoding);
}
} }
@ -103,7 +111,16 @@ public abstract class AbstractJackson2Encoder extends Jackson2CodecSupport imple
@Override @Override
public boolean canEncode(ResolvableType elementType, @Nullable MimeType mimeType) { public boolean canEncode(ResolvableType elementType, @Nullable MimeType mimeType) {
Class<?> clazz = elementType.toClass(); Class<?> clazz = elementType.toClass();
return supportsMimeType(mimeType) && (Object.class == clazz || if (!supportsMimeType(mimeType)) {
return false;
}
if (mimeType != null && mimeType.getCharset() != null) {
Charset charset = mimeType.getCharset();
if (!ENCODINGS.containsKey(charset)) {
return false;
}
}
return (Object.class == clazz ||
(!String.class.isAssignableFrom(elementType.resolve(clazz)) && getObjectMapper().canSerialize(clazz))); (!String.class.isAssignableFrom(elementType.resolve(clazz)) && getObjectMapper().canSerialize(clazz)));
} }
@ -270,10 +287,9 @@ public abstract class AbstractJackson2Encoder extends Jackson2CodecSupport imple
protected JsonEncoding getJsonEncoding(@Nullable MimeType mimeType) { protected JsonEncoding getJsonEncoding(@Nullable MimeType mimeType) {
if (mimeType != null && mimeType.getCharset() != null) { if (mimeType != null && mimeType.getCharset() != null) {
Charset charset = mimeType.getCharset(); Charset charset = mimeType.getCharset();
for (JsonEncoding encoding : JsonEncoding.values()) { JsonEncoding result = ENCODINGS.get(charset);
if (charset.name().equals(encoding.getJavaName())) { if (result != null) {
return encoding; return result;
}
} }
} }
return JsonEncoding.UTF8; return JsonEncoding.UTF8;

View File

@ -18,18 +18,13 @@ package org.springframework.http.codec.json;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.nio.charset.Charset;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import com.fasterxml.jackson.annotation.JsonView; import com.fasterxml.jackson.annotation.JsonView;
import com.fasterxml.jackson.core.JsonEncoding;
import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.TypeFactory; import com.fasterxml.jackson.databind.type.TypeFactory;
@ -80,9 +75,6 @@ public abstract class Jackson2CodecSupport {
new MimeType("application", "json"), new MimeType("application", "json"),
new MimeType("application", "*+json"))); new MimeType("application", "*+json")));
private static final Map<String, JsonEncoding> ENCODINGS = jsonEncodings();
protected final Log logger = HttpLogging.forLogName(getClass()); protected final Log logger = HttpLogging.forLogName(getClass());
@ -115,17 +107,7 @@ public abstract class Jackson2CodecSupport {
protected boolean supportsMimeType(@Nullable MimeType mimeType) { protected boolean supportsMimeType(@Nullable MimeType mimeType) {
if (mimeType == null) { return (mimeType == null || this.mimeTypes.stream().anyMatch(m -> m.isCompatibleWith(mimeType)));
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) { protected JavaType getJavaType(Type type, @Nullable Class<?> contextClass) {
@ -163,10 +145,4 @@ public abstract class Jackson2CodecSupport {
@Nullable @Nullable
protected abstract <A extends Annotation> A getAnnotation(MethodParameter parameter, Class<A> annotType); 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()));
}
} }

View File

@ -17,8 +17,11 @@
package org.springframework.http.converter.json; package org.springframework.http.converter.json;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.EnumSet; import java.util.EnumSet;
@ -36,6 +39,7 @@ import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectReader;
import com.fasterxml.jackson.databind.ObjectWriter; import com.fasterxml.jackson.databind.ObjectWriter;
import com.fasterxml.jackson.databind.SerializationConfig; import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.SerializationFeature;
@ -72,7 +76,7 @@ import org.springframework.util.TypeUtils;
*/ */
public abstract class AbstractJackson2HttpMessageConverter extends AbstractGenericHttpMessageConverter<Object> { public abstract class AbstractJackson2HttpMessageConverter extends AbstractGenericHttpMessageConverter<Object> {
private static final Map<String, JsonEncoding> ENCODINGS = jsonEncodings(); private static final Map<Charset, JsonEncoding> ENCODINGS = jsonEncodings();
/** /**
* The default charset used by the converter. * The default charset used by the converter.
@ -173,19 +177,17 @@ public abstract class AbstractJackson2HttpMessageConverter extends AbstractGener
return false; return false;
} }
@Override
protected boolean canRead(@Nullable MediaType mediaType) {
if (!super.canRead(mediaType)) {
return false;
}
return checkEncoding(mediaType);
}
@Override @Override
public boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType) { public boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType) {
if (!canWrite(mediaType)) { if (!canWrite(mediaType)) {
return false; return false;
} }
if (mediaType != null && mediaType.getCharset() != null) {
Charset charset = mediaType.getCharset();
if (!ENCODINGS.containsKey(charset)) {
return false;
}
}
AtomicReference<Throwable> causeRef = new AtomicReference<>(); AtomicReference<Throwable> causeRef = new AtomicReference<>();
if (this.objectMapper.canSerialize(clazz, causeRef)) { if (this.objectMapper.canSerialize(clazz, causeRef)) {
return true; return true;
@ -194,14 +196,6 @@ public abstract class AbstractJackson2HttpMessageConverter extends AbstractGener
return false; 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 * Determine whether to log the given exception coming from a
* {@link ObjectMapper#canDeserialize} / {@link ObjectMapper#canSerialize} check. * {@link ObjectMapper#canDeserialize} / {@link ObjectMapper#canSerialize} check.
@ -233,14 +227,6 @@ 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 @Override
protected Object readInternal(Class<?> clazz, HttpInputMessage inputMessage) protected Object readInternal(Class<?> clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException { throws IOException, HttpMessageNotReadableException {
@ -258,15 +244,31 @@ public abstract class AbstractJackson2HttpMessageConverter extends AbstractGener
} }
private Object readJavaType(JavaType javaType, HttpInputMessage inputMessage) throws IOException { private Object readJavaType(JavaType javaType, HttpInputMessage inputMessage) throws IOException {
MediaType contentType = inputMessage.getHeaders().getContentType();
Charset charset = getCharset(contentType);
boolean isUnicode = ENCODINGS.containsKey(charset);
try { try {
if (inputMessage instanceof MappingJacksonInputMessage) { if (inputMessage instanceof MappingJacksonInputMessage) {
Class<?> deserializationView = ((MappingJacksonInputMessage) inputMessage).getDeserializationView(); Class<?> deserializationView = ((MappingJacksonInputMessage) inputMessage).getDeserializationView();
if (deserializationView != null) { if (deserializationView != null) {
return this.objectMapper.readerWithView(deserializationView).forType(javaType). ObjectReader objectReader = this.objectMapper.readerWithView(deserializationView).forType(javaType);
readValue(inputMessage.getBody()); if (isUnicode) {
return objectReader.readValue(inputMessage.getBody());
}
else {
Reader reader = new InputStreamReader(inputMessage.getBody(), charset);
return objectReader.readValue(reader);
}
} }
} }
return this.objectMapper.readValue(inputMessage.getBody(), javaType); if (isUnicode) {
return this.objectMapper.readValue(inputMessage.getBody(), javaType);
}
else {
Reader reader = new InputStreamReader(inputMessage.getBody(), charset);
return this.objectMapper.readValue(reader, javaType);
}
} }
catch (InvalidDefinitionException ex) { catch (InvalidDefinitionException ex) {
throw new HttpMessageConversionException("Type definition error: " + ex.getType(), ex); throw new HttpMessageConversionException("Type definition error: " + ex.getType(), ex);
@ -276,6 +278,15 @@ public abstract class AbstractJackson2HttpMessageConverter extends AbstractGener
} }
} }
private static Charset getCharset(@Nullable MediaType contentType) {
if (contentType != null && contentType.getCharset() != null) {
return contentType.getCharset();
}
else {
return StandardCharsets.UTF_8;
}
}
@Override @Override
protected void writeInternal(Object object, @Nullable Type type, HttpOutputMessage outputMessage) protected void writeInternal(Object object, @Nullable Type type, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException { throws IOException, HttpMessageNotWritableException {
@ -363,7 +374,7 @@ public abstract class AbstractJackson2HttpMessageConverter extends AbstractGener
protected JsonEncoding getJsonEncoding(@Nullable MediaType contentType) { protected JsonEncoding getJsonEncoding(@Nullable MediaType contentType) {
if (contentType != null && contentType.getCharset() != null) { if (contentType != null && contentType.getCharset() != null) {
Charset charset = contentType.getCharset(); Charset charset = contentType.getCharset();
JsonEncoding encoding = ENCODINGS.get(charset.name()); JsonEncoding encoding = ENCODINGS.get(charset);
if (encoding != null) { if (encoding != null) {
return encoding; return encoding;
} }
@ -388,9 +399,9 @@ public abstract class AbstractJackson2HttpMessageConverter extends AbstractGener
return super.getContentLength(object, contentType); return super.getContentLength(object, contentType);
} }
private static Map<String, JsonEncoding> jsonEncodings() { private static Map<Charset, JsonEncoding> jsonEncodings() {
return EnumSet.allOf(JsonEncoding.class).stream() return EnumSet.allOf(JsonEncoding.class).stream()
.collect(Collectors.toMap(JsonEncoding::getJavaName, Function.identity())); .collect(Collectors.toMap(encoding -> Charset.forName(encoding.getJavaName()), Function.identity()));
} }
} }

View File

@ -16,7 +16,6 @@
package org.springframework.http.codec.cbor; package org.springframework.http.codec.cbor;
import java.nio.charset.StandardCharsets;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@ -28,7 +27,6 @@ import reactor.core.publisher.Flux;
import org.springframework.core.ResolvableType; import org.springframework.core.ResolvableType;
import org.springframework.core.io.buffer.DataBuffer; import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.testfixture.codec.AbstractDecoderTests; import org.springframework.core.testfixture.codec.AbstractDecoderTests;
import org.springframework.http.MediaType;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.util.MimeType; import org.springframework.util.MimeType;
import org.springframework.web.testfixture.xml.Pojo; import org.springframework.web.testfixture.xml.Pojo;
@ -64,11 +62,6 @@ public class Jackson2CborDecoderTests extends AbstractDecoderTests<Jackson2CborD
assertThat(decoder.canDecode(ResolvableType.forClass(String.class), null)).isFalse(); assertThat(decoder.canDecode(ResolvableType.forClass(String.class), null)).isFalse();
assertThat(decoder.canDecode(ResolvableType.forClass(Pojo.class), APPLICATION_JSON)).isFalse(); assertThat(decoder.canDecode(ResolvableType.forClass(Pojo.class), APPLICATION_JSON)).isFalse();
assertThat(this.decoder.canDecode(ResolvableType.forClass(Pojo.class),
new MediaType("application", "cbor", StandardCharsets.UTF_8))).isTrue();
assertThat(this.decoder.canDecode(ResolvableType.forClass(Pojo.class),
new MediaType("application", "cbor", StandardCharsets.ISO_8859_1))).isFalse();
} }
@Override @Override

View File

@ -18,7 +18,6 @@ package org.springframework.http.codec.cbor;
import java.io.IOException; import java.io.IOException;
import java.io.UncheckedIOException; import java.io.UncheckedIOException;
import java.nio.charset.StandardCharsets;
import java.util.function.Consumer; import java.util.function.Consumer;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
@ -29,7 +28,6 @@ import org.springframework.core.ResolvableType;
import org.springframework.core.io.buffer.DataBuffer; import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.testfixture.io.buffer.AbstractLeakCheckingTests; import org.springframework.core.testfixture.io.buffer.AbstractLeakCheckingTests;
import org.springframework.core.testfixture.io.buffer.DataBufferTestUtils; import org.springframework.core.testfixture.io.buffer.DataBufferTestUtils;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerSentEvent; import org.springframework.http.codec.ServerSentEvent;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.util.MimeType; import org.springframework.util.MimeType;
@ -75,12 +73,6 @@ public class Jackson2CborEncoderTests extends AbstractLeakCheckingTests {
// SPR-15464 // SPR-15464
assertThat(this.encoder.canEncode(ResolvableType.NONE, null)).isTrue(); assertThat(this.encoder.canEncode(ResolvableType.NONE, null)).isTrue();
assertThat(this.encoder.canEncode(ResolvableType.forClass(Pojo.class),
new MediaType("application", "cbor", StandardCharsets.UTF_8))).isTrue();
assertThat(this.encoder.canEncode(ResolvableType.forClass(Pojo.class),
new MediaType("application", "cbor", StandardCharsets.ISO_8859_1))).isFalse();
} }
@Test @Test

View File

@ -88,7 +88,7 @@ public class Jackson2JsonDecoderTests extends AbstractDecoderTests<Jackson2JsonD
assertThat(this.decoder.canDecode(ResolvableType.forClass(Pojo.class), assertThat(this.decoder.canDecode(ResolvableType.forClass(Pojo.class),
new MediaType("application", "json", StandardCharsets.UTF_8))).isTrue(); new MediaType("application", "json", StandardCharsets.UTF_8))).isTrue();
assertThat(this.decoder.canDecode(ResolvableType.forClass(Pojo.class), assertThat(this.decoder.canDecode(ResolvableType.forClass(Pojo.class),
new MediaType("application", "json", StandardCharsets.ISO_8859_1))).isFalse(); new MediaType("application", "json", StandardCharsets.ISO_8859_1))).isTrue();
} }
@Test // SPR-15866 @Test // SPR-15866
@ -235,6 +235,21 @@ public class Jackson2JsonDecoderTests extends AbstractDecoderTests<Jackson2JsonD
null); null);
} }
@Test
@SuppressWarnings("unchecked")
public void decodeNonUnicode() {
Flux<DataBuffer> input = Flux.concat(
stringBuffer("{\"føø\":\"bår\"}", StandardCharsets.ISO_8859_1)
);
testDecode(input, ResolvableType.forType(new ParameterizedTypeReference<Map<String, String>>() {
}),
step -> step.assertNext(o -> assertThat((Map<String, String>) o).containsEntry("føø", "bår"))
.verifyComplete(),
MediaType.parseMediaType("application/json; charset=iso-8859-1"),
null);
}
@Test @Test
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public void decodeMonoNonUtf8Encoding() { public void decodeMonoNonUtf8Encoding() {

View File

@ -16,7 +16,6 @@
package org.springframework.http.codec.json; package org.springframework.http.codec.json;
import java.nio.charset.StandardCharsets;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@ -28,7 +27,6 @@ import reactor.core.publisher.Flux;
import org.springframework.core.ResolvableType; import org.springframework.core.ResolvableType;
import org.springframework.core.io.buffer.DataBuffer; import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.testfixture.codec.AbstractDecoderTests; import org.springframework.core.testfixture.codec.AbstractDecoderTests;
import org.springframework.http.MediaType;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.util.MimeType; import org.springframework.util.MimeType;
import org.springframework.web.testfixture.xml.Pojo; import org.springframework.web.testfixture.xml.Pojo;
@ -65,12 +63,6 @@ public class Jackson2SmileDecoderTests extends AbstractDecoderTests<Jackson2Smil
assertThat(decoder.canDecode(ResolvableType.forClass(String.class), null)).isFalse(); assertThat(decoder.canDecode(ResolvableType.forClass(String.class), null)).isFalse();
assertThat(decoder.canDecode(ResolvableType.forClass(Pojo.class), APPLICATION_JSON)).isFalse(); assertThat(decoder.canDecode(ResolvableType.forClass(Pojo.class), APPLICATION_JSON)).isFalse();
assertThat(this.decoder.canDecode(ResolvableType.forClass(Pojo.class),
new MediaType("application", "x-jackson-smile", StandardCharsets.UTF_8))).isTrue();
assertThat(this.decoder.canDecode(ResolvableType.forClass(Pojo.class),
new MediaType("application", "x-jackson-smile", StandardCharsets.ISO_8859_1))).isFalse();
} }
@Override @Override

View File

@ -18,7 +18,6 @@ package org.springframework.http.codec.json;
import java.io.IOException; import java.io.IOException;
import java.io.UncheckedIOException; import java.io.UncheckedIOException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@ -33,7 +32,6 @@ import org.springframework.core.ResolvableType;
import org.springframework.core.io.buffer.DataBuffer; import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils; import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.core.testfixture.codec.AbstractEncoderTests; import org.springframework.core.testfixture.codec.AbstractEncoderTests;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerSentEvent; import org.springframework.http.codec.ServerSentEvent;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.util.MimeType; import org.springframework.util.MimeType;
@ -70,11 +68,6 @@ public class Jackson2SmileEncoderTests extends AbstractEncoderTests<Jackson2Smil
assertThat(this.encoder.canEncode(pojoType, STREAM_SMILE_MIME_TYPE)).isTrue(); assertThat(this.encoder.canEncode(pojoType, STREAM_SMILE_MIME_TYPE)).isTrue();
assertThat(this.encoder.canEncode(pojoType, null)).isTrue(); assertThat(this.encoder.canEncode(pojoType, null)).isTrue();
assertThat(this.encoder.canEncode(ResolvableType.forClass(Pojo.class),
new MediaType("application", "x-jackson-smile", StandardCharsets.UTF_8))).isTrue();
assertThat(this.encoder.canEncode(ResolvableType.forClass(Pojo.class),
new MediaType("application", "x-jackson-smile", StandardCharsets.ISO_8859_1))).isFalse();
// SPR-15464 // SPR-15464
assertThat(this.encoder.canEncode(ResolvableType.NONE, null)).isTrue(); assertThat(this.encoder.canEncode(ResolvableType.NONE, null)).isTrue();
} }

View File

@ -18,6 +18,7 @@ package org.springframework.http.converter.json;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
@ -44,6 +45,7 @@ import org.springframework.lang.Nullable;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.entry;
import static org.assertj.core.api.Assertions.within; import static org.assertj.core.api.Assertions.within;
/** /**
@ -65,7 +67,7 @@ public class MappingJackson2HttpMessageConverterTests {
assertThat(converter.canRead(MyBean.class, new MediaType("application", "json"))).isTrue(); assertThat(converter.canRead(MyBean.class, new MediaType("application", "json"))).isTrue();
assertThat(converter.canRead(Map.class, new MediaType("application", "json"))).isTrue(); assertThat(converter.canRead(Map.class, new MediaType("application", "json"))).isTrue();
assertThat(converter.canRead(MyBean.class, new MediaType("application", "json", StandardCharsets.UTF_8))).isTrue(); assertThat(converter.canRead(MyBean.class, new MediaType("application", "json", StandardCharsets.UTF_8))).isTrue();
assertThat(converter.canRead(MyBean.class, new MediaType("application", "json", StandardCharsets.ISO_8859_1))).isFalse(); assertThat(converter.canRead(MyBean.class, new MediaType("application", "json", StandardCharsets.ISO_8859_1))).isTrue();
} }
@Test @Test
@ -439,13 +441,25 @@ public class MappingJackson2HttpMessageConverterTests {
@Test @Test
public void readWithNoDefaultConstructor() throws Exception { public void readWithNoDefaultConstructor() throws Exception {
String body = "{\"property1\":\"foo\",\"property2\":\"bar\"}"; String body = "{\"property1\":\"foo\",\"property2\":\"bar\"}";
MockHttpInputMessage inputMessage = new MockHttpInputMessage(body.getBytes("UTF-8")); MockHttpInputMessage inputMessage = new MockHttpInputMessage(body.getBytes(StandardCharsets.UTF_8));
inputMessage.getHeaders().setContentType(new MediaType("application", "json")); inputMessage.getHeaders().setContentType(new MediaType("application", "json"));
assertThatExceptionOfType(HttpMessageConversionException.class).isThrownBy(() -> assertThatExceptionOfType(HttpMessageConversionException.class).isThrownBy(() ->
converter.read(BeanWithNoDefaultConstructor.class, inputMessage)) converter.read(BeanWithNoDefaultConstructor.class, inputMessage))
.withMessageStartingWith("Type definition error:"); .withMessageStartingWith("Type definition error:");
} }
@Test
@SuppressWarnings("unchecked")
public void readNonUnicode() throws Exception {
String body = "{\"føø\":\"bår\"}";
Charset charset = StandardCharsets.ISO_8859_1;
MockHttpInputMessage inputMessage = new MockHttpInputMessage(body.getBytes(charset));
inputMessage.getHeaders().setContentType(new MediaType("application", "json", charset));
HashMap<String, Object> result = (HashMap<String, Object>) this.converter.read(HashMap.class, inputMessage);
assertThat(result).containsExactly(entry("føø", "bår"));
}
interface MyInterface { interface MyInterface {

View File

@ -17,7 +17,6 @@
package org.springframework.http.converter.smile; package org.springframework.http.converter.smile;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.smile.SmileFactory; import com.fasterxml.jackson.dataformat.smile.SmileFactory;
@ -46,8 +45,6 @@ public class MappingJackson2SmileHttpMessageConverterTests {
assertThat(converter.canRead(MyBean.class, new MediaType("application", "x-jackson-smile"))).isTrue(); assertThat(converter.canRead(MyBean.class, new MediaType("application", "x-jackson-smile"))).isTrue();
assertThat(converter.canRead(MyBean.class, new MediaType("application", "json"))).isFalse(); assertThat(converter.canRead(MyBean.class, new MediaType("application", "json"))).isFalse();
assertThat(converter.canRead(MyBean.class, new MediaType("application", "xml"))).isFalse(); assertThat(converter.canRead(MyBean.class, new MediaType("application", "xml"))).isFalse();
assertThat(converter.canRead(MyBean.class, new MediaType("application", "x-jackson-smile", StandardCharsets.UTF_8))).isTrue();
assertThat(converter.canRead(MyBean.class, new MediaType("application", "x-jackson-smile", StandardCharsets.ISO_8859_1))).isFalse();
} }
@Test @Test
@ -55,8 +52,6 @@ public class MappingJackson2SmileHttpMessageConverterTests {
assertThat(converter.canWrite(MyBean.class, new MediaType("application", "x-jackson-smile"))).isTrue(); assertThat(converter.canWrite(MyBean.class, new MediaType("application", "x-jackson-smile"))).isTrue();
assertThat(converter.canWrite(MyBean.class, new MediaType("application", "json"))).isFalse(); assertThat(converter.canWrite(MyBean.class, new MediaType("application", "json"))).isFalse();
assertThat(converter.canWrite(MyBean.class, new MediaType("application", "xml"))).isFalse(); assertThat(converter.canWrite(MyBean.class, new MediaType("application", "xml"))).isFalse();
assertThat(converter.canWrite(MyBean.class, new MediaType("application", "x-jackson-smile", StandardCharsets.UTF_8))).isTrue();
assertThat(converter.canWrite(MyBean.class, new MediaType("application", "x-jackson-smile", StandardCharsets.ISO_8859_1))).isFalse();
} }
@Test @Test

View File

@ -17,6 +17,7 @@
package org.springframework.http.converter.xml; package org.springframework.http.converter.xml;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import com.fasterxml.jackson.annotation.JsonView; import com.fasterxml.jackson.annotation.JsonView;
@ -51,7 +52,7 @@ public class MappingJackson2XmlHttpMessageConverterTests {
assertThat(converter.canRead(MyBean.class, new MediaType("text", "xml"))).isTrue(); assertThat(converter.canRead(MyBean.class, new MediaType("text", "xml"))).isTrue();
assertThat(converter.canRead(MyBean.class, new MediaType("application", "soap+xml"))).isTrue(); assertThat(converter.canRead(MyBean.class, new MediaType("application", "soap+xml"))).isTrue();
assertThat(converter.canRead(MyBean.class, new MediaType("text", "xml", StandardCharsets.UTF_8))).isTrue(); assertThat(converter.canRead(MyBean.class, new MediaType("text", "xml", StandardCharsets.UTF_8))).isTrue();
assertThat(converter.canRead(MyBean.class, new MediaType("text", "xml", StandardCharsets.ISO_8859_1))).isFalse(); assertThat(converter.canRead(MyBean.class, new MediaType("text", "xml", StandardCharsets.ISO_8859_1))).isTrue();
} }
@Test @Test
@ -189,6 +190,21 @@ public class MappingJackson2XmlHttpMessageConverterTests {
this.converter.read(MyBean.class, inputMessage)); this.converter.read(MyBean.class, inputMessage));
} }
@Test
@SuppressWarnings("unchecked")
public void readNonUnicode() throws Exception {
String body = "<MyBean>" +
"<string>føø bår</string>" +
"</MyBean>";
Charset charset = StandardCharsets.ISO_8859_1;
MockHttpInputMessage inputMessage = new MockHttpInputMessage(body.getBytes(charset));
inputMessage.getHeaders().setContentType(new MediaType("application", "xml", charset));
MyBean result = (MyBean) converter.read(MyBean.class, inputMessage);
assertThat(result.getString()).isEqualTo("føø bår");
}
public static class MyBean { public static class MyBean {