Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

create jar with custom manifest with multiple libraries in classpath

I'm trying to create a jar from my eclipse and in order to be able to use the external .jars, I'm using this manifest with multiple .jars in the classpath:

Manifest-Version: 1.0
Sealed: true
Main-Class: src.BatchTester
Class-Path: . P:/Tools/xstream/1.4.2/lib/kxml2-2.3.0.jar P:/Tools/xstream/1.4.2/lib/xstream-1.4.2.jar P:/Tools/StringTemplate/4.0.5/lib/antlr-3.3-complete.jar P:/Tools/StringTemplate/4.0.5/lib/ST-4.0.5.jar P:/Tools/Jdbc/lib/sqljdbc4.jar

Obviously if I don't put the libraries in the classpath the following error appears:

java.lang.NoClassDefFoundError: com/thoughtworks/xstream/XStream

But when I put them in the classpath the error changes to:

java.lang.NoClassDefFoundError: src/BatchTester

So it seemps that it can't found my main class. I've tryed with several possibilities in the classpath, like adding or removing . to the classpath, but can't make it work.

Any idea of how can I solve this???

Thanks for your time and effort,


PS: After creating the .jar the classpath in the manifest inside looks like:

Class-Path: . P:/Tools/xstream/1.4.2/lib/kxml2-2.3.0.jar P:/Tools/xstr
 eam/1.4.2/lib/xstream-1.4.2.jar P:/Tools/StringTemplate/4.0.5/lib/ant
 lr-3.3-complete.jar P:/Tools/StringTemplate/4.0.5/lib/ST-4.0.5.jar P:
 /Tools/Jdbc/lib/sqljdbc4.jar 

with new lines and spaces, but even after changing it to the "right" format, I got the same problems.

PS2: I know that with some plugins like Fat-Jar you can make it work, but I don't want to insert more data than needed in my .jar

like image 534
magodiez Avatar asked Jun 07 '12 09:06

magodiez


3 Answers

Finally I've copied all the libs into the /lib folder and add them into the .jar with an ant target since seems to be OK with the IT guys (because it is a small application).

Here is the ant(in case is useful for someone):

<?xml version="1.0" encoding="UTF-8"?>
<project name="BatchTester" default="compile" basedir=".">
    <property name="external" value="lib/external-libs.jar"/>
    <target name="compile">
        <javac srcdir="jav"
               source="1.6"
        />
        <echo>Creating jar File</echo>
        <!--create a new .jar with all the external jars in /lib-->
        <jar jarfile="${external}">
            <zipgroupfileset dir="lib/">
                <include name="**/*.jar"/>
            </zipgroupfileset>
        </jar>
        <!--<sleep seconds="1"/>-->
        <!--create .jar file-->
        <jar jarfile="BatchTester.jar" index="true" filesetmanifest="mergewithoutmain">
            <fileset dir=".">
                <include name="**/jav/**/*.class"/>
                <exclude name="**/jav/**/*.java"/>
            </fileset>
            <zipfileset src="${external}">
                <exclude name="META-INF/*.SF"/>
            </zipfileset>
            <manifest>
                <attribute name="Main-Class" value="jav.BatchTester"/>
            </manifest>
        </jar>
        <!--delete previously created extern .jar-->
        <delete file="${external}"/>
    </target>
</project>
like image 196
magodiez Avatar answered Nov 15 '22 17:11

magodiez


Sorry If my questions sounds obvious for you.


*Launch Command *

In order to exclude any doubt, didn't you tried to launch your jar with this kind of command ?

java -jar myJar.jar -cp ./lib

If you use classpath option, you probably didn't ;). Option --classpath (or -cp) and -jar can't be uses together.

Prefer the use of relative path too, like ./lib instead of P:/Tools/... But, anyway, that won't solve your problem.


*Package Location *

As brimborium said, what is you real package ? src sounds very strange. We suspect an error around this.

In your BatchTester class, what have you written for package directive ? Nothing (i.e default package which isnot recommanded ?)?

Does you class begin with (get rid off comments)

public class BatchTester {

In that case, for sure, src should not be mentionned.

Here an example of manifest which work for me.

Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Created-By: Apache Maven
Built-By: jrRevy
Build-Jdk: 1.6.0_31
Main-Class: com.sopragroup.training.dojo1.MainSwingApp
Class-Path: dojo1-0.5.0-SNAPSHOT-lib/spring-core-3.1.1.RELEASE.jar doj
 o1-0.5.0-SNAPSHOT-lib/spring-asm-3.1.1.RELEASE.jar [blablabla]

with the following execution structure

/
|
+ --dojo1-0.5.0-SNAPSHOT.jar
|
+ --dojo1-0.5.0-SNAPSHOT-lib/
    |
    + --spring-core-3.1.1.RELEASE.jar

Obviously, I'm using maven for build my app, but the main idea is in.

like image 4
Jean-Rémy Revy Avatar answered Nov 15 '22 17:11

Jean-Rémy Revy


The manifest doesn't allow absolute paths in the Class-Path: tag. You have two alternatives:

  • Use relative paths as you already mention in your own answer

  • Use absolute paths via file protocol. This has been answered elsewhere too and it works absolute versus relative path names in jar manifest

    Class-Path: file:///P:/Tools/xstream/1.4.2/lib/kxml2-2.3.0.jar

In addition, you should not edit the manifest.mf manually without being aware of several limitations:

  • line maximum length must not exceed 72 characters, and after breaking one line you must insert an space in the first column.
  • There must be a carriage return after the last line otherwise, the file can't be parsed correctly
like image 2
Pedro Avatar answered Nov 15 '22 16:11

Pedro