# Jar Datei lässt sich nicht starten.



## DefconDev (11. Apr 2014)

Hallo zusammen,

ich habe schon etwas gegooglet finde aber nur wenige konkrete Themen dazu.

Ich habe ein Programm geschrieben mit Swing Komponenten und eine externe Libary importiert.

Als Werkzeug benutze ich Eclipse.

Als Jar oder Jar runnable lässt sich das Projekt nicht starten.

1. Schritt auswählen was ich erstellen möchte, habe jar gewählt.

2. Schritt dann mein Projekt ausgewählt plus die src dateien und die dort enthaltenden package dateien(default package) plus noch ein Ordner mit jpg. Die jpg sind im Code selber mit relativen Pfaden verbuden, also (src//jpg//name.jpg).

3. Schritt die standard Hächen wie export generated class files and ressis. Ebenso export Java source...
Genau so "compress the contents of jar file"

4. Export files class with compiling warning

5. Dann ebenso alles auf standard plus die Main auswählen.

Danach erstellt Eclipse mir eine Jar nur die lässt sich nicht ausführen, bzw. es passiert einfach nichts.
Wenn ich die mit Winrar öffne sind die Dateien alle vorhanden nur meine Manifest datei ist irgendwie etwas blank



```
Manifest-Version: 1.0
Sealed: true
Main-Class: Main
```

das ist das einzige was drin steht, ich denke mal es liegt an der Main, was genau muss da rein? Und wie gebe ich den Pfad der importierten Lib in meiner Manifest Datei an? Den Versuch die externe Lib in den src Ordner zu verschieben bringt auch keinen Nutzen. In Eclipse lässt sich das Projektw ie gewohnt starten und anwenden.

Meine Main heißt "Main".


----------



## Fab1 (11. Apr 2014)

Wenn du eine Runnable Jar mit Eclipse erstellst und es dann trotzdem nicht funktioniert, liegt es meiner Meinung nicht an der externen Lib.

Ich würde jetzt erstmal deine Jar mit der Konsole starten. In dieser bekommst du dann auch einen Fehler angezeigt und kannst gezielt vorgehen.

Mögliche Fehlerquellen:

Jar wird mit Java7 kompiliert, aber mit Java6 ausgefürt. Kann passieren wenn man Java Versionen nachinstalliert.
die externe Lib ist mir Java7 kompiliert und du hast allerdings nur Java6 drauf


am Pfad der Lib kann es natürlich schon liegen, wenn man allerdings eine Runnable jar erstellt, erstellt Eclipse automatisch eine Jar in Jar Loader Klasse und somit wird die Lib in die Jar gepackt.

Naja, einfach mal mit Konsole starten und Fehler googeln/posten.


----------



## DefconDev (13. Apr 2014)

Danke dir, für deine Antwort, werde die Tage das mal ausprobieren und dann berichten sollte die Fehlermeldung in der Konsole nichts in Google an Treffern bringen.


----------



## DefconDev (13. Apr 2014)

So habe die Jar ausgeführt in der Konsole und als erstes wird mir angezeigt dass meine ods. Datei nicht zu finden ist. Natürlich befindet sich die ods. in der Jar-Datei. 


```
Microsoft Windows [Version 6.1.7601]
Copyright (c) 2009 Microsoft Corporation. Alle Rechte vorbehalten.

C:\Users\Hades\Desktop>java -jar Polo2.jar
Exception in thread "main" java.io.FileNotFoundException: src\Test.ods (Das Syst
em kann den angegebenen Pfad nicht finden)
        at java.io.FileInputStream.open(Native Method)
        at java.io.FileInputStream.<init>(Unknown Source)
        at org.jopendocument.dom.ODPackage.<init>(Unknown Source)
        at org.jopendocument.dom.spreadsheet.SpreadSheet.createFromFile(Unknown
Source)
        at DateiHandler.einlesenWerte(DateiHandler.java:38)
        at Main.main(Main.java:24)
```


----------



## Fab1 (13. Apr 2014)

Nun gut, das ist doch schonmal was.

Du willst also eine .ods Datei einlesen. Java sucht also in dem falschen Ordner danach. Pfadprobleme sind in Java ja leider immer sehr eklig.

Am besten ist es du machst dir unter dem Root, also dem obersten Verzeichnis einfach einen Ordner "deinOrdner" in dem du deine Datei ablegst. Die Pfadangabe sollte dann "/deinOrdner/Test.ods" lauten alternativ sollte auch "../deinOrdner/Test.ods" gehen.

Fehlerquellen könnten hier sein, dass im Ordner src nach den Datei gesucht wird, diese aber im ordner bin (wo die kompilierten files drin sind) sucht. (Oder andersrum)

Solltest du die Variante mit dem eigenen Ordner testen, dann lösch bitte die alten Dateien aus dem Projekt, raus damit auch nur noch in dem Ordner die zu testende Datei vorhanden ist.


----------



## DefconDev (13. Apr 2014)

im Quellcode sieht mein String jetzt folgendermaßen aus:


```
File f = new File("/dokumente/Test.ods");
```

vorher:


```
File f = new File("src//Test.ods");
```

deine Variante liefert mir leider den selben Fehler.

Generell dachte ich bisher die Pfandangabe wird immer mit zwei Slashs angegeben.


----------



## Fab1 (14. Apr 2014)

Backslashes (\) müssen escaped werden. Ein normaler Slash (/) allerdings nicht.  BestPractise wäre hier wohl File.separator zu verwenden, dabei wird vom System das entspr. Zeichen aufgerufen.

Nun ist es wohl an der Zeit den Dateipfad einfach mal auszugeben in dem die Datei gesucht wird.

Das könnte z.B. so aussehen.

```
File f = new File("test.txt");
		
		if(f.exists()){
			
			System.out.println("Datei gefunden");
			System.out.println("Dateipfad: " + f.getAbsolutePath());
			
		}else{
			System.out.println("Datei nicht gefunden");
			System.out.println("Dateipfad: " +f.getAbsolutePath());
		}
```

If/Else kann man natürlich weglassen und einfach nur den Pfad ausgeben. Wichtig ist, dass du diese Ausgabe vor dem Benutzen der Datei einfügst, da ansonsten das Programm schon abschmiert bevor der Pfad ausgegeben wird.

Wenn du das Programm wieder über die Console startest, werden die Consolenausgaben darin natürlich angezeigt und du solltest den Pfad, nachdem gesucht wird, sehen.


----------



## turtle (14. Apr 2014)

> new File("/dokumente/Test.ods");


Das sieht so eigentlich ganz gut aus, aber...

Dies wird nicht beim Start aus einer JAR klappen, da eine JAR eine Zip-Datei ist und die ods-Datei  enthalten ist. Lies dir doch mal hierzu meinen Blog-Eintrag durch.

Üblicherweise werden "Dinge" aus dem ClassPath mit getClass().getResource("") geladen. Daher würde ich zunächst ein kleines Programm schreiben, welches die Resource lädt. Wenn dies eine korrekte Ausgabe, also nicht null ist, hast du den richtigen Pfad bzw. ClassPath zusammen.


```
import java.net.URL;

import javax.swing.JFrame;
import javax.swing.JOptionPane;

import static constant.ConstantEnum.*;

public class Turtle {
	public Turtle() {
		URL url = getClass().getResource("/dokumente/Test.ods");
		System.out.println(url);
	}

	public static void main(String[] args) {
		new Turtle();
	}
}
```


In Eclipse kann man sich den Classpath sehr schön anzeigen lassen, indem man bei einem Breakpoint sich die Properties per Rechts-Klick in der Debug-View anzeigen lässt. Bei mir 

```
...
C:\Java\jdk1.8.0\bin\javaw.exe -agentlib:jdwp=transport=dt_socket,suspend=y,address=localhost:50387 -Dfile.encoding=Cp1252 -classpath C:\Java\AllWorkspaces\JavaForum\Swing\bin;...
```
Und wenn man in das bin-Verzeichnis reinschaut sieht man, das darin alle Klassendateien aber AUCH der Dokumente-Ordner enthalten ist. Also ist der Pfad /dokumente/Test.ods richtig. 

Ich habe übrigens in Eclipse einen Ordner dokumente INNERHALB des src-Ordners angelegt. Und darin dann die Datei Test.ods erzeugt. Der "übliche" Eclipse-Build Prozess erzeugt nämlich aus den Java-Dateien die entsprechenden Class-Dateien UND kopiert alle anderen src-Teile (Bilder, Texte, ods-Dateien) ebenfalls in den Output-Ordner, den man im Build-Path angegeben hat.


----------



## DefconDev (14. Apr 2014)

Erst mal vielen Dank dass du dir die Zeit nimmst mir zu helfen!

Ich habe die Pfadausgabe jetzt mit eingebaut und konnte es endlich zum Starten bringen aber nur wenn ich die .ods Datei auslagere. Also wenn ich eine statische Pfadangabe aufs Dokument, welches sich dann auf dem Desktop befindet mache.


```
C:/Users/Hades/Desktop/Test.ods
```

Das Programm läuft wie erwartet, löst aber nicht ganz mein Problem.

Ich möchte schon dass es mit realtiven Pfaden arbeitet.

Hättest du ne weitere Idee? 



EDIT: @ Turtle, werde mir deinen Vorschlag direkt mal zu Gemüte führen.


----------



## DefconDev (14. Apr 2014)

Beim Versuch über  getClass().getResource("/dokumente/Test.ods"); Ist die Ausgabe aber leider Null.

Ich muss mich korrigieren... Geht, kann aber diese String /dokumente/Test.ods nicht in mein File f übertragen. Jedenfalls nicht wenn ich über Eclipse starte.


Ich muss mich etwas genauer ausdrücken. 


```
public class Pfad {
	
	
	public String getPfad() {
	        URL url = getClass().getResource("/dokumente/Test.ods");
	        System.out.println(url);
	        String z = url.toString();
	        return z;
	    	}
}
```


```
Pfad pfad = new Pfad();
	pfad.getPfad();
	File f = new File(pfad.getPfad());
```


----------



## DefconDev (14. Apr 2014)

C:/Users/Hades/Desktop/JavaProjekte/Age2MatchMaker/Age2Matchmaker/bin/dokumente/Test.ods

Das gibt syso an wenn ich f.getAbsolutePath()


----------



## turtle (14. Apr 2014)

> kann aber diese String /dokumente/Test.ods nicht in mein File f übertragen


Nein, das ist ja auch völlig falsch

Üblicherweise liest de aus einem File-Objekt, indem du einen FileInputStream zu einem File-Objekt bastelst.

Wie ich schon sagte, gibt es zu einer JAR-Datei keine File-Entsprechung, weil ja mehrere Dateien IN einer JAR stecken.

Und wenn du es aus einer JAR startest, sieht die URL bei mir so aus, also ist der String NICHT kompatibel zu dem wie ein File instanziert werden kann.

```
jar:file:/D:/turtle.jar!/dokumente/Test.ods
```

Aber du kriegst mit

```
InputStream resourceAsStream = getClass().getResourceAsStream("/dokumente/Test.ods");
```
einen InputStream, den du statt des FileInputStreams nehmen kannst,da Letzteres auch ein InputStream ist.


----------



## DefconDev (14. Apr 2014)

Das Problem welches ich jetzt habe, wenn ich komplett ohne File arbeite, kann jopendocument kein Spreadsheet erstellen, das geht nämlich nur mit der Klasse File.


----------



## turtle (15. Apr 2014)

Ich kenne jOpenDocument nicht.

Habs mir mal gerade runtergeladen und kurz angesehen. Und natürlich gibt es eine Methode, die ein Dokument OHNE File-Objekt lädt.

Ob das aber wirklich die beste Möglichkeit ist, muss jemand beantworten, der mehr Ahnung davon hat.

Mein kleines Test-Programm:

```
public static void main(String[] args) throws IOException {
		URL resource = ClassLoader.getSystemClassLoader().getResource("dokumente/test.ods");
		final JFrame mainFrame = new JFrame("Viewer");
		OpenDocument openDocument = new OpenDocument();
		openDocument.loadFrom(resource);
		//
		ODSViewerPanel viewerPanel = new ODSViewerPanel(openDocument);
		mainFrame.setContentPane(viewerPanel);
		mainFrame.pack();
		mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		mainFrame.setLocation(10, 10);
		mainFrame.setVisible(true);
	}
```

PS: Lese gerade noch,  "kein Spreadsheet erstellen". Das ist (natürlich) problematisch, da du in einer JAR nicht so ohne Weiteres eine Datei erstellen kannst. Da musst du genauer drüber nachdenken, was du eigentlich machen möchtest. LESEN sollte aus der JAR kein Problem sein, Ändern/Erstellen innerhalb einer JAR IST definitiv problematisch. Aber vielleicht verstehe ich deinen Workflow auch nicht

PS2: Es gibt übrigens den Konstruktor File(URI uri), den du ebenfalls verwenden kannst. Du musst "nur" aus der URL eine URI machen via resource.toURI().


----------



## DefconDev (15. Apr 2014)

Hallo Turtle,

du musst etwas Nachsicht mit mir haben, mir fehlt einfach noch die Erfahrung 

Mein Programm liest aus 4 verschiedenen Spreadsheets, also 4 Tabellen aus der .ods-Datei. Zur Laufzeit wird auch in die 4 Sheets geschrieben.

Es wäre natürlich nicht sehr tragisch wenn man die ods Datei außerhalb der Jar lagern würde.

Wie sähe es dann mit dem relativen Pfad aus? Wie muss ich den setzen, dass das Programm automatisch die ods Datei findet solange es sich im selben Verzeichnis befindet wie die jar-Datei? Ist das überhaupt möglich? Oder müsste ich eine Art import-Funktion einbauen?


Wie sähe denn generell die Möglichkeit aus mit einem exe-Wrapper? Kann ich die jar-datei und die ods. dort inkludieren und dann ohne Probleme in die ods.-Datei schreiben?


----------



## turtle (15. Apr 2014)

> du musst etwas Nachsicht mit mir haben, mir fehlt einfach noch die Erfahrung


Kein problem



> Wie muss ich den setzen, dass das Programm automatisch die ods Datei findet solange es sich im selben Verzeichnis befindet wie die jar-Datei? Ist das überhaupt möglich?


Klar geht das.
Und was muss gesetzt sein, damit Dateien ausserhalb der JAR-Datei gefunden werden?
Der ClassPath!

Das ändert NICHTS im Programm-Code, nur beim Aufruf muss der Ordner, in dem sich das/die Dokumente befinden, dem ClassPath hinzugefügt werden.

```
public static void main(String[] args) throws IOException, URISyntaxException {
		URL resource = ClassLoader.getSystemClassLoader().getResource("dokumente/test.ods");
		File spreadSheetFile = new File(resource.toURI());
		SpreadSheet spreadSheet = SpreadSheet.createFromFile(spreadSheetFile);
		System.out.println("Anzahl:" + spreadSheet.getSheetCount());
	}
```
Ich habe mal den dokumente-Ordner in Eclipse aus dem src-Zweig heraus genommen, also findet der ClassLoader die Resource nicht mehr. Du hast ja noch mein kleines Testprogramm, oder?
Danach habe ich den ClassPath bei der Run-Configuration geändert und den Ordner (OpenDocument) in dem der Dokumente-Ordner enthalten ist, hinzugefügt (siehe Screenshot). Mein kleines Testprogramm findet die Resource wieder, also ClassPath ok.

Damit beim Start der JAR der richtige ClassPath genommen wird, musst du das Programm richtig aufrufen. 

```
java -cp .;jOpenDocument-1.3.jar;turtle.jar Turtle
```
Der ClassPath ist also das aktuelle Verzeichnis (.), indem sich der Ordner dokumente mit dem Spreadsheet test.ods, die JAR-Datei turtle.jar (mit dem Hauptprogramm) und die Lib jOpenDocument befinden muss.

Mit einem EXE-Wrapper ändert sich da gar nichts. Du musst "nur" darauf achten, das deine Lieferung nicht nur aus der JAR besteht, sondern AUCH die OpenDocumente mit ausgeliefert werden müssen.


----------

