diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ResponseBodyEmitterReturnValueHandler.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ResponseBodyEmitterReturnValueHandler.java index c0c797fff91a..ee02ad1700af 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ResponseBodyEmitterReturnValueHandler.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ResponseBodyEmitterReturnValueHandler.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. @@ -18,6 +18,8 @@ import java.io.IOException; import java.io.OutputStream; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; @@ -33,6 +35,7 @@ import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.converter.StringHttpMessageConverter; import org.springframework.http.server.ServerHttpResponse; import org.springframework.http.server.ServletServerHttpResponse; import org.springframework.lang.Nullable; @@ -60,6 +63,8 @@ public class ResponseBodyEmitterReturnValueHandler implements HandlerMethodRetur private final List> messageConverters; + private final List> sseMessageConverters; + private final ReactiveTypeHandler reactiveHandler; @@ -72,6 +77,7 @@ public class ResponseBodyEmitterReturnValueHandler implements HandlerMethodRetur public ResponseBodyEmitterReturnValueHandler(List> messageConverters) { Assert.notEmpty(messageConverters, "HttpMessageConverter List must not be empty"); this.messageConverters = messageConverters; + this.sseMessageConverters = initSseConverters(messageConverters); this.reactiveHandler = new ReactiveTypeHandler(); } @@ -88,9 +94,22 @@ public ResponseBodyEmitterReturnValueHandler(List> messa Assert.notEmpty(messageConverters, "HttpMessageConverter List must not be empty"); this.messageConverters = messageConverters; + this.sseMessageConverters = initSseConverters(messageConverters); this.reactiveHandler = new ReactiveTypeHandler(registry, executor, manager); } + private static List> initSseConverters(List> converters) { + for (HttpMessageConverter converter : converters) { + if (converter.canWrite(String.class, MediaType.TEXT_PLAIN)) { + return converters; + } + } + List> result = new ArrayList<>(converters.size() + 1); + result.add(new StringHttpMessageConverter(StandardCharsets.UTF_8)); + result.addAll(converters); + return result; + } + @Override public boolean supportsReturnType(MethodParameter returnType) { @@ -186,7 +205,7 @@ public void send(Object data, @Nullable MediaType mediaType) throws IOException @SuppressWarnings("unchecked") private void sendInternal(T data, @Nullable MediaType mediaType) throws IOException { - for (HttpMessageConverter converter : ResponseBodyEmitterReturnValueHandler.this.messageConverters) { + for (HttpMessageConverter converter : ResponseBodyEmitterReturnValueHandler.this.sseMessageConverters) { if (converter.canWrite(data.getClass(), mediaType)) { ((HttpMessageConverter) converter).write(data, mediaType, this.outputMessage); this.outputMessage.flush(); diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ResponseBodyEmitterReturnValueHandlerTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ResponseBodyEmitterReturnValueHandlerTests.java index d71cd60378a0..36bb1cada870 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ResponseBodyEmitterReturnValueHandlerTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ResponseBodyEmitterReturnValueHandlerTests.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. @@ -16,7 +16,6 @@ package org.springframework.web.servlet.mvc.method.annotation; -import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.concurrent.atomic.AtomicReference; @@ -31,7 +30,6 @@ import org.springframework.core.ResolvableType; import org.springframework.http.ResponseEntity; import org.springframework.http.converter.HttpMessageConverter; -import org.springframework.http.converter.StringHttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.context.request.ServletWebRequest; @@ -72,8 +70,8 @@ public class ResponseBodyEmitterReturnValueHandlerTests { @BeforeEach public void setup() throws Exception { - List> converters = Arrays.asList( - new StringHttpMessageConverter(), new MappingJackson2HttpMessageConverter()); + List> converters = + Collections.singletonList(new MappingJackson2HttpMessageConverter()); this.handler = new ResponseBodyEmitterReturnValueHandler(converters); this.request = new MockHttpServletRequest();