7/28/2006

JDK 6 Supports * in Classpath But Be Aware of This

Finally JDK 6 (Mustang) lets me use wildcard (*) in classpath. I no longer have to enumerate all jar files in a lib directory. But with this added feature, it's easier to get errors like "javac: invalid flag:" For example, I want to complile a simple servlet, including all jar files in C:\Sun\AppServer\lib:

C:\tmp> javac -cp C:\Sun\AppServer\lib\*
HelloWorldServlet.java
javac: invalid flag: C:\Sun\AppServer\lib\addons
Usage: javac <options> <source>
use -help for a list of possible options
What's happening here is, the OS expands * to all files/directories in C:\Sun\AppServer\lib, since * has special meaning for the OS. So the real command resolves to:
javac -cp C:\Sun\AppServer\lib\activation.jar
C:\Sun\AppServer\lib\addon
C:\Sun\AppServer\lib\admin-cli.jar
C:\Sun\AppServer\lib\ant ... HelloWorldServlet.java
As all files/directories are expanded alphabetically, the first one (activation.jar) is treated as classpath element, and everything else starting with addon are treated as separate JVM options. Of course these are invalid JVM options, hence javac: invalid flag:

Note: if you are using javaw.exe instead of java.exe, * wildcard expansion in -cp or -classpath doesn't work, due to JDK 6 bug 6510337

So here are some tricks how to use * in classpath without getting burned:
  • "*" and "*.jar" have the same effect when used in classpath.
  • Quote it, if your classpath has a single element that uses *. For example,
    javac -cp "C:\Sun\AppServer\lib\*" HelloWorldServlet.java
  • This problem doesn't exist if you have more than one element in classpath, even though they do not exist. When in doubt, always quote your classpath value that uses wildcard.
    javac -cp C:\Sun\AppServer\lib\*;\nosuchdir HelloWorldServlet.java
  • This problem exists for all JDK tools that takes classpath option, including java. The error is different but solution is the same as above.
    java -cp C:\temp\* A
    Exception in thread "main" java.lang.NoClassDefFoundError: C:\temp\b/jar
  • Of course, if the directory contains 1 jar file, it will be expanded correctly, and you don't need to quote it. But using * doesn't save you much typing:
    java -cp C:\single-jar-file-folder\* A
    this is A
  • If on Unix, whether to quote or not quote wildcard classpath depends on which shell you are using. For example, tcsh or csh may fail with the following error: "java: No match." But the exact same command works under bash:
    java -cp tmp:$HOME/modules/*.jar Test abc

13 comments:

Riyad Kalla said...

Does -cp *.jar not work?

howto said...

No, -cp *.jar doesn't work, unless you have only 1 jar in that directory.

The real command after * has been resolved is something like:

-cp a.jar b.jar c.jar

While java is expecting these jars to be separated by ; or :, not by space.

Anonymous said...

error in installing mysql-connector-java-5.0.7-bin.jar
"Failed to load Main-Class manifest attribute from..."

admin said...

Are you trying to install mysql-connector-java-5.0.7-bin.jar? It doesn't look like an executable program packaged in a jar format. It is a library jar that contains mysql jdbc impl classes. You just need to include it in the classpath of your java app.

plush said...
This comment has been removed by a blog administrator.
photo soft said...
This comment has been removed by a blog administrator.
Anonymous said...

hahahahahahahahahahahahaha!!!!

Arun said...

Thanks a lot for your information

Uday Kumar said...

hi,

thanks for giving me the usefull information.

I got this when i'm running my java class in netbeans 6.7.

I don't know how to modify my complier options in netbeans.

Please help me in this.

javahowto said...

Uday, in NetBeans (or Eclipse), the project classpath (for compiler, runtime, and test) is not directly exposed to the users. But you can modify the project properties | build paths to add all jar files in one directory in one step.

You can either create a IDE library that can be shared among multiple projects, adding all jars to this new library;

OR just add these jars (called external jars in Eclipses) to the project.

The way I see it, wild card in classpath is very useful in command line, but less so in IDE.

Anonymous said...

Do you have an example of using JDK 6 style classpath with an ANT javac compile task?

We tried it like this

compile.classpath=c:....\WEB-INF\lib*;...websphere...\a.jar;...websphere...\b.jar; etc. and used this classpath in the javac task, but the libraries from WEB-INF\lib were not being recognised.

So, I am wondering if it is possible to use this type of construct with ANT. The ANT version is 1.7.x.

javahowto said...

Have you tried WEB-INF/lib/*? In your comment you had WEB-INF/lib*

Another possibility is windows path format issue. You can try use all / instead of \

Anonymous said...

Yes, we tried it. Currently, I am trying with keeping the websphere libraries expanded and just web-inf library in JDK6 format like below - removed other list of Websphere libraries from list

[echo] compile.classpath: ..........C:\Software\WAS85\wlp\lib\ws-launch.jar;C:\temp\build\classes;C:\Temp\RAD8ProjectsWAS7Server\TestWeb\WebContent\WEB-INF\lib\*;