Скрытие вызовов System.out.print класса

Я использую java-библиотеку (файл jar). Автор файла помещен в кучу System.out.print и System.out.println s. Есть ли способ скрыть эти сообщения для определенного объекта?

* EDIT: похоже, что файл jar создает цепочку потоков, и каждый поток имеет свой собственный System.out.println's...

Ответы

Ответ 1

Измените оригинальный PrintStream с помощью Dummy, который ничего не делает на нем write().

Не забудьте заменить оригинальный PrintStream, когда закончите.

System.out.println("NOW YOU CAN SEE ME");

PrintStream originalStream = System.out;

PrintStream dummyStream = new PrintStream(new OutputStream(){
    public void write(int b) {
        // NO-OP
    }
});

System.setOut(dummyStream);
System.out.println("NOW YOU CAN NOT");

System.setOut(originalStream);
System.out.println("NOW YOU CAN SEE ME AGAIN");

Ответ 2

System.setOut();, вероятно, то, что вы ищете

System.setOut(new PrintStream(new OutputStream() {
  public void write(int b) {
    // NO-OP
  }
}));

Источник

Ответ 3

Есть два способа, я могу думать о том, чтобы делать это иначе, чем то, что было ранее опубликовано:
1. Используйте декомпилятор Java и удалите каждый вызов System.out и перекомпилируйте банку. Я бы рекомендовал этот, если вы выберете этот маршрут.
2. Вы можете использовать трассировку стека для поиска вызывающего типа. (Из Как найти вызывающего метода с использованием stacktrace или reflection?)

List<String> classNames = ...
final PrintStream originalOut = System.out;
PrintStream filterStream = new PrintStream(new OutputStream() {
    public void write(int b) {
         StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
         if(!classNames.contains(stackTraceElements[someNumber].getClassName()){
              originalOut.write(b);
         }
    }
});
System.setOut(filterStream);

Где classNames - полное имя каждого класса в файле jar, а someNumber - правильное место в стеке, на которое вы должны смотреть (возможно, 1 или 2).

/e1
После некоторого тестирования я считаю, что число, которое вам понадобится для someNumber, равно 10 или 11. Это связано с тем, что System.out.print не вызывает непосредственно метод write.

Пример трассировки стека для записи h:
(Трассировки стека находятся в индексе, getClassName, getFileName, getMethodName порядок).

0   java.lang.Thread    null    getStackTrace
1   reflection.StackTrace$1 StackTrace.java write
2   java.io.OutputStream    null    write
3   java.io.PrintStream null    write
4   sun.nio.cs.StreamEncoder    null    writeBytes
5   sun.nio.cs.StreamEncoder    null    implFlushBuffer
6   sun.nio.cs.StreamEncoder    null    flushBuffer
7   java.io.OutputStreamWriter  null    flushBuffer
8   java.io.PrintStream null    write
9   java.io.PrintStream null    print
10  java.io.PrintStream null    println
11  reflection.StackTrace   StackTrace.java main

Пример трассировки стека для записи \n:

0   java.lang.Thread    null    getStackTrace
1   reflection.StackTrace$1 StackTrace.java write
2   java.io.OutputStream    null    write
3   java.io.PrintStream null    write
4   sun.nio.cs.StreamEncoder    null    writeBytes
5   sun.nio.cs.StreamEncoder    null    implFlushBuffer
6   sun.nio.cs.StreamEncoder    null    flushBuffer
7   java.io.OutputStreamWriter  null    flushBuffer
8   java.io.PrintStream null    newLine
9   java.io.PrintStream null    println
10  reflection.StackTrace   StackTrace.java main

reflection.StackTrace - это основной класс, который я использую для выполнения теста. reflection.StackTrace$1 является моим filterStream, и я вызываю System.out.println из метода main в reflection.StackTrace.

/е2
Это 11 или 10 несоответствий, по-видимому, связано с тем, что println вызывает print и newLine. print переходит к вызову write, а newLine непосредственно пишет новый символ строки в поток. Но это не имеет значения, поскольку в jar не будет java.io.PrintStream.

Ответ 4

Если у вас есть более крупная программа, рассмотрите что-то вроде

public abstract class Output {
    private static final PrintStream out = System.out;
    private static final PrintStream dummy = new PrintStream(new OutputStream() {@Override public void write(int b){} });

    private static boolean globalOutputOn = true;
    public static void toggleOutput() {
        System.setOut((globalOutputOn=!globalOutputOn)?dummy:out);
    }

    public static void toggleOutput(boolean on) {
        globalOutputOn = on;
        System.setOut(on?out:dummy);
    }
}

Это гарантирует, что вы можете включать и отключать вывод в разных классах, в то время как beur guranteed, чтобы иметь возможность позже выводить результат.

Вы, например, используете его, вызывая

toggleOutput(false) в начале каждого метода и

toggleOutput(true) в конце каждого метода.