简体   繁体   中英

How to get System out console from a jar loaded by a class loader?

I am running an external jar plugin like this:

  Class<?> pluginClass = pluginLoader.loadClass(".......");     
  Method main = pluginClass.getMethod("main", String[].class);
  main.invoke(null, new Object[] { new String[0] }); 

It works great. Now need to save the plugin console messages into a String

  ByteArrayOutputStream baos = new ByteArrayOutputStream();
  PrintStream ps = new PrintStream(baos); // how to indicate System.out coming from JAR plugin 
  System.setOut(ps); 
 // how to connect ps with plugin only 

But this code saves ALL console messages into String. I don't need all application messages. How to redirect plugin only messages......messages coming from this loaded jar into the string?

You can't do what you are asking. There is only one standard output stream in the process and it is shared with the plugin code and your code.

You could instead run the plugin code as a separate process and capture the output stream. You can use the "java.home" System Property to find the location of the JRE that launched your process and use that to form a command line to launch the plugin jar.

See https://docs.oracle.com/javase/8/docs/api/java/lang/ProcessBuilder.html

System.out is per process, no way to have different stream per class loader. If you desperately need to get the system out from plugin there are 2 options : 1. Pass output stream to your plugin if you have acces to its code and make plugin use this stream. 2. Run your plugin as external process. This way you will be able to redirect its output. Another option : if you can differentiate the plugins output, you can implement your own routing output stream and set it as system out.

I made this workaround:

public class CustomPrintStream extends PrintStream {
    private String prefix;

    public CustomPrintStream(String prefix, OutputStream out) {
        super(out);
        this.prefix = prefix;
    }

    @Override
    public void println(String s) {
        if(s.startsWith(prefix))
            super.println(s);
        else {
            System.setOut(new PrintStream(new FileOutputStream(FileDescriptor.out)));
            System.out.println(s);
            System.setOut(this);
        }
    }
}

This offers you the possibility to add a prefix to each of you main program's System.out.printlns, so that they get executed normally. The ones without the prefix (from your plugin) get directly into the defined out-stream (in my example the fileoutputstream)

It is used like this:

System.setOut(new CustomPrintStream("test", new FileOutputStream("C:\\out.txt"))); //Of course you can also use ByteArrayOutputStream, as you did before
System.out.println("test 1"); //this goes into the standard outstream
System.out.println("2"); //and this goes into the fileoutputstream
System.out.println("test 3");

Maybe this will help you :)

Edit: I switched it around so that the string with prefix goes into the normal outstream

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM