From cd1dc97b72f25f9960a1f3e21d9d59b01ca6243f Mon Sep 17 00:00:00 2001 From: Darren Foong Date: Sat, 28 Mar 2020 01:31:56 +0800 Subject: [PATCH 01/11] Update SpringFormEncoder to encode POJOs in multipart form-data payload --- feign-form-spring/pom.xml | 6 +- .../form/spring/PojoSerializationWriter.java | 65 +++++++++++++++++++ .../feign/form/spring/SpringFormEncoder.java | 9 +++ .../java/feign/form/feign/spring/Client.java | 40 ++++++++++-- .../java/feign/form/feign/spring/Pojo.java | 36 ++++++++++ .../java/feign/form/feign/spring/Server.java | 32 ++++++++- .../feign/spring/SpringFormEncoderTest.java | 21 ++++++ pom.xml | 4 +- 8 files changed, 202 insertions(+), 11 deletions(-) create mode 100644 feign-form-spring/src/main/java/feign/form/spring/PojoSerializationWriter.java create mode 100644 feign-form-spring/src/test/java/feign/form/feign/spring/Pojo.java diff --git a/feign-form-spring/pom.xml b/feign-form-spring/pom.xml index 17a9ff9..ffc75ee 100644 --- a/feign-form-spring/pom.xml +++ b/feign-form-spring/pom.xml @@ -44,7 +44,7 @@ limitations under the License. org.springframework spring-web - 5.1.5.RELEASE + 5.2.5.RELEASE compile @@ -58,13 +58,13 @@ limitations under the License. org.springframework.boot spring-boot-starter-web - 2.1.3.RELEASE + 2.2.6.RELEASE test org.springframework.cloud spring-cloud-starter-openfeign - 2.1.1.RELEASE + 2.2.2.RELEASE test diff --git a/feign-form-spring/src/main/java/feign/form/spring/PojoSerializationWriter.java b/feign-form-spring/src/main/java/feign/form/spring/PojoSerializationWriter.java new file mode 100644 index 0000000..476ec2a --- /dev/null +++ b/feign-form-spring/src/main/java/feign/form/spring/PojoSerializationWriter.java @@ -0,0 +1,65 @@ +/* + * Copyright 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package feign.form.spring; + +import static feign.form.ContentProcessor.CRLF; +import static feign.form.util.PojoUtil.isUserPojo; + +import org.springframework.http.MediaType; +import org.springframework.web.multipart.MultipartFile; + +import feign.codec.EncodeException; +import feign.form.multipart.AbstractWriter; +import feign.form.multipart.Output; + +import lombok.val; + +import java.io.IOException; + +/** + * + * @author Darren Foong + */ +public abstract class PojoSerializationWriter extends AbstractWriter { + @Override + public boolean isApplicable(Object object) { + return !(object instanceof MultipartFile) && !(object instanceof MultipartFile[]) && isUserPojo(object); + } + + @Override + public void write (Output output, String key, Object object) throws EncodeException { + try { + val string = new StringBuilder() + .append("Content-Disposition: form-data; name=\"").append(key).append('"') + .append(CRLF) + .append("Content-Type: ").append(getContentType()) + .append("; charset=").append(output.getCharset().name()) + .append(CRLF) + .append(CRLF) + .append(serialize(object)) + .toString(); + + output.write(string); + } catch (IOException e) { + throw new EncodeException(e.getMessage()); + } + } + + protected abstract MediaType getContentType(); + + protected abstract String serialize(Object object) throws IOException; +} diff --git a/feign-form-spring/src/main/java/feign/form/spring/SpringFormEncoder.java b/feign-form-spring/src/main/java/feign/form/spring/SpringFormEncoder.java index 2ce3321..6f081de 100644 --- a/feign-form-spring/src/main/java/feign/form/spring/SpringFormEncoder.java +++ b/feign-form-spring/src/main/java/feign/form/spring/SpringFormEncoder.java @@ -59,6 +59,15 @@ public SpringFormEncoder (Encoder delegate) { processor.addFirstWriter(new SpringManyMultipartFilesWriter()); } + public SpringFormEncoder(PojoSerializationWriter pojoSerializationWriter, Encoder delegate) { + super(delegate); + + val processor = (MultipartFormContentProcessor) getContentProcessor(MULTIPART); + processor.addFirstWriter(new SpringSingleMultipartFileWriter()); + processor.addFirstWriter(new SpringManyMultipartFilesWriter()); + processor.addFirstWriter(pojoSerializationWriter); + } + @Override public void encode (Object object, Type bodyType, RequestTemplate template) throws EncodeException { if (bodyType.equals(MultipartFile[].class)) { diff --git a/feign-form-spring/src/test/java/feign/form/feign/spring/Client.java b/feign-form-spring/src/test/java/feign/form/feign/spring/Client.java index d116fac..691b514 100644 --- a/feign-form-spring/src/test/java/feign/form/feign/spring/Client.java +++ b/feign-form-spring/src/test/java/feign/form/feign/spring/Client.java @@ -20,12 +20,15 @@ import static org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE; import static org.springframework.web.bind.annotation.RequestMethod.POST; +import java.io.IOException; import java.util.List; import java.util.Map; +import com.fasterxml.jackson.databind.ObjectMapper; import feign.Logger; import feign.Response; import feign.codec.Encoder; +import feign.form.spring.PojoSerializationWriter; import feign.form.spring.SpringFormEncoder; import org.springframework.beans.factory.ObjectFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -33,6 +36,7 @@ import org.springframework.cloud.openfeign.FeignClient; import org.springframework.cloud.openfeign.support.SpringEncoder; import org.springframework.context.annotation.Bean; +import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; @@ -57,7 +61,7 @@ public interface Client { consumes = MULTIPART_FORM_DATA_VALUE ) String upload1 (@PathVariable("folder") String folder, - @RequestPart MultipartFile file, + @RequestPart("file") MultipartFile file, @RequestParam(value = "message", required = false) String message); @RequestMapping( @@ -99,14 +103,28 @@ String upload4 (@PathVariable("id") String id, method = POST, consumes = MULTIPART_FORM_DATA_VALUE ) - String upload6Array (@RequestPart MultipartFile[] files); + String upload6Array (@RequestPart("files") MultipartFile[] files); @RequestMapping( path = "/multipart/upload6", method = POST, consumes = MULTIPART_FORM_DATA_VALUE ) - String upload6Collection (@RequestPart List files); + String upload6Collection (@RequestPart("files") List files); + + @RequestMapping( + path = "/multipart/upload7", + method = POST, + consumes = MULTIPART_FORM_DATA_VALUE + ) + String upload7 (@RequestPart("pojo") Pojo pojo); + + @RequestMapping( + path = "/multipart/upload8", + method = POST, + consumes = MULTIPART_FORM_DATA_VALUE + ) + String upload8 (@RequestPart("pojo") Pojo pojo, @RequestPart("files") List files); class ClientConfiguration { @@ -115,7 +133,21 @@ class ClientConfiguration { @Bean public Encoder feignEncoder () { - return new SpringFormEncoder(new SpringEncoder(messageConverters)); + PojoSerializationWriter pojoSerializationWriter = new PojoSerializationWriter() { + private ObjectMapper objectMapper = new ObjectMapper(); + + @Override + protected MediaType getContentType() { + return MediaType.APPLICATION_JSON; + } + + @Override + protected String serialize(Object object) throws IOException { + return objectMapper.writeValueAsString(object); + } + }; + + return new SpringFormEncoder(pojoSerializationWriter, new SpringEncoder(messageConverters)); } @Bean diff --git a/feign-form-spring/src/test/java/feign/form/feign/spring/Pojo.java b/feign-form-spring/src/test/java/feign/form/feign/spring/Pojo.java new file mode 100644 index 0000000..f0668c3 --- /dev/null +++ b/feign-form-spring/src/test/java/feign/form/feign/spring/Pojo.java @@ -0,0 +1,36 @@ +/* + * Copyright 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package feign.form.feign.spring; + +import static lombok.AccessLevel.PRIVATE; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.FieldDefaults; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@FieldDefaults(level = PRIVATE) +public class Pojo { + String field1; + + String field2; + + int field3; +} diff --git a/feign-form-spring/src/test/java/feign/form/feign/spring/Server.java b/feign-form-spring/src/test/java/feign/form/feign/spring/Server.java index 953a0b1..e6ecda6 100644 --- a/feign-form-spring/src/test/java/feign/form/feign/spring/Server.java +++ b/feign-form-spring/src/test/java/feign/form/feign/spring/Server.java @@ -25,6 +25,7 @@ import static org.springframework.web.bind.annotation.RequestMethod.POST; import java.io.IOException; +import java.util.List; import java.util.Map; import lombok.SneakyThrows; @@ -121,9 +122,11 @@ void upload5 (Dto dto) throws IOException { method = POST, consumes = MULTIPART_FORM_DATA_VALUE ) - public ResponseEntity upload6 (@RequestParam("popa1") MultipartFile popa1, - @RequestParam("popa2") MultipartFile popa2 + public ResponseEntity upload6 (@RequestPart("files") List files ) throws Exception { + MultipartFile popa1 = files.get(0); + MultipartFile popa2 = files.get(1); + HttpStatus status = I_AM_A_TEAPOT; String result = ""; if (popa1 != null && popa2 != null) { @@ -133,6 +136,31 @@ public ResponseEntity upload6 (@RequestParam("popa1") MultipartFile popa return ResponseEntity.status(status).body(result); } + @RequestMapping( + path = "/multipart/upload7", + method = POST, + consumes = MULTIPART_FORM_DATA_VALUE + ) + public ResponseEntity upload7 (@RequestPart("pojo") Pojo pojo + ) throws Exception { + val result = pojo.getField1() + pojo.getField2() + pojo.getField3(); + + return ResponseEntity.ok(result); + } + + @RequestMapping( + path = "/multipart/upload8", + method = POST, + consumes = MULTIPART_FORM_DATA_VALUE + ) + public ResponseEntity upload8 (@RequestPart("pojo") Pojo pojo, @RequestPart("files") List files + ) throws Exception { + val result1 = pojo.getField1() + pojo.getField2() + pojo.getField3(); + val result2 = new String(files.get(0).getBytes()) + new String(files.get(1).getBytes()); + + return ResponseEntity.ok(result1 + result2); + } + @RequestMapping( path = "/multipart/download/{fileId}", method = GET, diff --git a/feign-form-spring/src/test/java/feign/form/feign/spring/SpringFormEncoderTest.java b/feign-form-spring/src/test/java/feign/form/feign/spring/SpringFormEncoderTest.java index 1736cfa..c1a589e 100644 --- a/feign-form-spring/src/test/java/feign/form/feign/spring/SpringFormEncoderTest.java +++ b/feign-form-spring/src/test/java/feign/form/feign/spring/SpringFormEncoderTest.java @@ -133,4 +133,25 @@ public void upload6CollectionTest () throws Exception { val response = client.upload6Collection(list); Assert.assertEquals("Hello world", response); } + + @Test + public void upload7Test () throws Exception { + Pojo pojo = new Pojo("Hello", " world", 1); + + val response = client.upload7(pojo); + Assert.assertEquals("Hello world1", response); + } + + @Test + public void upload8Test () throws Exception { + Pojo pojo = new Pojo("Hello", " world", 1); + + List list = asList( + (MultipartFile) new MockMultipartFile("files", "popa1", null, "Hello".getBytes(UTF_8)), + (MultipartFile) new MockMultipartFile("files", "popa2", null, " world".getBytes(UTF_8)) + ); + + val response = client.upload8(pojo, list); + Assert.assertEquals("Hello world1Hello world", response); + } } diff --git a/pom.xml b/pom.xml index d038562..9a40ef1 100644 --- a/pom.xml +++ b/pom.xml @@ -146,13 +146,13 @@ limitations under the License. org.springframework.boot spring-boot-starter-web - 2.1.3.RELEASE + 2.2.6.RELEASE test org.springframework.boot spring-boot-starter-test - 2.1.3.RELEASE + 2.2.6.RELEASE test From 9deb0245140eeebd44d489bb4dc49a4f2c8a565c Mon Sep 17 00:00:00 2001 From: Darren Foong Date: Sat, 28 Mar 2020 16:42:15 +0800 Subject: [PATCH 02/11] Add upload6SameNameTests --- .../feign/spring/SpringFormEncoderTest.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/feign-form-spring/src/test/java/feign/form/feign/spring/SpringFormEncoderTest.java b/feign-form-spring/src/test/java/feign/form/feign/spring/SpringFormEncoderTest.java index c1a589e..876a5a3 100644 --- a/feign-form-spring/src/test/java/feign/form/feign/spring/SpringFormEncoderTest.java +++ b/feign-form-spring/src/test/java/feign/form/feign/spring/SpringFormEncoderTest.java @@ -134,6 +134,26 @@ public void upload6CollectionTest () throws Exception { Assert.assertEquals("Hello world", response); } + @Test + public void upload6ArraySameNameTest () throws Exception { + val file1 = new MockMultipartFile("popa0", "popa1", null, "Hello".getBytes(UTF_8)); + val file2 = new MockMultipartFile("popa0", "popa2", null, " world".getBytes(UTF_8)); + + val response = client.upload6Array(new MultipartFile[] { file1, file2 }); + Assert.assertEquals("Hello world", response); + } + + @Test + public void upload6CollectionSameNameTest () throws Exception { + List list = asList( + (MultipartFile) new MockMultipartFile("popa0", "popa1", null, "Hello".getBytes(UTF_8)), + (MultipartFile) new MockMultipartFile("popa0", "popa2", null, " world".getBytes(UTF_8)) + ); + + val response = client.upload6Collection(list); + Assert.assertEquals("Hello world", response); + } + @Test public void upload7Test () throws Exception { Pojo pojo = new Pojo("Hello", " world", 1); From d34d6fae100135958777c2dc1357870f9cceed0c Mon Sep 17 00:00:00 2001 From: Darren Foong Date: Sat, 28 Mar 2020 17:21:23 +0800 Subject: [PATCH 03/11] Remove unnecessary code in SpringFormEncoder --- .../feign/form/spring/SpringFormEncoder.java | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/feign-form-spring/src/main/java/feign/form/spring/SpringFormEncoder.java b/feign-form-spring/src/main/java/feign/form/spring/SpringFormEncoder.java index 6f081de..9cb8fe1 100644 --- a/feign-form-spring/src/main/java/feign/form/spring/SpringFormEncoder.java +++ b/feign-form-spring/src/main/java/feign/form/spring/SpringFormEncoder.java @@ -70,25 +70,10 @@ public SpringFormEncoder(PojoSerializationWriter pojoSerializationWriter, Encode @Override public void encode (Object object, Type bodyType, RequestTemplate template) throws EncodeException { - if (bodyType.equals(MultipartFile[].class)) { - val files = (MultipartFile[]) object; - val data = new HashMap(files.length, 1.F); - for (val file : files) { - data.put(file.getName(), file); - } - super.encode(data, MAP_STRING_WILDCARD, template); - } else if (bodyType.equals(MultipartFile.class)) { + if (bodyType.equals(MultipartFile.class)) { val file = (MultipartFile) object; val data = singletonMap(file.getName(), object); super.encode(data, MAP_STRING_WILDCARD, template); - } else if (isMultipartFileCollection(object)) { - val iterable = (Iterable) object; - val data = new HashMap(); - for (val item : iterable) { - val file = (MultipartFile) item; - data.put(file.getName(), file); - } - super.encode(data, MAP_STRING_WILDCARD, template); } else { super.encode(object, bodyType, template); } From 48880987296f80ffec1db5b8e33c46b2579484a9 Mon Sep 17 00:00:00 2001 From: Darren Foong Date: Sat, 28 Mar 2020 17:22:35 +0800 Subject: [PATCH 04/11] Remove unnecessary code in SpringFormEncoder --- .../main/java/feign/form/spring/SpringFormEncoder.java | 9 --------- 1 file changed, 9 deletions(-) diff --git a/feign-form-spring/src/main/java/feign/form/spring/SpringFormEncoder.java b/feign-form-spring/src/main/java/feign/form/spring/SpringFormEncoder.java index 9cb8fe1..fe0cbce 100644 --- a/feign-form-spring/src/main/java/feign/form/spring/SpringFormEncoder.java +++ b/feign-form-spring/src/main/java/feign/form/spring/SpringFormEncoder.java @@ -78,13 +78,4 @@ public void encode (Object object, Type bodyType, RequestTemplate template) thro super.encode(object, bodyType, template); } } - - private boolean isMultipartFileCollection (Object object) { - if (!(object instanceof Iterable)) { - return false; - } - val iterable = (Iterable) object; - val iterator = iterable.iterator(); - return iterator.hasNext() && iterator.next() instanceof MultipartFile; - } } From 6304efc22825ed778bbc687d80b8e859dd4e2b4d Mon Sep 17 00:00:00 2001 From: Darren Foong Date: Sat, 28 Mar 2020 17:34:03 +0800 Subject: [PATCH 05/11] Tidy code --- .../src/test/java/feign/form/feign/spring/Client.java | 6 +++--- .../java/feign/form/feign/spring/SpringFormEncoderTest.java | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/feign-form-spring/src/test/java/feign/form/feign/spring/Client.java b/feign-form-spring/src/test/java/feign/form/feign/spring/Client.java index 691b514..b4ad24f 100644 --- a/feign-form-spring/src/test/java/feign/form/feign/spring/Client.java +++ b/feign-form-spring/src/test/java/feign/form/feign/spring/Client.java @@ -120,9 +120,9 @@ String upload4 (@PathVariable("id") String id, String upload7 (@RequestPart("pojo") Pojo pojo); @RequestMapping( - path = "/multipart/upload8", - method = POST, - consumes = MULTIPART_FORM_DATA_VALUE + path = "/multipart/upload8", + method = POST, + consumes = MULTIPART_FORM_DATA_VALUE ) String upload8 (@RequestPart("pojo") Pojo pojo, @RequestPart("files") List files); diff --git a/feign-form-spring/src/test/java/feign/form/feign/spring/SpringFormEncoderTest.java b/feign-form-spring/src/test/java/feign/form/feign/spring/SpringFormEncoderTest.java index 876a5a3..3dbc874 100644 --- a/feign-form-spring/src/test/java/feign/form/feign/spring/SpringFormEncoderTest.java +++ b/feign-form-spring/src/test/java/feign/form/feign/spring/SpringFormEncoderTest.java @@ -146,8 +146,8 @@ public void upload6ArraySameNameTest () throws Exception { @Test public void upload6CollectionSameNameTest () throws Exception { List list = asList( - (MultipartFile) new MockMultipartFile("popa0", "popa1", null, "Hello".getBytes(UTF_8)), - (MultipartFile) new MockMultipartFile("popa0", "popa2", null, " world".getBytes(UTF_8)) + (MultipartFile) new MockMultipartFile("popa0", "popa1", null, "Hello".getBytes(UTF_8)), + (MultipartFile) new MockMultipartFile("popa0", "popa2", null, " world".getBytes(UTF_8)) ); val response = client.upload6Collection(list); From f3cfaca658e097a50b0f80e997540c359bb0d476 Mon Sep 17 00:00:00 2001 From: Darren Foong Date: Sat, 28 Mar 2020 17:34:48 +0800 Subject: [PATCH 06/11] Tidy code --- .../src/test/java/feign/form/feign/spring/Server.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/feign-form-spring/src/test/java/feign/form/feign/spring/Server.java b/feign-form-spring/src/test/java/feign/form/feign/spring/Server.java index e6ecda6..ff3930c 100644 --- a/feign-form-spring/src/test/java/feign/form/feign/spring/Server.java +++ b/feign-form-spring/src/test/java/feign/form/feign/spring/Server.java @@ -149,9 +149,9 @@ public ResponseEntity upload7 (@RequestPart("pojo") Pojo pojo } @RequestMapping( - path = "/multipart/upload8", - method = POST, - consumes = MULTIPART_FORM_DATA_VALUE + path = "/multipart/upload8", + method = POST, + consumes = MULTIPART_FORM_DATA_VALUE ) public ResponseEntity upload8 (@RequestPart("pojo") Pojo pojo, @RequestPart("files") List files ) throws Exception { From 776ce4cc363251f3654fa59f0f1a5c9737de0f31 Mon Sep 17 00:00:00 2001 From: Darren Foong Date: Sat, 28 Mar 2020 18:06:20 +0800 Subject: [PATCH 07/11] Add support for collection of POJOs --- .../form/spring/PojoSerializationWriter.java | 20 ++++++++++++++++++- .../java/feign/form/feign/spring/Client.java | 7 +++++++ .../java/feign/form/feign/spring/Server.java | 17 ++++++++++++++++ .../feign/spring/SpringFormEncoderTest.java | 17 ++++++++++++++++ 4 files changed, 60 insertions(+), 1 deletion(-) diff --git a/feign-form-spring/src/main/java/feign/form/spring/PojoSerializationWriter.java b/feign-form-spring/src/main/java/feign/form/spring/PojoSerializationWriter.java index 476ec2a..ce70335 100644 --- a/feign-form-spring/src/main/java/feign/form/spring/PojoSerializationWriter.java +++ b/feign-form-spring/src/main/java/feign/form/spring/PojoSerializationWriter.java @@ -37,7 +37,8 @@ public abstract class PojoSerializationWriter extends AbstractWriter { @Override public boolean isApplicable(Object object) { - return !(object instanceof MultipartFile) && !(object instanceof MultipartFile[]) && isUserPojo(object); + return !(object instanceof MultipartFile) && !(object instanceof MultipartFile[]) + && (isUserPojoCollection(object) || isUserPojo(object)); } @Override @@ -62,4 +63,21 @@ public void write (Output output, String key, Object object) throws EncodeExcept protected abstract MediaType getContentType(); protected abstract String serialize(Object object) throws IOException; + + private boolean isUserPojoCollection(Object object) { + if (!(object instanceof Iterable)) { + return false; + } + + val iterable = (Iterable) object; + val iterator = iterable.iterator(); + + if (iterator.hasNext()) { + val next = iterator.next(); + + return !(next instanceof MultipartFile) && isUserPojo(next); + } else { + return false; + } + } } diff --git a/feign-form-spring/src/test/java/feign/form/feign/spring/Client.java b/feign-form-spring/src/test/java/feign/form/feign/spring/Client.java index b4ad24f..35c9a38 100644 --- a/feign-form-spring/src/test/java/feign/form/feign/spring/Client.java +++ b/feign-form-spring/src/test/java/feign/form/feign/spring/Client.java @@ -126,6 +126,13 @@ String upload4 (@PathVariable("id") String id, ) String upload8 (@RequestPart("pojo") Pojo pojo, @RequestPart("files") List files); + @RequestMapping( + path = "/multipart/upload9", + method = POST, + consumes = MULTIPART_FORM_DATA_VALUE + ) + String upload9 (@RequestPart("pojos") List pojos, @RequestPart("files") List files); + class ClientConfiguration { @Autowired diff --git a/feign-form-spring/src/test/java/feign/form/feign/spring/Server.java b/feign-form-spring/src/test/java/feign/form/feign/spring/Server.java index ff3930c..584be6e 100644 --- a/feign-form-spring/src/test/java/feign/form/feign/spring/Server.java +++ b/feign-form-spring/src/test/java/feign/form/feign/spring/Server.java @@ -161,6 +161,23 @@ public ResponseEntity upload8 (@RequestPart("pojo") Pojo pojo, @RequestP return ResponseEntity.ok(result1 + result2); } + @RequestMapping( + path = "/multipart/upload9", + method = POST, + consumes = MULTIPART_FORM_DATA_VALUE + ) + public ResponseEntity upload9 (@RequestPart("pojos") List pojos, @RequestPart("files") List files + ) throws Exception { + val pojo1 = pojos.get(0); + val pojo2 = pojos.get(1); + + val result1 = pojo1.getField1() + pojo1.getField2() + pojo1.getField3(); + val result2 = pojo2.getField1() + pojo2.getField2() + pojo2.getField3(); + val result3 = new String(files.get(0).getBytes()) + new String(files.get(1).getBytes()); + + return ResponseEntity.ok(result1 + result2 + result3); + } + @RequestMapping( path = "/multipart/download/{fileId}", method = GET, diff --git a/feign-form-spring/src/test/java/feign/form/feign/spring/SpringFormEncoderTest.java b/feign-form-spring/src/test/java/feign/form/feign/spring/SpringFormEncoderTest.java index 3dbc874..fdd8497 100644 --- a/feign-form-spring/src/test/java/feign/form/feign/spring/SpringFormEncoderTest.java +++ b/feign-form-spring/src/test/java/feign/form/feign/spring/SpringFormEncoderTest.java @@ -21,6 +21,7 @@ import static org.junit.Assert.assertEquals; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.DEFINED_PORT; +import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -174,4 +175,20 @@ public void upload8Test () throws Exception { val response = client.upload8(pojo, list); Assert.assertEquals("Hello world1Hello world", response); } + + @Test + public void upload9Test () throws Exception { + List pojos = asList( + new Pojo("Hello", " world", 1), + new Pojo("Hello", " world", 2) + ); + + List list = asList( + (MultipartFile) new MockMultipartFile("files", "popa1", null, "Hello".getBytes(UTF_8)), + (MultipartFile) new MockMultipartFile("files", "popa2", null, " world".getBytes(UTF_8)) + ); + + val response = client.upload9(pojos, list); + Assert.assertEquals("Hello world1Hello world2Hello world", response); + } } From 73fcd11019137adfc17384b98b65871c42a6e504 Mon Sep 17 00:00:00 2001 From: Darren Foong Date: Sat, 28 Mar 2020 18:22:26 +0800 Subject: [PATCH 08/11] Add support for array of POJOs --- .../form/spring/PojoSerializationWriter.java | 6 ++++++ .../java/feign/form/feign/spring/Client.java | 9 ++++++++- .../feign/spring/SpringFormEncoderTest.java | 20 +++++++++++++++++-- 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/feign-form-spring/src/main/java/feign/form/spring/PojoSerializationWriter.java b/feign-form-spring/src/main/java/feign/form/spring/PojoSerializationWriter.java index ce70335..fca4472 100644 --- a/feign-form-spring/src/main/java/feign/form/spring/PojoSerializationWriter.java +++ b/feign-form-spring/src/main/java/feign/form/spring/PojoSerializationWriter.java @@ -65,6 +65,12 @@ public void write (Output output, String key, Object object) throws EncodeExcept protected abstract String serialize(Object object) throws IOException; private boolean isUserPojoCollection(Object object) { + if (object.getClass().isArray()) { + val array = (Object[]) object; + + return array.length > 1 && isUserPojo(array[0]); + } + if (!(object instanceof Iterable)) { return false; } diff --git a/feign-form-spring/src/test/java/feign/form/feign/spring/Client.java b/feign-form-spring/src/test/java/feign/form/feign/spring/Client.java index 35c9a38..69d03c6 100644 --- a/feign-form-spring/src/test/java/feign/form/feign/spring/Client.java +++ b/feign-form-spring/src/test/java/feign/form/feign/spring/Client.java @@ -131,7 +131,14 @@ String upload4 (@PathVariable("id") String id, method = POST, consumes = MULTIPART_FORM_DATA_VALUE ) - String upload9 (@RequestPart("pojos") List pojos, @RequestPart("files") List files); + String upload9Array (@RequestPart("pojos") Pojo[] pojos, @RequestPart("files") List files); + + @RequestMapping( + path = "/multipart/upload9", + method = POST, + consumes = MULTIPART_FORM_DATA_VALUE + ) + String upload9Collection (@RequestPart("pojos") List pojos, @RequestPart("files") List files); class ClientConfiguration { diff --git a/feign-form-spring/src/test/java/feign/form/feign/spring/SpringFormEncoderTest.java b/feign-form-spring/src/test/java/feign/form/feign/spring/SpringFormEncoderTest.java index fdd8497..1966e8c 100644 --- a/feign-form-spring/src/test/java/feign/form/feign/spring/SpringFormEncoderTest.java +++ b/feign-form-spring/src/test/java/feign/form/feign/spring/SpringFormEncoderTest.java @@ -177,7 +177,23 @@ public void upload8Test () throws Exception { } @Test - public void upload9Test () throws Exception { + public void upload9ArrayTest () throws Exception { + val pojos = new Pojo[]{ + new Pojo("Hello", " world", 1), + new Pojo("Hello", " world", 2) + }; + + List list = asList( + (MultipartFile) new MockMultipartFile("files", "popa1", null, "Hello".getBytes(UTF_8)), + (MultipartFile) new MockMultipartFile("files", "popa2", null, " world".getBytes(UTF_8)) + ); + + val response = client.upload9Array(pojos, list); + Assert.assertEquals("Hello world1Hello world2Hello world", response); + } + + @Test + public void upload9CollectionTest () throws Exception { List pojos = asList( new Pojo("Hello", " world", 1), new Pojo("Hello", " world", 2) @@ -188,7 +204,7 @@ public void upload9Test () throws Exception { (MultipartFile) new MockMultipartFile("files", "popa2", null, " world".getBytes(UTF_8)) ); - val response = client.upload9(pojos, list); + val response = client.upload9Collection(pojos, list); Assert.assertEquals("Hello world1Hello world2Hello world", response); } } From 955615767f2826fd84db3b62df9581d82126985a Mon Sep 17 00:00:00 2001 From: Darren Foong Date: Sat, 28 Mar 2020 18:24:25 +0800 Subject: [PATCH 09/11] Use val --- .../form/feign/spring/SpringFormEncoderTest.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/feign-form-spring/src/test/java/feign/form/feign/spring/SpringFormEncoderTest.java b/feign-form-spring/src/test/java/feign/form/feign/spring/SpringFormEncoderTest.java index 1966e8c..4fe96cd 100644 --- a/feign-form-spring/src/test/java/feign/form/feign/spring/SpringFormEncoderTest.java +++ b/feign-form-spring/src/test/java/feign/form/feign/spring/SpringFormEncoderTest.java @@ -126,7 +126,7 @@ public void upload6ArrayTest () throws Exception { @Test public void upload6CollectionTest () throws Exception { - List list = asList( + val list = asList( (MultipartFile) new MockMultipartFile("popa1", "popa1", null, "Hello".getBytes(UTF_8)), (MultipartFile) new MockMultipartFile("popa2", "popa2", null, " world".getBytes(UTF_8)) ); @@ -146,7 +146,7 @@ public void upload6ArraySameNameTest () throws Exception { @Test public void upload6CollectionSameNameTest () throws Exception { - List list = asList( + val list = asList( (MultipartFile) new MockMultipartFile("popa0", "popa1", null, "Hello".getBytes(UTF_8)), (MultipartFile) new MockMultipartFile("popa0", "popa2", null, " world".getBytes(UTF_8)) ); @@ -157,7 +157,7 @@ public void upload6CollectionSameNameTest () throws Exception { @Test public void upload7Test () throws Exception { - Pojo pojo = new Pojo("Hello", " world", 1); + val pojo = new Pojo("Hello", " world", 1); val response = client.upload7(pojo); Assert.assertEquals("Hello world1", response); @@ -165,9 +165,9 @@ public void upload7Test () throws Exception { @Test public void upload8Test () throws Exception { - Pojo pojo = new Pojo("Hello", " world", 1); + val pojo = new Pojo("Hello", " world", 1); - List list = asList( + val list = asList( (MultipartFile) new MockMultipartFile("files", "popa1", null, "Hello".getBytes(UTF_8)), (MultipartFile) new MockMultipartFile("files", "popa2", null, " world".getBytes(UTF_8)) ); @@ -183,7 +183,7 @@ public void upload9ArrayTest () throws Exception { new Pojo("Hello", " world", 2) }; - List list = asList( + val list = asList( (MultipartFile) new MockMultipartFile("files", "popa1", null, "Hello".getBytes(UTF_8)), (MultipartFile) new MockMultipartFile("files", "popa2", null, " world".getBytes(UTF_8)) ); @@ -194,12 +194,12 @@ public void upload9ArrayTest () throws Exception { @Test public void upload9CollectionTest () throws Exception { - List pojos = asList( + val pojos = asList( new Pojo("Hello", " world", 1), new Pojo("Hello", " world", 2) ); - List list = asList( + val list = asList( (MultipartFile) new MockMultipartFile("files", "popa1", null, "Hello".getBytes(UTF_8)), (MultipartFile) new MockMultipartFile("files", "popa2", null, " world".getBytes(UTF_8)) ); From 86a6d186c20431a60e38f5aa86ca885da3fe1fe9 Mon Sep 17 00:00:00 2001 From: Darren Foong Date: Sat, 28 Mar 2020 18:27:45 +0800 Subject: [PATCH 10/11] Tidy code --- .../feign/form/feign/spring/SpringFormEncoderTest.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/feign-form-spring/src/test/java/feign/form/feign/spring/SpringFormEncoderTest.java b/feign-form-spring/src/test/java/feign/form/feign/spring/SpringFormEncoderTest.java index 4fe96cd..6be67f7 100644 --- a/feign-form-spring/src/test/java/feign/form/feign/spring/SpringFormEncoderTest.java +++ b/feign-form-spring/src/test/java/feign/form/feign/spring/SpringFormEncoderTest.java @@ -146,7 +146,7 @@ public void upload6ArraySameNameTest () throws Exception { @Test public void upload6CollectionSameNameTest () throws Exception { - val list = asList( + List list = asList( (MultipartFile) new MockMultipartFile("popa0", "popa1", null, "Hello".getBytes(UTF_8)), (MultipartFile) new MockMultipartFile("popa0", "popa2", null, " world".getBytes(UTF_8)) ); @@ -179,13 +179,13 @@ public void upload8Test () throws Exception { @Test public void upload9ArrayTest () throws Exception { val pojos = new Pojo[]{ - new Pojo("Hello", " world", 1), - new Pojo("Hello", " world", 2) + new Pojo("Hello", " world", 1), + new Pojo("Hello", " world", 2) }; val list = asList( - (MultipartFile) new MockMultipartFile("files", "popa1", null, "Hello".getBytes(UTF_8)), - (MultipartFile) new MockMultipartFile("files", "popa2", null, " world".getBytes(UTF_8)) + (MultipartFile) new MockMultipartFile("files", "popa1", null, "Hello".getBytes(UTF_8)), + (MultipartFile) new MockMultipartFile("files", "popa2", null, " world".getBytes(UTF_8)) ); val response = client.upload9Array(pojos, list); From fa3ffe8a18f9f76b90f1dc51de77a596915d7ef3 Mon Sep 17 00:00:00 2001 From: Darren Foong Date: Sat, 28 Mar 2020 18:30:53 +0800 Subject: [PATCH 11/11] Remove unused import --- .../test/java/feign/form/feign/spring/SpringFormEncoderTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/feign-form-spring/src/test/java/feign/form/feign/spring/SpringFormEncoderTest.java b/feign-form-spring/src/test/java/feign/form/feign/spring/SpringFormEncoderTest.java index 6be67f7..3fbb886 100644 --- a/feign-form-spring/src/test/java/feign/form/feign/spring/SpringFormEncoderTest.java +++ b/feign-form-spring/src/test/java/feign/form/feign/spring/SpringFormEncoderTest.java @@ -21,7 +21,6 @@ import static org.junit.Assert.assertEquals; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.DEFINED_PORT; -import java.util.Collections; import java.util.HashMap; import java.util.List;