1

I'm noticing a weird issue with multipart request here.

Below is the Jersey2 implementation used in Spring Boot 2.4.2:

@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces({MediaType.MULTIPART_FORM_DATA, MediaType.APPLICATION_JSON})
public void upload(@FormDataParam("params") MyPojo req,
        @FormDataParam("file") FormDataBodyPart file, @Context HttpHeaders headers, @Suspended AsyncResponse ar)
{
    ...
}

and following the Spring Boot dependencies:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jersey</artifactId>
</dependency>
<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-multipart</artifactId>
</dependency>
<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-json-jackson</artifactId>
</dependency>

I am able to successfully upload JSON and file (as multipart/form-data) using Postman but the same request from Java client throws below error:

Caused by: org.springframework.web.multipart.MultipartException: Failed to parse multipart servlet request; nested exception is java.lang.IllegalStateException: Unable to process parts as no multi-part configuration has been provided

This article on SO says we need to add a CommonsMultipartResolver but why as it works all good from Postman client??

Appreciate any hints or suggestions, thanks.

Updating Java Apache client code:

        final Document document = getDocument(documentId);
        final String requestParams = getRequestParams(document);
        final String documentContentType = document.getContentType();
        final URL endpoint = getServiceEndpoint();
        
        final MultipartEntityBuilder entityBuilder = MultipartEntityBuilder.create().addTextBody(REQUEST_PARAMS_PARAMETER_NAME, requestParams, ContentType.APPLICATION_JSON);
        if (isSendDocument() && documentFile != null) {
            entityBuilder.addBinaryBody(DOCUMENT_CONTENT_PARAMETER_NAME, documentFile, ContentType.parse(documentContentType), document.getContentType());
        }
        
        final HttpEntity reqestEntity = entityBuilder.build();
        connection = (HttpURLConnection)endpoint.openConnection();
        connection.setAllowUserInteraction(false);
        connection.setConnectTimeout(getConnectionTimeout());
        connection.setReadTimeout(getReadTimeout());
        connection.setUseCaches(false);
        connection.setDoOutput(true);
        connection.setRequestMethod("POST");
        connection.addRequestProperty(X_REQUESTED_WITH_HEADER_NAME, "XMLHttpRequest");
        connection.addRequestProperty(X_REQUESTED_BY_HEADER_NAME, "XMLHttpRequest");
        connection.addRequestProperty(ACCEPT_HEADER_NAME, ContentType.APPLICATION_JSON.getMimeType());
        connection.addRequestProperty(CONTENT_TYPE_HEADER_NAME, reqestEntity.getContentType().getValue());
        outStream = connection.getOutputStream();
        reqestEntity.writeTo(outStream);
        outStream.flush();
Narwhal
  • 43
  • 6
  • check headers attentively, compare postman and the actual java-client call – Artem Ptushkin Feb 10 '21 at 11:59
  • Are the requests you're making with Postman and the Java client identical? `MultipartException` is a Spring Framework exception which would suggest that Jersey isn't handling the request made with the Java client. – Andy Wilkinson Feb 10 '21 at 12:29
  • 1
    Can you try to disable the Spring multipart support with `spring.servlet.multipart.enabled = true` – Paul Samsotha Feb 10 '21 at 19:54
  • @PaulSamsotha sorry I did not understand your suggestion. I'm using Jersey 2 implementation for exposing REST APIs (although it is running on Spring Boot application). If it is an issue with Spring multipart support, how the request from Postman works? Also I've updated the question with Java client for reference. Thanks. – Narwhal Feb 11 '21 at 08:05
  • Look at the exception, you can see springframework. So it is the Spring framework multipart being used here in this request. That's why I suggested to try to disable it. – Paul Samsotha Feb 11 '21 at 08:40
  • @PaulSamsotha But is this spring.servlet.multipart.enabled not set to true by default? At least Spring Boot docs says so https://github.com/spring-projects/spring-boot/blob/v2.4.2/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/MultipartProperties.java#L46 – Narwhal Feb 11 '21 at 10:22
  • I don't know, I don't use Spring, that's why I said to _try_. What other explanation would you have that the exception says anything about Spring? See above Andy's comment. – Paul Samsotha Feb 11 '21 at 11:30
  • 1
    Sorry, my comment should have been to _disable_ it. I just copy and pasted it from a post on SO. I forgot to change it to false. Sorry about that. – Paul Samsotha Feb 11 '21 at 12:00
  • @PaulSamsotha Sorry for the late update. After setting spring.servlet.multipart.enabled=false in application.properties I started getting HTTP 400 for multipart POST request with above Apache http client code. But Jersey client like in your post [link](https://stackoverflow.com/questions/27609569/file-upload-along-with-other-object-in-jersey-restful-web-service) works fine in sending a POST multipart request. How this could be different? – Narwhal Feb 23 '21 at 16:18
  • A 400 says there is something wrong with the request. Are you sure the multipart request is in the correct format? Do you know what a raw multipart request supposed to look like? If so, you should check the entire request and make sure that it is correct. That includes the Content-Type header, making sure it has the boundary. – Paul Samsotha Feb 23 '21 at 16:47

1 Answers1

1

As we intend the multipart to be handled by the Jersey servlet, @PaulSamsotha suggestion to disable Spring Boot's multipart processing spring.servlet.multipart.enabled = false resolved the original issue posted in the question - "java.lang.IllegalStateException: Unable to process parts as no multi-part configuration has been provided".

Later, I was getting a Http 400 error only with Apache client and that was due to malformed JSON payload. Thanks for all the support.

Narwhal
  • 43
  • 6