What's the best way to pipe the output from an java.io.OutputStream to a String in Java?
Say I have the method:
writeToStream(Object o, OutputStream out)
Which writes certain data from the object to the given stream. However, I want to get this output into a String as easily as possible.
I'm considering writing a class like this (untested):
class StringOutputStream extends OutputStream {
StringBuilder mBuf;
public void write(int byte) throws IOException {
mBuf.append((char) byte);
}
public String getString() {
return mBuf.toString();
}
}
But is there a better way? I only want to run a test!
I would use a ByteArrayOutputStream. And on finish you can call:
new String( baos.toByteArray(), codepage );
or better:
baos.toString( codepage );
For the String constructor, the codepage can be a String or an instance of java.nio.charset.Charset. A possible value is java.nio.charset.StandardCharsets.UTF_8.
The method toString() accepts only a String as a codepage parameter (stand Java 8).
I like the Apache Commons IO library. Take a look at its version of ByteArrayOutputStream, which has a toString(String enc) method as well as toByteArray(). Using existing and trusted components like the Commons project lets your code be smaller and easier to extend and repurpose.
This worked nicely
OutputStream output = new OutputStream() {
private StringBuilder string = new StringBuilder();
#Override
public void write(int b) throws IOException {
this.string.append((char) b );
}
//Netbeans IDE automatically overrides this toString()
public String toString() {
return this.string.toString();
}
};
method call =>> marshaller.marshal( (Object) toWrite , (OutputStream) output);
then to print the string or get it just reference the "output" stream itself
As an example, to print the string out to console =>> System.out.println(output);
FYI: my method call marshaller.marshal(Object,Outputstream) is for working with XML. It is irrelevant to this topic.
This is highly wasteful for productional use, there is a way too many conversion and it is a bit loose. This was just coded to prove to you that it is totally possible to create a custom OuputStream and output a string. But just go Horcrux7 way and all is good with merely two method calls.
And the world lives on another day....
Here's what I ended up doing:
Obj.writeToStream(toWrite, os);
try {
String out = new String(os.toByteArray(), "UTF-8");
assertTrue(out.contains("testString"));
} catch (UnsupportedEncondingException e) {
fail("Caught exception: " + e.getMessage());
}
Where os is a ByteArrayOutputStream.
baos.toString(StandardCharsets.UTF_8);
Converts the buffer's contents into a string by decoding the bytes using the named charset.
Java 17 - https://docs.oracle.com/
Here's what I did (don't use this in production, this is not great! But it makes fixing multiple errors easier.)
Create a list that holds Exceptions.
Create a logger to log exceptions.
Use the code below:
private static void exceptionChecker() throws Exception {
if(exceptionList.isEmpty()) return; //nothing to do :) great news
//create lock for multithreading
synchronized (System.err){
//create new error stream
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
PrintStream errorOut = new PrintStream(byteArrayOutputStream);
//save standard err out
PrintStream standardErrOut = System.err;
try{
//set new error stream
System.setErr(errorOut);
exceptionList.forEach(exception -> {
exception.printStackTrace();
System.err.println("<---------->");
});
} finally {
//reset everything back to normal
System.setErr(standardErrOut);
//Log all the exceptions
exceptionLogger.warning(byteArrayOutputStream.toString());
//throw final generic exception
throw new Exception();
}
}}
This isn't great as you are throwing an error in the finally block and it locks on the error stream, but it works for dev purposes.
Related
What I am trying to do seems to be a quite simple thing, get an InputStream from a Jersey webservice which is returned from a class RestResponse. But I don't get the stream to my client:
public class RestResponse {
private InputStream responseStream;
public RestResponse(InputStream responseBodyStream) throws IOException{
this.responseStream = responseBodyStream;
//here I can get the stream contents from this.responseStream
}
public InputStream getResponseStream() throws IOException {
//here stream content is empty, if called from outside
//only contains content, if called from constructor
return this.responseStream;
}
}
public class HttpURLConnectionClient{
public RestResponse call(){
try{
....
InputStream in = httpURLConnection.getInputStream();
RestResponse rr = new RestResponse(in);
}finally{
in.close(); <- this should be the suspect
}
}
}
RestResponse rr = httpURLConnectionClient.call()//call to some url
rr.getResponseStream(); //-> stream content is empty
Any ideas, what I am missing? Is is not possible to just pipe the stream through?
Certain types of InputStream can only be read once in Java. Based on your comment above, it appears that you are using the InputStream when you pipe it to System.out. Try commenting out the call to System.out and see if you can access your InputStream. Also make sure that the stream is not being consumed anywhere else in the code before the point where you need it.
Update:
It appears that your actual problem was being caused by closing the InputStream before you got a chance to use it. So the solution is to keep the stream open until you need it, and close it afterwards.
Typically, it is not a good design practice to open a stream and keep it open for a long time, because then the underlying resource won't be available to anyone else who needs it. So you should open the stream, and consume it only when you actually need it.
What's the best way to pipe the output from an java.io.OutputStream to a String in Java?
Say I have the method:
writeToStream(Object o, OutputStream out)
Which writes certain data from the object to the given stream. However, I want to get this output into a String as easily as possible.
I'm considering writing a class like this (untested):
class StringOutputStream extends OutputStream {
StringBuilder mBuf;
public void write(int byte) throws IOException {
mBuf.append((char) byte);
}
public String getString() {
return mBuf.toString();
}
}
But is there a better way? I only want to run a test!
I would use a ByteArrayOutputStream. And on finish you can call:
new String( baos.toByteArray(), codepage );
or better:
baos.toString( codepage );
For the String constructor, the codepage can be a String or an instance of java.nio.charset.Charset. A possible value is java.nio.charset.StandardCharsets.UTF_8.
The method toString() accepts only a String as a codepage parameter (stand Java 8).
I like the Apache Commons IO library. Take a look at its version of ByteArrayOutputStream, which has a toString(String enc) method as well as toByteArray(). Using existing and trusted components like the Commons project lets your code be smaller and easier to extend and repurpose.
This worked nicely
OutputStream output = new OutputStream() {
private StringBuilder string = new StringBuilder();
#Override
public void write(int b) throws IOException {
this.string.append((char) b );
}
//Netbeans IDE automatically overrides this toString()
public String toString() {
return this.string.toString();
}
};
method call =>> marshaller.marshal( (Object) toWrite , (OutputStream) output);
then to print the string or get it just reference the "output" stream itself
As an example, to print the string out to console =>> System.out.println(output);
FYI: my method call marshaller.marshal(Object,Outputstream) is for working with XML. It is irrelevant to this topic.
This is highly wasteful for productional use, there is a way too many conversion and it is a bit loose. This was just coded to prove to you that it is totally possible to create a custom OuputStream and output a string. But just go Horcrux7 way and all is good with merely two method calls.
And the world lives on another day....
Here's what I ended up doing:
Obj.writeToStream(toWrite, os);
try {
String out = new String(os.toByteArray(), "UTF-8");
assertTrue(out.contains("testString"));
} catch (UnsupportedEncondingException e) {
fail("Caught exception: " + e.getMessage());
}
Where os is a ByteArrayOutputStream.
baos.toString(StandardCharsets.UTF_8);
Converts the buffer's contents into a string by decoding the bytes using the named charset.
Java 17 - https://docs.oracle.com/
Here's what I did (don't use this in production, this is not great! But it makes fixing multiple errors easier.)
Create a list that holds Exceptions.
Create a logger to log exceptions.
Use the code below:
private static void exceptionChecker() throws Exception {
if(exceptionList.isEmpty()) return; //nothing to do :) great news
//create lock for multithreading
synchronized (System.err){
//create new error stream
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
PrintStream errorOut = new PrintStream(byteArrayOutputStream);
//save standard err out
PrintStream standardErrOut = System.err;
try{
//set new error stream
System.setErr(errorOut);
exceptionList.forEach(exception -> {
exception.printStackTrace();
System.err.println("<---------->");
});
} finally {
//reset everything back to normal
System.setErr(standardErrOut);
//Log all the exceptions
exceptionLogger.warning(byteArrayOutputStream.toString());
//throw final generic exception
throw new Exception();
}
}}
This isn't great as you are throwing an error in the finally block and it locks on the error stream, but it works for dev purposes.
Just assume there is a program which takes inputs from the standard input.
For example:
cin>>id;
What I want to figure out is how to execute the process and give some input to its standard input. Getting the output of the process is not an issue for me. It works properly. The question is how to feed inputs for such processes using java.lang.Process class.
If there are any other third party libraries like Apache commons please mention them also.
Thanks in advance!
Use Process.getOutputStream() and write() to it. It's a bit tricky since you use the output stream to input data to the process, but the name reflects the interface that is returned (from your app's point of view it's output because you are writing to it).
You need to start a separate thread which reads from the output of one process and writes it as input to the other process.
Something like this should do:
class DataForwarder extends Thread {
OutputStream out;
InputStream in;
public DataForwarder(InputStream in, OutputStream out) {
this.out = out;
this.in = in;
}
#Override
public void run() {
byte[] buf = new byte[1024];
System.out.println("Hej");
try {
int n;
while (-1 != (n = in.read(buf)))
out.write(buf, 0, n);
out.close();
} catch (IOException e) {
// Handle in some suitable way.
}
}
}
Which would be used for prod >> cons as follows:
class Test {
public static void main(String[] args) throws IOException {
Process prod = new ProcessBuilder("ls").start();
Process cons = new ProcessBuilder("cat").start();
// Start feeding cons with output from prod.
new DataForwarder(prod.getInputStream(), cons.getOutputStream()).start();
}
}
byte[] bytes = value.getBytes();
Process q = new ProcessBuilder("process","arg1", "arg2").start();
q.getOutputStream().write(bytes);
q.getOutputStream().flush();
System.out.println(q.getInputStream().available());
I'm trying to stream file contents to an executable and capture the output but the output(InputStream) is always empty. I can capture the output if i specify the the file location but not with streamed input.
How might I overcome this?
Try wrapping your streams with BufferedInputStream() and BufferedOutputStream():
http://download.oracle.com/javase/6/docs/api/java/lang/Process.html#getOutputStream%28%29
Implementation note: It is a good idea for the output stream to be buffered.
Implementation note: It is a good idea for the input stream to be buffered.
Even with buffered streams, it is still possible for the buffer to fill if you're dealing with large amounts of data, you can deal with this by starting a separate thread to read from q.getInputStream(), so you can still be reading from the process while writing to the process.
Perhaps the program you execute only starts its work when it detects the end of its input data. This is normally done by waiting for an EOF (end-of-file) symbol. You can send this by closing the output stream to the process:
q.getOutputStream().write(bytes);
q.getOutputStream().close();
Try this together with waiting for the process.
I dont know if something else may also be wrong here, but the other process ("process") does not even have time to respond, you are not waiting for it (the method available() does not block). To try this out you can first insert a sleep(2000) after the flush(), and if that works you should switch to query'ing q.getInputStream().available() multiple times with short pauses in between.
I think, you have to wait, until the process finished.
I implemented something like this this way:
public class ProcessReader {
private static final int PROCESS_LOOP_SLEEP_MILLIS = 100;
private String result;
public ProcessReader(Process process) {
BufferedReader resultReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
StringBuilder resultOutput = new StringBuilder();
try {
while (!checkProcessTerminated(process, resultReader, resultOutput)) {
}
} catch (Exception ex1) {
throw new RuntimeException(ex1);
}
result = resultOutput.toString();
}
public String getResult(){
return result;
}
private boolean checkProcessTerminated(Process process, BufferedReader resultReader, StringBuilder resultOutput) throws Exception {
try {
int exit = process.exitValue();
return true;
} catch (IllegalThreadStateException ex) {
Thread.sleep(PROCESS_LOOP_SLEEP_MILLIS);
} finally {
while (resultReader.ready()) {
String out = resultReader.readLine();
resultOutput.append(out).append("\n");
}
}
return false;
}
}
I just removed now some specific code, that you dont need, but it should work, try it.
Regards
This question already has answers here:
JUnit test for System.out.println()
(14 answers)
Closed 8 years ago.
I'm writing integration tests using JUnit to automate the testing of a console based application. The application is homework but this part isn't the homework. I want to automate these tests to be more productive -- I don't want to have to go back and retest already tested parts of the application. (Standard reasons to use Unit tests)
Anyway, I can't figure out or find an article on capturing the output so that I can do assertEquals on it nor providing automated input. I don't care if the output/input goes to the console/output pane. I only need to have the test execute and verify the the output is what is expected given the input.
Anyone have an article or code to help out with this.
Use System.setOut() (and System.setErr()) to redirect the output to an arbitrary printstream - which can be one that you read from programmatically.
For example:
final ByteArrayOutputStream myOut = new ByteArrayOutputStream();
System.setOut(new PrintStream(myOut));
// test stuff here...
final String standardOutput = myOut.toString();
The System class has methods setIn(), setOut() and setErr() that allow you to set the standard input, output and error streams, e.g. to a ByteArrayOutputStream that you can inspect at will.
Here is the solution in place of ByteArrayOutputStream. It does not add anything to the idea of System.setOut. Rather, I want to share the implementation that is better than capturing everything into ByteArrayOutputStream. I prefer to capture only selected information and let all log messages to appear in the console as they are logged rather than capturing everything into a balckbox (of which size?) for later processing.
/**
* Once started, std output is redirected to this thread.
* Thread redirects all data to the former system.out and
* captures some strings.*/
static abstract class OutputCaputre extends Thread {
// overrdie these methods for System.err
PrintStream getDownstream() { return System.out;}
void restoreDownstream() { System.setOut(downstream);}
// will be called for every line in the log
protected abstract void userFilter(String line);
final PrintStream downstream;
public final PipedInputStream pis;
private final PipedOutputStream pos;
OutputCaputre() throws IOException {
downstream = getDownstream();
pos = new PipedOutputStream();
pis = new PipedInputStream(pos);
System.setOut(new PrintStream(pos));
start();
}
public void run() {
try {
BufferedReader br = new BufferedReader(new InputStreamReader(pis));
// once output is resotred, we must terminate
while (true) {
String line = br.readLine();
if (line == null) {
return;
}
downstream.println(line);
userFilter(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void terminate() throws InterruptedException, IOException {
restoreDownstream(); // switch back to std
pos.close(); // there will be no more data - signal that
join(); // and wait until capture completes
}
};
Here is an example of using the class:
OutputCaputre outputCapture = new OutputCaputre() {
protected void userFilter(String line) {
downstream.println("Capture: " + line);
}
};
System.out.println("do you see me captured?");
// here is your test
outputCapture.terminate(); // finally, stop capturing