In my application I develop web service that get attached file.
The file is mapped to DataHandler object via JaxB,
and I have access to the file via DataHandler.getInputStream()
My problem is this:
When the file attribute exist in the web service request, but no file is attached,
I still get the DataHandler object, and its getInputStream().available() = 11 bytes
(a header I guess...??).
So I can I know that the inputStream is empty?
Thanks,
Alon
Read it and parse the data as it should be parsed. The answer is in there.
The InputStream#available() certainly does not return the length of the stream or so as you seem to think. In some cases it (by coincidence) may, but you shouldn't rely on that. It just returns the amount of bytes which are available for read without blocking other threads. Just read the stream the usual Java IO way fully until the last bit returned -1 and then intercept on the whole data you received.
Related
How does Jersey handle receiving files from a client (e.g. web application)?
I've looked around for a longer while and cannot seem to get the answers I need.
Let's say that I have an exposed Jersey endpoint that consumes a multipart data form with a file that looks pretty much like this:
#POST
public Response upload(#FormDataParam("file") InputStream inputStream,
#FormDataParam("file") FormDataContentDisposition fileDetails { ... }
I've noticed that if I try to upload the file, the endpoint is not called until the uploading is finished. Does Jersey attempt to read and buffer (memory? disk?) an entire file before handling it for further processing? Does it mean that the inputStream source and size is already known when the processing of endpoint logic starts (because it was already read)?
And finally, is it possible to handle it in a "as comes" manner, without waiting with further actions for whole file to be uploaded first?
so currently I'm retrieving the data from a url using the following code
Document doc = Jsoup.connect(url).get();
Before I fetch the data I've decided I want to get the content type, so I do that using the following.
Connection.Response res = Jsoup.connect(url).timeout(10*1000).execute();
String contentType = res.contentType();
Now I'm wondering, is this making 2 separate connections? Is this not efficient? Is there a way for me to get the content type and the document data in 1 single connection?
Thanks
Yes Jsoup.connect(url).get() and Jsoup.connect(url).timeout(10*1000).execute(); are two separate connections. Maybe you are looking for something like
Response resp = Jsoup.connect(url).timeout(10*1000).execute();
String contentType = res.contentType();
and later parse body of response as a Document
Document doc = resp.parse();
Anyway Jsoup by default parses only text/*, application/xml, or application/xhtml+xml and if content type is other, like application/pdf it will throw UnsupportedMimeTypeException so you shouldn't be worried about it.
Without looking at the Jsoup internals we can't know. Typically when you want to obtain just the headers of a file (the content type in your case) without downloading the actual file content, you use the HTTP GET method instead of the GET method to the same url. Perhaps the Jsoup API allows you to set the method, that code doesn't seem like it's doing it so I'd wager it's actually getting the entire file.
The HTTP spec allows clients to reuse the connection later, they are called HTTP persistent connections, and it avoids having to create a connection for each call to the same server. However it's up to the client, Jsoup in this case since you aren't handling the connections in your code, to make sure it's not closing the connections after each request.
I believe that the overhead of creating two connections is offset by not downloading the entire file if you're code decides that it shouldn't download the file if it's not of the content type that you want.
My main question is how can I pass JSON as well as File to post request to REST API? What needs in Spring framework to work as client and wait for response by passing post with JSON and File?
Options:
Do I need to use FileRepresentation with ClientResource? But how can I pass file as well as JSON?
By using RestTemplate for passing both JSON as well as File? How it can be used for posting JSON as well as File?
Any other option is available?
Sounds like an awful resource you're trying to expose. My suggestion is to separate them into 2 different requests. Maybe the JSON has the URI for the file to then be requested…
From a REST(ish) perspective, it sounds like the resource you are passing is a multipart/mixed content-type. One subtype will be application/json, and one will be whatever type the file is. Either or both could be base64 encoded.
You may need to write specific providers to serialize/deserialize this data. Depending on the particular REST framework, this article may help.
An alternative is to create a single class that encapsulates both the json and the file data. Then, write a provider specific to that class. You could optionally create a new content-type for it, such as "application/x-combo-file-json".
You basically have three choices:
Base64 encode the file, at the expense of increasing the data size
by around 33%.
Send the file first in a multipart/form-data POST,
and return an ID to the client. The client then sends the metadata
with the ID, and the server re-associates the file and the metadata.
Send the metadata first, and return an ID to the client. The client
then sends the file with the ID, and the server re-associates the
file and the metadata.
Basically I need to provide REST service that would receive a String param, use that param to fetch a file from another system and then return the fetched file back as the response.
The effect should be the same as when a user clicks on a pdf or any other binary file link and the browser prompts him to save/download that file.
A couple of points:
is it possible to stream the file (to send bytes as I receive them from source system). In other words, how to handle very large files?
also related to streaming, when using regular HttpServletResponse, do I have to wait until a large file is completely read to return response.build()?
How do I go around doing this using Apache Wink?
PS Sorry, this may be trivial for Wink gurus, but I'm just starting to wrap my head around developer guide.
You can just return the java.io.File from your method. You can wrap it with Response if you like. Wink will handle the streaming. The streaming doesn't start when you call to response.build(), but rather when your method finishes.
If you want a correct download dialog, you should return the proper Content-Disposition header. See How to set response header in JAX-RS so that user sees download popup for Excel?
In our rest application we use #RequestBody StreamSorce to upload xml file. The problem is that is xml itself is non-valid or contains some invalid characters, PUT request is failing(with http bad request response) before our logic, so we can not inform client about exact problem. I know that it is possible to use just plain String for requestBody, but does it make sense to use it? I guess if i will upload 100Mb xml each request will create String request body with same size, and while using StreamSource we are reading input stream while we need it.
What are the cons and pros for using String or StreamSource as requestbody. If i do it with StreamSorce will it scan the whole xml?
You already know the con of the StreamSource: in makes it not possible for you to pre-process the XML, in case it is invalid.
Using String: when XML would be so large, it would be a performance killer! Never use so large objects in Java - in multi-thread environment of application server it can easily lead to OutOfMemoryError, it makes your application vulnerable to DoS attack!
The best solution is to map #RequestBody as InputStream, and process that InputStream with SAX parser. You have low memory consumption (SAX parser doesn't store XML structure in memory) and you can handle exceptions, that can be thrown during the processing.