From 0ead0503ebb68461da8e0e3e2eefcbadfbf8bae8 Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Wed, 14 Feb 2018 12:09:07 -0500 Subject: [PATCH] AbstractJackson2Encoder uses private fields Make the protected fields in AbstractJackson2Encoder private plus minor refactoring to the way streaming separators are applied. The current (5.0.3) behavior is to always use '\n', but in 5.0.4 the newly supported "application/stream+x-jackson-smile" needs to be excluded from that. For now, separator determination remains private in the abstract base class, but current behavior remains which is to apply '\n' by default. Issue: SPR-15424 --- .../codec/json/AbstractJackson2Encoder.java | 43 ++++++++++++------- .../http/codec/json/Jackson2JsonEncoder.java | 3 +- .../http/codec/json/Jackson2SmileEncoder.java | 3 +- 3 files changed, 31 insertions(+), 18 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/http/codec/json/AbstractJackson2Encoder.java b/spring-web/src/main/java/org/springframework/http/codec/json/AbstractJackson2Encoder.java index 049a9863ac..6fef5ef485 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/json/AbstractJackson2Encoder.java +++ b/spring-web/src/main/java/org/springframework/http/codec/json/AbstractJackson2Encoder.java @@ -21,6 +21,7 @@ import java.io.OutputStream; import java.lang.annotation.Annotation; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; @@ -58,9 +59,18 @@ import org.springframework.util.MimeType; */ public abstract class AbstractJackson2Encoder extends Jackson2CodecSupport implements HttpMessageEncoder { - protected final List streamingMediaTypes = new ArrayList<>(1); + private static final byte[] NEWLINE_SEPARATOR = {'\n'}; - protected boolean streamingLineSeparator = true; + private static final Map STREAM_SEPARATORS; + + static { + STREAM_SEPARATORS = new HashMap<>(); + STREAM_SEPARATORS.put(MediaType.APPLICATION_STREAM_JSON, NEWLINE_SEPARATOR); + STREAM_SEPARATORS.put(MediaType.parseMediaType("application/stream+x-jackson-smile"), new byte[0]); + } + + + private final List streamingMediaTypes = new ArrayList<>(1); /** @@ -103,20 +113,23 @@ public abstract class AbstractJackson2Encoder extends Jackson2CodecSupport imple return Flux.from(inputStream).map(value -> encodeValue(value, mimeType, bufferFactory, elementType, hints)); } - else if (this.streamingMediaTypes.stream().anyMatch(mediaType -> mediaType.isCompatibleWith(mimeType))) { - return Flux.from(inputStream).map(value -> { - DataBuffer buffer = encodeValue(value, mimeType, bufferFactory, elementType, hints); - if (streamingLineSeparator) { - buffer.write(new byte[]{'\n'}); - } - return buffer; - }); - } - else { - ResolvableType listType = ResolvableType.forClassWithGenerics(List.class, elementType); - return Flux.from(inputStream).collectList().map(list -> - encodeValue(list, mimeType, bufferFactory, listType, hints)).flux(); + + for (MediaType streamingMediaType : this.streamingMediaTypes) { + if (streamingMediaType.isCompatibleWith(mimeType)) { + byte[] separator = STREAM_SEPARATORS.getOrDefault(streamingMediaType, NEWLINE_SEPARATOR); + return Flux.from(inputStream).map(value -> { + DataBuffer buffer = encodeValue(value, mimeType, bufferFactory, elementType, hints); + if (separator != null) { + buffer.write(separator); + } + return buffer; + }); + } } + + ResolvableType listType = ResolvableType.forClassWithGenerics(List.class, elementType); + return Flux.from(inputStream).collectList().map(list -> + encodeValue(list, mimeType, bufferFactory, listType, hints)).flux(); } private DataBuffer encodeValue(Object value, @Nullable MimeType mimeType, DataBufferFactory bufferFactory, 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 b46a943a12..6ba6ceed6c 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 @@ -16,6 +16,7 @@ package org.springframework.http.codec.json; +import java.util.Collections; import java.util.List; import java.util.Map; @@ -55,7 +56,7 @@ public class Jackson2JsonEncoder extends AbstractJackson2Encoder { public Jackson2JsonEncoder(ObjectMapper mapper, MimeType... mimeTypes) { super(mapper, mimeTypes); - this.streamingMediaTypes.add(MediaType.APPLICATION_STREAM_JSON); + setStreamingMediaTypes(Collections.singletonList(MediaType.APPLICATION_STREAM_JSON)); this.ssePrettyPrinter = initSsePrettyPrinter(); } diff --git a/spring-web/src/main/java/org/springframework/http/codec/json/Jackson2SmileEncoder.java b/spring-web/src/main/java/org/springframework/http/codec/json/Jackson2SmileEncoder.java index 0f222562ad..428684a4b7 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/json/Jackson2SmileEncoder.java +++ b/spring-web/src/main/java/org/springframework/http/codec/json/Jackson2SmileEncoder.java @@ -51,8 +51,7 @@ public class Jackson2SmileEncoder extends AbstractJackson2Encoder { public Jackson2SmileEncoder(ObjectMapper mapper, MimeType... mimeTypes) { super(mapper, mimeTypes); Assert.isAssignable(SmileFactory.class, mapper.getFactory().getClass()); - this.streamingMediaTypes.add(new MediaType("application", "stream+x-jackson-smile")); - this.streamingLineSeparator = false; + setStreamingMediaTypes(Collections.singletonList(new MediaType("application", "stream+x-jackson-smile"))); } }