LinuxQuestions.org
Review your favorite Linux distribution.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 05-17-2009, 07:49 PM   #1
r.stiltskin
Member
 
Registered: Oct 2003
Location: USA
Distribution: Xubuntu, Arch
Posts: 231

Rep: Reputation: 31
java - using apache.commons.collections


I'm trying to compile & run some simple java code ("BufferTest.java") that imports classes from apache.commons.collections (from libcommons-collections3-java package). These classes are in /usr/share/java/commons-collections3.jar.

I can compile the code with the command
Code:
javac -classpath commons-collections3-3.1.jar BufferTest.java
but when I try to run it with
Code:
java BufferTest
I get a NoClassDefFoundError:
Code:
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/collections/buffer/PriorityBuffer
        at BufferTest.main(BufferTest.java:10)
Caused by: java.lang.ClassNotFoundException: org.apache.commons.collections.buffer.PriorityBuffer
        at java.net.URLClassLoader$1.run(URLClassLoader.java:217)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:205)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:323)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:294)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:268)
        at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:336)
        ... 1 more
So, obviously I need more than just "java BufferTest".
What's the correct command to run it?
Thanks.

PS: there's not much to the code. It starts with:
Code:
import java.util.*;
import org.apache.commons.collections.buffer.PriorityBuffer;

public class IterTest {
  
  public static void main( String[] args ) {
    ArrayList<String> list = new ArrayList<String>();
    PriorityBuffer buff = new PriorityBuffer();
...

Last edited by r.stiltskin; 05-17-2009 at 07:52 PM.
 
Old 05-17-2009, 10:14 PM   #2
paulsm4
LQ Guru
 
Registered: Mar 2004
Distribution: SusE 8.2
Posts: 5,863
Blog Entries: 1

Rep: Reputation: Disabled
Hi -

1. I assume (hope) you're using the Sun JDK (and not Gnu Java).
"javac -version" will tell you.

2. More important, if you're "main" is in public class "IterTest"
... then it should be in a source named "IterTest" (otherwise, it should fail with a compile error)
... and your "run" command should be something like:
Quote:
java -classpath .:commons-collections3-3.1.jar IterTest
'Hope that helps .. PSM

Last edited by paulsm4; 05-17-2009 at 10:15 PM.
 
Old 05-17-2009, 10:19 PM   #3
kellinwood
Member
 
Registered: Jan 2006
Location: Culver City, California
Distribution: Fedora
Posts: 64

Rep: Reputation: 21
Its almost the same as the compile command...

Code:
java -classpath commons-collections3.jar BufferTest
And FYI, The classpath can have multiple items made up of directory paths that contain compiled classes and/or the pathnames of jar files. Individual entries must be separated by colons.

Code:
java -classpath my_classes_dir:somejavalib.jar:anotherjavalib.jar BufferTest
Hope that helps.
 
Old 05-17-2009, 11:00 PM   #4
r.stiltskin
Member
 
Registered: Oct 2003
Location: USA
Distribution: Xubuntu, Arch
Posts: 231

Original Poster
Rep: Reputation: 31
Nope. Thanks, but I still can't run it.

For the record, I accidentally posted the wrong code snippet earlier. The filename is BufferTest.java and the classname is BufferTest. And yes, I am using Sun JDK 6 (although I also tried open-jdk with the same lack of success).

No confusion this time; it can't get any simpler than this:
Code:
import org.apache.commons.collections.buffer.PriorityBuffer;

public class BufferTest {

  public static void main( String[] args ) {

    PriorityBuffer ascendingBuff = new PriorityBuffer(true);
//    PriorityBuffer descendingBuff = new PriorityBuffer(false);
    System.out.println("Hello");
  }
}
It compiles with no errors with this command:
Code:
 javac -classpath /usr/share/java/commons-collections3-3.1.jar BufferTest.java
I'm trying to run it with this command:
Code:
 java -classpath /usr/share/java/commons-collections3-3.1.jar BufferTest
Here is the error output:
Code:
Exception in thread "main" java.lang.NoClassDefFoundError: BufferTest
Caused by: java.lang.ClassNotFoundException: BufferTest
        at java.net.URLClassLoader$1.run(URLClassLoader.java:200)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:276)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
        at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:319)
Oh, and I can run it in Eclipse by configuring Project/Properties/Java Build Path/Libraries/Add External JARs/ pointing to the exact directory that I used as the classpath on the command line.
 
Old 05-17-2009, 11:04 PM   #5
kellinwood
Member
 
Registered: Jan 2006
Location: Culver City, California
Distribution: Fedora
Posts: 64

Rep: Reputation: 21
Right, so you need the directory containing BufferTest.class *and* the commons-collections.jar in the classpath. Try this:

Code:
java -classpath .:/usr/share/java/commons-collections3-3.1.jar BufferTest
The '.' in the classpath will cause java to also look for classes in the current directory.
 
Old 05-17-2009, 11:33 PM   #6
r.stiltskin
Member
 
Registered: Oct 2003
Location: USA
Distribution: Xubuntu, Arch
Posts: 231

Original Poster
Rep: Reputation: 31
Ohhhh! Thanks. I didn't notice the . in paulsm4's post. It never occurred to me that the current directory would have to be specified.

Why is it required for running & not for compiling? (& also not when all of the class files are in the current dir)

Last edited by r.stiltskin; 05-17-2009 at 11:34 PM.
 
Old 05-18-2009, 01:06 AM   #7
kellinwood
Member
 
Registered: Jan 2006
Location: Culver City, California
Distribution: Fedora
Posts: 64

Rep: Reputation: 21
The compiler has the concept of a "source path" in which it looks for the files you specify for compilation. It defaults to the current directory unless you override it using -sourcepath.
 
Old 05-18-2009, 01:58 AM   #8
r.stiltskin
Member
 
Registered: Oct 2003
Location: USA
Distribution: Xubuntu, Arch
Posts: 231

Original Poster
Rep: Reputation: 31
Maybe you misunderstood me. The compiler doesn't need the ".:"
It finds the source files in the current directory even if only the external JARs are mentioned in the command line classpath argument.

It's apparently only the JRE that needs the ".:" to find the local class files when a classpath is supplied on the command line. I was wondering why there is that inconsistency between the compiler and the runtime engine.
 
Old 05-18-2009, 09:16 AM   #9
kellinwood
Member
 
Registered: Jan 2006
Location: Culver City, California
Distribution: Fedora
Posts: 64

Rep: Reputation: 21
I understood you. My response was an attempt to answer your question "Why is it required for running & not for compiling?".

In my mind there isn't an inconsistency. The compiler needs to know how to find the sources and pre-compiled classes that the sources depend on. In your example, there are three logical path locations being used at various times. 1) the path to your source code, 2) the path to the classes generated by compiling your code, and 3) the path to commons-collections.jar. The compiler needs 1 and 3 specified as sourcepath and classpath respectively, because the source depends on commons-collections and nothing else. The JRE needs 2 and 3 because it only uses compiled code. Now here's the explanation of why you don't want all three working during compilation...

Its a bad idea to also put #2 in the classpath during compilation because by doing so you are telling the compiler that your source code is dependent on the class files generated during compilation. You might think this will never happen, but consider the following situation... a source directory with two files A.java and B.java. In the first version of this project A depends on B, so we have.

A.java
A.class
B.java
B.class

But then the developer decides to refactor the code so that B.java is no longer necessary and deletes B.java in preparation for that change.

Code:
rm B.java
But before chaning the code in A.java, the developer is distracted (by a mild earthquake for example, like there was in Los Angeles last night). When returning to the project, the code is compiled with the '.' in the classpath like so:

Code:
javac -classpath .:/usr/share/java/commons-collections.jar A.java
But the compile succeeds even thought it should fail due to the missing dependency (B.java no longer exists, but A.java was never changed). The compile succeeds here because of the '.' in the classpath and because the developer forgot to delete B.class. The remaining dependency in A.java on B.java is satisfied because B.class is found by the compiler as a result of the '.' in the classpath.

On the other hand, if the '.' was not used during compilation, the compile will fail even though B.class still remains.

Last edited by kellinwood; 05-18-2009 at 09:20 AM.
 
Old 05-18-2009, 10:05 AM   #10
r.stiltskin
Member
 
Registered: Oct 2003
Location: USA
Distribution: Xubuntu, Arch
Posts: 231

Original Poster
Rep: Reputation: 31
Sorry if I'm being dense, and if I didn't explain myself clearly, but despite your very detailed explanation you seem to be missing my point. Let me try to explain myself in your terms.

It appears to me that the compiler doesn't need #1 and #3 specified, but only #3. Apparently the compiler searches the current directory when no classpath is specified, AND it searches the current directory when a classpath is specified, even though the classpath list does NOT include the current directory. Thus if my code is entirely self-contained within the current directory I can compile it with the command
Code:
javac MyClass.java
and if my code depends on /usr/share/java/some-library.jar I can compile it with the command
Code:
javac -classpath /usr/share/java/some-library.jar MyClass.java
Note: no "." in that classpath.

What seems inconsistent to me is the behavior of the JRE. When no classpath is explicitly provided, the JRE by default looks in the current directory, but if ANY classpath is supplied to the JRE, ALL classpaths must be supplied explicitly, including the current directory. Thus, as you have stated, in order to RUN the program the command-line command is
Code:
java -classpath .:/usr/share/some-library.jar MyClass
including the "." in the explicit classpath.

(There is no CLASSPATH in my environment variables.)

Last edited by r.stiltskin; 05-18-2009 at 10:08 AM.
 
Old 05-18-2009, 11:29 AM   #11
kellinwood
Member
 
Registered: Jan 2006
Location: Culver City, California
Distribution: Fedora
Posts: 64

Rep: Reputation: 21
Maybe we are both a bit dense .

> It appears to me that the compiler doesn't need #1 and #3 specified, but only #3.

I know its confusing and it may seem like splitting hairs, but #1 is the path to the *source code*, e.g. the 'source path', which is different than the classpath and defaults to the current directory if not specified. #2 is the path to the compiled classes from #1, which are the same directory in our simple examples. In larger projects or as soon as you switch to an IDE, they will be different directories (i.e., the code will be in a 'src' directory, and the classes written to a 'classes' directory). The compiler does need #1 as the source path (but it gets one, even if via a default value). My detailed explanation was meant to show why you don't want to have the path to *your* generated class files in the classpath during compilation.

But I now awaken to my own 'denseness' with your point about the classpath for the JRE. I was not aware that if you don't explicitly specify a classpath that it defaults to using the current directory. I don't have an explanation other than it seems like reasonable behaviour. But this is the viewpoint of someone who long ago gave up compiling on the command line for an IDE, so I can see how it might seem confusing to someone else.
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
LXer: XML Fodder for Java Objects with Commons Digester 2.0 LXer Syndicated Linux News 0 01-08-2009 09:42 PM
Please help with Apache Web Server / Apache Tomcat / PHP / Java / PHP-Java Bridge jpmad4it Linux - Server 2 01-05-2009 06:07 AM
Apache Commons telnet connection with a continuous command clb Programming 2 12-29-2008 01:09 PM
LXer: Collections and arrays for the busy Java developer LXer Syndicated Linux News 0 11-15-2007 03:00 PM
snort data collections gabsik Linux - Networking 1 09-24-2006 12:01 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 02:55 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration