Laden der Hibernate Cfg in .jar

HerrInfo

Aktives Mitglied
Hallo zusammen,

ich habe ein kleines Managementsystem geschrieben und möchte nun ein lauffähiges Programm daraus machen, das ohne JRE läuft. Dafür muss jedoch zunächst die .jar-Datei funktionieren. In dieser tritt ein Fehler auf, der in der IDE (IntelliJ) nicht auftritt.

Code:
java.util.concurrent.ExecutionException: java.lang.NoClassDefFoundError: org/hibernate/cfg/Configuration
        at java.base/java.util.concurrent.FutureTask.report(FutureTask.java:122)
        at java.base/java.util.concurrent.FutureTask.get(FutureTask.java:191)
        at java.desktop/javax.swing.SwingWorker.get(SwingWorker.java:612)
        at net.tim.Main$1.done(Main.java:24)
        at java.desktop/javax.swing.SwingWorker$4.run(SwingWorker.java:749)
        at java.desktop/javax.swing.SwingWorker$DoSubmitAccumulativeRunnable.run(SwingWorker.java:847)
        at java.desktop/sun.swing.AccumulativeRunnable.run(AccumulativeRunnable.java:112)
        at java.desktop/javax.swing.SwingWorker$DoSubmitAccumulativeRunnable.actionPerformed(SwingWorker.java:857)
        at java.desktop/javax.swing.Timer.fireActionPerformed(Timer.java:311)
        at java.desktop/javax.swing.Timer$DoPostEvent.run(Timer.java:243)
        at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:318)
        at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:773)
        at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:720)
        at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:714)
        at java.base/java.security.AccessController.doPrivileged(AccessController.java:400)
        at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:87)
        at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:742)
        at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
        at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
        at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
        at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
        at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
        at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
Caused by: java.lang.NoClassDefFoundError: org/hibernate/cfg/Configuration
        at net.tim.tsdb.DB_Manager.<init>(DB_Manager.java:14)
        at net.tim.Main$1.doInBackground(Main.java:15)
        at net.tim.Main$1.doInBackground(Main.java:12)
        at java.desktop/javax.swing.SwingWorker$1.call(SwingWorker.java:305)
        at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
        at java.desktop/javax.swing.SwingWorker.run(SwingWorker.java:342)
        at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
        at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
        at java.base/java.lang.Thread.run(Thread.java:1583)
Caused by: java.lang.ClassNotFoundException: org.hibernate.cfg.Configuration
        at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
        at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:526)
        ... 9 more

Ich denke, es liegt daran, dass Hibernate die Konfigurationsdatei nicht findet. Diese befindet sich jedoch im Ressourcenordner und wird mit
Java:
configuration.configure(Objects.requireNonNull(getClass().getResource("/hibernate.cfg.xml")));
geladen.

Vielen Dank im Voraus für eine schnelle Antwort.
 
Es liegt NICHT daran, dass die Konfigurationsdatei nicht gefunden wird. Es liegt am Classpath. Für die Ausführung des JAR's muss der Classpath genauso verfügbar/angegeben sein, wie in der IDE.
 
Dafür muss jedoch zunächst die .jar-Datei funktionieren.
Wie erstellst Du denn die jar Datei? Wie hast Du die Abhängigkeiten mit eingebunden?

Der Stacktrace sagt ja recht deutlich, dass das Problem eine fehlende Klasse ist:
ava.lang.ClassNotFoundException: org.hibernate.cfg.Configuration

Somit scheint Hibernate im Classpath zu fehlen. Also muss entweder die Abhängigkeit mit vorhanden sein als jar Datei und der classpath im Manifest gesetzt sein oder Du musst eine "fat jar" bauen, d.h. die jar Datei enthält auch alle Abhängigkeiten.
 
Die JAR-Datei wird über den Maven-Lifecycle erstellt, und ich habe Hibernate einschließlich der Konfigurationsklasse über eine Abhängigkeit in Maven eingebunden. Siehe Pom.xml:
Code:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>net.tim</groupId>
    <artifactId>TS-System</artifactId>
    <version>1.0</version>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>3.2.0</version>
                <configuration>
                    <archive>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <mainClass>net.tim.Main</mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <properties>
        <maven.compiler.source>21</maven.compiler.source>
        <maven.compiler.target>21</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

    </properties>

    <dependencies>

        <dependency>
            <groupId>org.hibernate.orm</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>6.4.4.Final</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.33</version>
        </dependency>
       
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>5.10.2</version>
            <scope>test</scope>
        </dependency>


    </dependencies>

</project>

Habe ich richtig verstanden, dass bei der Erstellung einer JAR-Datei diese Abhängigkeiten ignoriert werden?
 
Habe ich richtig verstanden, dass bei der Erstellung einer JAR-Datei diese Abhängigkeiten ignoriert werden?
Nein, die Abhängigkeiten werden nicht ignoriert. Aber es wird auch nichts weiter damit gemacht. Es wird lediglich eine JAR gebaut mit den Inhalten deines Projekts und es wird ein Manifest mit classpath und main class erstelt.

Hier evtl. einfach einmal als kleiner Hinweis: Eine jar Datei ist auch nur vom Format her eine ZIP Datei. Du kannst Dir also im Detail ansehen, was das Ergebnis Deines Projektes ist. Du kannst Dir also das Manifest ansehen und dann schauen, was da eigentlich enthalte ist. Nach meiner Erfahrung ist es immer besser, im Detail zu verstehen, was eigentlich passiert um dann aktiv eingreifen zu können.

Um erst einmal das Manifest zu verstehen, ist evtl. Understanding the JAR Manifest File | Baeldung hilfreich.

Wenn Du in das Manifest in Deinem JAR schaust, wirst Du die Abhängigkeiten einfach aufgelistet vorfinden. Also etwas wie:
Class-Path: somedependencie.jar someotherdependencie.jar

Das heisst, Du brauchst bei deinem jar File noch diese beiden jar files.

Um das zu bekommen, könntest Du im Maven Projekt auch die Abhängigkeiten kopieren lassen. Dazu könntest Du das maven-dependency-plugin verwenden.

Eine andere Möglichkeit könnte aber auch sein, die Abhängigkeiten einfach mit in dein jar File zu integrieren. Dann brauchst Du nur noch diese eine jar Datei mtzugeben. Dazu könntest Du das maven-shade-plugin verwenden.
Hier aber noch der wichtige Hinweis: Hier gibt es durchaus ein paar Stolperfallen. So darf man z,B. Signaturen zu entfernen (So eine Abhängigkeit signiert wurde) oder wenn da Services Bestandteil sein, dann muss man das Shade Plugin dies auch behandeln lassen (Wenn ich das richtig gesehen habe, dürfte das notwendig sein für den jdbc Treiber, damit der funktioniert)...

Wenn es um die Weitergabe von fertigen Anwendungen geht, greife ich aber sehr gerne auf JPackage zurück. Wie das in einem Projekt aussehen könnte, habe ich in kneitzel/JavaMavenApp (github.com) mal aufgezeigt. Die Erstellung eines Images ist im Profil Image implementiert, welches neben dem Kopieren der Abhängigkeiten und der eigentlichen jar Datei auch den jpackage Aufruf enthält:

XML:
        <profile>
            <id>Image</id>
            <activation>
                <property>
                    <name>Image</name>
                </property>
            </activation>
            <build>
                <plugins>
                    <!-- Copy dependencies -->
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-dependency-plugin</artifactId>
                        <version>${maven.dependency.plugin}</version>
                        <executions>
                            <!-- copy dependencies for the classpath -->
                            <execution>
                                <id>copy-dependencies</id>
                                <phase>package</phase>
                                <goals>
                                    <goal>copy-dependencies</goal>
                                </goals>
                                <configuration>
                                    <outputDirectory>${project.build.directory}/modules</outputDirectory>
                                    <includeScope>runtime</includeScope>
                                    <overWriteReleases>false</overWriteReleases>
                                    <overWriteSnapshots>false</overWriteSnapshots>
                                    <overWriteIfNewer>true</overWriteIfNewer>
                                </configuration>
                            </execution>

                            <!-- Copy the project jar -->
                            <execution>
                                <id>copy</id>
                                <phase>install</phase>
                                <goals>
                                    <goal>copy</goal>
                                </goals>
                                <configuration>
                                    <outputDirectory>${project.build.directory}/modules</outputDirectory>
                                    <artifactItems>
                                        <artifactItem>
                                            <groupId>${project.groupId}</groupId>
                                            <artifactId>${project.artifactId}</artifactId>
                                            <version>${project.version}</version>
                                            <type>${project.packaging}</type>
                                            <destFileName>${project.build.finalName}.jar</destFileName>
                                        </artifactItem>
                                    </artifactItems>
                                    <overWriteIfNewer>true</overWriteIfNewer>
                                </configuration>
                            </execution>
                        </executions>
                    </plugin>

                    <!-- Create the image -->
                    <plugin>
                        <groupId>com.github.akman</groupId>
                        <artifactId>jpackage-maven-plugin</artifactId>
                        <version>${jpackage.maven.plugin}</version>
                        <configuration>
                            <name>${appName}</name>
                            <type>IMAGE</type>
                            <mainclass>${main.class}</mainclass>
                            <input>${project.build.directory}/modules</input>
                            <mainjar>${jar.filename}.jar</mainjar>
                        </configuration>
                        <executions>
                            <execution>
                                <phase>install</phase>
                                <goals>
                                    <goal>jpackage</goal>
                                </goals>
                            </execution>
                        </executions>
                    </plugin>
                </plugins>
            </build>
        </profile>
 
Habe noch weiter recherchiert und jetzt eine Fat-JAR mit dem Maven Assembly Plugin erstellt. Nun sieht mein POM wie folgt aus:
XML:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>net.tim</groupId>
    <artifactId>TS-System</artifactId>
    <version>1.0</version>

    <properties>
        <maven.compiler.source>21</maven.compiler.source>
        <maven.compiler.target>21</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

    </properties>

    <dependencies>

        <dependency>
            <groupId>org.hibernate.orm</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>6.4.4.Final</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.33</version>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>5.10.2</version>
            <scope>test</scope>
        </dependency>


    </dependencies>

    <build>
        <finalName>TS-System</finalName>
        <plugins>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>3.6.0</version>

                <configuration>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                    <archive>
                        <manifest>
                            <mainClass>net.tim.Main</mainClass>
                        </manifest>
                    </archive>
                </configuration>

                <executions>
                    <execution>
                        <id>make-assembly</id>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>

            </plugin>

        </plugins>
    </build>

</project>
So funktioniert es auch. Nebenbei, gibt es einen Weg in Hibernate, eine JProgressBar mit dem Verbindungsfortschritt zu verknüpfen?
 

Zurück
Oben