I am trying to develop an API call using Apache CXF that takes in an attachment along with the request. I followed this tutorial and this is what I have got so far.
@POST
@Path("/upload")
@RequireAuthentication(false)
public Response uploadWadl(MultipartBody multipartBody){
List<Attachment> attachments = multipartBody.getAllAttachments();
DataHandler dataHandler = attachments.get(0).getDataHandler();
try {
InputStream is = dataHandler.getInputStream();
} catch (IOException e) {
e.printStackTrace();
}
return Response("OK");
}
I am getting an InputStream object to the attachment and everything is working fine. However I need to pass the attachment as a java.io.File object to another function. I know I can create a file here, read from the inputstream and write to it. But is there a better solution? Has the CXF already stored it as a File? If so I could just go ahead and use that. Any suggestions?
I'm also interested on this matter. While discussing with Sergey on the CXF mailing list, I learned that CXF is using a temporary file if the attachment is over a certain threshold.
In the process I discovered this blogpost that explains how to use CXF attachment safely. You can be interested by the exemple on this page as well.
That's all I can say at the moment as I'm investigating right now, I hope that helps.
EDIT : At the moment here's how we handle attachment with CXF 2.6.x. About uploading a file using multipart content type.
In our REST resource we have defined the following method :
A few notes on that snippet :
@Multipart
is not standard to JAXRS, it's not even in JAXRS 2, it's part of CXF.MultipartBody
, the key here is to use an argument of typeAttachment
So yes as far as we know there is not yet a possibility to get directly the type we want in the method signature. So for example if you just want the
InputStream
of the attachment you cannot put it in the signature of the method. You have to use theorg.apache.cxf.jaxrs.ext.multipart.Attachment
type and write the following statement :Also we discovered with the help of Sergey Beryozkin that we could transform or wrap this
InputStream
, that's why in the above snippet we wrote :IncomingFile
is our custom wrapper around theInputStream
, for that you have to register aMessageBodyReader
,ParamHandler
won't help as they don't work with streams but withString
.Note however that there have been a few trials to understand what was passed, how, and the way to hot-fix bugs (For example the first letter of the first header of the attachment part was eat so you had
ontent-Type
instead ofContent-Type
).Of course the
entityStream
represents the actualInputStream
of the attachment. This stream will read data either from memory or from disk, depending on where CXF put the data ; there is a size threshold property (attachment-memory-threshold
) for that matter. You can also say where the temporary attachments will go (attachment-directory
).Just don't forget to close the stream when you are done (some tool do it for you).
Once everything was configured we tested it with Rest-Assured from Johan Haleby. (Some code are part of our test utils though) :
Or if you need to upload the file via curl in such a way :
To finish this answer, I'd like to mention it is possible to have JSON payload in multipart, for that you can use an
Attachment
type in the signature and then writeOr you can write an argument like :
Just don't forget to add the
Content-Type
header to the relevant part when performing the request.It might be worth to say that it is possible to have all the parts in a list, just write a method with a single argument of type
List<Attachment>
. However I prefer to have the actual arguments in the method signature as it's cleaner and less boilerplate.