Jar stürzt ab, obwohl in Eclipse alles ging

Wunderschönen Guten Tag,

ich muss ehrlich zugeben, ich bin gerade etwas verzweifelt. Ich habe das letzte halbe Jahr an einem Java-Projekt gearbeitet, was ich bei Zeiten in der Schule abgeben muss. Es ist nun fertig gestellt und in Eclipse läuft alles gigantisch knorke. :slight_smile: Zwischenzeitlich habe ich ab und an mal als jar exportiert, um einen Zwischenstand zu haben und anzusehen und es ging immer gut.
Nun bin ich mit dem Projekt fertig, exportiere es als jar-Datei und es öffnet sich einfach nicht. Mal geht es nicht auf, mal geht es kurz auf und stürzt danach ab. In Eclipse lässt sich das Spiel komplett durchspielen und läuft perfekt.

Ich weiß nicht, was ich da falsch gemacht habe. Und ich kann ja jetzt auch niemanden die Tausende Zeilen Quellcode durchackern lassen, das kann und möchte ich niemandem wirklich antun.

Aber ich kann ja mal etwas zu den Rahmenbedingungen erzählen.
Also, der Aufbau des Spiels ist folgender:

Im src Ordner stecken wie üblich alle Klassen drin. Diese habe ich ins Package ‚cafeint‘ gepackt.
Im Source-Ordner pictures liegen alle Bilder als png-Dateien vor.
Im Ordner Dateien liegen die beiden Dateien ‚bestenliste.txt‘ und ‚spielstand.txt‘.
Und im Ordner doc hab ich einfach ein Java-Doc reingenerieren lassen, weil ich um besser durchzusehen eh alle Methoden beschriftet habe.

Im Datei-Explorer sieht es so aus, um es mal kurz und schnell zu zeigen:

Exportiert habe ich das Programm als jar folgendermaßen in Eclipse, vielleicht ist der Vorgang ja falsch:

Wenn ich die Datei dann beispielsweise auf dem Desktop habe, habe ich parallel den Ordner dateien inclusive Inhalt, so wie ich das in Eclipse intern auch hatte.
Er lädt dann wie gesagt entweder nichts, oder den Willkommensbildschirm.

Der Quellcode aller Klassen ist hier zu sehen:

CafeIntMain enthält die Main-Methode.

Ich bin denkbar über jeden Hinweis darüber, was beim Exportieren schief gegangen sein könnte…

Vielen Dank! :slight_smile:

Gruß
Lukas

Hast Du das Jar schon mal in de Dos-Box gestartet, und den Stacktrace zu bekommen?

bye
TT

Hallo und Vielen Dank, dass Du mir antwortest! :slight_smile:

Ich muss gestehen, dass ich nicht weiß, was Du mit dos-Box meinst. Irgendein Konsolenähnliches Programm oder sowas?
Wie dem auch sei, ich habe mir gedacht, vielleicht meinst Du damit ja das Terminal (auf meinen OS X System) bzw. in Windows die Eingabeaufforderung.
Das habe ich also getan und habe das Programm versucht zu öffnen via Terminal:

java -jar CafeInternational.jar

Jetzt klappt es einwandfrei. Das gesamte Programm wird ausgeführt…
Aber die Datei auf dem Desktop als User anklicken, da passiert weiterhin nichts.
Ich muss ehrlich sagen, das verwirrt mich umso mehr.

PS: Es liegt nicht am Desktop, habe es gerade auch in zwei anderen Ordnern getestet.

Üblicherweise Verknüpft man Dateien mit Programmen die diese öffnen sollen.

Habe keinen Mac aber auf vielen Linux-Systemen sieht das ähnlich aus.

Rechtsklick auf das Jar oder wie man sonst das Kontextmenü erhält und dort unter Informationen sollte sich ein Öffnen mit finden.

Hier sollte dann java ausgewählt werden können. Evtl. steht dort was anderes.

Kann auch sein, dass man hierfür einen Launcher konfigurieren muss.

Dazu kommt, dass man unter Linux-System Dateien zuerst als ausführbar markieren muss. Sonst passiert eben nichts,
oder es wird versucht die Datei in einem Editor zu öffnen.

Hallöle,
vielen Dank allen für ihre Antworten.
Ich habe weitere Erkenntnisse.
Unter Windows ist es komplett ausführbar.

Auf meinem Mac wie gesagt nur über Terminal.
Markiert für Java zum Öffnen ist es. Als Standardprogramm ist der “Jar-Launcher 15.0.0” ausgewählt.
Nebenbei gesagt, habe ich das schon bei rund 20 anderen Programmen exportiert und sie waren immer ausführbar.
@BinaryLogic : Was meinst Du mit “als ausführbar markieren”? Bei mir startet er ja ab und an den Anfangsbildschirm des Programms.

Hatte noch nie ein Apple in der Hand von daher null Plan. Mit ausführbar meinte ich unter Linux “sudo chmod +x Dateiname”. (Ausführrechte). Aber das scheint eh nicht das Problem zu sein.

Nein, daran liegt es nicht. Die Ausführungrechte sind absolut korrekt eingestellt, gerade nochmal überprüft. :wink:

Verfolge mal weiter den Tipp vom Gast-Poster. Mit welchem Programm sind denn bei dir die Jar-Dateien verknüpft?

Moin,

ich habe mal einen kurzen blick ins repository geworfen. Ich gehe davon aus das so was nicht plattformübergreifend zuverlässig funktioniert:

[..]
public static File getWorkingDir() {
    return getAbsoluteFile(CURRENT);
}
[..]
public static URL getJarBase(Class<?> clazz) {
        URL rc = clazz.getResource(clazz.getSimpleName() + CONCAT);
        String name = clazz.getName().replace('.', '/').concat(CONCAT);
        name = rc.toString().replace(name, "");
        try {
            rc = new URL(null, name);
            return rc;
[..]
}
[..]
key = "./tisch_"+land+".png";
URL url = new URL(BaseURL.getJarBase(Spielfeld.class), key);
bitisch = ImageIO.read(url);```

Im Terminal oder aus Eclipse heraus ist das problemlos. Beim anklicken des JAR imho nicht.

Gruß
Fancy

Auch wenn einige der Auffassung sind das folgende Zeile schlecht wäre, wird dabei immer gerne wieder was verdreht.

if(!dir.isDirectory()) dir=dir.getParentFile();```
Warum wird Class.getProtectionDomain().getCodeSource() immer wieder als "schlecht" hingestellt : relativ einfach beantwortet : weil immer fälschlicherweise auf SE-API-Klassen rücksicht genommen wird.
Es ist richtig, führe ich diese Zeile z.B. mit String aus erhalte ich null. NA UND ? Sorry, aber ich hab es oft genug wiederholt : Was spielt das für eine Rolle und wen interessiert das überhaupt ? Es ist doch völlig belanglos das ein solches Konstrukt bei SE-API-Klasse NULL liefert wenn ich doch die aktuelle Klasse haben will. Oder um es andersrum zusammenzufassen : So lange diese Zeile in einer Klasse in einem Jar auf einem lokalen Datenträger ausgeführt wird funktioniert es.

Davon aber mal abgesehen ...

@TO
Du solltest komplett auf diesen Mist verzichten und direkt mit ClassLoader.getResourceAsStream() arbeiten.
Leider fehlen in deinem Repo die Grafiken, sonst könnte man das mal schnell zusammenbasteln. Normalerweise wird dafür ein gesondertes Verzeichnis, wie z.b. "rsc" genutzt was dann mit im JAR liegt. Dann gibt man noch den absoluten Pfad an und bekommt diese Zeile :
```//...
InputStream in=Thread.currentThread().getContextClassLoader().getResouceAsStream("/rsc/img/gast_"+this.gast.getLand()+"_"+this.gast.getGeschlecht()+".png");
//...```
Auch wenn das String-concat schon ziemlich evil aussieht (du solltest lieber eine vernünftige Ordnerstruktur nutzen statt eines komplexen Dateinamens) kannst du damit zuverlässig deines Grafiken laden ohne dich auch nur irgendwie mit irgendwelchen Pfaden auseinandersetzen zu müssen, denn das macht Java für dich.

Guten Abend und Vielen Lieben Dank für Eure Antworten,

das Einlesen von Dateien und das dann in JARs genauso machen ist bei mir seit jeher ein gigantisch blödes Problem, was ich irgendwie einfach nicht in den Griff bekomme. Es wäre sehr sehr schön, wenn ich das hier und jetzt (oder morgen, übermorgen und so hier im Thema, mit eurer Hilfe :wink: ) lösen könnte.

Also zur Vor-Geschichte:
Schaut euch mal das Thema hier an:
http://forum.byte-welt.net/java-forum-das-java-welt-kompetenz-zentrum-wir-wissen-und-helfen-/awt-swing-javafx-swt/14101-getsize-echte-hoehe-bestimmen.html
Ich selbst hatte damals in meiner Projektentwicklung haargenau das Problem schon mal und dachte damals, es gelöst zu haben.
Die Klasse BaseURL aus meinem GitHub Verzeichnis hab ich damals übrigens direkt auf Empfehlung von Spacerat aus dem Blog hier genommen und weiterbenützt.
Das sollte der Artikel hier gewesen sein:
http://forum.byte-welt.net/members/spacerat/2-von-arbeits-installations-und-resourcepfaden.html

So viel erst einmal dazu.

Das ist mein einjähriges Informatikprojekt und ich bin nun vor Monate vor Abgabe fertig und das ist das letzte Problem. Habe in der Zeit sehr viel dazu gelernt, auch durch euch hier! Vielen Dank! :slight_smile: Ist manchmal schockierend zu sehen, was ich damals für schockierende Fragen gestellt habe. :stuck_out_tongue:

Also zum Thema zurück, um das Problem anzugehen:

Leider fehlen in deinem Repo die Grafiken, sonst könnte man das mal schnell zusammenbasteln. Normalerweise wird dafür ein gesondertes Verzeichnis, wie z.b. „rsc“ genutzt was dann mit im JAR liegt.

Also wie gesagt ist das bei mir folgendermaßen:
Wenn man den Ordner öffnet, sind da fünf Verzeichnisse:

  • doc
  • bin
  • src
  • pictures
  • dateien (ähm, keine Ahnung, wieso das damals Deutsch benannt wurde)

doc, bin und src sollten in ihrer Funktion bekannt sein.
In Pictures lade ich direkt alle Bilder hoch, die dann auch direkt sofort ins Jar-Verzeichnis kommen.
Der Ordner Dateien enthält „bestenliste.txt“ und „spielstand.txt“, die werden während des Spiels aktiv beschrieben, weshalb sie also gesondert von der jar im Verzeichnis herum liegen sollten.

Ja, ich lade bei GitHub immer nur meine .java-Dateien hoch, vielleicht sollte ich mir angewöhnen alles hochzuladen, wäre einfacher gewesen.
Ich habe dies sofort nachgeholt.
Schaut euch das Verzeichnis an, da sind beide Ordner drin, für jemanden, der daran probieren möchte und vielleicht eine fesche Idee hat.
https://github.com/Dabendorf/CafeIntFiles
Ist jetzt nicht das gleiche Verzeichnis, weil ich das alte nicht verpfuschen wollte, aber ich schrieb ja oben, wo die gespeichert werden. :wink:

Auch wenn das String-concat schon ziemlich evil aussieht (du solltest lieber eine vernünftige Ordnerstruktur nutzen statt eines komplexen Dateinamens) kannst du damit zuverlässig deines Grafiken laden ohne dich auch nur irgendwie mit irgendwelchen Pfaden auseinandersetzen zu müssen, denn das macht Java für dich.

Ohne jetzt Deine Weisheit anzukratzen, aber das mit dem Dateinamen erfüllt doch den gleichen Zweck? :smiley:

Ich würde darum bitten, dass mir jemand nochmal erläutern könnte, wie ich das effektiver lösen könnte.

InputStream in=Thread.currentThread().getContextClassLoader().getResouceAsStream("/rsc/img/gast_"+this.gast.getLand()+"_"+this.gast.getGeschlecht()+".png");
//...```

Vielen Lieben Dank!
Schönes Wochenende
Lukas

Ich befürchte da sind leider - neben den Ressourcen - auch noch einige andere Probleme vorhanden. Das fängt schon damit an:

		 * Diese while-Schleife blockiert solange den weiteren Ablauf, bis der Spieler eine Taste drueckt.
		 * Da die Schleife nicht leer bleiben darf, enthaelt sie eine sinnfreie if-Bedingung, da der Zustand niemals auf 720 oder 2000 gesetzt werden wird.
		 */
		while(Variablen.getZustand()==-1)
            if(Variablen.getZustand()==720)
                Variablen.setZustand(2000);

Neben dem wtf Moment, ist die Variable hinter getZustand() nicht volatile. Auf einem richtigen Rechner wird diese Schleife niemals verlassen. Macht man die Variablen in Variablen (wtf) volatile, kommt man zwar einen Schritt weiter, aber dann fällt schnell auf das nicht alle Änderungen der Oberfläche vom EDT ausgeführt werden (fast keine?). Streut man ein paar SwingUtilities.invokeAndWait ein, sehe ich zwar das Spielfeld, Lust weiter zu sehen hatte ich dann aber leider auch nicht mehr.

Das soll alles nicht demotivierend klingen, aber ich befürchte da musst Du noch etwas Arbeit investieren.

Gruß
Fancy

Hallihallöle und vielen Dank für Deine Antwort,

ups, ich muss gestehen, diese unendliche While-Schleife ist mir im Nachhinein etwas peinlich. :smiley: Das muss in einem Moment gewesen sein, als ich nicht klar denken konnte und nur obskure Ideen hatte.
Ich habe die Schleife mal sofort wieder entfernt und aus dem System eliminiert. Stattdessen habe ich einfach den Quelltext, der nach der Schleife folgt und aufgehalten werden sollte in die Fenster-Schließen-Methode vom Startfenster (Programmstart.startbildschirm()) kopiert. Warum ich auf diese simple Sache nicht gleich gekommen bin, fragt einfach nicht weiter nach. :stuck_out_tongue:

Es funktioniert nun, so wie es im Schnelltest scheint einwandfrei!
Ich danke vielmals allen Menschen, die sich mit dem Problem mindestens eine Sekunde lang befasst haben.

Das soll alles nicht demotivierend klingen, aber ich befürchte da musst Du noch etwas Arbeit investieren.

Kein Problem. Das ist ja das Ziel des Projektes. :wink: Ich habe alles geschrieben und weiß, wo was liegt, wenn mir etwas auffällt, was besser laufen könnte (oder wenn jemand anders was sagt), bastle ich gerne herum.

Ich muss gestehen, das ist ganz schön obskur. Ich versuche seit Anfang des Projektes Ordnung im Programm zu halten und alles logisch aufeinander aufzubauen. Aber immer wenn ich eine neue Funktion hinzugefügt habe, wurde das System etwas untergraben. Finde es zum Beispiel seltsam, dass das Programm nun in „Spielstand“ und nicht bei „Programmstart“ anfängt.
Aber dass Du ohne viel gelesen zu haben sofort in die richtigen Methoden gekommen bist zeigt ja doch, dass ich es halbwegs übersichtlich gekriegt habe. :slight_smile:

Viele Grüße und Euch einen schönen Restsonntag!
Gruß
Lukas