1

I need to invoke a remote REST interface handler and submit it a file in request body. Please note that I don't control the server. I cannot change the request to be multipart, the client has to work in accordance to external specification.

So far I managed to make it work like this (omitting headers etc. for brevity):

byte[]  data = readFileCompletely ();
client.target (url).request ().post (Entity.entity (data, "file/mimetype"));

This works, but will fail with huge files that don't fit into memory. And since I have no restriction on filesize, this is a concern.

Question: is it somehow possible to use streams or something similar to avoid reading the whole file into memory?

If possible, I'd prefer to avoid implementation-specific extensions. If not, a solution that works with RESTEasy (on Wildfly) is also acceptable.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • What's the actual media type? `application/octet-stream` has a writer that can handle `InputStream`. Or I think [`StreamingOutput`](http://stackoverflow.com/a/12012867/2587435) even works on the client side for all media types, though I haven't tried it, but I imagine it _should_ work – Paul Samsotha Jul 04 '16 at 14:42
  • It fully depends on file contents, but usually will be "application/pdf". –  Jul 04 '16 at 14:43
  • I'd try the `StreamingOutput`. I think I've used it before on the client side. I can't remember. – Paul Samsotha Jul 04 '16 at 14:44
  • Have you tried simply putting the `InputStream` into the entity `Entity.entity(inputStream, "application/octetstream")`; AFAIK Jersey can handle it so I guess RestEasy should too. – Leonard Brünings Jul 04 '16 at 14:46
  • I kinda have a feeling that `InputStream` would actually work for _any_ media type also. Have you tried `InputStream`? – Paul Samsotha Jul 04 '16 at 14:58
  • @LeonardBrünings: Yes, you are right, it just works! Can you post this as an answer for the next person who searches for it? –  Jul 04 '16 at 15:00

2 Answers2

1

ReastEasy as well as Jersey support InputStream out of the box so simply use Entity.entity(inputStream, "application/octet-stream"); or whatever Content-Type header you want to set.

Leonard Brünings
  • 12,408
  • 1
  • 46
  • 66
0

You can go low-level and construct the HTTP request using a library such as the plain java.net.URLConnection.

I have not tried it myself but there is example code which reads a local file and writes it to the request stream without loading it into a byte array.

Upload files from Java client to a HTTP server

Of course this solution requires more manual coding but it should work (unless java.net.URLConnection loads the whole file into memory)

Community
  • 1
  • 1
mjn42
  • 830
  • 1
  • 8
  • 24
  • Yeah, might be that I have to use sth. like this in the end. –  Jul 04 '16 at 14:47
  • Interesting, I now made more tests. While passing `FileInputStream` (or even just `File` itself) to `Entity.entity()` works, what really transmitted over HTTP is a string "data:application/octet-stream;base64,...". I.e. not raw file contents which I hoped for. Server I cooperate with seems to handle that just fine, but it looks strange to me. Why not just put file contents raw? Encoding it first blows up size by a third *and* requires some extra processing from the server. And I don't see *any* benefits. –  Jul 07 '16 at 13:47