ChrLipp
ChrLipp

Reputation: 15668

JAX-RS with CXF / rest-assured: Handling multiparam file upload

I want to upload a JPG file and a JSON-serialized Java object. On the server I am using Apache CXF, on the client I am integration testing with rest-assured.

My server code looks like:

@POST
@Path("/document")
@Consumes(MediaType.MULTIPART_FORM_DATA)
public Response storeTravelDocument(
        @Context UriInfo uriInfo, 
        @Multipart(value = "document") JsonBean bean,
        @Multipart(value = "image") InputStream pictureStream)
        throws IOException
{}

My client code looks like:

given().
    multiPart("document", new File("./data/json.txt"), "application/json").
    multiPart("image", new File("./data/image.txt"), "image/jpeg").
expect().
    statusCode(Response.Status.CREATED.getStatusCode()).
when().
    post("/document");

Everything works fine when I read the json part from the file as in the first multiPart line. However, when I want to serialize the json instance I come into problems. I tried many variants, but none worked.

I thought this variant should work: on the client

JsonBean json = new JsonBean();
json.setVal1("Value 1");
json.setVal2("Value 2");

given().
    contentType("application/json").
    formParam("document", json).
    multiPart("image", new File("./data/image.txt"), "image/jpeg").
...

and on the server

public Response storeTravelDocument(
    @Context UriInfo uriInfo, 
    @FormParam(value = "document") JsonBean bean,
    @Multipart(value = "image") InputStream pictureStream)

but no. Can anyone tell me how it should be?

Upvotes: 2

Views: 5038

Answers (2)

ChrLipp
ChrLipp

Reputation: 15668

Multipart/form-data follows the rules of multipart MIME data streams, see w3.org. This means that each part of the request forms a part in the stream. Rest-assured supports already simple fields (strings), files and streams, but not object serialization into a part. After asking on the mailing list, Johan Haleby (the author of rest-assured) suggested to add an issue. The issue is already accepted, see issue 166.

The server will stay as it is:

@POST
@Path("/document")
@Consumes(MediaType.MULTIPART_FORM_DATA)
public Response storeTravelDocument(
        @Context UriInfo uriInfo, 
        @Multipart(value = "document") JsonBean bean,
        @Multipart(value = "image") InputStream pictureStream)
        throws IOException
{}

The client code will look like:

given().
    multiPartObject("document", objectToSerialize, "application/json").
    multiPart("image", new File("./data/image.txt"), "image/jpeg").
expect().
    statusCode(Response.Status.CREATED.getStatusCode()).
when().
    post("/document");

Maybe the name "multiPartObject" will change. We will see once it is implemented.

Upvotes: 0

Piotr Kochański
Piotr Kochański

Reputation: 22672

Try different approach (worked for me), I am not sure if this is suitable in your case.

Make JsonBean a JAXB entity, that it add @XmlRootEntity above class definition.

Then, instead of formParam

given().
    contentType("application/json").
    body(bean). //bean is your JsonBean
    multiPart("image", new File("./data/image.txt"), "image/jpeg").

then

public Response storeTravelDocument(
    @Context UriInfo uriInfo, 
    JsonBean bean, //should be deserialized properly
    @Multipart(value = "image") InputStream pictureStream)

I've never tried that with @Multipart part, but, hopefully it would work.

Upvotes: 1

Related Questions