-2

Recently, I had some trouble with command line execution in a Java application. Everything goes smooth when I execute a command.

Then a specific directory is created. However, when I want to do some more complicated it does not go very well.

Why is that happening? Normal one-phrase command go in and the other don't?

2 Answers2

1

The String passed to the exec method is automatically parsed to define the parameters of the command. Since your path contain spaces (and might contain special characters too), you should consider using ProcessBuilder to construct your command.

Moreover, the constructor of the ProcessBuilder is the command to execute but you can also change the working directory using the directory method.

try {
    String[] cmd = {"cmd", 
                    "/c", 
                    "gradlew", 
                    "assembleRelease"};
    ProcessBuilder pb = new ProcessBuilder(cmd);
    // Change working directory
    pb.directory(new File("C:\\Users\\CA_LTD\\AndroidStudioProjects\\AMBITION"));
    // Run command
    Process p = pb.start();
    // Wait for completion
    int exitValue = p.waitFor();
    // Check exit value
    if (exitValue != 0) {
        // TODO: Define your behaviour when process exits with non-zero exit value

        // Print command output
        BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream());
        String outLine = null;
        while ( (outLine = reader.readLine()) != null) {
            System.out.println(outLine);
        }

        // Print command error
        BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream());
        String errLine = null;
        while ( (errLine = reader.readLine()) != null) {
            System.err.println(errLine);
        }

        // Throw exit value exception
        throw new Exception("ERROR: CMD process exited with non-zero value: " + exitValue);
    }
} catch (IOException ioe) {
    ioe.printStackTrace();
}

If you don't want to check the exit value of the command (in Windows the exit value is a pseudo environment variable named errorlevel as described in here ), you can just do:

try {
    String[] cmd = {"cmd", 
                    "/c", 
                    "gradlew", 
                    "assembleRelease"};
    ProcessBuilder pb = new ProcessBuilder(cmd);
    // Change working directory
    pb.directory(new File("C:\\Users\\CA_LTD\\AndroidStudioProjects\\AMBITION"));
    // Run command
    Process p = pb.start();
    // Wait for completion
    p.waitFor();
} catch (IOException ioe) {
    ioe.printStackTrace();
}
Cristian Ramon-Cortes
  • 1,838
  • 1
  • 19
  • 32
  • I don't really know what are you expecting to execute with the cmd command so you should consider using a different cmd definition. – Cristian Ramon-Cortes Aug 02 '18 at 12:00
  • I want to make an APK file from that project by using that command. What is that non-zero exit value and why should I define my behaviour? Is the code: int exitValue = p.waitFor(); // Check exit value if (exitValue != 0) { // TODO: Define your behaviour when process exits with non-zero exit value throw new Exception("ERROR: CMD process exited with non-zero value: " + exitValue); } really needed? – Jonathan Crane Aug 02 '18 at 14:27
  • I do not know what should I do if I have non-zero exit value. Your code does not work. Maybe it is because of that I have that exception with non-zero exit value. – Jonathan Crane Aug 02 '18 at 14:39
  • If you were working only with the console, which will be the command you will execute? The exit value is the return code of the command (which can be checked with the pseudo environment variable named errorlevel). I will add a version without checking the exit value – Cristian Ramon-Cortes Aug 06 '18 at 12:19
  • It has non zero exit value and it does not work. What should I do then? – Jonathan Crane Aug 10 '18 at 09:15
  • Can you provide the exact command that you will type in the console and works as you expect? – Cristian Ramon-Cortes Aug 10 '18 at 10:53
  • Yest it is: C:\Users\CA_LTD\AndroidStudioProjects\AMBITION> gradlew assembleRelease – Jonathan Crane Aug 10 '18 at 11:48
  • Is it somehow helpful? – Jonathan Crane Aug 10 '18 at 13:05
  • The command to execute is gradlew but you want to execute it into an specific directory (which is not part of the command but the working directory). See my updated answer – Cristian Ramon-Cortes Aug 10 '18 at 13:31
  • I tried your updated answer. When I try the code with checking non-zero exit value it gives me an exception that CMD process exited with non zero value plus it does not create the apk file(which should be the result of executing that command). And when I use the code without checking exit value it just does not create apk file. Any thoughts? – Jonathan Crane Aug 11 '18 at 09:24
  • At the end of the error you should see the exitValue printed, which value is it? – Cristian Ramon-Cortes Aug 13 '18 at 07:35
  • Exception in thread "main" java.lang.Exception: ERROR: CMD process exited with non-zero value: 1 at com.example.test.TestingCmd.main(TestingCmd.java:43) - whole error log:( – Jonathan Crane Aug 13 '18 at 16:04
  • Exit value 1 can mean that the command is not found. You should check that `gradlew` is available on the PATH of the user that is executing the Java application. To debug further, I have updated the answer to show the output and the error of the command on the default out/err of the Java application. If you don't manage to find the error, please paste the new output and error logs. – Cristian Ramon-Cortes Aug 14 '18 at 08:50
  • I am sorry but on the lines " BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream());" and " BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream());" there is an error :"The constructor BufferedReader(InputStreamReader) is undefined". Can you correct your code?:) – Jonathan Crane Aug 14 '18 at 17:30
  • Ooops my bad! After importing InputStreamReader, the error vanished. Anyway I posted my output as an answer because it was to long by 500 characters to fit in a single comment. – Jonathan Crane Aug 14 '18 at 18:10
  • I have corrected the typo on assemble so that the solution finally works. Try to post the output command as an EDIT of your original post rather than a solution (because it is not). Also, feel free to [accept this answer](https://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work) if it helped. – Cristian Ramon-Cortes Aug 16 '18 at 07:47
0

So after a solution posted by @CristianRamon-Cortes I got this output:

FAILURE: Build failed with an exception.
Starting a Gradle Daemon, 1 incompatible and 1 stopped Daemons could not be reused, use --status for details
NDK is missing a "platforms" directory.
If you are using NDK, verify the ndk.dir is set to a valid NDK directory.  It is currently set to C:\Users\CA_LTD\AppData\Local\Android\Sdk\ndk-bundle.
If you are not using NDK, unset the NDK variable from ANDROID_NDK_HOME or local.properties to remove this warning.

Incremental java compilation is an incubating feature.

BUILD FAILED

Total time: 29.414 secs

* What went wrong:
Task '' not found in root project 'AMBITION'. Some candidates are: ''.

* Try:
Run gradlew tasks to get a list of available tasks. Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
Exception in thread "main" java.lang.Exception: ERROR: CMD process exited with non-zero value: 1
    at com.example.test.TestingCmd.main(TestingCmd.java:43)

EDIT: And heck, it was only about a letter "m" in the word. Thank You @CristianRamon-Cortes!!!