Changing output stream back to system.out - java

My main calls several classes, each of which redirects System.out so they can intercept what was printed by another class (even if this is bad practice - I have to do this).
Then, after they all finish, I would like to simply print on the screen with my main, but nothing happens.
Code in class1, class2:
doStuff() {
ByteArrayOutputStream outContent = new ByteArrayOutputStream();
System.setOut(new PrintStream(outContent));
...
Main:
class1.doStuff();
class2.doStuff();
...
System.setOut(System.out); //set output back
System.out.println("Success!"); //print something. doesn't work!

You have to save the original System.out somewhere.
System.setOut() modifies System.out, so you're essentially doing System.out = System.out; which of course does nothing.

Related

Capturing stdout from java.lang.reflect method invocation

I have an application that, among other things, runs Java methods via java.lang.reflect. It normally functions as normal; however, a user used it with one of their JARs, and it broke somewhat.
As you can see in the below code, I attempt to capture both stdout and stdin from the method. However, when the method is invoked, only the first line of what the method streams to stdout is actually captured.
Here's the relevant code. If you need to see more of the code, let me know, and I'll add some more:
String retVal = "";
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayOutputStream err = new ByteArrayOutputStream();
PrintStream origOut = System.out;
PrintStream origErr = System.err;
System.setOut(new PrintStream(out));
System.setErr(new PrintStream(err));
Exception myException = null;
try {
Object myRetVal = null;
myRetVal = m.invoke(obj, convertedMethodArguments);
if (myRetVal != null)
retVal = myRetVal.toString();
} catch (Exception e) {
myException = e;
}
returnObj.addProperty("stdout", out.toString());
returnObj.addProperty("stderr", err.toString());
returnObj.addProperty("rv", retVal);
returnObj.addProperty("rt", m.getReturnType().toString());
if (myException != null && myException.getCause() != null)
returnObj.addProperty("exception", myException.getCause().toString());
else
returnObj.addProperty("exception", "");
System.setOut(origOut);
System.setErr(origErr);
System.out.print(new Gson().toJson(returnObj));
// TODO: remove, debug purposes only
// Should use normal stdout
try {
System.out.println();
m.invoke(obj, convertedMethodArguments);
} catch (Exception e) {
System.out.println(e.toString());
}
When I execute the above code, it only prints out the first line of stdout. However, at the bottom of the code block, I invoke the method again, but this time without any redirection, and I get all of the stdout from the method.
Any help would be greatly appreciated!
EDIT #1: OK, get this. For fun, I commented-out the two lines where I redirect the default System streams (e.g. System.setOut and System.setErr). With these gone, I now expect all stdout to be written to the console directly when I run the app.
I added a message (e.g. System.out.println("Testing...");) at the very end of my code, so that it's the last thing that is executed. When I test the app, I get the first line of stdout, followed by my testing message, and THEN the rest of the stdout.
I have no clue what's going on here.
EDIT #2: Per #Titus's suggestion, I looked into whether or not the method I'm invoking is spinning off its own threads. Turns out, it is. Two threads are created, AWT-AppKit and AWT-Shutdown. The former thread seems to stay in RUNNABLE state, whereas the latter thread stays in the TIMED_WAITING state.
Over time, the AWT-Shutdown thread goes away, but the other one stays alive in its RUNNABLE state. Once my application exits, I believe the method I'm invoking also exits, and at that point the extra messages are displayed to the screen (which explains why I can't capture this bit of STDOUT).
What I don't understand is why this method won't terminate within my application.
Try to flush the streams after you call the method.
Here is an example:
PrintStream outPR = new PrintStream(out);
System.setOut(outPR);
....
outPR.flush();
returnObj.addProperty("stdout", out.toString());
You can even do this:
System.setOut(new PrintStream(out, true));
....
System.out.println();
returnObj.addProperty("stdout", out.toString());
The PrintStream is automatically flushed (if you use the constructor that I've used) when a \n (new line) is written to it.
Based on the edits to your question, it is possible that the method you're calling is creating new threads which means that it is possible that this new threads print to the console after the method returns.
If that is the case, you'll have to wait until this threads finish in order to get all the output.

System.out.print output to console seen immediately. So PrintStream flushes after each print, not only println?

From the PrintStream documentation:
Optionally, a PrintStream can be created so as to flush automatically;
this means that the flush method is automatically invoked after a byte
array is written, one of the println methods is invoked, or a newline
character or byte ('\n') is written.
Then given code
System.out.print("hi"); // gives console output: hi
System.out.print(7); // gives console output: 7
// prevents flushing when stream wiil be closed at app shutdown
for (;;) {
}
Why then I see output to my console? Nothing shall be written to console (PrintStream instance from System.out), because nothing shall be flushed so far!
This didn't answer this.
I guess, the answer is in the source code (private utility method BufferedWriter.flushBuffer()), but I don't understand the comment to code: "Flushes the output buffer to the underlying character stream, without flushing the stream itself": if PrintStream (which is tied to console output), which is "stream itself" is not flushed, output to console shall not be refreshed!...
Source for PrintStream.print(String):
private void write(String s) {
try {
synchronized (this) {
ensureOpen();
textOut.write(s);
textOut.flushBuffer();
charOut.flushBuffer();
if (autoFlush && (s.indexOf('\n') >= 0))
out.flush();
}
}
catch (InterruptedIOException x) {
Thread.currentThread().interrupt();
}
catch (IOException x) {
trouble = true;
}
}
Source for BufferedWriter.flushBuffer():
/**
* Flushes the output buffer to the underlying character stream, without
* flushing the stream itself. This method is non-private only so that it
* may be invoked by PrintStream.
*/
void flushBuffer() throws IOException {
synchronized (lock) {
ensureOpen();
if (nextChar == 0)
return;
out.write(cb, 0, nextChar);
nextChar = 0;
}
}
More details are also given here. It is very complicated, but seems like at some stage BufferedWriter is given to PrintStream constructor.
I went step by step using debugger and this is what I found:
String s is displayed in the console after 527th line, so it's before line 528 in which the check of having \n is done.
In charOut.flushBuffer() deep inside, there is the following method called:
In which, the check about \n is missing.
The flow is as it follows:
System.out#print(String s) calls PrintStream#print(String s).
PrintStream#print(String s) calls PrintStream#write(String s).
PrintStream#write(String s) calls OutputSteamWriter#flushBuffer().
OutputStreamWriter#flushBuffer() calls StreamEncoder#flushBuffer().
StreamEncoder#flushBuffer() calls StreamEncoder#implFlushBuffer().
StreamEncoder#implFlushBuffer() calls StreamEncoder#writeBytes().
StreamEncoder#writeBytes() calls PrintStream#write(byte buf[], int off, int len) which flushes the buffor if(autoFlush).
The most important snippets are above. The BufferedWriter seems not to be called in this flow.
https://bugs.openjdk.java.net/browse/JDK-8025883 describes this bug.
This bit me in a program that reads and parses a binary file, doing a lot of System.out.printf() calls, which took way longer that it should.
What I ended up doing was writing a helper class that violates the contract of Streams by not honoring every flush request:
class ForceBufferedOutputStream extends OutputStream {
OutputStream out;
byte[] buffer;
int buflen;
boolean haveNewline;
private static final int bufsize=16384;
public ForceBufferedOutputStream(OutputStream out) {
this.out=out;
this.buffer=new byte[bufsize];
this.buflen=0;
this.haveNewline=false;
}
#Override
public void flush() throws IOException {
if (this.haveNewline || this.buflen==bufsize) {
out.write(buffer, 0, buflen);
out.flush();
this.buflen=0;
this.haveNewline=false;
}
}
#Override
public void close() throws IOException {
out.close();
}
#Override
public void write(int b) throws IOException {
buffer[buflen++]=(byte)b;
if (b=='\n')
this.haveNewline=true;
if (buflen==bufsize)
this.flush();
}
}
then using a new PrintStream(new ForceBufferedOutputStream(System.out)) instead of System.out.
I consider this a horrible piece of software - as said, it violates the contract that flush() needs to make sure everything is written, and it could optimize array write calls. But in my case, runtime was cut from 17 minutes to 3:45, so if you need a copy/paste that speeds up a quick and dirty type of program, I hope it helps somewhat.

Why my PrintWriter doesn't print on console if I don't use PrintWriter(Writer out,boolean autoFlush) constructor?

The following code is from another Stack Overflow Thread about difference between PrintStream and PrintWriter.
import java.io.*;
public class PracticeWriter
{
public static void main(String[] args) {
System.out.println("Method 1");
PrintWriter writer = new PrintWriter(System.out,true);
writer.println("Method 2");
}
}
However,I added true later when I saw it's not printing Method 2 on the console.It's supposed to print using PrintWriter(Writer out) constructor.Why it is not doing so?
A flush writes from the buffer to the actual stream; with no closing, flushing or auto-flushing, the lack of output is entirely expected behaviour. Add a call to flush, or use the constructor in the way you have done (with auto-flushing enabled) - or just have a try-with-resources.

Synchronizing on System.out

I changed System.out to print to a file, by invoking System.setOut and System.setErr.
Every night at midnight, we want to rename (archive) the current log file, and create a new one.
if (out != null) {
out.close();
out = null;
File f = new File(outputfilename);
f.renameTo(new File(dir.getPath().replace(".log", "-" + System.currentTimeMillis() + ".log")))
StartLogFile();
}
The StartLogFile():
if (out == null) {
out = new FileOutputStream(outputfilename, true);
System.setOut(new PrintStream(out));
System.setErr(new PrintStream(out));
}
I've left exception-handling out.
My concern is that if something tries to print in between out.close() and setOut/setErr that I'm going to miss a log.
My real question is, how can I make this atomic with other calls to System.out.println?
I was thinking about trying
synchronized (System.out) {
}
but I'm not actually sure if the intrinsic lock here does anything. Especially since I'm nullifying the out object during the operation.
Does anyone know how I can ensure proper synchronization here?
I would create the new out before closing the old one:
PrintStream old = System.out;
out = new FileOutputStream(outputfilename, true);
System.setOut(new PrintStream(out));
old.close();
This way the old PrintStream is not closed until the new one is created and assigned. At all times there is a valid PrintStream in System.out.
There is no need for synchronized block, because everything is in the same thread.
Yes you can achieve proper synchronization that way. Here is a sample test.
#Test
public void test() throws InterruptedException {
new Thread(()->{
while(true){
System.out.println("printing something");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
}).start();
Thread.sleep(500);
synchronized (System.out){
System.out.println("changin system out");
Thread.sleep(2000);
System.out.println("finished with sysout");
}
Thread.sleep(2000);
}
and the output will be:
printing something
printing something
printing something
printing something
printing something
changin system out
finished with sysout
printing something
printing something
printing something
printing something
printing something
printing something
printing something
printing something
printing something
printing something
printing something
printing something
printing something
printing something
There is no way to make this work safely, since you have no control what the calling code is doing with System.out. Think of this:
public void doSomethingTakingALongTime(PrintStream target) {
// lots of code
}
// somewhere else
doSomethingTakingALongTime(System.out);
You can never be sure there isn't a copy of System.out reference somewhere out there in a local variable or method parameter.
The proper way to solve this would be to set System.out only once, at the very start of the program, and instead of using a standard PrintStream, you use your own implementation that delegates everything to the current target.
You are then in complete control of every output made through System.out and can synchronize at you leisure where required. If your own implementation synchronizes every operation, the question of what happens while you're changing the logging target doesn't even arise - every other caller will simply be blocked by the synchronization lock.
Btw. its questionable to use System.out for logging. The de-facto standard for logging would be using log4j. Consider switching to that.
Edit: Actually implementing this delegation can be rather easy. There is a constructor PrintStream(OutputStream). That means you can just implement delegation in an OutputStream (that has considerably less methods than PrintStream) and set System.out to your new PrintStream(YourRetargettingOutputStream).
You can define an object explicitly for locking like
static final Object lock = new Object();
How about locking over it like below
synchronized(lock){
if(out != null) {
out.close();
out = null;
File f = new File(outputfilename);
f.renameTo(new File(dir.getPath().replace(".log", "-" + System.currentTimeMillis() + ".log")))
StartLogFile();
}
}

System.out .write() executes but doesn't print

public class BRRead {
public static void main(String[] args) {
int b;
b='A';
System.out .write(b);
System.out .write('\n');
}
}
So when i execute the above program i get the expected output - A
but when comment out the last line System.out.write('\n'); the program executes but doesn't print the output - A.
Can any one explain what's exactly happening here?
public class BRRead {
public static void main(String[] args) {
int b;
b='A';
System.out .write(b);
//System.out .write('\n');
}
}
public void write(int b)
Writes the specified byte to this stream. If the byte is a newline and
automatic flushing is enabled then the flush method will be invoked.
In your example, flush() is not called automatically, if you call it explicitly the character will be printed.
From here
Basically, Java doesn't guarantee that output is actually sent to a
file, socket, the screen, or any other output device until you call
flush() on your OutputStream or Writer, or until it is closed. The
OutputStream or Writer may buffer the output, meaning that it will be
saved up and sent in larger chunks for efficiency. You can't really
predict how this will be done.
PrintWriter.println() will automatically call flush(), by the way,
although that doesn't matter here. But in any case, the general rule
is that if you want output to appear somewhere immediately, and you're
not using PrintWriter.println() (or PrintStream.println()), then call
flush() yourself.
Call System.out.flush() at the end of your code
From the write(int bytevalue) method body, the arg seems buffered/stored temporarily and not actually written until you write a new line.

Categories