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.
I have a custom Logger and I want to redirect all the sysout and syserr from the console into that custom logger. So I am thinking to redirect sysout and syserr in the following way:
By extending ByteArrayOutputStream
And then to set System.setErr and System.setOut
public class ServerLoggingPrintStream extends ByteArrayOutputStream {
public ServerLoggingPrintStream() {
super();
}
public void write(byte[] originalBytes, int originalOffset, int originalLength) {
synchronized(this) {
String str = new String(originalBytes);
if (str.length() == 0 || str.equals(System.getProperty("line.separator")) ) {
return;
}
//using my custom logger named TRACE_LOGGER
TRACE_LOGGER.log(LogLevel.INFO, this, "write", str);
}
}
}
ServerLoggingPrintStream serverLoggingPrintStreamStdOut_ = null;
ServerLoggingPrintStream serverLoggingPrintStreamStdErr_ = null;
serverLoggingPrintStreamStdErr_ = new ServerLoggingPrintStream();
System.setErr(new PrintStream(serverLoggingPrintStreamStdErr_));
serverLoggingPrintStreamStdOut_ = new ServerLoggingPrintStream();
System.setOut(new PrintStream(serverLoggingPrintStreamStdOut_));
Do you think is there a better way of doing it?
It is more complicated than that to get it right. That being said, there are open source projects that already do this, so you could borrow some code from there. One example is here:
http://docs.jboss.org/jbossas/javadoc/4.0.2/org/jboss/logging/util/LoggerStream.java.html
I would use an OutputStream that redirects to the logging framework you use. Its fairly easy to implement (I assumed the charset to be ISO, so there is no fancy handling for encoding):
final class RedirectionOutputStream extends OutputStream {
StringBuilder buffer = new StringBuilder();
#Override
public synchronized void write(final int b) throws IOException {
final char c = (char) (b & 0xFF);
buffer.append(c);
if (c == '\n') {
// send buffered data to logging framework (its a complete line now)
// reset buffer
buffer.setLength(0);
}
}
}
Thats the gist of it, but the details may be different for your logging framework. The main problem is that loggers usually expect strings to log and you get raw, encoded bytes from the redirected stream, so you have to reverse the encoding (by raw cast in this example, technically this should be done using a Reader).
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
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.