diff --git a/spring-web/src/main/java/org/springframework/http/codec/json/Jackson2CodecSupport.java b/spring-web/src/main/java/org/springframework/http/codec/json/Jackson2CodecSupport.java index d602b4b47e7d..fc256206f03a 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/json/Jackson2CodecSupport.java +++ b/spring-web/src/main/java/org/springframework/http/codec/json/Jackson2CodecSupport.java @@ -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. @@ -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; @@ -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 ENCODINGS = jsonEncodings(); + + protected final Log logger = HttpLogging.forLogName(getClass()); @@ -96,7 +105,17 @@ protected List 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) { @@ -125,4 +144,10 @@ protected MethodParameter getParameter(ResolvableType type) { @Nullable protected abstract A getAnnotation(MethodParameter parameter, Class annotType); + private static Map jsonEncodings() { + return EnumSet.allOf(JsonEncoding.class).stream() + .collect(Collectors.toMap(JsonEncoding::getJavaName, Function.identity())); + } + + } diff --git a/spring-web/src/test/java/org/springframework/http/codec/json/Jackson2JsonDecoderTests.java b/spring-web/src/test/java/org/springframework/http/codec/json/Jackson2JsonDecoderTests.java index 5252083c0b9e..9977ede10e2e 100644 --- a/spring-web/src/test/java/org/springframework/http/codec/json/Jackson2JsonDecoderTests.java +++ b/spring-web/src/test/java/org/springframework/http/codec/json/Jackson2JsonDecoderTests.java @@ -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 diff --git a/spring-web/src/test/java/org/springframework/http/codec/json/Jackson2JsonEncoderTests.java b/spring-web/src/test/java/org/springframework/http/codec/json/Jackson2JsonEncoderTests.java index b49dbd28eaeb..a6543b86b9df 100644 --- a/spring-web/src/test/java/org/springframework/http/codec/json/Jackson2JsonEncoderTests.java +++ b/spring-web/src/test/java/org/springframework/http/codec/json/Jackson2JsonEncoderTests.java @@ -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)); diff --git a/spring-web/src/test/java/org/springframework/http/codec/json/Jackson2SmileDecoderTests.java b/spring-web/src/test/java/org/springframework/http/codec/json/Jackson2SmileDecoderTests.java index 2fabea9319e0..7fb75ecb9deb 100644 --- a/spring-web/src/test/java/org/springframework/http/codec/json/Jackson2SmileDecoderTests.java +++ b/spring-web/src/test/java/org/springframework/http/codec/json/Jackson2SmileDecoderTests.java @@ -16,6 +16,7 @@ package org.springframework.http.codec.json; +import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.List; @@ -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 input = Flux.just(this.pojo1, this.pojo2) diff --git a/spring-web/src/test/java/org/springframework/http/codec/json/Jackson2SmileEncoderTests.java b/spring-web/src/test/java/org/springframework/http/codec/json/Jackson2SmileEncoderTests.java index 46e19e7bf659..0ff321ea3ba7 100644 --- a/spring-web/src/test/java/org/springframework/http/codec/json/Jackson2SmileEncoderTests.java +++ b/spring-web/src/test/java/org/springframework/http/codec/json/Jackson2SmileEncoderTests.java @@ -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; @@ -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)); }