Testing what's written to a Java OutputStream - java

I am about to write junit tests for a XML parsing Java class that outputs directly to an OutputStream. For example xmlWriter.writeString("foo"); would produce something like <aTag>foo</aTag> to be written to the outputstream held inside the XmlWriter instance. The question is how to test this behaviour. One solution would of course be to let the OutputStream be a FileOutputStream and then read the results by opening the written file, but it isn't very elegant.

Use a ByteArrayOutputStream and then get the data out of that using toByteArray(). This won't test how it writes to the stream (one byte at a time or as a big buffer) but usually you shouldn't care about that anyway.

If you can pass a Writer to XmlWriter, I would pass it a StringWriter. You can query the StringWriter's contents using toString() on it.
If you have to pass an OutputStream, you can pass a ByteArrayOutputStream and you can also call toString() on it to get its contents as a String.
Then you can code something like:
public void testSomething()
{
Writer sw = new StringWriter();
XmlWriter xw = new XmlWriter(sw);
...
xw.writeString("foo");
...
assertEquals("...<aTag>foo</aTag>...", sw.toString());
}

It's simple. As #JonSkeet said:
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// pass the baos to be writed with "value", for this example
byte[] byteArray = baos.toByteArray();
Assert.assertEquals("value", new String(byteArray));

Related

Java OutStreamWriter to ByteArrayInputStream

I am writing a csv file in a very old java application so i can not use all the new Java 8 streams.
Writer writer = new OutputStreamWriter(new FileOutputStream("file.csv"));
writer.append("data,");
writer.append("data,");
...
Then I need to transform the writer object into a ByteArrayInputStream.
How can i do it ?
Thanks in advance.
Best regards.
This depends on what you are trying to do.
If you are writing a bunch of data to the file and THEN reading the file you will want to use a FileInputStream in place of your ByteArrayInputStream.
If you want to write a bunch of data to a byte array then you should take a look at using a ByteArrayOutputStream. If you then need to read the byte array as a ByteArrayInputStream you can pass the ByteArrayOutputStream into the input stream like what is shown below. Keep in mind this only works for writing and THEN reading. You can not use this like a buffer.
//Create output stream
ByteArrayOutputStream out = new ByteArrayOutputStream();
//Create Writer
Writer writer = new OutputStreamWriter(out);
//Write stuff
...
//Close writer
writer.close();
//Create input stream using the byte array from out as input.
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
Short answer: you can't.
A ByteArrayInputStream is just not assignable from a OutputStreamWriter.
Since you're probably after write, you can just read the file back to a byte[] and then construct a ByteArrayInputStream with it:
File file = new File("S:\\Test.java");
FileInputStream fis = new FileInputStream(file);
byte[] content = new byte[(int) file.length()];
fis.read(content,0,content.length);
ByteArrayInputStream bais = new ByteArrayInputStream(content);

Remove <!DOCTYPE from output of property.storeToXML

Following are the sample of my code.
OutputStream outs = response.getOutputStream();
property.put("xyz", serverpath);
property.put("*abc", serverIPAddress);
property.storeToXML(outs, null, "UTF-8");
outs.close();
I don't require DOCTYPE declaration. How to remove it?
Current output is:
Like most of the Properties class, you can't change it. Instead, capture the XML string produced, modify it, then send it out manually.
property.put("xyz", "serverpath");
property.put("*abc", "serverIPAddress");
ByteArrayOutputStream out = new ByteArrayOutputStream();
property.storeToXML(out, null, "UTF-8");
String str = out.toString("UTF-8").replaceAll("<!DOCTYPE[^>]*>\n", "");
byte[] bytes = str.getBytes("UTF-8");
OutputStream outs = response.getOutputStream();
outs.write(bytes, 0, bytes.length);
outs.close();
FYI ByteArrayOutputStream is an in-memory output stream you can use to capture and retrieve what was written to it. Because a Properties object is in practice not going to have many entries, this approach does not pose a memory consumption risk.
If you already have string and want to remove it then you can make use of this
str.replaceAll("<!DOCTYPE((.|\n|\r)*?)\">", "");
Picked from here: http://www.gregbugaj.com/?p=270
Doctype is a header component, it shouldn't matter for most purposes.
If you really want to remove it, you should write the result to a StringWriter or ByteArrayOutputStream and remove the unwanted content.

How to put the ByteArrayInputStream content into a PDF using iText?

I have the following situation, into a method I have:
ByteArrayInputStream fis = new ByteArrayInputStream(Bean.getValoreString("PDFmulti", "PDF").getBytes());
As you can see fis varialbe is a ByteArrayInputStream and Bean.getValoreString("PDFmulti", "PDF").getBytes() returns a byte[]
So now I need to put the content of the fis object into a PDF using iText.
What can I do to do it? I think that I have to read this input stream and put its content into a ByteArrayOutputStream, something like this:
public static byte[] readFully(InputStream stream) throws IOException
{
byte[] buffer = new byte[8192];
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int bytesRead;
while ((bytesRead = stream.read(buffer)) != -1)
{
baos.write(buffer, 0, bytesRead);
}
return baos.toByteArray();
}
But then?
In a comment to your previous question https://stackoverflow.com/questions/28342714/how-to-convert-a-string-object-representing-a-pdf-into-a-bytearrayinputstream-th, you say I have to concatenate all the PDF to create a single PDF.
This is crucial information that you are omitting in your new question. If I read your new question, it's as if you want to persist a PDF that exists in a byte[] in some other form. For instance: you want to store it as a file.
If that is the case, then you don't need iText! Just write the bytes to a FileOutputStream!
However, now that I know that you need to concatenate files, I know that you need several PdfReader instances and then use these PdfReader instances in combination with PdfCopy (or PdfSmartCopy) to create a single PDF out of a series of different PDFs.
That's a completely different question! In that case, why would you create a ByteArrayOutputStream? There is a PdfReader contructor that accepts an InputStream as a parameter. Why not pass fis to that constructor?

Return file from Spring #Controller having OutputStream

I want to return a file from a Spring controller. I already have API that can give me any implementation of OutputStream and then I need to send it to a user.
So the flow is something like that:
getting outputstream -> service passes this outputstream to controller -> controller has to send it to a user
I think I need inputstream to do it and I have also found Apache Commons api feature that looks like this:
IOUtils.copy(InputStream is, OutputStream os)
but the problem is, it converts it to the other side -> not from os to is, but from is to os.
Edit
to be clear, because I see the answers are not hitting right thing:
I use Dropbox api and recieve file in OutputStream and I want this output stream to be sent to user while entering some URL
FileOutputStream outputStream = new FileOutputStream(); //can be any instance of OutputStream
DbxEntry.File downloadedFile = client.getFile("/fileName.mp3", null, outputStream);
Thats why i was talking about converting outputstream to inputstream, but have no idea how to do it. Furthermore, I suppose that there is better way to solve this (maybe return byte array somehow from outputstream)
I was trying to pass servlet outputstream [response.getOutputstream()] through parameter to the method that downloads file from dropbox, but it didnt work, at all
Edit 2
The "flow" of my app is something like this: #Joeblade
User enters url: /download/{file_name}
Spring Controller captures the url and calls the #Service layer to download the file and pass it to that controller:
#RequestMapping(value = "download/{name}", method = RequestMethod.GET)
public void getFileByName(#PathVariable("name") final String name, HttpServletResponse response) throws IOException {
response.setContentType("audio/mpeg3");
response.setHeader("Content-Disposition", "attachment; filename=" + name);
service.callSomeMethodAndRecieveDownloadedFileInSomeForm(name); // <- and this file(InputStream/OutputStream/byte[] array/File object/MultipartFile I dont really know..) has to be sent to the user
}
Now the #Service calls Dropbox API and downloads the file by specified file_name, and puts it all to the OutputStream, and then passes it (in some form.. maybe OutputStream, byte[] array or any other object - I dont know which is better to use) to the controller:
public SomeObjectThatContainsFileForExamplePipedInputStream callSomeMethodAndRecieveDownloadedFileInSomeForm(final String name) throws IOException {
//here any instance of OutputStream - it needs to be passed to client.getFile lower (for now it is PipedOutputStream)
PipedInputStream inputStream = new PipedInputStream(); // for now
PipedOutputStream outputStream = new PipedOutputStream(inputStream);
//some dropbox client object
DbxClient client = new DbxClient();
try {
//important part - Dropbox API downloads the file from Dropbox servers to the outputstream object passed as the third parameter
client.getFile("/" + name, null, outputStream);
} catch (DbxException e){
e.printStackTrace();
} finally {
outputStream.close();
}
return inputStream;
}
Controler recieves the file (I dont know, at all, in which form as I said upper) and passes it then to the user
So the thing is to recieve OutputStream with the downloaded file by calling dropboxClient.getFile() method and then this OutputStream that contains the downloaded file, has to be sent to the user, how to do this?
Get the OutputStream from the HttpServletResponse and write the file to it (in this example using IOUtils from Apache Commons)
#RequestMapping(value = "/download", method = RequestMethod.GET)
public void download(HttpServletResponse response) {
...
InputStream inputStream = new FileInputStream(new File(PATH_TO_FILE)); //load the file
IOUtils.copy(inputStream, response.getOutputStream());
response.flushBuffer();
...
}
Make sure you use a try/catch to close the streams in case of an exception.
The most preferable solution is to use InputStreamResource with ResponseEntity. All you need is set Content-Length manually:
#RequestMapping(value = "/download", method = RequestMethod.GET)
public ResponseEntity download() throws IOException {
String filePath = "PATH_HERE";
InputStream inputStream = new FileInputStream(new File(filePath));
InputStreamResource inputStreamResource = new InputStreamResource(inputStream);
HttpHeaders headers = new HttpHeaders();
headers.setContentLength(Files.size(Paths.get(filePath)));
return new ResponseEntity(inputStreamResource, headers, HttpStatus.OK);
}
You could use the ByteArrayOutputStream and ByteArrayInputStream. Example:
// A ByteArrayOutputStream holds the content in memory
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
// Do stuff with your OutputStream
// To convert it to a byte[] - simply use
final byte[] bytes = outputStream.toByteArray();
// To convert bytes to an InputStream, use a ByteArrayInputStream
ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);
You can do the same with other stream pairs. E.g. the file streams:
// Create a FileOutputStream
FileOutputStream fos = new FileOutputStream("filename.txt");
// Write contents to file
// Always close the stream, preferably in a try-with-resources block
fos.close();
// The, convert the file contents to an input stream
final InputStream fileInputStream = new FileInputStream("filename.txt");
And, when using Spring MVC you can definitely return a byte[] that contains your file. Just make sure that you annotate your response with #ResponseBody. Something like this:
#ResponseBody
#RequestMapping("/myurl/{filename:.*}")
public byte[] serveFile(#PathVariable("file"} String file) throws IOException {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
DbxEntry.File downloadedFile = client.getFile("/" + filename, null, outputStream);
return outputStream.toByteArray();
}
I recommend reading this answer
#ResponseBody
#RequestMapping("/photo2", method = RequestMethod.GET, produces = MediaType.IMAGE_JPEG_VALUE)
public byte[] testphoto() throws IOException {
InputStream in = servletContext.getResourceAsStream("/images/no_image.jpg");
return IOUtils.toByteArray(in);
}
answered by michal.kreuzman
I was going to write something similar myself but ofcourse it's already been answered.
If you want to just pass the stream instead of first getting everything in memory you could use this answer
I haven't tested this (not at work) but it looks legit :)
#RequestMapping(value = "report1", method = RequestMethod.GET, produces = "application/pdf")
#ResponseBody
public void getReport1(OutputStream out) {
InputStream in; // retrieve this from wherever you are receiving your stream
byte[] buffer = new byte[1024];
int len;
while ((len = in.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
in.close();
out.flush(); // out.close?
}
The thing is, this is pretty much the same as IOUtils.copy / IOUtils.copyLarge does. line: 2128
Which you say copies the wrong direction.
However first make sure you understand what you ask. If you want to read from an outputstream(object for writing) and write to an input stream (object to read from) then I think what you really want is to write to an object that also supplies a read option.
for that you could use a PipedInputStream and PipedOutputStream. These are connected together so that bytes written to the outputstream are available to be read from the corresponding input stream.
so in the location where you are receiving the bytes I assume you are writing bytes to an outputstream.
there do this:
// set up the input/output stream so that bytes written to writeToHere are available to be read from readFromhere
PipedInputStream readFromHere = new PipedInputStream();
PipedOutputStream writeToHere = new PipedOutputStream(readFromHere);
// write to the outputstream as you like
writeToHere.write(...)
// or pass it as an outputstream to an external method
someMather(writeToHere);
// when you're done close this end.
writeToHere.close();
// then whenever you like, read from the inputstream
IOUtils.copy(readFromHere, out, new byte[1024]);
If you use IOUtils.copy it will continue to read until the outputstream is closed. so make sure that it is already closed before starting (if you run write/read on the same thread) or use another thread to write to the output buffer and close it at the end.
If this is still not what you're looking for then you'll have to refine your question.
The most memory-efficient solution in your case would be to pass the response OutputStream right to the Dropbox API:
#GetMapping(value = "download/{name}")
public void getFileByName(#PathVariable("name") final String name, HttpServletResponse response)
throws IOException, DbxException {
response.setContentType("audio/mpeg3");
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + name + "\"");
response.setContentLength(filesize); // if you know size of the file in advance
new DbxClient().getFile("/" + name, null, response.getOutputStream());
}
Data read by the API will be sent directly to the user. No additional byte buffer of any type is required.
As for PipedInputStream/PipedOutputStream, they are intended for the blocking communication between 2 threads. PipedOutputStream blocks writing thread after 1024 bytes (by default) until some other thread start reading from the end of the pipe (PipedInputStream).
One thing to keep in mind when writing to the response outputstream is that it is a very good idea to call flush() on whatever writer that you've wrapped it with periodically. The reason for this is that a broken connection (for example caused by a user canceling a download) may not end up throwing an exception for a long time, if ever. This can effectively be a resource leak on your container.

Is there an alternative to FileOutputStream type , which does not create a file?

To process some images in my android application I currently use code like this:
FileOutputStream fileOuputStream = new FileOutputStream(imgpath);
[..DO SOME STUFF..]
Bitmap data = BitmapFactory.decodeByteArray(bFile, 0, bFile.length, options);
data.compress(Bitmap.CompressFormat.JPEG, 90, fileOuputStream);
[..DO SOME STUFF..]
File file = new File(imgpath);
FileInputStream imageInFile = new FileInputStream(file);
byte imageData[] = new byte[(int) file.length()];
imageInFile.read(imageData);
[..DO SOME STUFF..]
file.delete();
//NOTE: The code is all in the same method
the problem is that passing my image from one part of the code to another using this method creates a temporary file.
I was looking for a way to read / write the file data using a memory variable, something like "generic stream" in which store data in order to replace use of "FileInputStream " and "FileOutputStream " and do not write temporary file.
If you are able to use an InputStream or OutputStream you can use ByteArrayInputStream or ByteArrayOutputStream for in memory handling of the data.
If you have two thread you can also use PipedInputStream and PipedOutputStream together to communicate between the threads.
You could write your data to a ByteArrayOutputStream and use the byte array of that stream:
ByteArrayOutputStream out = new ByteArrayOutputStream();
data.compress(Bitmap.CompressFormat.JPEG, 90, out);
// now take the bytes out of your Stream
byte[] imgData = out.toByteArray();

Categories

Resources