Skip to content

Commit

Permalink
merge MultipartFileArgumentResolver into RequestPartArgumentResolver
Browse files Browse the repository at this point in the history
spring-projectsgh-31139

Signed-off-by: Dmitrii Bocharov <bdshadow@gmail.com>
  • Loading branch information
bdshadow committed Sep 3, 2023
1 parent a1adf24 commit 24f0128
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,6 @@ private List<HttpServiceArgumentResolver> initArgumentResolvers() {
// Specific type
resolvers.add(new UrlArgumentResolver());
resolvers.add(new HttpMethodArgumentResolver());
resolvers.add(new MultipartFileArgumentResolver());

return resolvers;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,13 @@
import org.springframework.core.ReactiveAdapter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.codec.multipart.Part;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.multipart.MultipartFile;

/**
* {@link HttpServiceArgumentResolver} for {@link RequestPart @RequestPart}
Expand Down Expand Up @@ -77,8 +79,18 @@ public RequestPartArgumentResolver(HttpExchangeAdapter exchangeAdapter) {
@Override
protected NamedValueInfo createNamedValueInfo(MethodParameter parameter) {
RequestPart annot = parameter.getParameterAnnotation(RequestPart.class);
return (annot == null ? null :
new NamedValueInfo(annot.name(), annot.required(), null, "request part", true));
boolean isMultiPartFile = parameter.nestedIfOptional().getNestedParameterType().equals(MultipartFile.class);

if (annot != null && isMultiPartFile) {
return new NamedValueInfo(annot.name(), annot.required(), null, "MultipartFile", true);
}
else if (annot != null) {
return new NamedValueInfo(annot.name(), annot.required(), null, "request part", true);
}
else if (isMultiPartFile) {
return new NamedValueInfo("", true, null, "MultipartFile", true);
}
return null;
}

@Override
Expand Down Expand Up @@ -106,6 +118,18 @@ protected void addRequestValue(
return;
}
}
if (value instanceof MultipartFile file) {
HttpHeaders headers = new HttpHeaders();
if (file.getOriginalFilename() != null) {
headers.setContentDispositionFormData(name, file.getOriginalFilename());
}
if (file.getContentType() != null) {
headers.add(HttpHeaders.CONTENT_TYPE, file.getContentType());
}

requestValues.addRequestPart(name, new HttpEntity<>(file.getResource(), headers));
return;
}

requestValues.addRequestPart(name, value);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,36 +49,57 @@ class MultipartFileArgumentResolverTests {

@Test
void multipartFile() {
MultipartFile testFile = mockMultipartFile();
this.multipartService.postMultipartFile(testFile);
testMultipartFile(testFile, "file");
}

@Test
void requestPartMultipartFile() {
MultipartFile testFile = mockMultipartFile();
this.multipartService.postRequestPartMultipartFile(testFile);
testMultipartFile(testFile, "myFile");
}

@Test
void requestPartOptionalMultipartFile() {
MultipartFile testFile = mockMultipartFile();
this.multipartService.postRequestPartOptionalMultipartFile(Optional.of(testFile));
testMultipartFile(testFile, "file");
}

@Test
void optionalMultipartFile() {
this.multipartService.postOptionalMultipartFile(Optional.empty(), "anotherPart");
Object value = client.getRequestValues().getBodyValue();

assertThat(value).isInstanceOf(MultiValueMap.class);
MultiValueMap<String, HttpEntity<?>> map = (MultiValueMap<String, HttpEntity<?>>) value;
assertThat(map).containsOnlyKeys("anotherPart");
}

private MultipartFile mockMultipartFile() {
String fileName = "testFileName";
String originalFileName = "originalTestFileName";
MultipartFile testFile = new MockMultipartFile(fileName, originalFileName, "text/plain", "test".getBytes());
return new MockMultipartFile(fileName, originalFileName, "text/plain", "test".getBytes());
}

this.multipartService.postMultipartFile(testFile);
private void testMultipartFile(MultipartFile testFile, String partName) {
Object value = this.client.getRequestValues().getBodyValue();

assertThat(value).isInstanceOf(MultiValueMap.class);
MultiValueMap<String, HttpEntity<?>> map = (MultiValueMap<String, HttpEntity<?>>) value;
assertThat(map).hasSize(1);

HttpEntity<?> entity = map.getFirst("file");
HttpEntity<?> entity = map.getFirst(partName);
assertThat(entity).isNotNull();
assertThat(entity.getBody()).isEqualTo(testFile.getResource());

HttpHeaders headers = entity.getHeaders();
assertThat(headers.getContentType()).isEqualTo(MediaType.TEXT_PLAIN);
assertThat(headers.getContentDisposition().getType()).isEqualTo("form-data");
assertThat(headers.getContentDisposition().getName()).isEqualTo("file");
assertThat(headers.getContentDisposition().getFilename()).isEqualTo(originalFileName);
}

@Test
void optionalMultipartFile() {
this.multipartService.postOptionalMultipartFile(Optional.empty(), "anotherPart");
Object value = client.getRequestValues().getBodyValue();

assertThat(value).isInstanceOf(MultiValueMap.class);
MultiValueMap<String, HttpEntity<?>> map = (MultiValueMap<String, HttpEntity<?>>) value;
assertThat(map).containsOnlyKeys("anotherPart");
assertThat(headers.getContentDisposition().getName()).isEqualTo(partName);
assertThat(headers.getContentDisposition().getFilename()).isEqualTo(testFile.getOriginalFilename());
}


Expand All @@ -88,6 +109,12 @@ private interface MultipartService {
@PostExchange
void postMultipartFile(MultipartFile file);

@PostExchange
void postRequestPartMultipartFile(@RequestPart(name = "myFile") MultipartFile file);

@PostExchange
void postRequestPartOptionalMultipartFile(@RequestPart Optional<MultipartFile> file);

@PostExchange
void postOptionalMultipartFile(Optional<MultipartFile> file, @RequestPart String anotherPart);

Expand Down

0 comments on commit 24f0128

Please sign in to comment.