• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

java -cp option issue

 
Ranch Hand
Posts: 185
Netbeans IDE Firefox Browser Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi all,

Can someone explain to me how to correctly pass in classpath(s) to a java program using -cp or -classpath?

I put the required jars into a folder called /home/alan/jars:
ls /home/alan/jars
gf-client.jar RemoteInterfaces-1.0.jar

I was trying to use the $CLASSPATH variable which had my jars in it i.e.

echo $CLASSPATH
/home/alan/jars/gf-client.jar:/home/alan/jars/RemoteInterfaces-1.0.jar

Then ran java -cp RemoteClient-1.0.jar:$CLASSPATH com.alan.remoteclient.Main. (RemoteClient-1.0.jar contains my main method). This didn't work, and found out why here on stackoverflow.

Edit: When I do this however and add my client jar to the CLASSPATH, it manages to pick up the main method, but not the classes from the required jars in the $CLASSPATH!!
(So my classpath now looks like this:
echo $CLASSPATH
/home/alan/NetBeansProjects/RemoteClient/target/RemoteClient-1.0.jar:/home/alan/jars/RemoteInterfaces-1.0.jar:/home/alan/jars/gf-client.jar)
java -cp $CLASSPATH com.alan.remoteclient.Main
Hello World Remote Client!
Feb 03, 2015 2:49:36 PM com.alan.remoteclient.Main main
SEVERE: null
javax.naming.NoInitialContextException: Cannot instantiate class: com.sun.enterprise.naming.SerialInitContextFactory [Root exception is java.lang.ClassNotFoundException: com.sun.enterprise.naming.SerialInitContextFactory]

How come it picked up the main from RemoteClient-1.0.jar in the CLASSPATH, but not the classes in the other jars??

Then I used java -cp "RemoteClient-1.0.jar:/home/alan/jars/*" com.alan.remoteclient.Main. This picked up the main but bombed when it tried to find classes in the required jars in /home/alan/jars. But according to this page, this should have worked.

The only way I have gotten it to work is if I pass every jar location to it directly i.e.

java -cp RemoteClient-1.0.jar:/home/alan/jars/gf-client.jar:/home/alan/jars/RemoteInterfaces-1.0.jar com.alan.remoteclient.Main
Hello World Remote Client!
Hello from SessionBean!

Any idea how to add multiple jars to the cp option without having to specify each individual jar with complete path?

Thanks

ps. the project is a small test of a stand alone client for a remote ejb that is deployed on glassfish. The com.alan.remoteclient.Main class looks up the bean and simply calls a hello() method from the bean that prints "Hello from SessionBean!".
 
Bartender
Posts: 1810
28
jQuery Netbeans IDE Eclipse IDE Firefox Browser MySQL Database Chrome Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I generally recommend that people avoid using the $CLASSPATH environment variable. It just leads to headaches like this. You should be able to specify the directory where your jar files are located like so:

javac -cp /home/alan/jars main



You can't combine the $CLASSPATH and the -cp option. When you use -cp or -classpath it takes precedence over the environment variable.
 
Alan Smith
Ranch Hand
Posts: 185
Netbeans IDE Firefox Browser Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

J. Kevin Robbins wrote:I generally recommend that people avoid using the $CLASSPATH environment variable. It just leads to headaches like this. You should be able to specify the directory where your jar files are located like so:

javac -cp /home/alan/jars main



You can't combine the $CLASSPATH and the -cp option. When you use -cp or -classpath it takes precedence over the environment variable.



Assuming that the compile time environment can be different from the runtime environment, my client jar is already built using maven. If I want to run it elsewhere and bring the appropriate jars to run it with it, then I can't compile with javac.

If the environment variable is used i.e. I don't run java with -cp or -classpath, the same thing happens. It doesn't pick up the jars from the CLASSPATH env variable. The only way it has successfully found the jars is if I run it like I have stated above, with the full paths to each required jar. Is there no better approach than this?
 
J. Kevin Robbins
Bartender
Posts: 1810
28
jQuery Netbeans IDE Eclipse IDE Firefox Browser MySQL Database Chrome Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
You shouldn't need to specify the full jar file name in either the environment variable or the -cp option, only the directory or directories where the jars are located.

Think of it like the $PATH environment variable in Windows or *nix. You don't specify the name of each executable file, only the directories where the executables are located.
 
Alan Smith
Ranch Hand
Posts: 185
Netbeans IDE Firefox Browser Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

J. Kevin Robbins wrote:You shouldn't need to specify the full jar file name in either the environment variable or the -cp option, only the directory or directories where the jars are located.

Think of it like the $PATH environment variable in Windows or *nix. You don't specify the name of each executable file, only the directories where the executables are located.



Ok, thanks for the help.
 
Saloon Keeper
Posts: 27919
198
Android Eclipse IDE Tomcat Server Redhat Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

J. Kevin Robbins wrote:You shouldn't need to specify the full jar file name in either the environment variable or the -cp option, only the directory or directories where the jars are located.



Huh? Not unless something has changed that I don't know about.

Thinking that you could just point to a directory full of JARs and have all the classes in all the JARs automatically available is one of the oldest newbie problems in the book.

A classpath consists of a collection of directories and/or jars. Effectively, a directory is (almost) handled the same way as a directory that you've unzipped a JAR into. However the reverse is not true. A directory containing class files and JARs will be able to provide all of the classes in files and none of the classes in the JARs. The default classloader doesn't do deep scanning.

There are cases where you do have directories full of Jars. One such is the Tomcat webapp server. However, if you look at its startup script, you'll discover that the script reads the Tomcat lib directory and adds each jar as an element in the classpath that it builds before launching the Tomcat JVM.

I've also worked a project where I wrote a custom classloader to pull classes by scanning one or more directories and examining the jar contents. But without doing this, the classes in the jars weren't seen.

As far as I'm aware, a "-cp myjar.jar:$CLASSPATH:anotherjar.jar" should be just fine - I'm pretty sure that the JVM doesn't (and probably can't) redefine the shell CLASSPATH variable, which itself is supposed to have been expanded by the shell before the actual JVM launch command line is invoked.

"globbing" ("-cp classdirectory/*.jar") doesn't work in most shells. I think that the JVM would have had to have had glob support built into it, and they probably ruled that out for security reasons and/or because globs are all-or-nothing operations.

The advice you got from StackOverflow was good. My CLASSPATH variable is almost always empty. Webapp servers actually don't have a single classpath, they typically have 5 or more, including one for each webapp and the classpaths are built up by the server itself rather than simply taking the JVM default. Again, I refer you to Tomcat as an example, although it also builds classpaths internally using custom classloaders.
 
Alan Smith
Ranch Hand
Posts: 185
Netbeans IDE Firefox Browser Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Tim Holloway wrote:
Thinking that you could just point to a directory full of JARs and have all the classes in all the JARs automatically available is one of the oldest newbie problems in the book.



Hi Tim,

the above seems to be correct...

For example, the below works:

java -cp "NonGFClient-1.0.jar:/home/alan/jars/*:/home/alan/programs/glassfish-4.1/glassfish/lib/gf-client.jar" com.alan.Main; where NonGFClient-1.0.jar is a standalone client that contains the main and a lookup of an EJB that is deployed on a local glassfish server. /home/alan/jars/* contains my remote interface, and the javaee jar that the client depends on. The gf-client.jar is a jar that all standalone clients that lookup EJBs on glassfish need.

ls /home/alan/jars/*
/home/alan/jars/javaee-api-7.0.jar /home/alan/jars/RemoteInterfaces-1.0.jar

Also, I have discovered that using -cp with the $CLASSPATH variable is pointless, as it completely ignores it by name. However, if I make another "CLASSPATH" variable called, for example, JARS, that works. e.g.

java -cp "NonGFClient-1.0.jar:$JARS/*:/home/alan/programs/glassfish-4.1/glassfish/lib/gf-client.jar" com.alan.Main

echo $JARS
/home/alan/jars

ls $JARS
javaee-api-7.0.jar RemoteInterfaces-1.0.jar

All in all, I'm still not sure of the correct way to utilise a classpath for an application that isn't packed as an ear or war, as they both can contain lib directories for their specific dependencies, and they can also utilise the app servers provided classpath for every else. Food for thought I guess.

Cheers
 
Rancher
Posts: 4801
50
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Tim Holloway wrote:"globbing" ("-cp classdirectory/*.jar") doesn't work in most shells. I think that the JVM would have had to have had glob support built into it, and they probably ruled that out for security reasons and/or because globs are all-or-nothing operations.



According to the docs for the java command:
"
As a special convenience, a class path element that contains a base name of * is considered equivalent to specifying a list of all the files in the directory with the extension .jar or .JAR. A Java program cannot tell the difference between the two invocations.
"

It's not the JVM, it's the java.exe itself that does the work.
As far as I'm aware there is no shell specific thing about it.
 
J. Kevin Robbins
Bartender
Posts: 1810
28
jQuery Netbeans IDE Eclipse IDE Firefox Browser MySQL Database Chrome Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Tim Holloway wrote:
There are cases where you do have directories full of Jars. One such is the Tomcat webapp server. However, if you look at its startup script, you'll discover that the script reads the Tomcat lib directory and adds each jar as an element in the classpath that it builds before launching the Tomcat JVM.


It seems this is where I got confused because the CLASSPATH on my web server looks like this:

CLASSPATH=.:/usr/share/tomcat5/common/lib/:/usr/share/tomcat5/bin/



Just directories. I didn't realize the startup script was building a new classpath of the jars contained in those directories. I apologize if I confused the issue.

But then this is from the Oracle docs and seems to indicate that directory names are fine, so I'm still a bit confused. Is this trying to say that ending with a directory name only works for *.class files and not *.jar files?

Class paths to the JAR, zip or class files. Each class path should end with a file name or directory depending on what you are setting the class path to, as follows:

For a JAR or zip file that contains class files, the class path ends with the name of the zip or JAR file.

For class files in an unnamed package, the class path ends with the directory that contains the class files.

For class files in a named package, the class path ends with the directory that contains the root package, which is the first package in the full package name.

Multiple path entries are separated by semicolons with no spaces around the equals sign (=) in Windows and colons in Oracle Solaris.

The default class path is the current directory. Setting the CLASSPATH variable or using the -classpath command-line option overrides that default, so if you want to include the current directory in the search path, then you must include a dot (.) in the new settings.

Class path entries that are neither directories nor archives (.zip or JAR files) nor the asterisk (*) wildcard character are ignored.

 
Dave Tolls
Rancher
Posts: 4801
50
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
No, as I said above, it says that only the following is a valid use of a wildcard:
/some/path/to/lib/*
which, at a guess, is expanded by java.exe into a list of jars contained in that directory.

A directory by itself is presumed to be the root path for class files.
reply
    Bookmark Topic Watch Topic
  • New Topic