# Erstellen einer ausführbaren JAR-Datei mit externen Libaries



## Ollek (26. Feb 2010)

Hallo,

ich will gerade meine erste JAR Datei erstellen mit externenen Libaries erstellen..

Allerdings bekomme ich immer wieder die gleiche Fehlermeldung:
---------------------------
Java Virtual Machine Launcher
---------------------------
Could not find the main class: unterordner.SFTPCopy. Program will exit.
---------------------------
OK   
---------------------------

Ich habe die JAR auch durch eine Konsole gestartet... Da habe ich folgende Exception bekommen... Ich muss sagen, in Eclipse läuft das Projekt einwandfrei, ohne Exceptions. Die Exception habe ich als JPG angehängt an den Post.

So meine Schritte, wie ich die JAR erstelle:

Schritte: src - rechtsklick - Export --> JAR File --> sourcen ausgewählt --> Next --> Next --> User existing manifest from workspace --> manifest.txt ausgewählt, die im Projekt liegt --> Finish

In meiner Manifest.TXT steht folgendes:


```
Manifest-Version: 1.0
Main-Class: de.unterordner.core.SFTPCopy
Class-Path: . ./ .lib/*.jar .lib/*.zip
```

Dann habe ich einen Ordner erstellt mit einem weiteren Ordner lib. Die JAR liegt im ersten Ordner.

Was mache ich denn nun falsch?? Die Exception, die die Konsole wirft hilft mir leider auch nicht weiter.. Bzw. ich verstehe es nicht, da es in Eclipse ja einwandfrei läuft... Muss es nur heute fertig bekommen :-( Quäle mich schon 2 Tage daran, habe schon lange gegoogelt und einiges ausprobiert.

Gruß

Ollek


----------



## Gast2 (26. Feb 2010)

Es gibt einen mehrere ANT Tasks um ein richtiges "FatJar" zu bauen. Z.B. One-JAR Task baut dir ein Jar in dem alle zur runtime benötigten Jars mit reingepackt werden.

Deliver Your Java Application in One-JAR™ !

Im build.xml musst du gar nicht mal viel machen, den Task einbinden:

[XML]
<property name="one-jar.dist.dir" value="./lib/compile/" />
<property name="one-jar.version" value="0.96" />

<path id="oneJar.Classpath">
    <pathelement location="${basedir}/lib/one-jar-ant-task-${one-jar.version}.jar" />
</path>
<taskdef name="one-jar" classname="com.simontuffs.onejar.ant.OneJarTask" classpathref="oneJar.Classpath" />
[/XML]

Dann noch fix ein Manifest anlegen:

[XML]
<echo file="${build.dist}/${build.distname}.mf" append="false">
Manifest-Version: 1.0
Specification-Title: ${build.distname}
Main-Class: com.simontuffs.onejar.Boot
One-Jar-Main-Class: com.mypackage.MainClass
</echo>
[/XML]

Letzlich der Aufruf von dem OneJar Task:

[XML]
<one-jar destfile="${build.dist}/${build.distname}-standalone.jar" manifest="${build.dist}/${build.distname}.mf">
    <main>
        <fileset dir="${build.classes}">
            <include name="**/**" />
        </fileset>
    </main>
    <lib>
        <fileset dir="./lib/runtime">
            <include name="**/*.jar" />
         </fileset>
    </lib>
</one-jar>
[/XML]

Das funktioniert bei mir immer - einzige Ausnahmen ist wenn du native libs einpackst wie odbc und oci nutzt. Dann wirft der erste Classloader eine fiese Warnung - funktoniert aber trotzdem


----------



## Ollek (26. Feb 2010)

Puuuuh... einfacher geht das nicht???
Gibts dazu nicht tutorials oder sonstiges??? :-(


----------



## eRaaaa (26. Feb 2010)

Eclipse sollte das auch können, benutze anstatt 
	
	
	
	





```
Export -> JAR File[/c] einfach mal[code]Export -> Runnable JAR File
```
 (ab 3.4 *glaub*)


----------



## Ollek (26. Feb 2010)

Hat geklappt.... Allerdings habe ich meinen lib Ordner (hatte ich vorher im Projekt Ordner) in den src-Ordner gepackt und dann hate rs gemacht...

Aber ich würde trotzdem gerne mal wissen, wie man eine JAR Datei erstellt, die die libs aus dem lib ordner liest... Da ich das Programm ja so erweitern kann bzw. falls es mal updates gibt... Gibts dazu nen tutorial???


----------



## faetzminator (26. Feb 2010)

Ich würde an Stelle von [c]Class-Path: . ./ .lib/*.jar .lib/*.zip[/c] einfach die ganzen Namen der Jars angeben. Mach ich immer so.


----------



## Ollek (26. Feb 2010)

habe ich auch gemacht, alelrdings hat er trotzdem gemeckert... Ansich ist das Thema ja erledigt, nur fürs nächste mal würde ichs halt schonmal gerne wissen und ausprobieren ;-)


----------



## faetzminator (26. Feb 2010)

Wird das Jar aus dem Ordner ausgeführt, welcher es beinhaltet? Dann sollte es funktionieren.


----------



## Ollek (26. Feb 2010)

Wie meinst du das??

Also das jar liegt in einem Ordner und in diesem Ordner gibts einen Unterordner der lib heißt, wo die verschiedenenen Libaries drin liegen.


----------



## Gast2 (26. Feb 2010)

Ollek hat gesagt.:


> Hat geklappt.... Allerdings habe ich meinen lib Ordner (hatte ich vorher im Projekt Ordner) in den src-Ordner gepackt und dann hate rs gemacht...
> 
> Aber ich würde trotzdem gerne mal wissen, wie man eine JAR Datei erstellt, die die libs aus dem lib ordner liest... Da ich das Programm ja so erweitern kann bzw. falls es mal updates gibt... Gibts dazu nen tutorial???



Was hast du gegen ANT? Ist eigentlich gar nicht so schwierig und aufwändig. Wenn du einmal eine Basis build.xml hast verwendest du die immer wieder:

Also hier kommt dein gefordertes Tutorial in kurzform:

Ich lege meine Projekte immer so an:



```
Project
  - src
  - test-src
  - lib
      \- compile // enthält nur libs die fürs compilieren notwenig sind, z.b. ant contrib
      \- runtime // enthält die libs die zur runtime benötigt werden
  - conf
  build.xml
  build.properties
```

Die build.xml enthält dann:
[XML]
<?xml version="1.0"?>
<project name="myProject" basedir="." default="ProjectBuild">

	<description>
       blubber
    </description>

	<property file="build.properties" />

	<import file="${basedir}/lib/compile/one-jar-ant-task.xml" />

	<!--  classpath -->
	<path id="compilepath">
		<pathelement location="${basedir}/lib/compile/ant-contrib-0.6.jar" />
		<pathelement location="${basedir}/lib/compile/one-jar-ant-task-0.96.jar" />
	</path>

	<path id="classpath">
		<fileset dir="${build.dir}/topack">
			<include name="*.jar" />
		</fileset>
	</path>

	<taskdef resource="net/sf/antcontrib/antcontrib.properties" classpathref="compilepath" />


	<!-- ****************************************************************************************************************************
            Default target
    **************************************************************************************************************************** -->

	<target name="ProjectBuild" depends="dist" description="build the project" />


	<!-- ****************************************************************************************************************************
        Private targets below... 
    **************************************************************************************************************************** -->

	<target name="prepare" depends="clean">
		<mkdir dir="${build.dir}" />
		<mkdir dir="${build.dir}/src" />
		<mkdir dir="${build.dir}/classes" />
		<mkdir dir="${build.dir}/topack" />
		<!-- copy source folders -->
		<copy todir="${build.dir}/src" overwrite="true">
			<fileset dir="${basedir}/src">
				<include name="**/**" />
			</fileset>
		</copy>
		<!-- copy libs -->
		<copy todir="${build.dir}/topack" overwrite="true">
			<fileset dir="${basedir}/lib/runtime">
				<include name="**/**" />
			</fileset>
		</copy>
	</target>


	<target name="clean">
		<delete dir="${build.dir}" />
	</target>

	<target name="compile" depends="prepare">
		<javac srcdir="${build.dir}/src" destdir="${build.dir}/classes" deprecation="false" nowarn="true" target="1.6" source="1.6" debug="true" classpathref="classpath" debuglevel="lines,vars,source" />
	</target>

	<target name="manifest">
		<if>
			<equals arg1="${build.oneJar}" arg2="yes" casesensitive="false" />
			<then>
				<echo file="${build.dir}/MANIFEST.mf" append="false">
Manifest-Version: 1.0
Specification-Title: ${build.project}
Main-Class: com.simontuffs.onejar.Boot
One-Jar-Main-Class: ${build.mainclass}
               </echo>
			</then>
			<else>
				<echo file="${build.dir}/MANIFEST.mf" append="false">
Manifest-Version: 1.0
Specification-Title: ${build.project}
Main-Class: ${build.mainclass}
         </echo>
			</else>
		</if>

	</target>

	<target name="dist" depends="compile,manifest">
		<if>
			<equals arg1="${build.oneJar}" arg2="yes" casesensitive="false" />
			<then>
				<echo>Building oneJar distribution</echo>
				<one-jar destfile="${build.dir}/${build.project}-${build.version}-standalone.jar" manifest="${build.dir}/MANIFEST.mf">
					<main>
						<fileset dir="${build.dir}/classes">
							<include name="**/**" />
						</fileset>
					</main>
					<lib>
						<fileset dir="${build.dir}/topack">
							<include name="**/**" />
						</fileset>
					</lib>
				</one-jar>
			</then>
			<else>
				<echo>Building normal jar</echo>
				<jar destfile="${build.dir}/${build.project}-${build.version}-nolib.jar" basedir="${build.dir}/classes}" manifest="${build.dir}/MANIFEST.mf">
				</jar>
			</else>
		</if>
	</target>

</project>
[/XML]

die build.properties:

[XML]
# the version of the build
build.version=0.01
# name of the project
build.project=myProject

# decides if a one Jar standalone version will be build or a classic jar
build.oneJar=Yes

# the Class with the main to start
build.mainclass = com.mypackage.MyMain
[/XML]

die one-jar-ant-task.xml in lib/compile 
[XML]
<?xml version="1.0"?>
<project>
    <!-- The following property is expected to be overridden by caller -->   
    <property name="one-jar.dist.dir" value="./lib/compile/"/>   
    <property name="one-jar.version" value="0.96"/>
	<taskdef name="one-jar" classname="com.simontuffs.onejar.ant.OneJarTask" 
		classpath="${one-jar.dist.dir}/one-jar-ant-task-${one-jar.version}.jar" onerror="report"/>

</project>
[/XML]

Ansonsten in lib/compile rein:
ant-contrib-0.6.jar <- einfach mal nach googlen
one-jar-ant-task-0.96.jar - einfach mal nach googlen, bzw mein ersten kommentar folgen


Dann einfach die build.xml in den ANT view ziehen in Eclipse und doppelklicken - fertig.

EDIT: hab die build.xml nochmal angepasst


----------

