diff --git a/spring-integration-http/src/main/java/org/springframework/integration/http/outbound/AbstractHttpRequestExecutingMessageHandler.java b/spring-integration-http/src/main/java/org/springframework/integration/http/outbound/AbstractHttpRequestExecutingMessageHandler.java index 74b5810dc51..b36ad1e93ba 100644 --- a/spring-integration-http/src/main/java/org/springframework/integration/http/outbound/AbstractHttpRequestExecutingMessageHandler.java +++ b/spring-integration-http/src/main/java/org/springframework/integration/http/outbound/AbstractHttpRequestExecutingMessageHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2021 the original author or authors. + * Copyright 2017-2022 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. @@ -118,8 +118,8 @@ public AbstractHttpRequestExecutingMessageHandler(Expression uriExpression) { /** * Set the encoding mode to use. - * By default this is set to {@link DefaultUriBuilderFactory.EncodingMode#TEMPLATE_AND_VALUES}. - * For more complicated scenarios consider to configure an {@link org.springframework.web.util.UriTemplateHandler} + * By default, this is set to {@link DefaultUriBuilderFactory.EncodingMode#TEMPLATE_AND_VALUES}. + * For more complicated scenarios consider configuring an {@link org.springframework.web.util.UriTemplateHandler} * on an externally provided {@link org.springframework.web.client.RestTemplate}. * @param encodingMode the mode to use for uri encoding * @since 5.3 @@ -151,7 +151,7 @@ public void setHttpMethod(HttpMethod httpMethod) { /** * Specify whether the outbound message's payload should be extracted * when preparing the request body. - * Otherwise the Message instance itself is serialized. + * Otherwise, the Message instance itself is serialized. * The default value is {@code true}. * @param extractPayload true if the payload should be extracted. */ @@ -189,7 +189,7 @@ public void setExpectReply(boolean expectReply) { /** * Specify the expected response type for the REST request. - * Otherwise it is null and an empty {@link ResponseEntity} is returned from HTTP client. + * Otherwise, it is null and an empty {@link ResponseEntity} is returned from HTTP client. * To take advantage of the HttpMessageConverters * registered on this adapter, provide a different type). * @param expectedResponseType The expected type. @@ -378,8 +378,8 @@ private HttpEntity createHttpEntityFromPayload(Message message, HttpMethod : resolveContentType(payload); httpHeaders.setContentType(contentType); } - if ((MediaType.APPLICATION_FORM_URLENCODED.equals(httpHeaders.getContentType()) || - MediaType.MULTIPART_FORM_DATA.equals(httpHeaders.getContentType())) + if ((MediaType.APPLICATION_FORM_URLENCODED.equalsTypeAndSubtype(httpHeaders.getContentType()) || + MediaType.MULTIPART_FORM_DATA.equalsTypeAndSubtype(httpHeaders.getContentType())) && !(payload instanceof MultiValueMap)) { Assert.isInstanceOf(Map.class, payload, @@ -471,8 +471,7 @@ private boolean isMultipart(Map map) { if (value.getClass().isArray()) { value = CollectionUtils.arrayToList(value); } - if (value instanceof Collection) { - Collection cValues = (Collection) value; + if (value instanceof Collection cValues) { for (Object cValue : cValues) { if (cValue != null && !(cValue instanceof String)) { return true; diff --git a/spring-integration-http/src/test/java/org/springframework/integration/http/HttpProxyScenarioTests-context.xml b/spring-integration-http/src/test/java/org/springframework/integration/http/HttpProxyScenarioTests-context.xml index e3a3f8284b2..8370d4e93c1 100644 --- a/spring-integration-http/src/test/java/org/springframework/integration/http/HttpProxyScenarioTests-context.xml +++ b/spring-integration-http/src/test/java/org/springframework/integration/http/HttpProxyScenarioTests-context.xml @@ -1,14 +1,12 @@ + http://www.springframework.org/schema/integration https://www.springframework.org/schema/integration/spring-integration.xsd"> @@ -25,15 +23,14 @@ - - - - - - + message-converters="formHttpMessageConverter"/> + + + + + + diff --git a/spring-integration-http/src/test/java/org/springframework/integration/http/HttpProxyScenarioTests.java b/spring-integration-http/src/test/java/org/springframework/integration/http/HttpProxyScenarioTests.java index 8126251035b..ce883ee2241 100644 --- a/spring-integration-http/src/test/java/org/springframework/integration/http/HttpProxyScenarioTests.java +++ b/spring-integration-http/src/test/java/org/springframework/integration/http/HttpProxyScenarioTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2020 the original author or authors. + * Copyright 2013-2022 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. @@ -46,6 +46,7 @@ import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.web.client.RestTemplate; @@ -120,19 +121,19 @@ public void testHttpProxyScenario() throws Exception { final String contentDispositionValue = "attachment; filename=\"test.txt\""; Mockito.doAnswer(invocation -> { - String uri = invocation.getArgument(0); - assertThat(uri).isEqualTo("http://testServer/test?foo=bar&FOO=BAR"); - HttpEntity httpEntity = (HttpEntity) invocation.getArguments()[2]; - HttpHeaders httpHeaders = httpEntity.getHeaders(); - assertThat(httpHeaders.getIfModifiedSince()).isEqualTo(ifModifiedSince); - assertThat(httpHeaders.getFirst("If-Unmodified-Since")).isEqualTo(ifUnmodifiedSinceValue); - assertThat(httpHeaders.getFirst("Connection")).isEqualTo("Keep-Alive"); - - MultiValueMap responseHeaders = new LinkedMultiValueMap<>(httpHeaders); - responseHeaders.set("Connection", "close"); - responseHeaders.set("Content-Disposition", contentDispositionValue); - return new ResponseEntity<>(responseHeaders, HttpStatus.OK); - }).when(template) + String uri = invocation.getArgument(0); + assertThat(uri).isEqualTo("http://testServer/test?foo=bar&FOO=BAR"); + HttpEntity httpEntity = (HttpEntity) invocation.getArguments()[2]; + HttpHeaders httpHeaders = httpEntity.getHeaders(); + assertThat(httpHeaders.getIfModifiedSince()).isEqualTo(ifModifiedSince); + assertThat(httpHeaders.getFirst("If-Unmodified-Since")).isEqualTo(ifUnmodifiedSinceValue); + assertThat(httpHeaders.getFirst("Connection")).isEqualTo("Keep-Alive"); + + MultiValueMap responseHeaders = new LinkedMultiValueMap<>(httpHeaders); + responseHeaders.set("Connection", "close"); + responseHeaders.set("Content-Disposition", contentDispositionValue); + return new ResponseEntity<>(responseHeaders, HttpStatus.OK); + }).when(template) .exchange(Mockito.anyString(), Mockito.any(HttpMethod.class), Mockito.any(HttpEntity.class), (Class) isNull(), Mockito.anyMap()); @@ -160,12 +161,14 @@ public void testHttpProxyScenario() throws Exception { } @Test + @SuppressWarnings("unchecked") public void testHttpMultipartProxyScenario() throws Exception { - MockHttpServletRequest request = new MockHttpServletRequest("POST", "/testmp"); - - request.addHeader("Connection", "Keep-Alive"); - request.setContentType("multipart/form-data;boundary=----WebKitFormBoundarywABD2xqC1FLBijlQ"); - request.setContent("foo".getBytes()); + MockHttpServletRequest request = + MockMvcRequestBuilders.multipart("/testmp") + .file("foo", "foo".getBytes()) + .contentType("multipart/form-data;boundary=----WebKitFormBoundarywABD2xqC1FLBijlQ") + .header("Connection", "Keep-Alive") + .buildRequest(null); Object handler = this.handlerMapping.getHandler(request).getHandler(); assertThat(handler).isNotNull(); @@ -174,23 +177,24 @@ public void testHttpMultipartProxyScenario() throws Exception { RestTemplate template = Mockito.spy(new RestTemplate()); Mockito.doAnswer(invocation -> { - String uri = invocation.getArgument(0); - assertThat(uri).isEqualTo("http://testServer/testmp"); - HttpEntity httpEntity = (HttpEntity) invocation.getArguments()[2]; - HttpHeaders httpHeaders = httpEntity.getHeaders(); - assertThat(httpHeaders.getFirst("Connection")).isEqualTo("Keep-Alive"); - assertThat(httpHeaders.getContentType().toString()) - .isEqualTo("multipart/form-data;boundary=----WebKitFormBoundarywABD2xqC1FLBijlQ"); - - HttpEntity entity = (HttpEntity) invocation.getArguments()[2]; - assertThat(entity.getBody()).isInstanceOf(byte[].class); - assertThat(new String((byte[]) entity.getBody())).isEqualTo("foo"); - - MultiValueMap responseHeaders = new LinkedMultiValueMap<>(httpHeaders); - responseHeaders.set("Connection", "close"); - responseHeaders.set("Content-Type", "text/plain"); - return new ResponseEntity<>(responseHeaders, HttpStatus.OK); - }).when(template) + String uri = invocation.getArgument(0); + assertThat(uri).isEqualTo("http://testServer/testmp"); + HttpEntity httpEntity = (HttpEntity) invocation.getArguments()[2]; + HttpHeaders httpHeaders = httpEntity.getHeaders(); + assertThat(httpHeaders.getFirst("Connection")).isEqualTo("Keep-Alive"); + assertThat(httpHeaders.getContentType().toString()) + .isEqualTo("multipart/form-data;boundary=----WebKitFormBoundarywABD2xqC1FLBijlQ"); + + HttpEntity entity = (HttpEntity) invocation.getArguments()[2]; + assertThat(entity.getBody()).isInstanceOf(MultiValueMap.class); + assertThat(((MultiValueMap) entity.getBody()).getFirst("foo")) + .isEqualTo("foo".getBytes()); + + MultiValueMap responseHeaders = new LinkedMultiValueMap<>(httpHeaders); + responseHeaders.set("Connection", "close"); + responseHeaders.set("Content-Type", "text/plain"); + return new ResponseEntity<>(responseHeaders, HttpStatus.OK); + }).when(template) .exchange(Mockito.anyString(), Mockito.any(HttpMethod.class), Mockito.any(HttpEntity.class), (Class) isNull(), Mockito.anyMap()); diff --git a/spring-integration-http/src/test/java/org/springframework/integration/http/outbound/HttpRequestExecutingMessageHandlerTests.java b/spring-integration-http/src/test/java/org/springframework/integration/http/outbound/HttpRequestExecutingMessageHandlerTests.java index 1275fe14672..5e74448442e 100644 --- a/spring-integration-http/src/test/java/org/springframework/integration/http/outbound/HttpRequestExecutingMessageHandlerTests.java +++ b/spring-integration-http/src/test/java/org/springframework/integration/http/outbound/HttpRequestExecutingMessageHandlerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2022 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. @@ -61,6 +61,7 @@ import org.springframework.lang.Nullable; import org.springframework.messaging.Message; import org.springframework.messaging.MessageChannel; +import org.springframework.messaging.MessageHeaders; import org.springframework.messaging.PollableChannel; import org.springframework.messaging.support.GenericMessage; import org.springframework.mock.http.client.MockClientHttpResponse; @@ -85,10 +86,12 @@ */ public class HttpRequestExecutingMessageHandlerTests { + // Used in the HttpOutboundWithinChainTests-context.xml public static ParameterizedTypeReference> testParameterizedTypeReference() { - return new ParameterizedTypeReference>() { + return new ParameterizedTypeReference<>() { }; + } @Test @@ -104,7 +107,11 @@ public void simpleStringKeyStringValueFormData() { form.put("a", "1"); form.put("b", "2"); form.put("c", "3"); - Message message = MessageBuilder.withPayload(form).build(); + Message message = + MessageBuilder.withPayload(form) + .setHeader(MessageHeaders.CONTENT_TYPE, + MediaType.APPLICATION_FORM_URLENCODED_VALUE + ";charset=UTF-8") + .build(); QueueChannel replyChannel = new QueueChannel(); handler.setOutputChannel(replyChannel); @@ -115,12 +122,14 @@ public void simpleStringKeyStringValueFormData() { HttpEntity request = template.lastRequestEntity.get(); Object body = request.getBody(); assertThat(request.getHeaders().getContentType()).isNotNull(); - assertThat(body instanceof MultiValueMap).isTrue(); + assertThat(body).isInstanceOf(MultiValueMap.class); MultiValueMap map = (MultiValueMap) body; assertThat(map.get("a").iterator().next()).isEqualTo("1"); assertThat(map.get("b").iterator().next()).isEqualTo("2"); assertThat(map.get("c").iterator().next()).isEqualTo("3"); - assertThat(request.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_FORM_URLENCODED); + assertThat(request.getHeaders().getContentType()).isNotEqualTo(MediaType.APPLICATION_FORM_URLENCODED); + assertThat(request.getHeaders().getContentType().equalsTypeAndSubtype(MediaType.APPLICATION_FORM_URLENCODED)) + .isTrue(); } @Test @@ -541,7 +550,7 @@ public void contentAsByteArray() { HttpEntity request = template.lastRequestEntity.get(); Object body = request.getBody(); - assertThat(body instanceof byte[]).isTrue(); + assertThat(body).isInstanceOf(byte[].class); assertThat(new String(bytes)).isEqualTo("Hello World"); assertThat(request.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_OCTET_STREAM); } @@ -564,7 +573,7 @@ public void contentAsXmlSource() { HttpEntity request = template.lastRequestEntity.get(); Object body = request.getBody(); - assertThat(body instanceof Source).isTrue(); + assertThat(body).isInstanceOf(Source.class); assertThat(request.getHeaders().getContentType()).isEqualTo(MediaType.TEXT_XML); } @@ -784,7 +793,7 @@ public void acceptHeaderForSerializableResponse() throws IOException { assertThat(requestHeaders.getAccept()).isNotNull(); assertThat(requestHeaders.getAccept().size() > 0).isTrue(); List accept = requestHeaders.getAccept(); - assertThat(accept.size() > 0).isTrue(); + assertThat(accept).hasSizeGreaterThan(0); assertThat(accept.get(0).getType()).isEqualTo("application"); assertThat(accept.get(0).getSubtype()).isEqualTo("x-java-serialized-object"); } @@ -815,13 +824,13 @@ public void acceptHeaderForSerializableResponseMessageExchange() throws IOExcept assertThat(requestHeaders.getAccept()).isNotNull(); assertThat(requestHeaders.getAccept().size() > 0).isTrue(); List accept = requestHeaders.getAccept(); - assertThat(accept.size() > 0).isTrue(); + assertThat(accept).hasSizeGreaterThan(0); assertThat(accept.get(0).getType()).isEqualTo("application"); assertThat(accept.get(0).getSubtype()).isEqualTo("x-java-serialized-object"); } @Test - public void testNoContentTypeAndSmartConverter() throws IOException { + public void testNoContentTypeAndSmartConverter() { Sinks.One httpHeadersSink = Sinks.one(); RestTemplate testRestTemplate = new RestTemplate() { @Nullable