Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>A way to get rid of those unwanted prints <em>permanently</em> would be to use <em>bytecode manipulation</em> to remove the print statements from the troublesome library. This can be done for example using <a href="http://asm.ow2.org/" rel="nofollow">ASM</a> (or one of the other higher level and easier to use <a href="http://en.wikipedia.org/wiki/Aspect-oriented_programming" rel="nofollow">AOP</a> frameworks).</p> <p>You can do this either at runtime or as a one-time operation of rewriting the library's class files. Refer to ASM's documentation to find out how. Here is a proof of concept. What it does is that it replaces all references to <code>System.out</code> with a reference to a <code>PrintStream</code> which does nothing.</p> <p>First the tests. They use some utility classes from <a href="https://github.com/orfjackal/dimdwarf" rel="nofollow">my project</a> to help with testing bytecode transformations (testing it requires creating a custom class loader and applying the bytecode transformations to the right class but not any other classes).</p> <pre><code>package net.orfjackal.dimdwarf.aop; import net.orfjackal.dimdwarf.aop.conf.*; import org.junit.*; import org.objectweb.asm.*; import org.objectweb.asm.util.CheckClassAdapter; import java.io.*; import java.lang.instrument.ClassFileTransformer; import java.lang.reflect.*; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; public class RemoveCallsToSystemOutTest { private PrintStream originalOut; private ByteArrayOutputStream collectedOut; @Before public void collectSystemOut() { originalOut = System.out; collectedOut = new ByteArrayOutputStream(); System.setOut(new PrintStream(collectedOut)); } @After public void restoreOriginalSystemOut() { System.setOut(originalOut); } @Test public void the_target_class_prints_when_not_manipulated() throws Exception { String safetyCheck = callPrintSomething(TroublesomePrinter.class); assertThat(safetyCheck, is("it did execute")); assertThat(collectedOut.size(), is(greaterThan(0))); } @Test public void the_target_class_does_not_print_when_it_has_been_manipulated() throws Exception { String safetyCheck = callPrintSomething(instrumentClass(TroublesomePrinter.class)); assertThat(safetyCheck, is("it did execute")); assertThat(collectedOut.size(), is(0)); } private static String callPrintSomething(Class&lt;?&gt; clazz) throws Exception { Method m = clazz.getMethod("printSomething"); m.setAccessible(true); return (String) m.invoke(null); } private static Class&lt;?&gt; instrumentClass(Class&lt;?&gt; cls) throws ClassNotFoundException { ClassFileTransformer transformer = new AbstractTransformationChain() { protected ClassVisitor getAdapters(ClassVisitor cv) { cv = new CheckClassAdapter(cv); cv = new RemoveCallsToSystemOut(cv); return cv; } }; ClassLoader loader = new TransformationTestClassLoader(cls.getPackage().getName() + ".*", transformer); return loader.loadClass(cls.getName()); } } class TroublesomePrinter { public static String printSomething() { System.out.println("something"); return "it did execute"; } } </code></pre> <p>And then the implementation. Please note that you should not use this code without first understanding it. Do not <a href="http://pragprog.com/the-pragmatic-programmer/extracts/coincidence" rel="nofollow">program by coincidence</a>.</p> <pre><code>class SilentSystem { public static final PrintStream out = new PrintStream(new OutputStream() { public void write(int b) { } }); } class RemoveCallsToSystemOut extends ClassAdapter { public RemoveCallsToSystemOut(ClassVisitor cv) { super(cv); } @Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { return new MyMethodAdapter(super.visitMethod(access, name, desc, signature, exceptions)); } private static class MyMethodAdapter extends MethodAdapter { public MyMethodAdapter(MethodVisitor mv) { super(mv); } @Override public void visitFieldInsn(int opcode, String owner, String name, String desc) { if (opcode == Opcodes.GETSTATIC &amp;&amp; owner.equals("java/lang/System") &amp;&amp; name.equals("out") &amp;&amp; desc.equals("Ljava/io/PrintStream;")) { super.visitFieldInsn(opcode, "net/orfjackal/dimdwarf/aop/SilentSystem", name, desc); } else { super.visitFieldInsn(opcode, owner, name, desc); } } } } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload