web-dev-qa-db-fra.com

ClassNotFoundException lors de l'exécution de JAR, aucune erreur lors de l'exécution dans IntelliJ IDEA

Je commence juste à construire des applications Java (j'ai une expérience .NET) et j'essayais de construire une petite application de test dont le code entier est le suivant:

package com.company;

import com.Microsoft.sqlserver.jdbc.SQLServerDataSource;

import Java.sql.Connection;
import Java.sql.PreparedStatement;
import Java.sql.ResultSet;
import Java.sql.SQLException;

public class Main {

    public static void main(String[] args) throws SQLException {
        System.out.println("Buna lume!");

        SQLServerDataSource ds = new SQLServerDataSource();
        ds.setIntegratedSecurity(true);
        ds.setServerName("localhost");
        ds.setPortNumber(1433);
        ds.setDatabaseName("Test");
        Connection con = ds.getConnection();

        String SQL = "SELECT * FROM Test WHERE ID = ?";
        PreparedStatement stmt = con.prepareStatement(SQL);
        stmt.setInt(1, 2);
        ResultSet rs = stmt.executeQuery();

        while (rs.next()) {
            System.out.println(rs.getInt(1) + ", " + rs.getString(2));
        }
        rs.close();
        stmt.close();

        con.close();
    }
}

Si j'exécute l'application dans le IDE (IntelliJ IDEA 12.1.6 Community Edition), ayant SQL Server disponible, l'application fonctionne bien en faisant exactement ce qu'elle devrait.

Le pilote SQL Server est téléchargé à partir de Microsoft et ajouté en tant que bibliothèque externe. J'ai créé un artefact en tant que fichier JAR:

enter image description here

Maintenant, si j'inclus le sqljdbc4.jar dans le cliTest.jar (mon JAR), le JAR résultant est gros (550 Ko et inclut également les classes dans ce JAR). Ou je peux l'exclure. De toute façon, en cours d'exécution

Java -jar cliTest.jar

Résulte en

Buna lume!
Exception in thread "main" Java.lang.NoClassDefFoundError: com/Microsoft/sqlserv
er/jdbc/SQLServerDataSource
        at com.company.Main.main(Main.Java:15)
Caused by: Java.lang.ClassNotFoundException: com.Microsoft.sqlserver.jdbc.SQLSer
verDataSource
        at Java.net.URLClassLoader$1.run(Unknown Source)
        at Java.net.URLClassLoader$1.run(Unknown Source)
        at Java.security.AccessController.doPrivileged(Native Method)
        at Java.net.URLClassLoader.findClass(Unknown Source)
        at Java.lang.ClassLoader.loadClass(Unknown Source)
        at Sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
        at Java.lang.ClassLoader.loadClass(Unknown Source)
        ... 1 more

Je parie que je manque quelque chose d'assez basique, mais je n'arrive pas à comprendre ce qui cause exactement cela.

LE1: J'ai essayé d'ajouter sqljdbc4.jar (bien que cela ne semble pas nécessaire) et sqljdbc_auth.dll dans le répertoire contenant le JAR mais toujours pas de changement.

Édition ultérieure 2: Sur la base de la réponse de Nikolay, j'ai fait ce qui suit:

  1. Supprimé l'artefact existant
  2. Créé un nouvel artefact comme ceci:

enter image description here

enter image description here

.. et a abouti à ceci:

enter image description here

  1. Construire -> Construire des artefacts -> cliTest.jar -> Reconstruire

  2. Invite CMD dans le dossier contenant:

[cliTest.jar 566 Ko a été généré]

Java -jar cliTest.jar

Maintenant je reçois:

Exception in thread "main" Java.lang.SecurityException: Invalid signature file d
igest for Manifest main attributes
    at Sun.security.util.SignatureFileVerifier.processImpl(Unknown Source)
    at Sun.security.util.SignatureFileVerifier.process(Unknown Source)
    at Java.util.jar.JarVerifier.processEntry(Unknown Source)
    at Java.util.jar.JarVerifier.update(Unknown Source)
    at Java.util.jar.JarFile.initializeVerifier(Unknown Source)
    at Java.util.jar.JarFile.getInputStream(Unknown Source)
    at Sun.misc.URLClassPath$JarLoader$2.getInputStream(Unknown Source)
    at Sun.misc.Resource.cachedInputStream(Unknown Source)
    at Sun.misc.Resource.getByteBuffer(Unknown Source)
    at Java.net.URLClassLoader.defineClass(Unknown Source)
    at Java.net.URLClassLoader.access$100(Unknown Source)
    at Java.net.URLClassLoader$1.run(Unknown Source)
    at Java.net.URLClassLoader$1.run(Unknown Source)
    at Java.security.AccessController.doPrivileged(Native Method)
    at Java.net.URLClassLoader.findClass(Unknown Source)
    at Java.lang.ClassLoader.loadClass(Unknown Source)
    at Sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
    at Java.lang.ClassLoader.loadClass(Unknown Source)
    at Sun.launcher.LauncherHelper.checkAndLoadMain(Unknown Source)
16
Andrei Rînea

Eh bien, j'aurais dû construire le JAR sans le sqljdbc4.jar intégré.

La deuxième chose que j'aurais dû exécuter la commande comme ceci:

Java -classpath sqljdbc4.jar;cliTest.jar com.company.Main

.. et puis tout a fonctionné!

4
Andrei Rînea

Utilisation Java -cp au lieu de Java -jar et placez tous vos fichiers de dépendances dans classpath.

Une autre façon est de regrouper toutes les dépendances dans un seul pot, ce qui vous permet d'exécuter l'application en utilisant Java -jar.

MODIFIER:

Dans Java * .jar contient un grand nombre de classes. Lorsque vous créez votre propre application, le fichier jar de résultat contient généralement uniquement vos classes, mais doit toujours charger les classes à partir des bibliothèques externes que vous utilisez ( soi-disant dépendances).

Cela peut se faire de deux manières différentes:

  1. Vous créez un dossier pour votre application, par exemple, appelé lib et placez votre jar d'application et toutes les dépendances dans. Ensuite, vous exécutez l'application à l'aide de Java -cp lib:/\* com.company.Main ou (merci @NilsH, cette variante me manque) vous faites MANIFEST.MF fichier et spécifiez Main-Class et Classpath attributs à l'intérieur comme décrit ici

  2. Vous utilisez un outil spécial (comme maven-dependency-plugin si vous utilisez maven pour la construction) pour emballer toutes les classes, soit la vôtre, soit externe à un seul pot. Vous avez un énorme fichier et pouvez l'exécuter en utilisant Java -jar cliTest.jar.

Généralement, la première approche est préférée et en utilisant un MANIFEST.MF le fichier est une bonne forme.

5
Nikolay