1

I am looking for a way to upload a file (multipart form data) with the jax-rs client only using the standard apis.

The closest solution I could find was this https://www.adam-bien.com/roller/abien/entry/sending_an_inputstream_to_jax but that does not produce a MultiPart request.

All I have found are specific solutions to a concrete client implementation like RestEASY (https://mkyong.com/webservices/jax-rs/file-upload-example-in-resteasy/) or Jersey (https://howtodoinjava.com/jersey/jersey-file-upload-example/) or skipping JaxRs completely and using HttpClient (FileUpload with JAX-RS), but as the implementation provider will most likely change in the future my best bet would be to stay strictly to the standard API.

Is there something, maybe with JaxRs 2.1 or at least a cross implementation solution? A library providing a MessageBodyWriter or Feature that has just to be registered would be nice too.

dag
  • 1,133
  • 12
  • 25
  • There is no standard JAX-RS API (unless you want to build the raw request yourself, which is doable, but not a simple task). Could you use a third-party library like Apache http client? – Paul Samsotha Dec 15 '20 at 19:26
  • We've used Apache HttpClient before, but in most use cases is so much more verbose and cumbersome to use than what can be achieved in a few simple lines of JaxRs code. That's why we want to migrate to this api wherever possible. Unfortunately I get the feeling, that the JaxRs Client API is rarely adopted and it's a more common to use specific libraries like OkHttp or RestEASY. – dag Dec 16 '20 at 08:14

1 Answers1

1

As far as I know, there is no direct support for uploading multipart form data in the JAX-RS client. But by using the MultipartEntityBuilder from the Apache HTTP Client within a JAX-RS StreamingOutput, it is possible to do a multipart form data upload from a JAX-RS client with only some lines of code:

import java.io.File;
import java.util.UUID;

import javax.ws.rs.client.*;
import javax.ws.rs.core.*;

import org.apache.http.HttpEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;

public class MultipartJaxRsClient {

    public static void main(String[] args) {

        // prepare MultipartEntityBuilder:
        String boundary = "-----------" + UUID.randomUUID().toString().replace("-", "");
        MultipartEntityBuilder entityBuilder = MultipartEntityBuilder.create().setBoundary(boundary);

        // add file(s):
        String multipartFieldName = "file1";
        File fileToUpload = new File("test.pdf");
        ContentType contentType = ContentType.create("application/pdf");
        entityBuilder.addBinaryBody(multipartFieldName, fileToUpload, contentType, fileToUpload.getName()).build();
        // ... add more files ...

        // wrap HttpEntity in StreamingOutput:
        HttpEntity entity = entityBuilder.build();
        StreamingOutput streamingOutput = out -> entity.writeTo(out);

        // use StreamingOutput in JAX-RS post request:
        WebTarget target = ClientBuilder.newClient().target("http://server/path/to/upload");
        String multipartContentType = MediaType.MULTIPART_FORM_DATA + "; boundary=\"" + boundary + "\"";
        Response response = target.request().post(Entity.entity(streamingOutput, multipartContentType));
        System.out.println("HTTP Status: " + response.getStatus());
    }
}

The above code was tested with Apache HTTP Client 4.5.13 and Apache CXF 3.5.4 JAX-RS client:

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpmime</artifactId>
    <version>4.5.13</version>
</dependency>
<dependency>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-rt-rs-client</artifactId>
    <version>3.5.4</version>
</dependency>
Steffen D.
  • 71
  • 3