How does one locate the java executable and various JAR files in the classpath?

O

Oliver Wong

Note: This post mentions Eclipse to show what parts of the design I have
no control over, but I believe you don't actually need to know much about
Eclipse development to help contribute a useful answer.

I have a JAR file which does some useful stuff, including generating
some files into the "current directory". That is, it creates new File
objects using relative paths, and so these files appear relative to the
directory from which the JAR was invoked. I can read the source code for
this JAR, but I'm pretty much not allowed to make changes to the code in it.

I'm writing a plugin for Eclipse, and one of the functionalities is to
invoke this JAR. That is, I want to give the user the ability to right click
somewhere in their project hierarchy, and select "Generate files here" from
the context menu, and in responce to that, I'll invoke the JAR file, passing
it command line arguments based on settings that the user specified earlier.

The cleanest solution, I think, would have been to invoke the static
main function in the JAR directly, 'cause then I could catch any exceptions
thrown from there and handle them specially, but I think there is no way to
set the "current directory" in Java, and so doing this would result in my
not being able to control where the files get generated.

The next solution that came to my mind was to use Runtime.exec(String,
String[], File)

http://java.sun.com/j2se/1.5.0/docs...ang.String, java.lang.String[], java.io.File)

Thanks to the last argument, I can specify the working directory for the
subprocess.

However, I'm not at a lost of how to construct the String for the first
parameter. I want to run the "java" interpreter, something of the form:
"java -jar myHelper.jar Other Command Line Arguments", but this assumes both
that "java" and "myHelper.jar" can be found from the current working
directory, which will not nescessarily be the case.

Any advice on how to find both the java executable and the jar file? Or
how to programmatically affect the current working directory (so that I may
use the original cleaner solution)?

- Oliver
 
A

Andrew Thompson

Oliver said:
Any advice on how to find both the java executable and the jar file?

URL urlToClass = this.getClass().getResource(
"get/any/class/in/mysterious/Jar.class" );

I am sure there is also something more specific for classes,
just cannot recall it.
 
R

Rhino

Oliver Wong said:
Note: This post mentions Eclipse to show what parts of the design I
have no control over, but I believe you don't actually need to know much
about Eclipse development to help contribute a useful answer.

I have a JAR file which does some useful stuff, including generating
some files into the "current directory". That is, it creates new File
objects using relative paths, and so these files appear relative to the
directory from which the JAR was invoked. I can read the source code for
this JAR, but I'm pretty much not allowed to make changes to the code in
it.

I'm writing a plugin for Eclipse, and one of the functionalities is to
invoke this JAR. That is, I want to give the user the ability to right
click somewhere in their project hierarchy, and select "Generate files
here" from the context menu, and in responce to that, I'll invoke the JAR
file, passing it command line arguments based on settings that the user
specified earlier.

The cleanest solution, I think, would have been to invoke the static
main function in the JAR directly, 'cause then I could catch any
exceptions thrown from there and handle them specially, but I think there
is no way to set the "current directory" in Java, and so doing this would
result in my not being able to control where the files get generated.

The next solution that came to my mind was to use Runtime.exec(String,
String[], File)

http://java.sun.com/j2se/1.5.0/docs...ang.String, java.lang.String[], java.io.File)

Thanks to the last argument, I can specify the working directory for
the subprocess.

However, I'm not at a lost of how to construct the String for the first
parameter. I want to run the "java" interpreter, something of the form:
"java -jar myHelper.jar Other Command Line Arguments", but this assumes
both that "java" and "myHelper.jar" can be found from the current working
directory, which will not nescessarily be the case.

Any advice on how to find both the java executable and the jar file? Or
how to programmatically affect the current working directory (so that I
may use the original cleaner solution)?
Wouldn't it be more appropriate to ask your questions on a suitable Eclipse
forum? (Don't ask me which one: there are lots of them and I always get lost
trying to find the right one :)

Rhino
 
O

Oliver Wong

Andrew Thompson said:
URL urlToClass = this.getClass().getResource(
"get/any/class/in/mysterious/Jar.class" );

I am sure there is also something more specific for classes,
just cannot recall it.

I had actually tried:

this.getClass().getClassLoader().getResource("myMysteriousJARFile.jar");
//[1]

.... but null was returned. The JAR file is on my classpath at compile time,
but I'm not so sure it's there at invocation time when Eclipse invokes my
plugin (though I suspect it should be, or else how could I call methods
located within that JAR?)

I also strongly suspect that Eclipse uses its own custom classloader for
loading plugins. Not sure how that might affect the above code's ability to
locate my JAR.

- Oliver

[1]: I want the JAR file, and not any particular class within the JAR,
because I want to construct a string to pass to Runtime.exec(). Something
like Runtime.exec("java -jar /path/to/jar/myMysteriousJARFile.jar", null,
myDesiredWorkingDirectory); I was hoping to take the URL from the
classloader, assuming it points to the local filesystem, and then convert it
to an absolute path using the File class.
 
O

Oliver Wong

Wouldn't it be more appropriate to ask your questions on a suitable
Eclipse forum? (Don't ask me which one: there are lots of them and I
always get lost trying to find the right one :)

I posted it to eclipse.newcomer on Eclipse.org's usenet server, but
since I thought the question doesn't specifically rely on knowledge of
eclipse, it might be worth asking it here as well. Hopefully people will
excuse the multi-posting as the messages lie on completely detached servers.

- Oliver
 
R

Roedy Green

I am sure there is also something more specific for classes,
just cannot recall it.

you were thinking of getProctectionDomain?

import java.net.URL;
import java.security.CodeSource;

/**
* Find out where a class on the classpath will be loaded from.
* Fully qualified classname goes on the command line.
*/
public class Where
{
/**
* main
* @param args name of fully qualified class to find, using dots,
but no dot class.
* e.g. java.exe Where javax.mail.internet.MimeMessage
*/
public static void main ( String[] args )
{
try
{
String qualifiedClassName = args[0];
Class qc = Class.forName( qualifiedClassName );
CodeSource source = qc.getProtectionDomain().getCodeSource();
if ( source != null )
{
URL location = source.getLocation();
System.out.println ( qualifiedClassName + " : " + location
);
}
else
{
System.out.println ( qualifiedClassName + " : " + "unknown
source, likely rt.jar" );
}
}
catch ( Exception e )
{
System.err.println( "Unable to locate class on command line."
);
e.printStackTrace();
}
}
}
 
O

Oliver Wong

Roedy Green said:
import java.net.URL;
import java.security.CodeSource;

/**
* Find out where a class on the classpath will be loaded from.
* Fully qualified classname goes on the command line.
*/
public class Where
{
/**
* main
* @param args name of fully qualified class to find, using dots,
but no dot class.
* e.g. java.exe Where javax.mail.internet.MimeMessage
*/
public static void main ( String[] args )
{
try
{
String qualifiedClassName = args[0];
Class qc = Class.forName( qualifiedClassName );
CodeSource source = qc.getProtectionDomain().getCodeSource();
if ( source != null )
{
URL location = source.getLocation();
System.out.println ( qualifiedClassName + " : " + location
);
}
else
{
System.out.println ( qualifiedClassName + " : " + "unknown
source, likely rt.jar" );
}
}
catch ( Exception e )
{
System.err.println( "Unable to locate class on command line."
);
e.printStackTrace();
}
}
}

Thanks, after embedding your code into my project, I was able to confirm
that the JAR I was seeking was not on the classpath at runtime. I've fixed
that, and now your code does return the correct path to the JAR file. You've
helped me a lot. Thank you.

- Oliver
 
O

Oliver Wong

Oliver Wong said:
I've fixed that, and now your code does return the correct path to the JAR
file.

Just in case anyone is curious, I solved the other problem, of locating
Sun's java executable, like this:

System.getProperty("java.home") + "/bin/java";

- Oliver
 
R

Rhino

Oliver Wong said:
I posted it to eclipse.newcomer on Eclipse.org's usenet server, but
since I thought the question doesn't specifically rely on knowledge of
eclipse, it might be worth asking it here as well. Hopefully people will
excuse the multi-posting as the messages lie on completely detached
servers.
I'm not complaining :)

Rhino
 
D

DM McGowan II

Oliver said:
[1]: I want the JAR file, and not any particular class within the JAR,
because I want to construct a string to pass to Runtime.exec(). Something
like Runtime.exec("java -jar /path/to/jar/myMysteriousJARFile.jar", null,
myDesiredWorkingDirectory); I was hoping to take the URL from the
classloader, assuming it points to the local filesystem, and then convert
it to an absolute path using the File class.

Is it possible to write a class loader then load the JAR rather than take
the performance hit of running a separate Java process? Just curious.
 
C

Chris Uppal

Oliver said:
I have a JAR file which does some useful stuff, including generating
some files into the "current directory". That is, it creates new File
objects using relative paths, and so these files appear relative to the
directory from which the JAR was invoked.

[I see that you've already found a workaround, and anyway this is just an
observation.]

IMO, any API that /depends/ on the idea of a "current directory" is broken in
this day and age. There's nothing wrong with allowing relative filenames to be
specified as inputs to the API, but it seems foolish to create files in
locations that the user (programmer) can't control.

Perhaps you can encourage the authors of your JAR to un-break the API ?

-- chris
 
R

Roedy Green

IMO, any API that /depends/ on the idea of a "current directory" is broken in
this day and age. There's nothing wrong with allowing relative filenames to be
specified as inputs to the API, but it seems foolish to create files in
locations that the user (programmer) can't control.

It makes not much sense in a multithread program. Each thread would
need its own version of the CWD.

Your problem really is Windows There are so many ways to invoke a
program it is easy to get confused what CWD you are giving it.

Some experiments are in order . Just display the CWD first thing on
the console, and experiment till you feel confident you have it under
control.

See http://mindprod.com/jgloss/file.html
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top