From e0bf63bed1d88e7ee9c736e121983196a0cfb6c3 Mon Sep 17 00:00:00 2001 From: Eugene Date: Wed, 5 Sep 2018 23:07:56 +0300 Subject: [PATCH] Added support for MultipartFile (#66) Fixes gh-62 ### Notes The solution is based on ``` io.github.openfeign.form feign-form-spring 3.3.0 ``` Class `feign.form.spring.SpringFormEncoder` was added inside `org.springframework.cloud.openfeign.support.SpringEncoder` because it's doesn't has some checks: 1. Check of `bodyType` on null. `org.springframework.cloud.openfeign.support.SpringEncoder#encode` don't handle situation when `bodyType` is null. 2. No check for content type `multipart/form-data` in header. `feign.form.FormEncoder` requires `multipart/form-data` in header for proper processing. All this checks added and tests are passed. --- spring-cloud-openfeign-core/pom.xml | 4 +++ .../openfeign/support/SpringEncoder.java | 17 +++++++++++ .../openfeign/support/SpringEncoderTests.java | 28 +++++++++++++++++++ spring-cloud-openfeign-dependencies/pom.xml | 6 ++++ 4 files changed, 55 insertions(+) diff --git a/spring-cloud-openfeign-core/pom.xml b/spring-cloud-openfeign-core/pom.xml index 804b8ae6..8692b734 100644 --- a/spring-cloud-openfeign-core/pom.xml +++ b/spring-cloud-openfeign-core/pom.xml @@ -93,6 +93,10 @@ feign-core true + + io.github.openfeign.form + feign-form-spring + io.github.openfeign feign-slf4j diff --git a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/SpringEncoder.java b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/SpringEncoder.java index 0ee52016..fa4508ab 100644 --- a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/SpringEncoder.java +++ b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/SpringEncoder.java @@ -24,6 +24,7 @@ import java.lang.reflect.Type; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.Collection; +import java.util.Objects; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -35,10 +36,12 @@ import org.springframework.http.MediaType; import org.springframework.http.converter.ByteArrayHttpMessageConverter; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.protobuf.ProtobufHttpMessageConverter; +import org.springframework.web.multipart.MultipartFile; import feign.RequestTemplate; import feign.codec.EncodeException; import feign.codec.Encoder; +import feign.form.spring.SpringFormEncoder; import static org.springframework.cloud.openfeign.support.FeignUtils.getHeaders; import static org.springframework.cloud.openfeign.support.FeignUtils.getHttpHeaders; @@ -51,6 +54,8 @@ public class SpringEncoder implements Encoder { private static final Log log = LogFactory.getLog(SpringEncoder.class); + private final SpringFormEncoder springFormEncoder = new SpringFormEncoder(); + private ObjectFactory messageConverters; public SpringEncoder(ObjectFactory messageConverters) { @@ -71,6 +76,18 @@ public class SpringEncoder implements Encoder { requestContentType = MediaType.valueOf(type); } + if (bodyType != null && bodyType.equals(MultipartFile.class)) { + if (Objects.equals(requestContentType, MediaType.MULTIPART_FORM_DATA)) { + springFormEncoder.encode(requestBody, bodyType, request); + return; + } else { + String message = "Content-Type \"" + MediaType.MULTIPART_FORM_DATA + + "\" not set for request body of type " + + requestBody.getClass().getSimpleName(); + throw new EncodeException(message); + } + } + for (HttpMessageConverter messageConverter : this.messageConverters .getObject().getConverters()) { if (messageConverter.canWrite(requestType, requestContentType)) { diff --git a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/support/SpringEncoderTests.java b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/support/SpringEncoderTests.java index f3672d94..fcc9b53e 100644 --- a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/support/SpringEncoderTests.java +++ b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/support/SpringEncoderTests.java @@ -40,9 +40,11 @@ import org.springframework.http.converter.AbstractGenericHttpMessageConverter; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.http.converter.HttpMessageNotWritableException; +import org.springframework.mock.web.MockMultipartFile; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; @@ -50,6 +52,7 @@ import static org.hamcrest.Matchers.nullValue; import static org.junit.Assert.assertThat; import feign.RequestTemplate; +import feign.codec.EncodeException; /** * @author Spencer Gibb @@ -96,6 +99,31 @@ public class SpringEncoderTests { assertThat("request charset is not null", request.charset(), is(nullValue())); } + + @Test(expected = EncodeException.class) + public void testMultipartFile1() { + SpringEncoder encoder = this.context.getInstance("foo", SpringEncoder.class); + assertThat(encoder, is(notNullValue())); + RequestTemplate request = new RequestTemplate(); + + MultipartFile multipartFile = new MockMultipartFile("test_multipart_file", "hi".getBytes()); + encoder.encode(multipartFile, MultipartFile.class, request); + + assertThat("request charset is not null", request.charset(), is(nullValue())); + } + + @Test + public void testMultipartFile2() { + SpringEncoder encoder = this.context.getInstance("foo", SpringEncoder.class); + assertThat(encoder, is(notNullValue())); + RequestTemplate request = new RequestTemplate(); + request = request.header("Content-Type", MediaType.MULTIPART_FORM_DATA_VALUE); + + MultipartFile multipartFile = new MockMultipartFile("test_multipart_file", "hi".getBytes()); + encoder.encode(multipartFile, MultipartFile.class, request); + + assertThat("request charset is not null", request.charset(), is(nullValue())); + } class MediaTypeMatcher implements ArgumentMatcher { diff --git a/spring-cloud-openfeign-dependencies/pom.xml b/spring-cloud-openfeign-dependencies/pom.xml index a8de436e..17a23e53 100644 --- a/spring-cloud-openfeign-dependencies/pom.xml +++ b/spring-cloud-openfeign-dependencies/pom.xml @@ -15,6 +15,7 @@ Spring Cloud OpenFeign Dependencies 9.5.1 + 3.3.0 @@ -33,6 +34,11 @@ feign-core ${feign.version} + + io.github.openfeign.form + feign-form-spring + ${feign-form.version} + io.github.openfeign feign-slf4j