Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Java > a question about creating the JAR file

Reply
Thread Tools

a question about creating the JAR file

 
 
zyng
Guest
Posts: n/a
 
      10-26-2012
Hi:

I am a bit confused here. My code uses a third party JAR file, helper.jar. Now, I have finished compiling my code, with helper.jar on the classpath ofcourse. Now it's time to create the executable JAR(hello.jar) for delivery..

My confusion is do I need to bundle helper.jar into hello.jar? One thought I have is that during compiling, all the code needed from helper.jar has been extracted and combined into the generated *.clss files in build/ directory. So, for creating hello.jar, I only need to bundle all *.class files in build/ directory. But I am not sure that is correct.

Currently, I have to unjar(expand) helper.jar into build/ directory before I jar everything in build/. The result hello.jar works fine. If I skip unjarring helper.jar into build/ directory, no complain for creating hello.jar.But when running it, an exception of no class definition for a class inside helper.jar is thrown.

Thank you very much.

 
Reply With Quote
 
 
 
 
Lew
Guest
Posts: n/a
 
      10-26-2012
zyng wrote:
> I am a bit confused here. My code uses a third party JAR file, helper.jar. Now, I have finished
> compiling my code, with helper.jar on the classpath of course. Now it's time to create the
> executable JAR(hello.jar) for delivery.
>
> My confusion is do I need to bundle helper.jar into hello.jar?


No, in fact that would be stupid.

> One thought I have is that during compiling, all the code needed from helper.jar has been extracted
> and combined into the generated *.clss [sic] files in build/ directory.
> So, for creating hello.jar, I only need to bundle all *.class files in build/ directory.
> But I am not sure that is correct.


It is not.

> Currently, I have to unjar(expand) helper.jar into build/ directory before I jar everything in build/.


No, you don't. You didn't read the docs on "jar", did you?

> The result hello.jar works fine. If I skip unjarring helper.jar into build/ directory, no complain [sic] for
> creating hello.jar.


How are you creating "hello.jar"?

Be specific.

> But when running it, an exception of no class definition for a class inside helper.jar is thrown.


Do not paraphrase error messages. Copy and paste them into your post.

How are you running the JAR?

You give such incomplete information!

If you are doing this:

$ java -cp hello.jar your.package.Main

then you need to add the third-party JAR to the "-cp" argument.

I will pretend you are attempting this:

$ java -jar hello.jar

which is the normal way to run a JAR. You should package the JAR with its antecedent JARs
into a delivery vehicle like a ZIP file or some installer package that lets the user unpack the
application ("hello.jar") and its antecedents ("helper.jar") into a controlled directory structure.

Two are common - app and antecedents in the same directory, or antecedents in a "lib/"
subdirectory relative to where the app JAR resides.

So one of these:

somedirectory/ somedirectory/
|| ||
||== hello.jar ||== hello.jar
||== lib/ ||== helper.jar
||== helper.jar

You set up the manifest in the app JAR ("hello.jar") to specify the "Class-Path:" relative to its own
location, so

Class-Path: lib/helper.jar

for the "lib/" scenario.
("java -jar" ignores the classpath command argument and the CLASSPATH envar.)

RTFM.
http://docs.oracle.com/javase/7/docs...jar/index.html

--
Lew
 
Reply With Quote
 
 
 
 
Sven Köhler
Guest
Posts: n/a
 
      10-27-2012
Am 26.10.2012 22:58, schrieb zyng:
> My confusion is do I need to bundle helper.jar into hello.jar? One
> thought I have is that during compiling, all the code needed from
> helper.jar has been extracted and combined into the generated *.clss
> files in build/ directory. So, for creating hello.jar, I only need to
> bundle all *.class files in build/ directory. But I am not sure that
> is correct.
>
> Currently, I have to unjar(expand) helper.jar into build/ directory
> before I jar everything in build/. The result hello.jar works fine.
> If I skip unjarring helper.jar into build/ directory, no complain for
> creating hello.jar. But when running it, an exception of no class
> definition for a class inside helper.jar is thrown.


There are at least two ways of doing this:

1) create hello.jar (for example with ant) and embed a manifest file,
which includes helper.jar in the classpath. The good thing is: inside
the manifest, you can use relative paths. Doring java -jar hello.jar,
these paths will be resolved (AFAIK, relative to hello.jar)

2) unpack helper.jar, and include (almost) all files of helper.jar in
hello.jar. Now it's not always possible to do that, especially if you
have multiple JAR files. Some paths are reserved. For example, if you
create a StAX XML Reader, the API search the classpaths for certain
failes. Each files may contain the names of classes that implement the
StAX API. Now when you merge multiple JAR files, you would have to merge
these files as well. (This is actually a bad example, as you only want
only one StAX implementation anyways, but it illustrates the problem)
What about signed JARs?


Now method (2) has gained popularity. Probably, because "big fat JAR
plugins" for several IDEs exist (at least for Eclipse this is true).
However, I think this method should be avoided for any big application.


Regards,
Sven
 
Reply With Quote
 
Jan Burse
Guest
Posts: n/a
 
      10-27-2012
Sven Köhler schrieb:
> Now method (2) has gained popularity. Probably, because "big fat JAR
> plugins" for several IDEs exist (at least for Eclipse this is true).
> However, I think this method should be avoided for any big application.


I agree. If your .jar file is an application (something you
double click on the desktop provided your environment has the
right association for .jar extension), then this comes handy.

But I also see the following advantage of 2): When your .jar file
is an API collection, and you want to allow access to the API of
multiple .jars. Then I doubt method 1) works.

Here is the scenario:

util1.jar: Provides class A
util2.jar: Provides class B
I want to make superutil.jar that provides class A and B
so that I can compile against it, i.e.:

javac -cp superutil.jar ....

I guess javac does not understand the Class-Path: manifest
attribute. Right? So you would need to unpack/pack the two
..jars into one .jar. I guess you can use something along the
fileset in the jar ant task for this purpose, no need to
buy an expensive tool.

Bye
 
Reply With Quote
 
Jan Burse
Guest
Posts: n/a
 
      10-27-2012
Jan Burse schrieb:
>
> I guess javac does not understand the Class-Path: manifest
> attribute. Right? So you would need to unpack/pack the two
> .jars into one .jar. I guess you can use something along the
> fileset in the jar ant task for this purpose, no need to
> buy an expensive tool.


Corr.:
Somebody says javac does, since jdk 1.5:

"Everything comes with a reason. Since jdk1.5, both java and javac
recurse the manifest classpath of a jar on the java classpath."

http://j2eeblogger.blogspot.ch/2008/...t-compile.html

Oki, Doki, thats colo. So for after 1.5, with the right basic
tools, Sven Köhlers advice is valid. Although there are still
some reasons for option 2), also from the above blog:

"Conclusion? Well, I don't know what to say here, but this looks
something similiar to the windows DLL hell problem. And it was
called DLL 'Hell' for a reason."

Bye
 
Reply With Quote
 
Sven Köhler
Guest
Posts: n/a
 
      10-27-2012
Am 27.10.2012 17:24, schrieb Jan Burse:
> Jan Burse schrieb:
>>
>> I guess javac does not understand the Class-Path: manifest
>> attribute. Right? So you would need to unpack/pack the two
>> .jars into one .jar. I guess you can use something along the
>> fileset in the jar ant task for this purpose, no need to
>> buy an expensive tool.

>
> Corr.:
> Somebody says javac does, since jdk 1.5:


Even if javac would not support that, then I would still recommend to
keep JARs seperate. If my library needs some 3rdparty library, then I
have to document that, and the user has to put that 3rd party library in
the classpath as well, when compiling. This allows the user to update
the 3rd party library separate from my own. This also avoid duplicates
in the classpath (for example, if two libraries include different
versions of the same library in their JAR files).


Regards,
Sven
 
Reply With Quote
 
Lew
Guest
Posts: n/a
 
      10-28-2012
Sven Köhler wrote:
> There are at least two ways of doing this:
>
> 1) create hello.jar (for example with ant) and embed a manifest file,
> which includes helper.jar in the classpath. The good thing is: inside
> the manifest, you can use relative paths. Doring java -jar hello.jar,
> these paths will be resolved (AFAIK, relative to hello.jar)


"AFAIK" transforms to "It is thus" when you read the docs.

It would not make any sense to use absolute paths in the manifest.

> 2) unpack helper.jar, and include (almost) all files of helper.jar in
> hello.jar. Now it's not always possible to do that, especially if you
> have multiple JAR files. Some paths are reserved. For example, if you
> create a StAX XML Reader, the API search the classpaths for certain
> failes. Each files may contain the names of classes that implement the
> StAX API. Now when you merge multiple JAR files, you would have to merge
> these files as well. (This is actually a bad example, as you only want
> only one StAX implementation anyways, but it illustrates the problem)


It illustrates _a_ problem; I wouldn't call it _the_ problem.

The problem is that it's a stupid idea.

You destroy the purpose of JARs, you tangle up code from multiple sources
into a single vehicle, you violate copyright and licensing terms, you make it
more difficult to update third-party JARs, and there's absolutely no need for
it.

> What about signed JARs?
>
> Now method (2) has gained popularity. Probably, because "big fat JAR
> plugins" for several IDEs exist (at least for Eclipse this is true).


That's a result of bundling third-party JAR contents inappropriately?

> However, I think this method should be avoided for any big application.


Drop the word "big" and you have good advice.

--
Lew
 
Reply With Quote
 
zyng
Guest
Posts: n/a
 
      10-31-2012
Thank you for the reply. All you said makes sense and I am following you and I agree with your recommendation of zipping hello.jar, helper.jar etc and the two ways of organizing the files.

However, I still have part of my question unanswered: I have two Eclipse projects(HELPER and HELLO). The project HELLO depends on the project HELPER. Now, I want to create an executable JAR file for HELLO project, in build.xml of HELLO project:

<path id="project.classpath">
<pathelement location="${build.dir}" />

<fileset dir="${helper.lib.dir}">
<include name="helper.jar"/>
</fileset>
</path>
Of course, I built helper.jar using Ant beforehand. So now, compiling HELLO code using Ant goes through. As said previously, the code of HELLO project uses the code in HELPER project. The target of "jar" is bundling everything in build directory.

(Pardon me for sticking to my big fat JAR approach). If I don't expand helper.jar into build directory before running "jar" target, running hello.jar will have java.lang.NoClassDefFoundError: aaa/bbb/ccc/AClassInHelper

To make it work, I need expanding helper.jar into build/ beforehand. I thought during compiling the HELLO project, aaa/bbb/ccc/AClassInHelper from helper.jar has been extracted into the binary code xxx/yyy/zzz/AClassInHelloUsingHelperClass.class

Thank you.


 
Reply With Quote
 
Lew
Guest
Posts: n/a
 
      10-31-2012
zyng wrote:
> Thank you for the reply. All you said makes sense and I am following you and I agree with your
> recommendation of zipping hello.jar, helper.jar etc and the two ways of organizing the files.>
>
> However, I still have part of my question unanswered: I have two Eclipse projects(HELPER and HELLO).
> The project HELLO depends on the project HELPER. Now, I want to create an executable JAR file for
> HELLO project, in build.xml of HELLO project:
>
> <path id="project.classpath">
> <pathelement location="${build.dir}" />
> <fileset dir="${helper.lib.dir}">
> <include name="helper.jar"/>
> </fileset>
> </path>
>
> Of course, I built helper.jar using Ant beforehand. So now, compiling HELLO code using Ant goes
> through. As said previously, the code of HELLO project uses the code in HELPER project. The target of
> "jar" is bundling everything in build directory.


I don't suppose you'd consider actually showing us that target instead of giving a vague and
approximate description?

> (Pardon me for sticking to my big fat JAR approach). If I don't expand helper.jar into build directory
> before running "jar" target, running hello.jar will have java.lang.NoClassDefFoundError:
> aaa/bbb/ccc/AClassInHelper


That's because you haven't followed the advice given earlier.

> To make it work, I need expanding helper.jar into build/ beforehand. I thought during compiling the
> HELLO project, aaa/bbb/ccc/AClassInHelper from helper.jar has been extracted into the binary code
> xxx/yyy/zzz/AClassInHelloUsingHelperClass.class


Why would you think that? That's not how Java works.

Java doesn't extract code from a antecedent class into a dependent class. It loads the
antecedent class into the JVM from whatever JAR or other source it comes.

In order for your "Hello" program to work, the antecedent JAR, helper.jar in your case,
must be in the classpath.

Unbundling JARs is the wrong thing to do. We've said this to you already. You don't "need
expanding [sic] helper.jar into build/ beforehand". That's the wrong thing to do.

Don't do that.

Read the documentation indicated, which surely you have not done yet.

Isn't it rather rude to keep asking for help when you haven't explored the advice you've
already received?

I repeat:

You set up the manifest in the app JAR ("hello.jar") to specify the "Class-Path:" relative to its own
location, so

Class-Path: lib/helper.jar

for the "lib/" scenario.
("java -jar" ignores the classpath command argument and the CLASSPATH envar.)

RTFM.
http://docs.oracle.com/javase/7/docs...jar/index.html

RTFM. RTFM. RTFM. RTFM. RTFM. RTFM. RTFM. RTFM. RTFM. RTFM. RTFM. RTFM. RTFM. RTFM. RTFM.

--
Lew
 
Reply With Quote
 
Roedy Green
Guest
Posts: n/a
 
      11-02-2012
On Fri, 26 Oct 2012 13:58:45 -0700 (PDT), zyng <(E-Mail Removed)>
wrote, quoted or indirectly quoted someone who said :

>
>My confusion is do I need to bundle helper.jar into hello.jar?


You could do in that way, but repackingt would be considered the baby
way. Embedding a intact jar in a jar is an unnatural act.

You could use Java Webstart to ensure the user has the latest jars.
See http://mindprod.com/jgloss/javawebstart.html

You could some sort of installer to handle this for you.
see http://mindprod.com/jgloss/installer.html

You could do it bare-chested style with an embedded
Class-Path in the master jar.
see http://mindprod.com/jgloss/jar.html
--
Roedy Green Canadian Mind Products http://mindprod.com
Ironically, even though the Internet was created by the US military
[DARPA (Defense Advanced Research Projects Agency)]
to withstand a nuclear attack, it is almost defenceless against malice
from any of its users


 
Reply With Quote
 
 
 
Reply

Thread Tools

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 On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
java -cp a.jar -jar b.jar => Works on Windows, not on Debian cyberco Java 4 02-14-2006 06:27 AM
jaas.jar, jta.jar jdbc-stdext.jar missing from jdk1.5 RPM muttley Java 0 10-20-2005 02:40 PM
Differences of xercesImpl.jar, xercesImpl-J.jar, dom3-xercesImpl.jar ? Arnold Peters Java 0 01-05-2005 10:59 PM
Differences of xercesImpl.jar, xercesImpl-J.jar, dom3-xercesImpl.jar ? Arnold Peters XML 0 01-05-2005 10:59 PM
how to disassembly a .jar file? how to see what are the classes inside the .jar file? lucy Java 6 09-07-2004 09:54 PM



Advertisments