Creating a runnable jar referencing already installed thrid party jars - java

I have a java application that uses several 3rd party libraries. Up to this point, I've been exporting the java application (using Eclipse) to a runnable jar with those libraries packed into the jar. All has been well, but it started itching me how large the jar is. Considering this jar will be deployed over a WAN to thousands of work stations regularly, it would be best to make the package as small as possible. Where I'm at now, is I have Eclipse exporting the runnable jar and putting the external jar libraries in a sub folder next to the jar. This has considerably reduced the footprint of my application.... but I've come to realize that all of those jars in the sub folder already exist on the systems so it seems to be a waste of disk space to have a copy of them next to my application.
I would think that there would be a way to create a runnable jar that utilizes the CLASSPATH variable to utilize the existing libraries instead of having to have a copy of them nearby. Is there.... Or better yet, is there a better approach.
Thank you.

One way might be to manually specify a Class-Path in the manifest of the runnable jar. Class-Path entries are specified as URLs relative to the runnable jar location rather than an absolute value.
https://docs.oracle.com/javase/8/docs/technotes/guides/jar/jar.html#classpath
Additionally, when running the executable jar, the "-cp" parameter, and CLASSPATH environment variable will be ignored. The class path is set from the Class-Path line in the manifest.
http://docs.oracle.com/javase/8/docs/technotes/tools/windows/java.html

Related

Classpath and portability

I am new to Java and am using Eclipse to write Java code.
I've added lots of library (.jar) files as referenced libraries. I've also exported my project as a JAR file. My question is if I run this file on a computer where the referenced libraries are not at the same place as in my computer, will it run successfully?
I also made a runnable JAR file, whose size was much larger (~29 MB) as compared to the previous file (~24 KB).
My question is if I run this file on a computer where the referenced libraries are not at the same place as in my computer, will it run successfully?
No. You need to package the referenced JARs alongside your program JAR. It would be inconvenient for the end-user to have to download all the libraries that your program depends on. A couple of options, both possible using the Eclipse Export function.
Unpack all your dependent JARs and package them together with your code into one single executable JAR.
Specify in your program JAR manifest the classpath, which will contain relative paths to the location of your dependent JARs. These could be for example in a lib folder. The location of the lib folder relative to your program JAR would need to be the same for all your end-users, so it would make sense to package it all together.
It depends on the way you package jars with the runnable jar app. if you do it inside the jar or outside it then you should make a classpath entry to your manifest.mf.
you can even bundle the reference library in the same jar. So as you reduced the size to that extent i assume you removed those from the jar, which is not good approach in most cases. It is not recommended not to include referenced jar, unless you are 100% (not even 99.9%) sure those library WILL be in the system you would want to run.
EDIT:
to include the referenced jar in eclipse, you need to goto
project-properties>java-build-path>order-and-export
here check whatever libraries you want.

NoClassDefFoundError when referencing library

ok I have been search the internet all day and I have tried everything I have seen so i am wondering if someone could help.
I have a class that references a jar file which i have copied into my workspace in the lib folder the jar is: Classifier4J.jar, My class run perfectly on the console no error at all. When I try to package the .jar together and run the .jar from another program it gives me this error:
Exception in thread "pool-2-thread-1" java.lang.NoClassDefFoundError: net/sf/classifier4J/bayesian/IWordsDataSource...(10 more)
So clearly when i create the .jar its not able to reference the classifier4j library that it needs.
Things I have tried:
-Configure my build path
-Change the manifest file
-packaged the .jar with my .jar
-in eclipse went to file>export>java>runnable .jar then references the libraries
and many other things and nothing worked.
If anyway has had a similar issue or knows why this is happening could you please help me its really wrecking my head. Is this a problem with eclipse? can it be done through eclipse?
Thanks in advance
Jay
Ok after hours of looking at the problem i finally found the solution, When I output my classes as a .jar file I pointed it to my manifest file. I couldn't find what i was doing wrong because it didn't work. I decided to look at what was actually put into the jar and i saw that eclipse wasn't putting the correct manifest file i asked it to into the jar. It was putting a new one that looked like:
Manifest-Version: 1.0
where it should have looked like:
Manifest-Version: 1.0
Class-Path: ../lib/Classifier4J.jar
where the lib folder was back a directory from where my jar was. Everything is working perfectly now. Thank you for all your help.
Jay
It is hard to understand what you are actually trying to do, what you have actually tried, and what you expect to work, but I think the clue is here:
packaged the .jar with my .jar
This seems to imply that you are trying to create an "executable JAR" that contains all of the dependent JARs ... as-is. That won't work, an "executable JAR" cannot contain other JARs. (Well is can ... but you can't put them on your application's classpath without doing seriously complicated things.)
Basically, you have two options:
Don't try to include the dependent JARs in your (executable or not) application JAR. Keep them separate, and configure the execution classpath to include them. (And beware that for an executable JAR, the execution classpath must be configured as a Manifest entry. If you use java -jar ..., the -cp argument and $CLASS_PATH are ignored!)
Create a so-called "uber-JAR" by exploding the application JAR and all of the dependent JARs into a single directory and then creating a single JAR (with a suitable Manifest) from the lot. Your build tool or IDE may have support for this via some plugin.
I personally prefer the former approach ... combined with an "installation directory" for the application and a wrapper script. With the latter approach you make it hard for the user (or deployer) to mix-and-match versions of dependent JARs. Furthermore, the "uber-JAR" approach could conflict with a 3rd-party library's license.
At last, maybe we can get somewhere
.... the .jar file is ran from a tomcat application its a simple adapter for log files that all.
OK. You should have mentioned that before, because it is a critical piece of information. In order for a JAR file to usable within in a web container (i.e. in the same JVM as Tomcat), there must be a copy of the JAR file and all of its dependent JAR files in the web container's directory tree. There are two choices. Either you put them in the webapp's lib directory (i.e. webapp/WEB-INFO/lib) or you put them in the shared library directory ... which depends on which version of Tomcat you are using.
(The "executable JAR" approach won't work here. The classpath stuff you put in the Manifest is irrelevant. And nesting JAR files won't work either.)
The particular library is not included in your jar. You could either try to fix your eclipses build configuration to include that library, or add the library's jar to the classpath when you run the program.
The later may be easier. Just add the following to the command when you execute your program.
java -cp yourjar.jar;thelibrarysjar.jar com.your.Mainclass
You need to understand that NoClassDefFoundError hardly ever means that the identified class can't be found. Far more often, the class was found, but something prevented it from being successfully loaded.
The two most likely problems are -
Some other missing class that prevents the named class from being "verified".
Some incompatibility due to a different version of a class (usually another class) being used in compilation vs execution.
In your case it's most likely that when you have the problem you're picking up a different (and incompatible) version of some other jar, vs the environment during compilation.

How to package libraries into my jar using Ant

My application relies on two external libraries, I have both in jar format and have added them to my classpath, making it possible to run my application within NetBeans.
However, I would like to package my application in an easy to use jar file. When I tried the automatic method of jar creation provided by NetBeans (where it auto generates a jarfile in dist/) and ran it on another computer, I got lots of ClassNotFound (or similar) exceptions for classes that I could tell were supposed to be provided by my other libraries.
Is there a way I can include the other jarfiles I have into my own jar? I've never created an application which relies on other libraries before so this is a first for me.
You can add a "Class-path" line to your jar's manifest. The drawback is that you have to hard code the paths to a file system (not jar) location in the manifest. If you put them all in the same directory or a consistent relative directory, it should be manageable.
See: http://docs.oracle.com/javase/tutorial/deployment/jar/downman.html
Alternately you can try something line One-JAR: http://one-jar.sourceforge.net/

Adding comm.jar into my jar

I add comm.jar library into my .jar and I get javax.comm.NoSuchPortException.
Is this bug because I haven't add javax.comm.properties and win32com.dll into my jar? How can I add this file inside manifest?
Java does not support Jars within Jars. The correct way to ensure the javax.comm packages are on the run-time class-path of the application is to add a manifest that provides a relative path to the dependent Jar, and ensure that Jar is in the right place to be found. For details see Working with Manifest Files: The Basics & particularly Adding Classes to the JAR File's Classpath in the Java Tutorial.
There are other methods that can be used for applets and apps. launched using Java Web Start.
#Gogoo's answer says to copy stuff into your JVM installation directory.
It should work, but it is generally not a good idea:
The stuff that you install that way will be shared by all applications that you run using that installation. Depending on the what it is, it may interfere with other applications.
Each time you update your JVM, you have to remember to copy those files into the new installation directory.
IMO, a better idea is to put those files in a separate directory tree, and write a wrapper script to launch your application with the files on the classpath and library path. And/or see #Andrew Thompson's answer.
Try FatJar.
The Fat Jar Eclipse Plug-In is a Deployment-Tool which deploys an
Eclipse java-project into one executable jar.
It adds the Entry "Build Fat-JAR" to the Export-Wizard. In addition to
the eclipse standard jar-exporter referenced classes and jars are
included to the "Fat-Jar", so the resulting jar contains all needed
classes and can be executed directly with "java -jar", no classpath
has to be set, no additional jars have to be deployed.
copy comm.jar \jdk1.6\jre\lib\ext
copy win32com.dll \jdk1.6\bin
copy javax.comm.properties \jdk1.6\jre\lib
and start your.jar over command line:
java -jar your.jar

How to combine library with my jar?

Ok so i wrote a program that makes use of a 3rd party open source library and i want to package it with my program in a single jar. I'm using netbeans 6.8 and everything I've tried java always spit back the error:
java.lang.NoClassDefFoundError: libraryname;
off topic:also i would like to know how to make an executable-jar(exe) through netbeans if it is possible. (ive seen programs that were written in java but were an .exe)
EDIT discovered a plugin for eclipse called FatJar which can do what i want, but i cant find something similar for netbeans, is there such thing?
I'll start off with the obligatory disclaimer: Java executable JARs do not work this way. An executable JAR has a main class defined in the JAR's MANIFEST.MF file, and the MANIFEST also allows the definition of a class path to include libraries that the code in the executable JAR will need. The class path definition in the MANIFEST must enumerate every JAR or folder to put on the class path, relative paths are relative to the location of the executable JAR - not to paths contained inside the executable JAR. Executable JARs are launched with the "-jar" argument to the java executable, and both the java "-cp" flag and the CLASSPATH environment variable are ignored. As for why executable JARs were designed this way, you should be aware of the primary disadvantage of loading classes from JARs contained within JARs, even though the rest of this reply will focus on doing just that.
NOTE: I lost the original sun forum topic that explained it fully, but essentially it is because entries in the top level JAR can be read in a random access manner, but the entire embedded JAR must be read before any entries can be accessed, because the top level JAR might have compressed its entries.
I have used One-Jar successfully in the past, but the structure of the final resulting jar may not be what you expect. Essentially the One-Jar classes are the only non-JARd classes in the final jar; all other code (your code and any dependent library code) is included in the resulting as JAR as JAR files. Your application is JARed as a regular JAR file named "main.jar" in the final JAR's "main" folder. Any libraries your code needs is placed, as JAR files, in the final JAR's "lib" folder. And last but not least the final JAR's MANIFEST.MF file tells One-Jar what your main class is. Execution is a dead simple "java -jar final.jar [args your app uses]". I don't know how to take the next step of converting to an OS-native EXE regarding your off-topic question, but it would probably be best to use a different packaging mechanism than One-Jar anyway. I'm not sure how to go about this with NetBeans, my advice there is to use a build tool to package the final jar. Fortunately One-Jar provides instructions on generating the final jar with Ant, and that should be easily integratable into NetBeans.
I believe the Eclipse FatJar plugin creates a One-Jar executable JAR, so if that plugin seems to do what you want, then One-Jar is the way to do it. Personally, I used a Maven assembly.
There is a caveat - any signed libraries that require (or desire) to take advantage of Java's signed JAR verification may not work this way - Java Cryptographic Extension (JCE) implementations like BouncyCastle are a notable example. I think the reason is that the signature verification runs against the final JAR, not the signed library. Fortunately One-Jar allows the end user to add additional libraries to the classpath, something that is explicitly precluded when running an executable JAR; to workaround this you might be better off delivering the problematic JARs with the final JAR and an OS dependent launch script (.bat, .sh, etc).
I realize that this doesn't achieve exactly what you want, but I'll describe the customary method of distributing a standalone application. If it does meet your needs, you'll find that it's better supported by tools and more readily understood by users, because it follows established conventions.
Put your code in a jar (I'll call it app.jar) along with a META-INF/MANIFEST.MF file with entries like this:
Main-Class: com.y.app.AppMain
Class-path: third-party.jar blort.jar foo.jar
Then, you can throw all of the jars into a directory and run AppMain like this:
java -jar app.jar
If you want, you can put the third-party libraries in a single directory like lib and refer to them in the Class-path attribute using a path relative to the main jar: lib/third-party.jar That helps keep your distribution tidy.
My generic answer to your off-topic question is a (rather lengthy) article: Convert Java to EXE - Why, When, When Not and How. It has lots of links to free and commercial tools, but I have never seen a Netbeans plugin with such functionality, sorry.
To include another jar in your jar, you might find jarjar useful.
Executable jars just have a class defined as 'Main', if I'm not mistaken. This may be useful.
If there's not any concern of repackaging 3rd party jars into your final big jar, then this should be the easiest method.
If there are no licencing issues then the most preffered way is to unjar the actual jar and rejar it with your class files in it, to a new jar.
You can simply use the jar cmd itself for this, no big deal!!
if you use MAVEN, use "maven-shade-plugin" plugin. It will compile jar with all dependencies(3rd party and etc.)

Categories

Resources