4

Currently, I am trying to read the console output of my program when there is a method call. How it works is, my Java program calls the JNI wrapper to invoke the C++ method call. My C++ is using std::cout. The payload.invoke will invoke my c++ library API. Inside the c++ API there are a few cout statements. That is the statement I want to read it as a variable in Java.

The current PrintStream only supports out, print, println and printf.Each time when there is a method call, there are bunch of logs being printed out in command prompt. Now, I would like my java program to read those output which my C++ prints out.

This is my current Java code:

public void execute() {
    try {
        Matcher m = Pattern.compile("([^()]*)[(]([^()]*)[)]").matcher(getPayloadString());
        m.find();
        boolean passed;
        if (m.group(2).isEmpty()) {
            // this is where it invoke the method
            passed = (boolean) payload.invoke(testcase);
            System.out.println("Boolean is: " + passed + "\n"); 
        }else {
            passed = (boolean) payload.invoke(testcase, ObjectCreator.convertParameters(m.group(2)));
            System.out.println("Boolean2 is: " + passed + "\n");

        }
        String output = passed ? "PASS" : "FAIL";
        // I want to use the console output string variable here -> xxxx
        TestCase.printResult(payload.getName(), output, m.group(2), xxxx, "");
    } catch (Exception ex) {
        ex.printStackTrace();
    }
}

Are there any ways to do it? Previously I tried using one of the tutorial from here. but that seems not working. Can someone help me out with this please. Thanks in advance.

Raaj Lokanathan
  • 479
  • 3
  • 7
  • 19
  • This might be what you're looking for; [https://stackoverflow.com/questions/8708342/redirect-console-output-to-string-in-java](https://stackoverflow.com/questions/8708342/redirect-console-output-to-string-in-java) – Fecid Oct 20 '20 at 09:48
  • @Fecid I am not really sure, because I went through it just now, but I am not really sure how can I use it because, the link is based on system.out outputs. – Raaj Lokanathan Oct 20 '20 at 09:54
  • Wouldn't it suffice to just store all output in a variable before printing? Then you could just read these stored values. – MDK Oct 20 '20 at 10:42
  • If you see in the code there, I am not using neither the System.out or print(). I am programatically calling the method using .invoke. I am not really sure how can I capture the output when the invoke method is triggered? – Raaj Lokanathan Oct 20 '20 at 11:07
  • If text is appearing on the console, some part of your program uses print(), although it might be some library function you didn't write yourself. What type does this payload have? Is it a class from a library? – MDK Oct 20 '20 at 11:50
  • This payload is declared as `Method payload`. the payload act as a method invocator. For example, `A.methodA()`. – Raaj Lokanathan Oct 21 '20 at 01:21
  • @Abra yes you are correct, my c++ application is calling a `std::cout`. If that's the case how can I capture the output? – Raaj Lokanathan Oct 21 '20 at 01:30
  • This is not trivial, but only because of the poor choice of standard output as a “return value”. Is that really not changeable? – Davis Herring Oct 27 '20 at 05:10
  • What it be an option to perform the method call in a separate process? This is a big hammer for your problem but it would at least make capturing the output simple. Alternatively, can you change your native to code to print to a file rather than `cout`? Then you could pick up the output from that file. – Daniel Junglas Oct 27 '20 at 05:44
  • @DanielJunglas You mean instead of cout you want me to write it to a text file. And then using my Java app to read the text file? – Raaj Lokanathan Oct 27 '20 at 06:46
  • 1
    @RaajLokanathan, yes, that is what I had in mind. Another option would be to have the native code print to a `std::stringstream` and then return `std::stringstream::str()` from that function? – Daniel Junglas Oct 27 '20 at 07:09
  • As for the second option which you mentioned, I dont think its possible because my method only returns boolen as the status Pass or Fail. – Raaj Lokanathan Oct 27 '20 at 07:15
  • Answer linked by @ Fecid is a good solution. Once you replace System.out with your stream, output will get collected there. – Jayan Nov 01 '20 at 12:23

2 Answers2

0

If you have full control of the .cpp codebase it is possible for you to change the std::cout to become a ostream& instead.

By referencing a base class you can easily switch the implementation.

Do a JNI-Stream whichh extends the ostream& and just overwrite the operators you need to send JNI wrapped callbacks to java.

Then depending on if you run native or Java style use your JNI-Stream instead of the std::cout.

I would do something as seen in the link below to package and send the data to Java:

JNI - How to callback from C++ or C to Java?

that is my 2 cents.

-1

Read carefully the JNI tutorial.

https://www.baeldung.com/jni

Follow the tutorial. Basically you need to create a java class with a static block to load the C++ library:

static {
    System.loadLibrary("native");
}

Then you can create your own static java method and invoke a method on the library.

If what you need is read the output from a system call, it's a different matter. This can help you:

Java Runtime.getRuntime(): getting output from executing a command line program

Saxon
  • 739
  • 3
  • 6