Java Forum / General / July 2006
NoClassDefFoundError and jars, classpath, and ant newbie question
bill turner - 21 Jul 2006 17:40 GMT I have been away from java for awhile and never spent much time with it. I am having what is a very basic problem that I have not been able to resolve. I am trying to include a jar from one project into the classpath of another project. My directory structure is as follows:
src - my source files class - my class files lib - external jars, zips to be used by this project (currently my jar from the other project - util) jar - my generated jar file make - build.xml and manifest file
i have tried running both via cygwin bash and dos. The results below are from the cygwin bash execution (the dos results are identical). The java.lang.NoClassDefFoundError exception is for a class within the util.jar, the included jar, not jequire.jar, my current project.
/home/Wizard/bin>sh jequire.sh Exception in thread "main" java.lang.NoClassDefFoundError: com/changent/util/ui/ButtonPanel at com.changent.jequire.JequireTabs.makeTypeTabs(JequireTabs.java:33) at com.changent.jequire.JequireTabs.<init>(JequireTabs.java:25) at com.changent.jequire.Jequire.<init>(Jequire.java:48) at com.changent.jequire.Jequire.main(Jequire.java:115)
The bash script for executing this is: #!/usr/bin/bash
cd ${HOME}/jequire
export CLASSPATH=
$JAVA_HOME/bin/java -jar jar/jequire.jar
I realize the classpath should be taken from the manifest. The manifest from jequire.jar looks like: Manifest-Version: 1.0 Ant-Version: Apache Ant 1.6.5 Created-By: 1.5.0_07-b03 (Sun Microsystems Inc.) Built-By: Wizard Main-Class: com/changent/jequire/Jequire Class-Path: util.jar
My ant script (I am not strong with ant, either), looks like: <target name="jar_java" depends="compile_java" description="Create ${ant.project.name}.jar java file" > <manifest file="MANIFEST.MF"> <attribute name="Built-By" value="${user.name}"/> <attribute name="Main-Class" value="com/changent/jequire/Jequire"/> <attribute name="Class-Path" value="util.jar" /> </manifest> <jar destfile = "${jar}/${ant.project.name}.jar" manifest="MANIFEST.MF"> <fileset dir="${class}" excludes="**/*.tws" /> <fileset dir="${lib}" /> </jar> </target>
The resultant jar has all the jequire classes, as would be expected, the manifest, and the util.jar with no path info. I do not know what I am doing wrong. Should I change the ant script somehow? The way the jar is executed? Or something else?
Your help is greatly appreciated!
Mark Space - 21 Jul 2006 17:51 GMT > I have been away from java for awhile and never spent much time with > it. I am having what is a very basic problem that I have not been able > to resolve. I am trying to include a jar from one project into the > classpath of another project. My directory structure is as follows: I'm having a similar problem right now with both NetBeans and on the command line. If I find something I'll let you know, otherwise I may be posting my own version soon.
bill turner - 21 Jul 2006 18:19 GMT > > I have been away from java for awhile and never spent much time with > > it. I am having what is a very basic problem that I have not been able [quoted text clipped - 4 lines] > command line. If I find something I'll let you know, otherwise I may be > posting my own version soon. Okay, I appreciate it. Funny thing is, I have no problems returning to the code, just getting it to run. :-(
lordy - 21 Jul 2006 18:28 GMT > I realize the classpath should be taken from the manifest. The manifest > from jequire.jar looks like: [quoted text clipped - 4 lines] > Main-Class: com/changent/jequire/Jequire > Class-Path: util.jar Does it have a blank line at the end?
Lordy
bill turner - 22 Jul 2006 00:06 GMT > > I realize the classpath should be taken from the manifest. The manifest > > from jequire.jar looks like: [quoted text clipped - 8 lines] > > Lordy To what does it refer?
lordy - 22 Jul 2006 00:46 GMT >> > I realize the classpath should be taken from the manifest. The manifest >> > from jequire.jar looks like: [quoted text clipped - 10 lines] > > To what does it refer? "It" refers to subject of the quoted paragraph - "the manifest". Or more correctly - every "section" or group of Name-Value pairs...
http://www.iona.com/support/docs/e2a/asp/5.1/j2ee/petstore/tutorial4.html
From http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html Name-Value pairs and sections:
section: *header +newline <-[Every section must be followed by a blank line] nonempty-section: +header +newline newline: CR LF | LF | CR (not followed by LF) header: name : value name: alphanum *headerchar value: SPACE *otherchar newline *continuation continuation: SPACE *otherchar newline alphanum: {A-Z} | {a-z} | {0-9} headerchar: alphanum | - | _ otherchar: any UTF-8 character except NUL, CR and LF
Lordy
bill turner - 22 Jul 2006 02:44 GMT > >> > I realize the classpath should be taken from the manifest. The manifest > >> > from jequire.jar looks like: [quoted text clipped - 31 lines] > > Lordy Okay. Well, I don't know how it would have one. Nor does it seem to have one. Each line is terminated with CRLF (it is Windows, after all). My manifest looks exactly as above. So, it seems it conforms to spec. Hmmmm...
Chris Uppal - 22 Jul 2006 08:19 GMT > Okay. Well, I don't know how it would have one. Nor does it seem to > have one. Each line is terminated with CRLF (it is Windows, after all). > My manifest looks exactly as above. So, it seems it conforms to spec. > Hmmmm... Just to be sure: is the /last/ line terminated by a CRLF ? Many Windows editors (correctly for that platform) treat CRLF as a line /separator/ and don't put one at the end of the last line unless you explicitly type <return>. The manifest file parser (brokenly. IMO) cannot cope with that, but does not issue any kind of error message either.
As far as I can see, that problem still remains in 1.5. If the manifest file (the actual one in the archive) lacks a terminating CRLF (or some variant) then the launcher's parser will ignore that line silently. The jar creation tool seems to have a similar problem and doesn't actually copy the last line of the supplied manifest into the jar-ed manifest unless it is terminated (and again doesn't report any error). I don't know whether either of those problem could be affecting you, but it's worth checking a second time.
-- chris
bill turner - 22 Jul 2006 17:07 GMT > > Okay. Well, I don't know how it would have one. Nor does it seem to > > have one. Each line is terminated with CRLF (it is Windows, after all). [quoted text clipped - 16 lines] > > -- chris Yes, it does. See my reply to lordy. I appreciate your jumping in!
lordy - 22 Jul 2006 14:36 GMT >> >> > I realize the classpath should be taken from the manifest. The manifest >> >> > from jequire.jar looks like: [quoted text clipped - 15 lines] >> >> section: *header +newline <-[Every section must be followed by a blank line] [SNIP]
> Okay. Well, I don't know how it would have one. Nor does it seem to > have one. Each line is terminated with CRLF (it is Windows, after all). > My manifest looks exactly as above. So, it seems it conforms to spec. > Hmmmm... Yes each line should be terminated by a new line but there should be an *extra* new line at the end - ie a completely empty blank line with nothing on it. No spaces, no letter, nothing. Does it have this?
Failing that try swapping your 'Built-By' and 'Class-Path' perhaps?
Lordy
bill turner - 22 Jul 2006 17:05 GMT > >> >> > I realize the classpath should be taken from the manifest. The manifest > >> >> > from jequire.jar looks like: [quoted text clipped - 30 lines] > > Lordy Following the word util.jar, viewing a hex editor, are the characters 0D 0A 0D 0A, in other words CRLF, CRLF. This seems to comply with what you are suggesting. I changed my ant script to look like the following:
<target name="jar_java" depends="compile_java" description="Create ${ant.project.name}.jar java file" > <manifest file="MANIFEST.MF"> <attribute name="Main-Class" value="com/changent/jequire/Jequire" /> <attribute name="Class-Path" value="util.jar" /> <attribute name="Built-By" value="${user.name}" /> </manifest> <jar destfile = "${jar}/${ant.project.name}.jar" manifest="MANIFEST.MF"> <fileset dir="${class}" excludes="**/*.tws" /> <fileset dir="${lib}" excludes="**/junit.jar" /> </jar> </target>
You'll notice that I have moved "Built-By" to the end of the manifest. However, this does not create the manifest as expected. Instead, Built-By still comes before Class-Path. See below. It is still followed with the requisite CRLF CRLF at the end.
Manifest-Version: 1.0 Ant-Version: Apache Ant 1.6.5 Created-By: 1.5.0_07-b03 (Sun Microsystems Inc.) Main-Class: com/changent/jequire/Jequire Built-By: Wizard Class-Path: util.jar
This still does not work, of course, and still fails with the same error. I'll try to manually change this, but have to try that later today. In the meantime, if you have any other thoughts, I sure would appreciate them.
Bill
lordy - 22 Jul 2006 18:46 GMT > I have been away from java for awhile and never spent much time with > it. I am having what is a very basic problem that I have not been able [quoted text clipped - 7 lines] > jar - my generated jar file > make - build.xml and manifest file [SNIP]
> $JAVA_HOME/bin/java -jar jar/jequire.jar Another attack vector :). Try
EITHER
putting util.jar in the same directory as your application jar file.
OR
ensuring that your Manifest Class-Path has the correct relative path from your application jar to util.jar
E.g. Class-Path: lib/util.jar (if lib directory is inside 'jar' directory) or Class-Path: ../lib/util.jar (if lib directory is in same directory as your 'jar' directory)
If thats the fix - sorry about the wild goose chase :(
Lordy
bill turner - 22 Jul 2006 22:06 GMT > > I have been away from java for awhile and never spent much time with > > it. I am having what is a very basic problem that I have not been able [quoted text clipped - 32 lines] > > Lordy Option one does not make sense to me. I do not want to mix my executable (application) jar with jars imported into the project.
Option two is what I think I already have. The application (executable) jar contains the util jar. The class path lists util jar without path information. The application jar has the util jar without class info. An abbreviated look at the application jar (jequire.jar) looks as follows when viewed in winzip:
Jequire.class com\changent\jequire JequireTabs.class com\changent\jequire Manifest.mf meta-inf\ util.jar
Since the manifest does not specify path info and jequire.jar contains no path info for util.jar, I do not see why I should change it to do so. I have no idea to what it should be changed. Can you explain further?
bill turner - 23 Jul 2006 00:02 GMT > > > I have been away from java for awhile and never spent much time with > > > it. I am having what is a very basic problem that I have not been able [quoted text clipped - 51 lines] > so. I have no idea to what it should be changed. Can you explain > further? I have continued to play. I threw in a display of system properties. The classpath property id below: java.class.path=Jequire.jar
Since I state in the manifest that util.jar is in the classpath, and it is at the top level of Jequire.jar, I am wondering if I am misunderstanding altogether. Does the Class-Path property define the run time classpath? If so, why isn't that reflected in the System java.class.path property? FWIW, I've tried specifying -classpath on the command line and the system classpath property still comes up as above. Isn't it possible, when executing a jar, to provide further classpath info? If not, and the manifest Class-Path property doesn't specify the run time path, how is it determined when executing a jar and how can one change it?
lordy - 23 Jul 2006 10:57 GMT >> [SNIP] >> [quoted text clipped - 26 lines] > Option two is what I think I already have. The application (executable) > jar contains the util jar. AFAIK you should not have your utils jar inside your main jar. That sounds more like mixing imported jars than simply having them side by side in the same directory.
Either have
the files <path>/app.jar <path>/util.jar in you distribution out on the file system And have "Class-Path: util.jar" in your manifest..
OR (but I havent tried it)
have the files <path>/app.jar and <path>/lib/utils.jar And have Class-Path: lib/util.jar in your manifest..
But dont embed utils.jar in your main .jar. If you want to put the util.jar inside you main jar then I think this is worse than having the two jars in the same directory personally, but I'm not sure if Java can load your util classes directly. You'd have to read up on it. it makes it awkward if you want to upgrade your 'utils.jar' at a later point. Most apps (ant etc) have util jars sitting out on the file system somewhere, not embedded in their own jar.
When you install your application you should simply have ...
<install-path>/your-app.jar <install-path>/lib/util.jar As two separate files.
The Manifest of your main app should then contain Class-Path:lib/util.jar
I suspect.
Lordy
bill turner - 23 Jul 2006 02:12 GMT > > I have been away from java for awhile and never spent much time with > > it. I am having what is a very basic problem that I have not been able [quoted text clipped - 32 lines] > > Lordy Okay! I got it! Whew! It was as you suggested, i needed to specify the class path attribute in ant as follows:
<attribute name="Class-Path" value="../lib/util.jar" />
I also made some changes to the shell script, but the above was the real kicker. I didn't realize that the classpath was for items *outside* the application jar, that to load classes from a jar packaged within a jar needed to be done programmatically. I finally came upon the explanation at http://java.sun.com/docs/books/tutorial/deployment/jar/downman.html which states:
"Note: The Class-Path header points to classes or JAR files on the local file system, not JAR files within the JAR file or classes on the network. To load classes in JAR files within a JAR file into the class path, you must write custom code to load those classes. For example, if MyJar.jar contains another JAR file called MyUtils.jar, you cannot use the Class-Path header in MyJar.jar's manifest to load classes in MyUtils.jar into the class path."
You had put me on to the correct solution, I just didn't have enough knowledge to properly understand your solution.
Thanks again for your help!
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|