Hi guys,
I am trying to execute a .jar executable within a java file but nothing happens, no errors, just nothing in general!

public void executeCmd(){
        Runtime run = Runtime.getRuntime();
        try {
			Process proc = run.exec(cmd);
		} catch (IOException e) {
			//sendmessage saying there was an error
		}
	}

Recommended Answers

All 18 Replies

Well, if that's your real code, I can believe it's not "sending any errors", as you're ignoring them.

On the other hand, why don't you read the manifest file to get the Main class name, then start a thread, create a classloader, and call the main method from that main class using that classloader, rather than using runtime exec?

What value is assigned to cmd when you call this?

I put a System.err.print in exception area and sure enough it errored but only when I try to execute .jar files.

I'm working on understanding class loader but so far I don't understand how that can help me.

The classloader is simply so that the executed jar (when you simply call main from the mainclass) has it's own classloader rather than having the classes that it loads, loaded into the rest of the application. Essentially, it is to give it it's own "sandbox", so that you can execute "internally", but still have it "separate" from the application that started it. You can also call main without creating a new classloader (as long as the jarfile is already on the classpath), but then any class loaded from the jar is "visible" to the entire application, which might not be want you want.

commented: Good info. +18

I am sorry. I am having a lot of trouble with understanding, how to use this, I read the documentation and now I have no idea.

Haha all I want to do is launch another jar file within a java script.

Well, it's not quite as easy as I make it sound, as you also have to read the classpath entries from the manifest file in order to start the URLClassLoader properly, but, if I get time in the next couple of days, I may, and I repeat may write one up for you (as a Generic class for launching other applications).

Your original approach, using Runtime should work just fine, and has got to be the easiest way to go. What exactly are you passing in as cmd, and what exactly is the error/exception?

Your original approach, using Runtime should work just fine, and has got to be the easiest way to go. What exactly are you passing in as cmd, and what exactly is the error/exception?

Except, of course, that it varies from system to system and installation to installation and so, is only ever certain to work on that system on which it was developed, as long as the installation parameters don't change.

So, yes, should be easy to get working, but oooooo God is it dependable, huh?

The Runtime API itself is not system dependent, but the command you execute must be a valid command for the system it's running on, so you may need to test the OS to see whether it's javaw or javaws. Similarly the file path/name will vary according to OS, but that would be true regardless of the approach. Having said that, exec ("javaw -jar thing.jar") should work on any version of Windows with a standard Java installation.

No, but PATH defintions are.

Runtime.exec and ProcessBuilder are tools of last resort, IMHO.

And, anytime they are used, it is truely only guaranteed to work on the system on which it was developed as long as no installation parameters have changed. Sorry, that's just the way it is.

Hi masijade.
Sorry if the tone of my previous post seemed aggressive, please don't think I'm just here for an argument! You're certainly right about paths (as I said in my previous post), but this will be an issue for any code that tries to access an external jar file. I guess we'll have to agree to disagree about Runtime :-)
Certainly I think the following is a lot easier than parsing a jar and using a custom class loader.

try {
	JFileChooser fc = new JFileChooser();
	fc.showOpenDialog(null);
	File file = fc.getSelectedFile();
	String cmd = "javaw -jar " + "\"" + file.getAbsolutePath() + "\"";
	Runtime run = Runtime.getRuntime();
	Process proc = run.exec(cmd);
} catch (Exception e) {
	e.printStackTrace();
}

Parsing a Jar is not hard however. Look at the JarFile class, it's getManifest() method. With that read the Main-Class Attribute, and the Classpath Attribute and build a URL array, and call new URLClassLoader with this array. And, you know, the only real path involved is the path to the jarfile, initially. It is actually quite easy, just need to make sure to cover all the bases, and nothing about the extraneous system changes any little piece of it.

P.S., by paths (in my previous post) I meant the PATH environment variable. If that does not contain the proper path, to the proper bin directory "javaw" (alone without the full path to the command) does not work.

Edit: Also, if there are spaces in that filename (or the path leading to it) be careful. The spaces (due to the way Runtime.exec operates) will cause problems, whether you use quotes or not. Those quotes are evaluated by system shells, and runtime.exec doesn't have one.

Parsing a Jar is not hard however. ...

I agree, but it's not easy for a beginner.

P.S., by paths I mean the PATH environment variable. If that does not contain the proper path, to the proper bin directory "javaw" does not work.

Yes, that's right. I don't know how common that would be with default installations.

Also, if there are spaces in that filename (or the path leading to it) be careful. The spaces (due to the way Runtime.exec operates) will cause problems, whether you use quotes or not. Those quotes are evaluated by system shells, and runtime.exec doesn't have one.

I tested the code with a file on my desktop under XP, where the path includes two spaces. With the extra quotes around the absolute path this does work.

James

I agree, but it's not easy for a beginner.

No one said it would be. But the easy way is, often times, not the right way.

Yes, that's right. I don't know how common that would be with default installations.

Quite often considering the number of "unrecognised command" questions I've seen here, and on other forums.

I tested the code with a file on my desktop under XP, where the path includes two spaces. With the extra quotes around the absolute path this does work.

James

So in this instance it did, that doesn't mean it always will. Did you look at what getAbsoluteFilename returns? Does it return the "long" name, or the Progr~1 type name, in this instance?

So in this instance it did, that doesn't mean it always will. Did you look at what getAbsoluteFilename returns? Does it return the "long" name, or the Progr~1 type name, in this instance?

Yes, it's the long name, with embedded blanks

I accept your first two points - I think we've just got a difference of emphasis, that's all.

Hi masijade.
Sorry if the tone of my previous post seemed aggressive, please don't think I'm just here for an argument! You're certainly right about paths (as I said in my previous post), but this will be an issue for any code that tries to access an external jar file. I guess we'll have to agree to disagree about Runtime :-)
Certainly I think the following is a lot easier than parsing a jar and using a custom class loader.

try {
	JFileChooser fc = new JFileChooser();
	fc.showOpenDialog(null);
	File file = fc.getSelectedFile();
	String cmd = "javaw -jar " + "\"" + file.getAbsolutePath() + "\"";
	Runtime run = Runtime.getRuntime();
	Process proc = run.exec(cmd);
} catch (Exception e) {
	e.printStackTrace();
}

This worked, Thank-you.

This worked, Thank-you.

Glad to help!
But, to be fair, if you need a solution that will work consistently and reliably across different configurations or OSs, then you should look into masijade's approach.

Just for Fun, I decided to actually set it up last night, and sat down for about an hour, and here it is

package test;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
import java.util.jar.JarFile;
import java.util.jar.Manifest;

public class JarStarter extends Thread {

	private File f;
	private JarFile jf;

	public JarStarter(File f) throws IOException {
		this.f = f;
		try {
			jf = new JarFile(f);
		} catch (IOException ioe) {
			System.err.println("Error loading JarFile.");
			jf = null;
			throw ioe;
		}
	}

	public void run() {
		if (jf == null) return;  // Should never be possible, but ....
		try {
			String mainClass = getMainClass();
			if ((mainClass == null) || (mainClass.trim().length() == 0)) return;
			ClassLoader cl = createClassLoader(getClassPath());
			if (cl == null) return;
			setContextClassLoader(cl);
			Class<?> c = cl.loadClass(mainClass);
			c.getMethod("main", String[].class).invoke(null, (Object) new String[0]);
		} catch (InvocationTargetException ite) {
			ite.printStackTrace();
		} catch (IllegalAccessException iae) {
			iae.printStackTrace();
		} catch (NoSuchMethodException nsme) {
			nsme.printStackTrace();
		} catch (ClassNotFoundException cnfe) {
			cnfe.printStackTrace();
		} catch (IOException ioe) {
			ioe.printStackTrace();
		} finally {
			try { jf.close(); } catch (IOException ioe) {}
		}
	}

	private String getMainClass() throws IOException {
		Manifest man = jf.getManifest();
		return man.getMainAttributes().getValue("Main-Class");
	}

	private String[] getClassPath() throws IOException {
		Manifest man = jf.getManifest();
		String classpath = man.getMainAttributes().getValue("Class-Path");
		if (classpath == null) return new String[0];
		return classpath.split("\\s+");
	}

	private ClassLoader createClassLoader(String[] items) {
		String dir = f.getParentFile().getAbsolutePath();

		List<URL> urls = new ArrayList<URL>();
		try {
			urls.add(f.toURL());
			for (String item : items) {
				urls.add(new File(dir + item).toURL());
			}
		} catch (MalformedURLException murle) {
			murle.printStackTrace();
			return null;
		}

		return new URLClassLoader(urls.toArray(new URL[0]), getClass().getClassLoader());
	}

	public static void main(String[] args) {
		try {
			JarStarter st = new JarStarter(new File(args[0]));
			st.start();
		} catch (IOException ioe) {
			ioe.printStackTrace();
		}
	}
}

The class has a main method so you can test it, but, obviously, you can create an instance and start it from other classes as well.

This class works (at least for fairly simply applications, as of yet I have not tested it on anything "major"). Now, would I use it to start, say, tomcat, probably not, but I might just try it one day (although for that, quite a few environment variables also need to be set, which is the reason it comes with a start script (and "exe" on Windows)).

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.