Hi,

Below is my technology stack: Spring Boot --> 2.1.6.RELEASE spring-cloud-starter-openfeign --> 2.1.2.RELEASE feign-form-spring --> 3.3.0

I have following code in my Interface of Rest Controller Implementation

@PostMapping(value = "/files", consumes = {MediaType.MULTIPART_FORM_DATA_VALUE})
    ResponseEntity<Output> createFile(
            @RequestPart("file") MultipartFile file,
            @RequestPart("properties") Map<String, String> properties);

My Feign client just extends this interface and it has Feign Client Annotation like below

@FeignClient(name = "feign-client", url = "${host}/store/v1/", configuration = FeignConfig.class)
public interface StoreClient extends StoreInterface {
}

When I try to start my Spring Boot app, I get below exception

Caused by: java.lang.IllegalStateException: Method has too many Body parameters: public abstract org.springframework.http.ResponseEntity au.com.macquarie.bfs.ml.store.v1.StoreClient.createFile(org.springframework.web.multipart.MultipartFile,java.util.Map)

I tried googling and adopting many solutions, but looks like this is not supported yet.

Can some one help me resolve this and get around?

Comment From: ryanjbaxter

If you place the createFile method in the the Feign interface itself does it work?

Comment From: mazkozi

Nope. It doesnt.

Comment From: bpzhang

try to add a config file like this:

@Configuration
public class MultipartSupportConfig {
    @Autowired
    private ObjectFactory<HttpMessageConverters> messageConverters;

    @Bean
    public Encoder feignFormEncoder() {
        return new SpringFormEncoder(new SpringEncoder(messageConverters));
    }

}

Comment From: mazkozi

Hi @bpzhang . I did try this and it didn't work either.

Comment From: poznachowski

SpringMvcContract seems to process @RequestParam annotations, not @RequestPart ones.

Comment From: ryanjbaxter

This should work as it was addressed in https://github.com/spring-cloud/spring-cloud-openfeign/issues/62.

What version are you using?

Comment From: j-bernard

The problem here is not to support MultipartFile but to support 2 @RequestPart. @mazkozi did you find a workaround?

Comment From: mazkozi

The problem here is not to support MultipartFile but to support 2 @RequestPart. @mazkozi did you find a workaround?

Hi j-bernand, I had to remove one @RequestPart. That is the only way I could get it work.

Comment From: thekalinga

I tried this on spring-cloud-openfeign-core-2.1.1.RELEASE & I see this to be a problem

Unless I remove one of the request part, the proxy creation fails

With this bug in place, I cant send a multipart request with multiple parts

Comment From: thekalinga

This is what I have

@PostMapping(value = "/fileUpload", produces = MULTIPART_FORM_DATA_VALUE)
String multipartRequest(@RequestPart("file") MultipartFile file, @RequestPart("additionalFormArg") String additionalFormArg);

Comment From: MrBogue

+1

Comment From: antemooo

@thekalinga @MrBogue

If you are still facing the problem, look to the Issue #62 . After reading the issue which provide a solution, I put another solution in the comments. You can directly see it here

Comment From: arbarre

I'm facing the same issue mentioned by @thekalinga and @mazkozi and would love to see a solution to this...

@thekalinga @MrBogue

If you are still facing the problem, look to the Issue #62 . After reading the issue which provide a solution, I put another solution in the comments. You can directly see it here

Actually I don't see how it solves the issue exposed here (correct me if I'm wrong, but it doesn't seem you are dealing with multiple @RequestPart).

Comment From: tchibatron

Looks like this feature is not supported yet...

Comment From: aaronjwhiteside

+1 here too, the multipart support of MultipartFile isn't working.

Ideally the following should also be supported:

@PostMapping(value = "/fileUpload", consumes = MULTIPART_FORM_DATA_VALUE)
String multipartRequest(@RequestPart("file1") MultipartFile file1, @RequestPart("file2") MultipartFile file2);

@PostMapping(value = "/fileUpload", consumes = MULTIPART_FORM_DATA_VALUE)
String multipartRequest(@RequestPart("files") List<MultipartFile> files);

@PostMapping(value = "/fileUpload", consumes = MULTIPART_FORM_DATA_VALUE)
String multipartRequest(@RequestPart("something") String something, @RequestPart("dto") SomeDto someDto, @RequestPart("files") List<MultipartFile> files);

Also from the @RequestPart javadoc, it should be possible to mix and match @RequestParam in a multipart/form-data request too..

https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/RequestPart.html

Note that @RequestParam annotation can also be used to associate the part of a "multipart/form-data" request with a method argument supporting the same method argument types. The main difference is that when the method argument is not a String or raw MultipartFile / Part, @RequestParam relies on type conversion via a registered Converter or PropertyEditor while RequestPart relies on HttpMessageConverters taking into consideration the 'Content-Type' header of the request part. RequestParam is likely to be used with name-value form fields while RequestPart is likely to be used with parts containing more complex content e.g. JSON, XML).

So the following should be supported too:

@PostMapping(value = "/fileUpload", consumes = MULTIPART_FORM_DATA_VALUE)
String multipartRequest(@RequestParam("something") SomeDto someDto, @RequestPart("file") MultipartFile file);

@PostMapping(value = "/fileUpload", consumes = MULTIPART_FORM_DATA_VALUE)
String multipartRequest(@RequestParam("something") String something, @RequestPart("file") MultipartFile file);

However this raises the question of how do you know if something should be a query parameter vs a form parameter.. perhaps it's best to ignore this at the moment and put everything with a @RequestPart annotation in multipart body..

Comment From: aaronjwhiteside

I have a fix for this in the works, just writing comprehensive tests at the moment, expect a pull request soon.

Comment From: josoriorios

I'm having the same issue in my project, I couldn't find a fix for it so, I had to change one of the two parameters to "@RequestParam" annotation. I hope the library could support it soon.

Comment From: wakedeer

works! If feign doesn't sent POJO - just add bean JsonFormWriter in feign configuration:

import org.springframework.cloud.openfeign.support.AbstractFormWriter;
import org.springframework.cloud.openfeign.support.JsonFormWriter;
@Configuration
@ComponentScan
@EnableFeignClients
public class ClientConfiguration {
    @Bean
    public AbstractFormWriter jsonFormWriter() {
        return new JsonFormWriter();
    }
}

Thanks @darrenfoong for the fix: https://github.com/spring-cloud/spring-cloud-openfeign/pull/314

Comment From: voduku

@wakedeer can you help me with this issue? I am current using spring boot 2.4.1 and cloud 2020.0.0 but this api give me a feign.codec.EncodeException: Error converting request body @PostMapping("/storage/files") ResponseWrapper<FileDTO> uploadFile(@RequestPart("file") MultipartFile file, @RequestPart("folderPath") String folderPath, @RequestPart("isPublic") String isPublic);

Comment From: wakedeer

@wakedeer can you help me with this issue? I am current using spring boot 2.4.1 and cloud 2020.0.0 but this api give me a feign.codec.EncodeException: Error converting request body @PostMapping("/storage/files") ResponseWrapper<FileDTO> uploadFile(@RequestPart("file") MultipartFile file, @RequestPart("folderPath") String folderPath, @RequestPart("isPublic") String isPublic);

Hey @VuDo98, unfortunately I haven't run into the same issue. I suppose, you'd better use stackoverflow for such questions. Can you add an example or more details ? Thanks

Comment From: Xu-Justin

If you have this issue and have tried all solutions above but still couldn't solve it, try this:

@PostMapping(value = "/files", consumes = {MediaType.MULTIPART_FORM_DATA_VALUE})
    ResponseEntity<Output> createFile(
            @PathVariable("file") MultipartFile file,
            @PathVariable("properties") Map<String, String> properties);

This solution solved mine.