Running maven command from Java using Runtime - java

I am trying to run maven command from java main but it is not working for me as desired.
When i run the below code it runs the maven command on the same existing project in which this main class residing, but i want to run this maven command from this class to any another project folder.
Please help!
Thanks in advance!
package com.codecoverage.runner;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class MavenCoberturaRunner {
public static void main(String[] args) throws IOException, InterruptedException {
Process p = null;
try {
p = Runtime.getRuntime().exec("C:/apache-maven-2.0.9/apache-maven-2.0.9/bin/mvn.bat clean cobertura:cobertura -Dcobertura.report.format=xml");
} catch (IOException e) {
System.err.println("Error on exec() method");
e.printStackTrace();
}
copy(p.getInputStream(), System.out);
p.waitFor();
}
static void copy(InputStream in, OutputStream out) throws IOException {
while (true) {
int c = in.read();
if (c == -1)
break;
out.write((char) c);
}
}
}

You should use Runtime.exec(String command, String[] envp, File dir) method,
which executes the specified string command in a separate process with the specified environment and working directory.
What you want is to set working directory so it points to the place you need to run Maven at.

use -f in command line
C:/apache-maven-2.0.9/apache-maven-2.0.9/bin/mvn.bat -f path/to/your/pom.xml clean cobertura:cobertura -Dcobertura.report.format=xml

Related

Bash -c with Java Process API

I've been messing about with the java process API and ran into the following case:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main {
public static void main(String[] args) throws IOException, InterruptedException {
var command = "echo foo";
System.out.println(command);
run(command);
command = "bash -c 'echo bar'";
System.out.println(command);
run(command);
}
public static void run(String command) throws IOException, InterruptedException {
Process p = Runtime.getRuntime().exec(command);
p.waitFor();
var br = new BufferedReader(new InputStreamReader(p.getInputStream()));
br.lines().forEach(System.out::println);
}
}
Why does bar not print? I've also tried other commands like systemctl poweroff and mkdir, but none seem to execute. I've also experimented with nohup, which works on its own but not with bash -c.
You call exec(String), which in turn calls exec(String,String,File), which in turn uses a StringTokenizer to chop the command line passed as a single string into an argument list, and then calls exec(String[],String,File).
However, that tokenizer just chops at spaces (it doesn't know that it's working with a command line or what shell would be involved). That means you end up with these tokens as the command: bash, -c, 'echo, foo' --- note the single quotes; Runtime.exec does not involve a shell to handle quotes (or variable substitution or such).
bash then complains about the 'echo, but you don't see that cause you only print the child process' stdout, but not stderr. Add code like this to run:
br = new BufferedReader(new InputStreamReader(p.getErrorStream()));
System.out.println("stderr:");
br.lines().forEach(System.out::println);
This gets me:
stderr:
bar': -c: line 1: unexpected EOF while looking for matching `''
bar': -c: line 2: syntax error: unexpected end of file
Now if you remove the single quotes from the call, you just get a single empty line because bash -c expects only one argument to run, which here is the echo, which prints a new line.
To fix this, you need to call the exec version that takes a String[] directly so that you control what is one argument:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main {
public static void main(String[] args) throws IOException, InterruptedException {
run("echo", "foo");
run("bash", "-c", "echo bar");
}
public static void run(String... command) throws IOException, InterruptedException {
Process p = Runtime.getRuntime().exec(command);
p.waitFor();
var br = new BufferedReader(new InputStreamReader(p.getInputStream()));
System.out.println("stdout:");
br.lines().forEach(System.out::println);
br = new BufferedReader(new InputStreamReader(p.getErrorStream()));
System.out.println("stderr:");
br.lines().forEach(System.out::println);
}
}
Personally, I'd use something higher level like the standard ProcessBuilder class or the exec library from Apache Commons instead, as they have better support for building complicated commands to execute:
import java.io.IOException;
import org.apache.commons.exec.*;
public class ExecDemo {
// Build and execute a command with Apache Commons Exec
private static void demoApacheExec()
throws IOException, ExecuteException {
var cmd = new CommandLine("sh");
cmd.addArgument("-c");
cmd.addArgument("echo test 1", false);
System.out.println("Command: " + cmd);
var executor = new DefaultExecutor();
executor.execute(cmd);
}
// Build and execute a command with ProcessBuilder
private static void demoProcessBuilder()
throws IOException, InterruptedException {
// Can also take a List<String> of arguments
var pb = new ProcessBuilder("sh", "-c", "echo test 2").inheritIO();
System.out.println("Command: " + pb.command());
pb.start().waitFor();
}
public static void main(String[] args) {
try {
demoApacheExec();
demoProcessBuilder();
} catch (Exception e) {
System.err.println("Error executing program: " + e);
System.exit(1);
}
}
}
The important thing is making each argument its own separate thing instead of relying on trying to parse a single string like a shell would (A.C.E has a CommandLine.parse() function, but even it has issues with quoting; addArgument likes to put actual quotes around arguments with spaces in them when it doesn't actually need to unless you tell it not to.).

java: call external jar program (-> 'create process error')

I'm trying toopen/execute another program, which is a .jar file, but I'm getting the following error:
it is not a windows application
(java.io.IOException: CreateProcess error=193)
Here is my code:
import java.io.IOException;
public class Test8 {
public static void main(String[] args) {
try {
String filepath = "C://Users//Alex//Desktop//Speedtest.jar";
Process p = Runtime.getRuntime().exec(filepath);
} catch (IOException e) {
e.printStackTrace();
}
}
}
At the command-line, JARs are executed with java -jar. Try passing a String array:
String[] args = new String[] {"java", "-jar", "/path/to/myJar.jar"};
Process p = Runtime.getRuntime().exec(args);

Can you run a java class from within a java program?

I have been creating a program that writes and run java classes. So far I have been able to write a "Runable.java" class but not able to run it. I have tried to run a "runjava.bat" and get the .bat to run the "Runable.java" class but I keep getting a "Error: Could not find or load main class application.Runable.class". I was wondering what I am doing wrong or if there is a better way to go about running a java class from within a java program?
Here is my code(Simplify Slightly):
Main.java:
package application;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Platform;
import javafx.stage.FileChooser;
public class Main {
final static String Program =
"package application;\n"
+ "public class Runable {\n"
+ "public static void main(String[] args) {\n"
+ "System.out.println(\"Hello\");\n"
+ "}\n"
+ "}\n";
public static void main(String[] args) throws IOException {
Scanner s = new Scanner(System.in);
while(true){
System.out.println("State a comand.");
String Command = s.nextLine();
if (Command.equalsIgnoreCase("Write") || Command.equalsIgnoreCase("Save")){
FileChooser fileChooser = new FileChooser();
//Set extension filter
FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter("TXT files (*.txt)", "*.txt");
fileChooser.getExtensionFilters().add(extFilter);
//Show save file dialog
File file = new File("src/application/Runable.class");
if(file != null){
SaveFile(Program, file);
}
}
else if (Command.equalsIgnoreCase("Run") || Command.equalsIgnoreCase("Play")){
ProcessBuilder builder = new ProcessBuilder(
"src/runjava.bat");
builder.redirectErrorStream(true);
Process p = builder.start();
BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
while (true) {
line = r.readLine();
if (line == null) { break; }
System.out.println(line);
}
}
else if (Command.equalsIgnoreCase("End") || Command.equalsIgnoreCase("Exit")){
Platform.exit();
}
else{
System.err.println("Command not recognized.");
System.err.println("Please try again.");
}
}
}
private static void SaveFile(String content, File file){
try {
FileWriter fileWriter = null;
fileWriter = new FileWriter(file);
fileWriter.write(content);
fileWriter.close();
} catch (IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
runjava.bat:
javac "src\application\Runable.java"
java application.Runable.class
and Runable.java if you didn't get it from the Main.java:
package application;
public class Runable {
public static void main(String[] args) {
System.out.println("Hello");
}
}
The java command expects a class name, not a filename. Unless your class is called "class" in the package "application.Runable" (which it isn't) you probably wanted to use:
java application.Runable
Because you can't execute a .java file like that. You must first compile it to get a .class file, and change the code that executes the class to point to Runable.class
The reason it is not running, is because the .java file is the code you type, and the .class file is the compiled version of the code that Java Virtual Machine executes.
Another solution to compile and run the program compared to executing the .bat file is to use the javax.tools API or another library based off of it. I have found InMemoryJavaCompiler library that makes it easy to compile and run the programs. This approach means that the program will run on the same JVM as your UI which may be helpful.
The following code shows how you might invoke the program using the library.
try{
Class<?> clazz = InMemoryJavaCompiler.compile("apllication.Runable", Program);
clazz.getMethod("main", String[].class).invoke(null, new String[0]);
}catch(Exception e){
e.printStackTrace();
}
In your Main.java's "Run" block, you should have
ProcessBuilder builder = new ProcessBuilder("runjava.bat");
In your runjava.bat, you should have (as immibis said)
javac -d . src/application/Runable.java
java application.Runable
** not Runable.class in the second line.
And runjava.bat should be placed in parallel with the parent folder of application\ but not the src\application folder. In other words, you should have something like classes\runjava.bat, classes\application\Main.class and classes\application\Runable.class. Hope it helps.

ProcessBuilder cannot run bat file with spaces in path

I have the following code segment to run a bat file:
String workingDir = System.getProperty("user.dir");
ProcessBuilder pb = new ProcessBuilder("cmd", "/c",
"\"" + workingDir + File.separator + "midl.bat\"");
Process ddsBuildProc = pb.start();
ddsBuildProc.waitFor();
The workingDir includes spaces in the path. Eventhough I use quotes to enclose the workingDir+fileName string, the shell still splits the workingDir and doesn't run the bat file. If a try and copy-paste-execute the bat file path string in the Windows command window manually, it works as expected. What can be the problem here?
Also, please do not close this question as duplicate because I tried all the solutions in the other questions with no success.
Don't quote commands in a command list, unless the command been executed expects it, this will just stuff things up
user.dir is your programs current executing context...so it actually makes no sense to include it, you could just use midl.bat by itself (assuming the command exists within the current execution context)
I wrote a really simple batch file...
#echo off
dir
Which I put in my "C:\Program Files" directory, as I need a path with spaces and used....
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.logging.Level;
import java.util.logging.Logger;
public class RunBatch {
public static void main(String[] args) {
ProcessBuilder pb = new ProcessBuilder(
"cmd", "/c", "listme.bat"
);
pb.directory(new File("C:/Program Files"));
pb.redirectError();
try {
Process process = pb.start();
InputStreamConsumer.consume(process.getInputStream());
System.out.println("Exited with " + process.waitFor());
} catch (IOException | InterruptedException ex) {
ex.printStackTrace();
}
}
public static class InputStreamConsumer implements Runnable {
private InputStream is;
public InputStreamConsumer(InputStream is) {
this.is = is;
}
public static void consume(InputStream inputStream) {
new Thread(new InputStreamConsumer(inputStream)).start();
}
#Override
public void run() {
int in = -1;
try {
while ((in = is.read()) != -1) {
System.out.print((char) in);
}
} catch (IOException exp) {
exp.printStackTrace();
}
}
}
}
To run it without any issues...

ZipException when attempting to open jar file

I keep getting a java.util.zip.ZipException when I try to open a jar file. I was able to reproduce the issue with the following stripped-down bit of code (ignore the weird populateSamples() method name):
import java.io.File;
import java.util.jar.JarFile;
public class Test {
public static void main(String[] args) {
Test test = new Test();
test.populateSamples();
}
private void populateSamples() {
JarFile jf = null;
try {
String s = new File(this.getClass().getResource("Test.class").getPath()).getParent().replaceAll("(!|file:\\\\)", "");
jf = new JarFile(s);
} catch(IOException e) {
e.printStackTrace();
} finally {
try {
jf.close();
} catch(Exception e) {
e.printStackTrace();
}
}
}
}
Here is the exception I get:
$ java -jar EclipseTest.jar
java.util.zip.ZipException: error in opening zip file
at java.util.zip.ZipFile.open(Native Method)
at java.util.zip.ZipFile.<init>(ZipFile.java:128)
at java.util.jar.JarFile.<init>(JarFile.java:136)
at java.util.jar.JarFile.<init>(JarFile.java:73)
at Test.populateSamples(Test.java:40)
at Test.main(Test.java:17)
java.lang.NullPointerException
at Test.populateSamples(Test.java:54)
at Test.main(Test.java:17)
I can list the contents of the jar file with jar tf just fine. Any ideas?
I have found the solution to the problem. The replaceAll("(!|file:\\\\)", ""); bit was not working as expected as the "file:" bit was not being replaced. I shall now embark on a quest to figure out why not, and complete this answer.

Categories