Oct 2, 2010

Java program compiling from command prompt

Common problem when compiling a java code from the terminal.
Exception in thread "main" java.lang.NoClassDefFoundError: TopLevelDemo
Caused by: java.lang.ClassNotFoundException: TopLevelDemo
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:248)

Since I have my code inside the component package. I have to run the
file using java COMPONENTNAME.javaCLASSNAME
Instead of just java javaCLASSNAME

1. Compiling a java code:

Compiling Java code is tricky because you need to keep track of several related but different things:
The target file you're compiling.
The directory where the compiler looks for .java files that the target file imports.
The directory where the compiler looks for .class files the target file imports.
The directory where the compiler puts the compiled output.

By default, the javac compiler thinks all of these are the current working directory, which is almost never what you want. Consequently, you need to explicitly specify each of these elements when you compile.

2. Where the output goes:

Assuming there are no syntax errors, javac places the compiled .class file in the same directory where the .java file is. You do not want this. Mixing .class and .java files makes it very hard to clean up the compiled files without accidentally deleting .java files you want to keep. This makes clean builds problematic and tends to result in versioning problems. It also makes it hard to jar up just the compiled .class files when distributing a binary. Therefore, you need to tell the compiler to put the compiled output in a completely different directory. The -d switch specifies the output directory (usually called bin, build, or classes):
$ javac -d bin src/test/TestWekaCluster.java

3. Compiling multiple directories in the sourcepath
to compile source files in different locations

You can actually have more than one directory in your sourcepath, separated by colons, though this is usually not necessary. For example, if I want to include both the local src directory and the directory /Users/alimurreza/Documents/Project1/src where I keep the source code for another project, I can compile like this:
$ javac -d bin -sourcepath src:/Users/alimurreza/Documents/Project1/src src/test/TestWekaCluster.java

4. Setting the classpath
to add class files in different locations

In medium-to-large projects, recompiling every file every time can be time-consuming. You can ease this burden by separately compiling and storing independent parts of the same project in different classes or bin directories. These directories are added to the classpath.

There are several ways to add a class to the classpath. The -classpath command-line switch is the only one you should use, however. For example, suppose I want to import files from another project that I've previously compiled into the directory /Users/elharo/classes. Then I would add -classpath /Users/alimurreza/Documents/Project1/classes to the command line like so:
$ javac -d bin -sourcepath src:/Users/alimurreza/Documents/Project1/src src/test/TestWekaCluster.java

5. Adding third-party libraries(jar files)
So far, I've assumed the program is complete onto itself and does not use any separately compiled third-party libraries. If it does, you'll need to add them to the classpath too. Libraries are usually distributed as JAR files such as junit.jar or icu4j.jar. In this case, it is the JAR file itself that you add to the classpath, not the directory that contains it. (In essence, the JAR file acts as a directory that contains compiled .class files.) For example, the following command adds three things to the classpath: the directory /Users/elharo/classes, the file javaml-0.1.6.jar in the current working directory, and the file weka.jar in ./javaml-0.1.6/lib/:
javac -d bin -classpath ../javaml-0.1.6/javaml-0.1.6.jar:../javaml-0.1.6/lib/weka.jar -sourcepath src src/test TestWekaCluster.java

JAR files are only used for .class files and the classpath, not for .java files and the sourcepath.


Running the program

You have now successfully compiled your program, and are ready to run it. This is similar to but simpler than compiling. When running a program, you only need to specify two things:
1. The classpath.
The fully package qualified name of the class that contains your main() method.

2. You do not need to specify the sourcepath.
Usually the classpath is the same classpath you used to compile the program, with the addition of the directory where the compiled output was placed. For example, if the compile command was this:

java -classpath bin:../javaml-0.1.6/javaml-0.1.6.jar:../javaml-0.1.6/lib/weka.jar:../javaml-0.1.6/lib/commons-math-1.2.jar:../javaml-0.1.6/lib/Jama-1.0.2.jar:../javaml-0.1.6/lib/ajt-2.5.jar:../javaml-0.1.6/lib/libsvm.jar test.TestWekaCluster

Reference

No comments:

Down with the Dictatorship!

    "Let them hate me, so that they fear me" - Caligula 41AD