From dbc86ec04382fe53a22cc7b01acbc0fa70b9ae37 Mon Sep 17 00:00:00 2001 From: Sebastien Deleuze Date: Tue, 27 Sep 2016 21:57:17 +0200 Subject: [PATCH] Refine Jackson canEncode() / canDecode() implementation This commit refine Jackson canEncode() / canDecode() implementation by using ObjectMapper canSerialize() / canDeserialize() methods. Issue: SPR-14748 --- .../java/org/springframework/core/codec/Decoder.java | 2 +- .../java/org/springframework/core/codec/Encoder.java | 2 +- .../http/codec/json/Jackson2JsonDecoder.java | 8 ++++---- .../http/codec/json/Jackson2JsonEncoder.java | 6 ++---- .../http/codec/json/Jackson2JsonDecoderTests.java | 7 ++++--- .../http/codec/json/Jackson2JsonEncoderTests.java | 9 +++++++-- 6 files changed, 19 insertions(+), 15 deletions(-) diff --git a/spring-core/src/main/java/org/springframework/core/codec/Decoder.java b/spring-core/src/main/java/org/springframework/core/codec/Decoder.java index 2a6911422c0..21fce51ac4a 100644 --- a/spring-core/src/main/java/org/springframework/core/codec/Decoder.java +++ b/spring-core/src/main/java/org/springframework/core/codec/Decoder.java @@ -42,7 +42,7 @@ public interface Decoder { * Whether the decoder supports the given target element type and the MIME * type of the source stream. * @param elementType the target element type for the output stream - * @param mimeType the mime type associated with the stream to decode + * @param mimeType the mime type associated with the stream to decode, can be {@code null} if not specified. * @return {@code true} if supported, {@code false} otherwise */ boolean canDecode(ResolvableType elementType, MimeType mimeType); diff --git a/spring-core/src/main/java/org/springframework/core/codec/Encoder.java b/spring-core/src/main/java/org/springframework/core/codec/Encoder.java index a831f91451a..96c6352deb0 100644 --- a/spring-core/src/main/java/org/springframework/core/codec/Encoder.java +++ b/spring-core/src/main/java/org/springframework/core/codec/Encoder.java @@ -43,7 +43,7 @@ public interface Encoder { * Whether the encoder supports the given source element type and the MIME * type for the output stream. * @param elementType the type of elements in the source stream - * @param mimeType the MIME type for the output stream + * @param mimeType the MIME type for the output stream, can be {@code null} if not specified. * @return {@code true} if supported, {@code false} otherwise */ boolean canEncode(ResolvableType elementType, MimeType mimeType); diff --git a/spring-web/src/main/java/org/springframework/http/codec/json/Jackson2JsonDecoder.java b/spring-web/src/main/java/org/springframework/http/codec/json/Jackson2JsonDecoder.java index 2cab2c31fa3..56c59c7124b 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/json/Jackson2JsonDecoder.java +++ b/spring-web/src/main/java/org/springframework/http/codec/json/Jackson2JsonDecoder.java @@ -23,6 +23,7 @@ import java.util.Map; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectReader; +import com.fasterxml.jackson.databind.type.TypeFactory; import org.reactivestreams.Publisher; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -63,10 +64,9 @@ public class Jackson2JsonDecoder extends AbstractJackson2Codec implements Decode @Override public boolean canDecode(ResolvableType elementType, MimeType mimeType) { - if (mimeType == null) { - return true; - } - return JSON_MIME_TYPES.stream().anyMatch(m -> m.isCompatibleWith(mimeType)); + JavaType javaType = this.mapper.getTypeFactory().constructType(elementType.getType()); + return this.mapper.canDeserialize(javaType) && + (mimeType == null || JSON_MIME_TYPES.stream().anyMatch(m -> m.isCompatibleWith(mimeType))); } @Override diff --git a/spring-web/src/main/java/org/springframework/http/codec/json/Jackson2JsonEncoder.java b/spring-web/src/main/java/org/springframework/http/codec/json/Jackson2JsonEncoder.java index ec6e418a0d9..aa67d9924c1 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/json/Jackson2JsonEncoder.java +++ b/spring-web/src/main/java/org/springframework/http/codec/json/Jackson2JsonEncoder.java @@ -68,10 +68,8 @@ public class Jackson2JsonEncoder extends AbstractJackson2Codec implements Encode @Override public boolean canEncode(ResolvableType elementType, MimeType mimeType) { - if (mimeType == null) { - return true; - } - return JSON_MIME_TYPES.stream().anyMatch(m -> m.isCompatibleWith(mimeType)); + return this.mapper.canSerialize(elementType.getRawClass()) && + (mimeType == null || JSON_MIME_TYPES.stream().anyMatch(m -> m.isCompatibleWith(mimeType))); } @Override 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 8cbf005770f..96aac02d0c4 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 @@ -46,9 +46,10 @@ public class Jackson2JsonDecoderTests extends AbstractDataBufferAllocatingTestCa @Test public void canDecode() { Jackson2JsonDecoder decoder = new Jackson2JsonDecoder(); - - assertTrue(decoder.canDecode(null, MediaType.APPLICATION_JSON)); - assertFalse(decoder.canDecode(null, MediaType.APPLICATION_XML)); + ResolvableType type = ResolvableType.forClass(Pojo.class); + assertTrue(decoder.canDecode(type, MediaType.APPLICATION_JSON)); + assertTrue(decoder.canDecode(type, null)); + assertFalse(decoder.canDecode(type, MediaType.APPLICATION_XML)); } @Test 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 eac0cf05f4d..6b18c9c47c4 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 @@ -31,6 +31,7 @@ import org.springframework.core.io.buffer.AbstractDataBufferAllocatingTestCase; import org.springframework.core.io.buffer.DataBuffer; import org.springframework.http.MediaType; import org.springframework.http.codec.Pojo; +import org.springframework.http.codec.ServerSentEvent; import org.springframework.tests.TestSubscriber; import static org.junit.Assert.*; @@ -45,8 +46,12 @@ public class Jackson2JsonEncoderTests extends AbstractDataBufferAllocatingTestCa @Test public void canEncode() { - assertTrue(this.encoder.canEncode(null, MediaType.APPLICATION_JSON)); - assertFalse(this.encoder.canEncode(null, MediaType.APPLICATION_XML)); + ResolvableType pojoType = ResolvableType.forClass(Pojo.class); + assertTrue(this.encoder.canEncode(pojoType, MediaType.APPLICATION_JSON)); + assertTrue(this.encoder.canEncode(pojoType, null)); + assertFalse(this.encoder.canEncode(pojoType, MediaType.APPLICATION_XML)); + ResolvableType sseType = ResolvableType.forClass(ServerSentEvent.class); + assertFalse(this.encoder.canEncode(sseType, MediaType.APPLICATION_JSON)); } @Test