From 6d24e62e8372f9795bbea6c6b48cee01c720db49 Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Sun, 19 Feb 2023 17:43:31 +0100 Subject: [PATCH] Polishing --- .../src/docs/asciidoc/core/core-aot.adoc | 6 +- .../ExecutingResponseCreatorTests.java | 7 +- .../TransactionalOperatorExtensions.kt | 2 +- .../json/ProblemDetailJacksonMixin.java | 2 +- .../json/ProblemDetailJacksonXmlMixin.java | 15 +- .../json/ProblemDetailJacksonMixinTests.java | 81 ++-- spring-webmvc/spring-webmvc.gradle | 11 +- ...questResponseBodyMethodProcessorTests.java | 392 +++++++----------- 8 files changed, 226 insertions(+), 290 deletions(-) diff --git a/framework-docs/src/docs/asciidoc/core/core-aot.adoc b/framework-docs/src/docs/asciidoc/core/core-aot.adoc index a7df2ada16..d4f0fca362 100644 --- a/framework-docs/src/docs/asciidoc/core/core-aot.adoc +++ b/framework-docs/src/docs/asciidoc/core/core-aot.adoc @@ -16,9 +16,9 @@ Applying such optimizations early implies the following restrictions: * The classpath is fixed and fully defined at build time. * The beans defined in your application cannot change at runtime, meaning: ** `@Profile`, in particular profile-specific configuration needs to be chosen at build time. -** Environment properties that impact the presence of a bean (`@Conditional`) are only considered at build time. -* Bean definitions with instance suppliers (lambdas or method references) can't be transformed Ahead of Time (see https://github.com/spring-projects/spring-framework/issues/29555[spring-framework#29555] related issue) -* The return type of methods annotated with `@Bean` should be the most specific one in order to allow proper hint inference (typically the concrete class, not an interface). +** `Environment` properties that impact the presence of a bean (`@Conditional`) are only considered at build time. +* Bean definitions with instance suppliers (lambdas or method references) cannot be transformed ahead-of-time (see related https://github.com/spring-projects/spring-framework/issues/29555[spring-framework#29555] issue). +* The return type of methods annotated with `@Bean` should be the most specific type possible (typically the concrete class, not an interface) in order to support proper type inference without invoking the corresponding `@Bean` method at build time. When these restrictions are in place, it becomes possible to perform ahead-of-time processing at build time and generate additional assets. A Spring AOT processed application typically generates: diff --git a/spring-test/src/test/java/org/springframework/test/web/client/response/ExecutingResponseCreatorTests.java b/spring-test/src/test/java/org/springframework/test/web/client/response/ExecutingResponseCreatorTests.java index a03fee5621..89e42995e8 100644 --- a/spring-test/src/test/java/org/springframework/test/web/client/response/ExecutingResponseCreatorTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/client/response/ExecutingResponseCreatorTests.java @@ -52,11 +52,11 @@ class ExecutingResponseCreatorTests { @Test void ensureRequestIsMock() { - final ExecutingResponseCreator responseCreator = new ExecutingResponseCreator((uri, method) -> null); - ClientHttpRequest notAMockRequest = mock(); + ExecutingResponseCreator responseCreator = new ExecutingResponseCreator((uri, method) -> null); + ClientHttpRequest mockitoMockRequest = mock(); assertThatIllegalStateException() - .isThrownBy(() -> responseCreator.createResponse(notAMockRequest)) + .isThrownBy(() -> responseCreator.createResponse(mockitoMockRequest)) .withMessage("Expected a MockClientHttpRequest"); } @@ -91,4 +91,5 @@ class ExecutingResponseCreatorTests { assertThat(request.getHeaders()).isNotSameAs(originalRequest.getHeaders()); }); } + } diff --git a/spring-tx/src/main/kotlin/org/springframework/transaction/reactive/TransactionalOperatorExtensions.kt b/spring-tx/src/main/kotlin/org/springframework/transaction/reactive/TransactionalOperatorExtensions.kt index 09d7e7efd2..3b117b37ea 100644 --- a/spring-tx/src/main/kotlin/org/springframework/transaction/reactive/TransactionalOperatorExtensions.kt +++ b/spring-tx/src/main/kotlin/org/springframework/transaction/reactive/TransactionalOperatorExtensions.kt @@ -24,7 +24,7 @@ import kotlinx.coroutines.reactive.awaitLast import kotlinx.coroutines.reactor.asFlux import kotlinx.coroutines.reactor.mono import org.springframework.transaction.ReactiveTransaction -import java.util.* +import java.util.Optional import kotlin.coroutines.CoroutineContext import kotlin.coroutines.EmptyCoroutineContext diff --git a/spring-web/src/main/java/org/springframework/http/converter/json/ProblemDetailJacksonMixin.java b/spring-web/src/main/java/org/springframework/http/converter/json/ProblemDetailJacksonMixin.java index 27b49005a3..23b32eeffa 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/json/ProblemDetailJacksonMixin.java +++ b/spring-web/src/main/java/org/springframework/http/converter/json/ProblemDetailJacksonMixin.java @@ -33,7 +33,7 @@ import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; * the Jackson library. * *

The annotations ensure the {@link ProblemDetail#getProperties() properties} - * map is unwrapped and rendered as top level JSON properties, and likewise that + * map is unwrapped and rendered as top-level JSON properties, and likewise that * the {@code properties} map contains unknown properties from the JSON. * *

{@link Jackson2ObjectMapperBuilder} automatically registers this as a diff --git a/spring-web/src/main/java/org/springframework/http/converter/json/ProblemDetailJacksonXmlMixin.java b/spring-web/src/main/java/org/springframework/http/converter/json/ProblemDetailJacksonXmlMixin.java index f3a14a5813..ccaccc4ebf 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/json/ProblemDetailJacksonXmlMixin.java +++ b/spring-web/src/main/java/org/springframework/http/converter/json/ProblemDetailJacksonXmlMixin.java @@ -30,15 +30,14 @@ import org.springframework.lang.Nullable; import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; /** - * Provides the same declarations as {@link ProblemDetailJacksonMixin}, and - * some additional ones to support XML serialization when - * jackson-dataformat-xml is on the classpath. Customizes the XML root element - * name and adds namespace information. + * Provides the same declarations as {@link ProblemDetailJacksonMixin} and some + * additional ones to support XML serialization when {@code jackson-dataformat-xml} + * is on the classpath. Customizes the XML root element name and adds namespace + * information. * - *

Note that we can't use {@code JsonRootName} to specify the namespace - * since that is not inherited by fields of the class. This is why we need a - * dedicated mixin for use when jackson-dataformat-xml is on the classpath. - * For more details, see + *

Note that we cannot use {@code @JsonRootName} to specify the namespace since that + * is not inherited by fields of the class. This is why we need a dedicated "mix-in" + * when {@code jackson-dataformat-xml} is on the classpath. For more details, see * FasterXML/jackson-dataformat-xml#355. * * @author Rossen Stoyanchev diff --git a/spring-web/src/test/java/org/springframework/http/converter/json/ProblemDetailJacksonMixinTests.java b/spring-web/src/test/java/org/springframework/http/converter/json/ProblemDetailJacksonMixinTests.java index 0e46a70a1e..afcdb8331f 100644 --- a/spring-web/src/test/java/org/springframework/http/converter/json/ProblemDetailJacksonMixinTests.java +++ b/spring-web/src/test/java/org/springframework/http/converter/json/ProblemDetailJacksonMixinTests.java @@ -16,11 +16,11 @@ package org.springframework.http.converter.json; - import java.net.URI; import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.jupiter.api.Test; +import org.skyscreamer.jsonassert.JSONAssert; import org.springframework.http.HttpStatus; import org.springframework.http.ProblemDetail; @@ -34,64 +34,73 @@ import static org.assertj.core.api.Assertions.assertThat; * @author Rossen Stoyanchev * @since 6.0 */ -public class ProblemDetailJacksonMixinTests { +class ProblemDetailJacksonMixinTests { private final ObjectMapper mapper = new Jackson2ObjectMapperBuilder().build(); + @Test void writeStatusAndHeaders() throws Exception { - testWrite( - ProblemDetail.forStatusAndDetail(HttpStatus.BAD_REQUEST, "Missing header"), - "{\"type\":\"about:blank\"," + - "\"title\":\"Bad Request\"," + - "\"status\":400," + - "\"detail\":\"Missing header\"}"); + ProblemDetail detail = ProblemDetail.forStatusAndDetail(HttpStatus.BAD_REQUEST, "Missing header"); + testWrite(detail, + """ + { + "type": "about:blank", + "title": "Bad Request", + "status": 400, + "detail": "Missing header" + }"""); } @Test void writeCustomProperty() throws Exception { - ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(HttpStatus.BAD_REQUEST, "Missing header"); - problemDetail.setProperty("host", "abc.org"); - problemDetail.setProperty("user", null); + ProblemDetail detail = ProblemDetail.forStatusAndDetail(HttpStatus.BAD_REQUEST, "Missing header"); + detail.setProperty("host", "abc.org"); + detail.setProperty("user", null); - testWrite(problemDetail, - "{\"type\":\"about:blank\"," + - "\"title\":\"Bad Request\"," + - "\"status\":400," + - "\"detail\":\"Missing header\"," + - "\"host\":\"abc.org\"," + - "\"user\":null}"); + testWrite(detail, """ + { + "type": "about:blank", + "title": "Bad Request", + "status": 400, + "detail": "Missing header", + "host": "abc.org", + "user": null + }"""); } @Test void readCustomProperty() throws Exception { - ProblemDetail detail = this.mapper.readValue( - "{\"type\":\"about:blank\"," + - "\"title\":\"Bad Request\"," + - "\"status\":400," + - "\"detail\":\"Missing header\"," + - "\"host\":\"abc.org\"," + - "\"user\":null}", ProblemDetail.class); + ProblemDetail detail = this.mapper.readValue(""" + { + "type": "about:blank", + "title": "Bad Request", + "status": 400, + "detail": "Missing header", + "host": "abc.org", + "user": null + }""", ProblemDetail.class); assertThat(detail.getType()).isEqualTo(URI.create("about:blank")); assertThat(detail.getTitle()).isEqualTo("Bad Request"); assertThat(detail.getStatus()).isEqualTo(HttpStatus.BAD_REQUEST.value()); assertThat(detail.getDetail()).isEqualTo("Missing header"); - assertThat(detail.getProperties()).containsEntry("host", "abc.org"); - assertThat(detail.getProperties()).containsEntry("user", null); + assertThat(detail.getProperties()) + .containsEntry("host", "abc.org") + .containsEntry("user", null); } @Test void readCustomPropertyFromXml() throws Exception { ObjectMapper xmlMapper = new Jackson2ObjectMapperBuilder().createXmlMapper(true).build(); - ProblemDetail detail = xmlMapper.readValue( - "" + - "about:blank" + - "Bad Request" + - "400" + - "Missing header" + - "abc.org" + - "", ProblemDetail.class); + ProblemDetail detail = xmlMapper.readValue(""" + + about:blank + Bad Request + 400 + Missing header + abc.org + """, ProblemDetail.class); assertThat(detail.getType()).isEqualTo(URI.create("about:blank")); assertThat(detail.getTitle()).isEqualTo("Bad Request"); @@ -102,7 +111,7 @@ public class ProblemDetailJacksonMixinTests { private void testWrite(ProblemDetail problemDetail, String expected) throws Exception { String output = this.mapper.writeValueAsString(problemDetail); - assertThat(output).isEqualTo(expected); + JSONAssert.assertEquals(expected, output, false); } } diff --git a/spring-webmvc/spring-webmvc.gradle b/spring-webmvc/spring-webmvc.gradle index 5996e8fbc3..96ea41bc76 100644 --- a/spring-webmvc/spring-webmvc.gradle +++ b/spring-webmvc/spring-webmvc.gradle @@ -57,14 +57,15 @@ dependencies { exclude group: "pull-parser", module: "pull-parser" exclude group: "xpp3", module: "xpp3" } - testImplementation("jaxen:jaxen") - testImplementation("org.xmlunit:xmlunit-assertj") - testImplementation("org.xmlunit:xmlunit-matchers") - testImplementation("org.hibernate:hibernate-validator") - testImplementation("jakarta.validation:jakarta.validation-api") testImplementation("io.projectreactor:reactor-core") testImplementation("io.reactivex.rxjava3:rxjava") + testImplementation("jakarta.validation:jakarta.validation-api") + testImplementation("jaxen:jaxen") + testImplementation("org.hibernate:hibernate-validator") testImplementation("org.jetbrains.kotlin:kotlin-script-runtime") + testImplementation("org.skyscreamer:jsonassert") + testImplementation("org.xmlunit:xmlunit-assertj") + testImplementation("org.xmlunit:xmlunit-matchers") testRuntimeOnly("org.apache.httpcomponents.client5:httpclient5") testRuntimeOnly("org.jetbrains.kotlin:kotlin-scripting-jsr223") testRuntimeOnly("org.jruby:jruby") diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestResponseBodyMethodProcessorTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestResponseBodyMethodProcessorTests.java index 27bc565bf0..1f7406353a 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestResponseBodyMethodProcessorTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestResponseBodyMethodProcessorTests.java @@ -22,9 +22,7 @@ import java.io.Serializable; import java.lang.reflect.Method; import java.lang.reflect.Type; import java.nio.charset.StandardCharsets; -import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.List; import com.fasterxml.jackson.annotation.JsonTypeInfo; @@ -32,8 +30,9 @@ import com.fasterxml.jackson.annotation.JsonTypeName; import com.fasterxml.jackson.annotation.JsonView; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.skyscreamer.jsonassert.JSONAssert; +import org.xmlunit.assertj.XmlAssert; import org.springframework.aop.framework.ProxyFactory; import org.springframework.aop.target.SingletonTargetSource; @@ -56,7 +55,9 @@ import org.springframework.http.converter.support.AllEncompassingFormHttpMessage import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter; import org.springframework.lang.Nullable; import org.springframework.util.MultiValueMap; +import org.springframework.util.ReflectionUtils; import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; +import org.springframework.web.HttpMediaTypeNotAcceptableException; import org.springframework.web.accept.ContentNegotiationManagerFactoryBean; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.RequestBody; @@ -76,86 +77,63 @@ import org.springframework.web.util.WebUtils; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; /** - * Test fixture for a {@link RequestResponseBodyMethodProcessor} with - * actual delegation to {@link HttpMessageConverter} instances. Also see - * {@link RequestResponseBodyMethodProcessorMockTests}. + * Tests for {@link RequestResponseBodyMethodProcessor} with actual delegation to + * {@link HttpMessageConverter} instances. * * @author Rossen Stoyanchev * @author Sebastien Deleuze + * @author Sam Brannen + * @see RequestResponseBodyMethodProcessorMockTests */ @SuppressWarnings("unused") -public class RequestResponseBodyMethodProcessorTests { +class RequestResponseBodyMethodProcessorTests { - protected static final String NEWLINE_SYSTEM_PROPERTY = System.lineSeparator(); + private final ModelAndViewContainer container = new ModelAndViewContainer(); + private final MockHttpServletRequest servletRequest = new MockHttpServletRequest(); - private ModelAndViewContainer container; + private final MockHttpServletResponse servletResponse = new MockHttpServletResponse(); - private MockHttpServletRequest servletRequest; + private final NativeWebRequest request = new ServletWebRequest(servletRequest, servletResponse); - private MockHttpServletResponse servletResponse; + private final ValidatingBinderFactory factory = new ValidatingBinderFactory(); - private NativeWebRequest request; + private final Method method = ReflectionUtils.findMethod(getClass(), "handle", + List.class, SimpleBean.class, MultiValueMap.class, String.class); - private ValidatingBinderFactory factory; - - private MethodParameter paramGenericList; - private MethodParameter paramSimpleBean; - private MethodParameter paramMultiValueMap; - private MethodParameter paramString; - private MethodParameter returnTypeString; - - - @BeforeEach - public void setup() throws Exception { - container = new ModelAndViewContainer(); - servletRequest = new MockHttpServletRequest(); - servletRequest.setMethod("POST"); - servletResponse = new MockHttpServletResponse(); - request = new ServletWebRequest(servletRequest, servletResponse); - this.factory = new ValidatingBinderFactory(); - - Method method = getClass().getDeclaredMethod("handle", - List.class, SimpleBean.class, MultiValueMap.class, String.class); - paramGenericList = new MethodParameter(method, 0); - paramSimpleBean = new MethodParameter(method, 1); - paramMultiValueMap = new MethodParameter(method, 2); - paramString = new MethodParameter(method, 3); - returnTypeString = new MethodParameter(method, -1); - } + private final MethodParameter paramGenericList = new MethodParameter(method, 0); + private final MethodParameter paramSimpleBean = new MethodParameter(method, 1); + private final MethodParameter paramMultiValueMap = new MethodParameter(method, 2); + private final MethodParameter paramString = new MethodParameter(method, 3); + private final MethodParameter returnTypeString = new MethodParameter(method, -1); @Test - public void resolveArgumentParameterizedType() throws Exception { + void resolveArgumentParameterizedType() throws Exception { String content = "[{\"name\" : \"Jad\"}, {\"name\" : \"Robert\"}]"; this.servletRequest.setContent(content.getBytes(StandardCharsets.UTF_8)); this.servletRequest.setContentType(MediaType.APPLICATION_JSON_VALUE); - List> converters = new ArrayList<>(); - converters.add(new MappingJackson2HttpMessageConverter()); + List> converters = List.of(new MappingJackson2HttpMessageConverter()); RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(converters); @SuppressWarnings("unchecked") List result = (List) processor.resolveArgument( paramGenericList, container, request, factory); - assertThat(result).isNotNull(); - assertThat(result.get(0).getName()).isEqualTo("Jad"); - assertThat(result.get(1).getName()).isEqualTo("Robert"); + assertThat(result).map(SimpleBean::getName).containsExactly("Jad", "Robert"); } @Test - public void resolveArgumentRawTypeFromParameterizedType() throws Exception { + void resolveArgumentRawTypeFromParameterizedType() throws Exception { String content = "fruit=apple&vegetable=kale"; this.servletRequest.setMethod("GET"); this.servletRequest.setContent(content.getBytes(StandardCharsets.UTF_8)); this.servletRequest.setContentType(MediaType.APPLICATION_FORM_URLENCODED_VALUE); - List> converters = new ArrayList<>(); - converters.add(new AllEncompassingFormHttpMessageConverter()); + List> converters = List.of(new AllEncompassingFormHttpMessageConverter()); RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(converters); @SuppressWarnings("unchecked") @@ -168,13 +146,12 @@ public class RequestResponseBodyMethodProcessorTests { } @Test - public void resolveArgumentClassJson() throws Exception { + void resolveArgumentClassJson() throws Exception { String content = "{\"name\" : \"Jad\"}"; this.servletRequest.setContent(content.getBytes(StandardCharsets.UTF_8)); this.servletRequest.setContentType("application/json"); - List> converters = new ArrayList<>(); - converters.add(new MappingJackson2HttpMessageConverter()); + List> converters = List.of(new MappingJackson2HttpMessageConverter()); RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(converters); SimpleBean result = (SimpleBean) processor.resolveArgument( @@ -185,47 +162,43 @@ public class RequestResponseBodyMethodProcessorTests { } @Test - public void resolveArgumentClassString() throws Exception { + void resolveArgumentClassString() throws Exception { String content = "foobarbaz"; this.servletRequest.setContent(content.getBytes(StandardCharsets.UTF_8)); this.servletRequest.setContentType("application/json"); - List> converters = new ArrayList<>(); - converters.add(new StringHttpMessageConverter()); + List> converters = List.of(new StringHttpMessageConverter()); RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(converters); String result = (String) processor.resolveArgument( paramString, container, request, factory); - assertThat(result).isNotNull(); assertThat(result).isEqualTo("foobarbaz"); } @Test // SPR-9942 - public void resolveArgumentRequiredNoContent() { + void resolveArgumentRequiredNoContent() { this.servletRequest.setContent(new byte[0]); this.servletRequest.setContentType("text/plain"); - List> converters = new ArrayList<>(); - converters.add(new StringHttpMessageConverter()); + List> converters = List.of(new StringHttpMessageConverter()); RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(converters); assertThatExceptionOfType(HttpMessageNotReadableException.class).isThrownBy(() -> processor.resolveArgument(paramString, container, request, factory)); } @Test // SPR-12778 - public void resolveArgumentRequiredNoContentDefaultValue() throws Exception { + void resolveArgumentRequiredNoContentDefaultValue() throws Exception { this.servletRequest.setContent(new byte[0]); this.servletRequest.setContentType("text/plain"); - List> converters = Collections.singletonList(new StringHttpMessageConverter()); - List advice = Collections.singletonList(new EmptyRequestBodyAdvice()); + List> converters = List.of(new StringHttpMessageConverter()); + List advice = List.of(new EmptyRequestBodyAdvice()); RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(converters, advice); String arg = (String) processor.resolveArgument(paramString, container, request, factory); - assertThat(arg).isNotNull(); assertThat(arg).isEqualTo("default value for empty body"); } @Test // SPR-9964 - public void resolveArgumentTypeVariable() throws Exception { + void resolveArgumentTypeVariable() throws Exception { Method method = MyParameterizedController.class.getMethod("handleDto", Identifiable.class); HandlerMethod handlerMethod = new HandlerMethod(new MySimpleParameterizedController(), method); MethodParameter methodParam = handlerMethod.getMethodParameters()[0]; @@ -234,8 +207,7 @@ public class RequestResponseBodyMethodProcessorTests { this.servletRequest.setContent(content.getBytes(StandardCharsets.UTF_8)); this.servletRequest.setContentType(MediaType.APPLICATION_JSON_VALUE); - List> converters = new ArrayList<>(); - converters.add(new MappingJackson2HttpMessageConverter()); + List> converters = List.of(new MappingJackson2HttpMessageConverter()); RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(converters); SimpleBean result = (SimpleBean) processor.resolveArgument(methodParam, container, request, factory); @@ -245,7 +217,7 @@ public class RequestResponseBodyMethodProcessorTests { } @Test // SPR-14470 - public void resolveParameterizedWithTypeVariableArgument() throws Exception { + void resolveParameterizedWithTypeVariableArgument() throws Exception { Method method = MyParameterizedControllerWithList.class.getMethod("handleDto", List.class); HandlerMethod handlerMethod = new HandlerMethod(new MySimpleParameterizedControllerWithList(), method); MethodParameter methodParam = handlerMethod.getMethodParameters()[0]; @@ -254,21 +226,18 @@ public class RequestResponseBodyMethodProcessorTests { this.servletRequest.setContent(content.getBytes(StandardCharsets.UTF_8)); this.servletRequest.setContentType(MediaType.APPLICATION_JSON_VALUE); - List> converters = new ArrayList<>(); - converters.add(new MappingJackson2HttpMessageConverter()); + List> converters = List.of(new MappingJackson2HttpMessageConverter()); RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(converters); @SuppressWarnings("unchecked") List result = (List) processor.resolveArgument( methodParam, container, request, factory); - assertThat(result).isNotNull(); - assertThat(result.get(0).getName()).isEqualTo("Jad"); - assertThat(result.get(1).getName()).isEqualTo("Robert"); + assertThat(result).map(SimpleBean::getName).containsExactly("Jad", "Robert"); } @Test // SPR-11225 - public void resolveArgumentTypeVariableWithNonGenericConverter() throws Exception { + void resolveArgumentTypeVariableWithNonGenericConverter() throws Exception { Method method = MyParameterizedController.class.getMethod("handleDto", Identifiable.class); HandlerMethod handlerMethod = new HandlerMethod(new MySimpleParameterizedController(), method); MethodParameter methodParam = handlerMethod.getMethodParameters()[0]; @@ -277,10 +246,9 @@ public class RequestResponseBodyMethodProcessorTests { this.servletRequest.setContent(content.getBytes(StandardCharsets.UTF_8)); this.servletRequest.setContentType(MediaType.APPLICATION_JSON_VALUE); - List> converters = new ArrayList<>(); HttpMessageConverter target = new MappingJackson2HttpMessageConverter(); HttpMessageConverter proxy = ProxyFactory.getProxy(HttpMessageConverter.class, new SingletonTargetSource(target)); - converters.add(proxy); + List> converters = List.of(proxy); RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(converters); SimpleBean result = (SimpleBean) processor.resolveArgument(methodParam, container, request, factory); @@ -290,12 +258,11 @@ public class RequestResponseBodyMethodProcessorTests { } @Test // SPR-9160 - public void handleReturnValueSortByQuality() throws Exception { + void handleReturnValueSortByQuality() throws Exception { this.servletRequest.addHeader("Accept", "text/plain; q=0.5, application/json"); - List> converters = new ArrayList<>(); - converters.add(new MappingJackson2HttpMessageConverter()); - converters.add(new StringHttpMessageConverter()); + List> converters = + List.of(new MappingJackson2HttpMessageConverter(), new StringHttpMessageConverter()); RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(converters); processor.writeWithMessageConverters("Foo", returnTypeString, request); @@ -304,11 +271,9 @@ public class RequestResponseBodyMethodProcessorTests { } @Test - public void handleReturnValueString() throws Exception { - List>converters = new ArrayList<>(); - converters.add(new ByteArrayHttpMessageConverter()); - converters.add(new StringHttpMessageConverter()); - + void handleReturnValueString() throws Exception { + List> converters = + List.of(new ByteArrayHttpMessageConverter(), new StringHttpMessageConverter()); RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(converters); processor.handleReturnValue("Foo", returnTypeString, container, request); @@ -317,14 +282,12 @@ public class RequestResponseBodyMethodProcessorTests { } @Test // SPR-13423 - public void handleReturnValueCharSequence() throws Exception { - List>converters = new ArrayList<>(); - converters.add(new ByteArrayHttpMessageConverter()); - converters.add(new StringHttpMessageConverter()); - + void handleReturnValueCharSequence() throws Exception { Method method = ResponseBodyController.class.getMethod("handleWithCharSequence"); MethodParameter returnType = new MethodParameter(method, -1); + List> converters = + List.of(new ByteArrayHttpMessageConverter(), new StringHttpMessageConverter()); RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(converters); processor.handleReturnValue(new StringBuilder("Foo"), returnType, container, request); @@ -333,12 +296,11 @@ public class RequestResponseBodyMethodProcessorTests { } @Test - public void handleReturnValueStringAcceptCharset() throws Exception { + void handleReturnValueStringAcceptCharset() throws Exception { this.servletRequest.addHeader("Accept", "text/plain;charset=UTF-8"); - List> converters = new ArrayList<>(); - converters.add(new ByteArrayHttpMessageConverter()); - converters.add(new StringHttpMessageConverter()); + List> converters = + List.of(new ByteArrayHttpMessageConverter(), new StringHttpMessageConverter()); RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(converters); processor.writeWithMessageConverters("Foo", returnTypeString, request); @@ -346,17 +308,14 @@ public class RequestResponseBodyMethodProcessorTests { assertThat(servletResponse.getHeader("Content-Type")).isEqualTo("text/plain;charset=UTF-8"); } - // SPR-12894 - - @Test - public void handleReturnValueImage() throws Exception { + @Test // SPR-12894 + void handleReturnValueImage() throws Exception { this.servletRequest.addHeader("Accept", "*/*"); Method method = getClass().getDeclaredMethod("getImage"); MethodParameter returnType = new MethodParameter(method, -1); - List> converters = new ArrayList<>(); - converters.add(new ResourceHttpMessageConverter()); + List> converters = List.of(new ResourceHttpMessageConverter()); RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(converters); ClassPathResource resource = new ClassPathResource("logo.jpg", getClass()); @@ -366,33 +325,29 @@ public class RequestResponseBodyMethodProcessorTests { } @Test // gh-26212 - public void handleReturnValueWithObjectMapperByTypeRegistration() throws Exception { + void handleReturnValueWithObjectMapperByTypeRegistration() throws Exception { MediaType halFormsMediaType = MediaType.parseMediaType("application/prs.hal-forms+json"); MediaType halMediaType = MediaType.parseMediaType("application/hal+json"); + this.servletRequest.addHeader("Accept", halFormsMediaType + "," + halMediaType); + ObjectMapper objectMapper = new ObjectMapper(); objectMapper.configure(SerializationFeature.INDENT_OUTPUT, true); - MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); - converter.registerObjectMappersForType(SimpleBean.class, map -> map.put(halMediaType, objectMapper)); - - this.servletRequest.addHeader("Accept", halFormsMediaType + "," + halMediaType); - SimpleBean simpleBean = new SimpleBean(); simpleBean.setId(12L); simpleBean.setName("Jason"); + MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); + converter.registerObjectMappersForType(SimpleBean.class, map -> map.put(halMediaType, objectMapper)); RequestResponseBodyMethodProcessor processor = - new RequestResponseBodyMethodProcessor(Collections.singletonList(converter)); + new RequestResponseBodyMethodProcessor(List.of(converter)); MethodParameter returnType = new MethodParameter(getClass().getDeclaredMethod("getSimpleBean"), -1); processor.writeWithMessageConverters(simpleBean, returnType, this.request); assertThat(this.servletResponse.getHeader("Content-Type")).isEqualTo(halMediaType.toString()); - assertThat(this.servletResponse.getContentAsString()).isEqualTo( - "{" + NEWLINE_SYSTEM_PROPERTY + - " \"id\" : 12," + NEWLINE_SYSTEM_PROPERTY + - " \"name\" : \"Jason\"" + NEWLINE_SYSTEM_PROPERTY + - "}"); + JSONAssert.assertEquals(""" + { "id" : 12, "name" : "Jason" }""", this.servletResponse.getContentAsString(), true); } @Test @@ -419,7 +374,6 @@ public class RequestResponseBodyMethodProcessorTests { } private void testProblemDetailMediaType(String expectedContentType) throws Exception { - ProblemDetail problemDetail = ProblemDetail.forStatus(HttpStatus.BAD_REQUEST); this.servletRequest.setRequestURI("/path"); @@ -437,20 +391,24 @@ public class RequestResponseBodyMethodProcessorTests { assertThat(this.servletResponse.getContentType()).isEqualTo(expectedContentType); if (expectedContentType.equals(MediaType.APPLICATION_PROBLEM_XML_VALUE)) { - assertThat(this.servletResponse.getContentAsString()).isEqualTo( - "" + - "about:blank" + - "Bad Request" + - "400" + - "/path" + - ""); + XmlAssert.assertThat(this.servletResponse.getContentAsString()).and(""" + + about:blank + Bad Request + 400 + /path + """) + .ignoreWhitespace() + .areIdentical(); } else { - assertThat(this.servletResponse.getContentAsString()).isEqualTo( - "{\"type\":\"about:blank\"," + - "\"title\":\"Bad Request\"," + - "\"status\":400," + - "\"instance\":\"/path\"}"); + JSONAssert.assertEquals(""" + { + "type": "about:blank", + "title": "Bad Request", + "status": 400, + "instance": "/path" + }""", this.servletResponse.getContentAsString(), false); } } @@ -461,24 +419,23 @@ public class RequestResponseBodyMethodProcessorTests { } @Test // SPR-13135 - public void handleReturnValueWithInvalidReturnType() throws Exception { + void handleReturnValueWithInvalidReturnType() throws Exception { Method method = getClass().getDeclaredMethod("handleAndReturnOutputStream"); MethodParameter returnType = new MethodParameter(method, -1); - assertThatIllegalArgumentException().isThrownBy(() -> { - RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(new ArrayList<>()); - processor.writeWithMessageConverters(new ByteArrayOutputStream(), returnType, this.request); - }); + List> converters = List.of(new StringHttpMessageConverter()); + RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(converters); + assertThatExceptionOfType(HttpMediaTypeNotAcceptableException.class).isThrownBy(() -> + processor.writeWithMessageConverters(new ByteArrayOutputStream(), returnType, this.request)); } @Test - public void addContentDispositionHeader() throws Exception { + void addContentDispositionHeader() throws Exception { ContentNegotiationManagerFactoryBean factory = new ContentNegotiationManagerFactoryBean(); factory.addMediaType("pdf", new MediaType("application", "pdf")); factory.afterPropertiesSet(); RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor( - Collections.singletonList(new StringHttpMessageConverter()), - factory.getObject()); + List.of(new StringHttpMessageConverter()), factory.getObject()); assertContentDisposition(processor, false, "/hello.json", "safe extension"); assertContentDisposition(processor, false, "/hello.pdf", "registered extension"); @@ -502,14 +459,13 @@ public class RequestResponseBodyMethodProcessorTests { } @Test - public void addContentDispositionHeaderToErrorResponse() throws Exception { + void addContentDispositionHeaderToErrorResponse() throws Exception { ContentNegotiationManagerFactoryBean factory = new ContentNegotiationManagerFactoryBean(); factory.addMediaType("pdf", new MediaType("application", "pdf")); factory.afterPropertiesSet(); RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor( - Collections.singletonList(new StringHttpMessageConverter()), - factory.getObject()); + List.of(new StringHttpMessageConverter()), factory.getObject()); this.servletRequest.setRequestURI("/hello.dataless"); this.servletResponse.setStatus(400); @@ -521,117 +477,105 @@ public class RequestResponseBodyMethodProcessorTests { } @Test - public void supportsReturnTypeResponseBodyOnType() throws Exception { + void supportsReturnTypeResponseBodyOnType() throws Exception { Method method = ResponseBodyController.class.getMethod("handle"); MethodParameter returnType = new MethodParameter(method, -1); - List> converters = new ArrayList<>(); - converters.add(new StringHttpMessageConverter()); - + List> converters = List.of(new StringHttpMessageConverter()); RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(converters); assertThat(processor.supportsReturnType(returnType)).as("Failed to recognize type-level @ResponseBody").isTrue(); } @Test - public void supportsReturnTypeRestController() throws Exception { + void supportsReturnTypeRestController() throws Exception { Method method = TestRestController.class.getMethod("handle"); MethodParameter returnType = new MethodParameter(method, -1); - List> converters = new ArrayList<>(); - converters.add(new StringHttpMessageConverter()); - + List> converters = List.of(new StringHttpMessageConverter()); RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(converters); assertThat(processor.supportsReturnType(returnType)).as("Failed to recognize type-level @RestController").isTrue(); } @Test - public void jacksonJsonViewWithResponseBodyAndJsonMessageConverter() throws Exception { + void jacksonJsonViewWithResponseBodyAndJsonMessageConverter() throws Exception { Method method = JacksonController.class.getMethod("handleResponseBody"); HandlerMethod handlerMethod = new HandlerMethod(new JacksonController(), method); MethodParameter methodReturnType = handlerMethod.getReturnType(); - List> converters = new ArrayList<>(); - converters.add(new MappingJackson2HttpMessageConverter()); - + List> converters = List.of(new MappingJackson2HttpMessageConverter()); RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor( - converters, null, Collections.singletonList(new JsonViewResponseBodyAdvice())); + converters, null, List.of(new JsonViewResponseBodyAdvice())); Object returnValue = new JacksonController().handleResponseBody(); processor.handleReturnValue(returnValue, methodReturnType, this.container, this.request); - String content = this.servletResponse.getContentAsString(); - assertThat(content.contains("\"withView1\":\"with\"")).isFalse(); - assertThat(content.contains("\"withView2\":\"with\"")).isTrue(); - assertThat(content.contains("\"withoutView\":\"without\"")).isFalse(); + assertThat(this.servletResponse.getContentAsString()) + .doesNotContain("\"withView1\":\"with\"") + .contains("\"withView2\":\"with\"") + .doesNotContain("\"withoutView\":\"without\""); } @Test - public void jacksonJsonViewWithResponseEntityAndJsonMessageConverter() throws Exception { + void jacksonJsonViewWithResponseEntityAndJsonMessageConverter() throws Exception { Method method = JacksonController.class.getMethod("handleResponseEntity"); HandlerMethod handlerMethod = new HandlerMethod(new JacksonController(), method); MethodParameter methodReturnType = handlerMethod.getReturnType(); - List> converters = new ArrayList<>(); - converters.add(new MappingJackson2HttpMessageConverter()); - + List> converters = List.of(new MappingJackson2HttpMessageConverter()); HttpEntityMethodProcessor processor = new HttpEntityMethodProcessor( - converters, null, Collections.singletonList(new JsonViewResponseBodyAdvice())); + converters, null, List.of(new JsonViewResponseBodyAdvice())); Object returnValue = new JacksonController().handleResponseEntity(); processor.handleReturnValue(returnValue, methodReturnType, this.container, this.request); - String content = this.servletResponse.getContentAsString(); - assertThat(content.contains("\"withView1\":\"with\"")).isFalse(); - assertThat(content.contains("\"withView2\":\"with\"")).isTrue(); - assertThat(content.contains("\"withoutView\":\"without\"")).isFalse(); + assertThat(this.servletResponse.getContentAsString()) + .doesNotContain("\"withView1\":\"with\"") + .contains("\"withView2\":\"with\"") + .doesNotContain("\"withoutView\":\"without\""); } @Test // SPR-12149 - public void jacksonJsonViewWithResponseBodyAndXmlMessageConverter() throws Exception { + void jacksonJsonViewWithResponseBodyAndXmlMessageConverter() throws Exception { Method method = JacksonController.class.getMethod("handleResponseBody"); HandlerMethod handlerMethod = new HandlerMethod(new JacksonController(), method); MethodParameter methodReturnType = handlerMethod.getReturnType(); - List> converters = new ArrayList<>(); - converters.add(new MappingJackson2XmlHttpMessageConverter()); - + List> converters = List.of(new MappingJackson2XmlHttpMessageConverter()); RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor( - converters, null, Collections.singletonList(new JsonViewResponseBodyAdvice())); + converters, null, List.of(new JsonViewResponseBodyAdvice())); Object returnValue = new JacksonController().handleResponseBody(); processor.handleReturnValue(returnValue, methodReturnType, this.container, this.request); - String content = this.servletResponse.getContentAsString(); - assertThat(content.contains("with")).isFalse(); - assertThat(content.contains("with")).isTrue(); - assertThat(content.contains("without")).isFalse(); + assertThat(this.servletResponse.getContentAsString()) + .doesNotContain("with") + .contains("with") + .doesNotContain("without"); } @Test // SPR-12149 - public void jacksonJsonViewWithResponseEntityAndXmlMessageConverter() throws Exception { + void jacksonJsonViewWithResponseEntityAndXmlMessageConverter() throws Exception { Method method = JacksonController.class.getMethod("handleResponseEntity"); HandlerMethod handlerMethod = new HandlerMethod(new JacksonController(), method); MethodParameter methodReturnType = handlerMethod.getReturnType(); - List> converters = new ArrayList<>(); - converters.add(new MappingJackson2XmlHttpMessageConverter()); - + List> converters = List.of(new MappingJackson2XmlHttpMessageConverter()); HttpEntityMethodProcessor processor = new HttpEntityMethodProcessor( - converters, null, Collections.singletonList(new JsonViewResponseBodyAdvice())); + converters, null, List.of(new JsonViewResponseBodyAdvice())); Object returnValue = new JacksonController().handleResponseEntity(); processor.handleReturnValue(returnValue, methodReturnType, this.container, this.request); - String content = this.servletResponse.getContentAsString(); - assertThat(content.contains("with")).isFalse(); - assertThat(content.contains("with")).isTrue(); - assertThat(content.contains("without")).isFalse(); + assertThat(this.servletResponse.getContentAsString()) + .doesNotContain("with") + .contains("with") + .doesNotContain("without"); } @Test // SPR-12501 - public void resolveArgumentWithJacksonJsonView() throws Exception { + void resolveArgumentWithJacksonJsonView() throws Exception { String content = "{\"withView1\" : \"with\", \"withView2\" : \"with\", \"withoutView\" : \"without\"}"; this.servletRequest.setContent(content.getBytes(StandardCharsets.UTF_8)); this.servletRequest.setContentType(MediaType.APPLICATION_JSON_VALUE); @@ -640,11 +584,9 @@ public class RequestResponseBodyMethodProcessorTests { HandlerMethod handlerMethod = new HandlerMethod(new JacksonController(), method); MethodParameter methodParameter = handlerMethod.getMethodParameters()[0]; - List> converters = new ArrayList<>(); - converters.add(new MappingJackson2HttpMessageConverter()); - + List> converters = List.of(new MappingJackson2HttpMessageConverter()); RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor( - converters, null, Collections.singletonList(new JsonViewRequestBodyAdvice())); + converters, null, List.of(new JsonViewRequestBodyAdvice())); JacksonViewBean result = (JacksonViewBean) processor.resolveArgument(methodParameter, this.container, this.request, this.factory); @@ -656,7 +598,7 @@ public class RequestResponseBodyMethodProcessorTests { } @Test // SPR-12501 - public void resolveHttpEntityArgumentWithJacksonJsonView() throws Exception { + void resolveHttpEntityArgumentWithJacksonJsonView() throws Exception { String content = "{\"withView1\" : \"with\", \"withView2\" : \"with\", \"withoutView\" : \"without\"}"; this.servletRequest.setContent(content.getBytes(StandardCharsets.UTF_8)); this.servletRequest.setContentType(MediaType.APPLICATION_JSON_VALUE); @@ -665,11 +607,9 @@ public class RequestResponseBodyMethodProcessorTests { HandlerMethod handlerMethod = new HandlerMethod(new JacksonController(), method); MethodParameter methodParameter = handlerMethod.getMethodParameters()[0]; - List> converters = new ArrayList<>(); - converters.add(new MappingJackson2HttpMessageConverter()); - + List> converters = List.of(new MappingJackson2HttpMessageConverter()); HttpEntityMethodProcessor processor = new HttpEntityMethodProcessor( - converters, null, Collections.singletonList(new JsonViewRequestBodyAdvice())); + converters, null, List.of(new JsonViewRequestBodyAdvice())); @SuppressWarnings("unchecked") HttpEntity result = (HttpEntity) @@ -683,7 +623,7 @@ public class RequestResponseBodyMethodProcessorTests { } @Test // SPR-12501 - public void resolveArgumentWithJacksonJsonViewAndXmlMessageConverter() throws Exception { + void resolveArgumentWithJacksonJsonViewAndXmlMessageConverter() throws Exception { String content = "" + "with" + "with" + @@ -695,11 +635,9 @@ public class RequestResponseBodyMethodProcessorTests { HandlerMethod handlerMethod = new HandlerMethod(new JacksonController(), method); MethodParameter methodParameter = handlerMethod.getMethodParameters()[0]; - List> converters = new ArrayList<>(); - converters.add(new MappingJackson2XmlHttpMessageConverter()); - + List> converters = List.of(new MappingJackson2XmlHttpMessageConverter()); RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor( - converters, null, Collections.singletonList(new JsonViewRequestBodyAdvice())); + converters, null, List.of(new JsonViewRequestBodyAdvice())); JacksonViewBean result = (JacksonViewBean) processor.resolveArgument(methodParameter, this.container, this.request, this.factory); @@ -711,7 +649,7 @@ public class RequestResponseBodyMethodProcessorTests { } @Test // SPR-12501 - public void resolveHttpEntityArgumentWithJacksonJsonViewAndXmlMessageConverter() throws Exception { + void resolveHttpEntityArgumentWithJacksonJsonViewAndXmlMessageConverter() throws Exception { String content = "" + "with" + "with" + @@ -723,11 +661,9 @@ public class RequestResponseBodyMethodProcessorTests { HandlerMethod handlerMethod = new HandlerMethod(new JacksonController(), method); MethodParameter methodParameter = handlerMethod.getMethodParameters()[0]; - List> converters = new ArrayList<>(); - converters.add(new MappingJackson2XmlHttpMessageConverter()); - + List> converters = List.of(new MappingJackson2XmlHttpMessageConverter()); HttpEntityMethodProcessor processor = new HttpEntityMethodProcessor( - converters, null, Collections.singletonList(new JsonViewRequestBodyAdvice())); + converters, null, List.of(new JsonViewRequestBodyAdvice())); @SuppressWarnings("unchecked") HttpEntity result = (HttpEntity) @@ -741,63 +677,60 @@ public class RequestResponseBodyMethodProcessorTests { } @Test // SPR-12811 - public void jacksonTypeInfoList() throws Exception { + void jacksonTypeInfoList() throws Exception { Method method = JacksonController.class.getMethod("handleTypeInfoList"); HandlerMethod handlerMethod = new HandlerMethod(new JacksonController(), method); MethodParameter methodReturnType = handlerMethod.getReturnType(); - List> converters = new ArrayList<>(); - converters.add(new MappingJackson2HttpMessageConverter()); + List> converters = List.of(new MappingJackson2HttpMessageConverter()); RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(converters); Object returnValue = new JacksonController().handleTypeInfoList(); processor.handleReturnValue(returnValue, methodReturnType, this.container, this.request); - String content = this.servletResponse.getContentAsString(); - assertThat(content.contains("\"type\":\"foo\"")).isTrue(); - assertThat(content.contains("\"type\":\"bar\"")).isTrue(); + assertThat(this.servletResponse.getContentAsString()) + .contains("\"type\":\"foo\"") + .contains("\"type\":\"bar\""); } @Test // SPR-13318 - public void jacksonSubType() throws Exception { + void jacksonSubType() throws Exception { Method method = JacksonController.class.getMethod("handleSubType"); HandlerMethod handlerMethod = new HandlerMethod(new JacksonController(), method); MethodParameter methodReturnType = handlerMethod.getReturnType(); - List> converters = new ArrayList<>(); - converters.add(new MappingJackson2HttpMessageConverter()); + List> converters = List.of(new MappingJackson2HttpMessageConverter()); RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(converters); Object returnValue = new JacksonController().handleSubType(); processor.handleReturnValue(returnValue, methodReturnType, this.container, this.request); - String content = this.servletResponse.getContentAsString(); - assertThat(content.contains("\"id\":123")).isTrue(); - assertThat(content.contains("\"name\":\"foo\"")).isTrue(); + assertThat(this.servletResponse.getContentAsString()) + .contains("\"id\":123") + .contains("\"name\":\"foo\""); } @Test // SPR-13318 - public void jacksonSubTypeList() throws Exception { + void jacksonSubTypeList() throws Exception { Method method = JacksonController.class.getMethod("handleSubTypeList"); HandlerMethod handlerMethod = new HandlerMethod(new JacksonController(), method); MethodParameter methodReturnType = handlerMethod.getReturnType(); - List> converters = new ArrayList<>(); - converters.add(new MappingJackson2HttpMessageConverter()); + List> converters = List.of(new MappingJackson2HttpMessageConverter()); RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(converters); Object returnValue = new JacksonController().handleSubTypeList(); processor.handleReturnValue(returnValue, methodReturnType, this.container, this.request); - String content = this.servletResponse.getContentAsString(); - assertThat(content.contains("\"id\":123")).isTrue(); - assertThat(content.contains("\"name\":\"foo\"")).isTrue(); - assertThat(content.contains("\"id\":456")).isTrue(); - assertThat(content.contains("\"name\":\"bar\"")).isTrue(); + assertThat(this.servletResponse.getContentAsString()) + .contains("\"id\":123") + .contains("\"name\":\"foo\"") + .contains("\"id\":456") + .contains("\"name\":\"bar\""); } @Test // SPR-14520 - public void resolveArgumentTypeVariableWithGenericInterface() throws Exception { + void resolveArgumentTypeVariableWithGenericInterface() throws Exception { this.servletRequest.setContent("\"foo\"".getBytes(StandardCharsets.UTF_8)); this.servletRequest.setContentType(MediaType.APPLICATION_JSON_VALUE); @@ -805,9 +738,7 @@ public class RequestResponseBodyMethodProcessorTests { HandlerMethod handlerMethod = new HandlerMethod(new MyControllerImplementingInterface(), method); MethodParameter methodParameter = handlerMethod.getMethodParameters()[0]; - List> converters = new ArrayList<>(); - converters.add(new MappingJackson2HttpMessageConverter()); - + List> converters = List.of(new MappingJackson2HttpMessageConverter()); RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(converters); assertThat(processor.supportsParameter(methodParameter)).isTrue(); @@ -817,7 +748,7 @@ public class RequestResponseBodyMethodProcessorTests { } @Test // gh-24127 - public void resolveArgumentTypeVariableWithGenericInterfaceAndSubclass() throws Exception { + void resolveArgumentTypeVariableWithGenericInterfaceAndSubclass() throws Exception { this.servletRequest.setContent("\"foo\"".getBytes(StandardCharsets.UTF_8)); this.servletRequest.setContentType(MediaType.APPLICATION_JSON_VALUE); @@ -825,9 +756,7 @@ public class RequestResponseBodyMethodProcessorTests { HandlerMethod handlerMethod = new HandlerMethod(new SubControllerImplementingInterface(), method); MethodParameter methodParameter = handlerMethod.getMethodParameters()[0]; - List> converters = new ArrayList<>(); - converters.add(new MappingJackson2HttpMessageConverter()); - + List> converters = List.of(new MappingJackson2HttpMessageConverter()); RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(converters); assertThat(processor.supportsParameter(methodParameter)).isTrue(); @@ -854,9 +783,9 @@ public class RequestResponseBodyMethodProcessorTests { .isNull(); } - this.servletRequest = new MockHttpServletRequest(); - this.servletResponse = new MockHttpServletResponse(); - this.request = new ServletWebRequest(servletRequest, servletResponse); + this.servletRequest.clearAttributes(); + this.servletResponse.setCommitted(false); + this.servletResponse.reset(); } @@ -1087,10 +1016,7 @@ public class RequestResponseBodyMethodProcessorTests { @ResponseBody @SuppressWarnings("unchecked") public List handleTypeInfoList() { - List list = new ArrayList<>(); - list.add((T) new Foo("foo")); - list.add((T) new Bar("bar")); - return list; + return List.of((T) new Foo("foo"), (T) new Bar("bar")); } }