Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ClassNotFoundException upon running JAR, no errors while running in IntelliJ IDEA

I'm just starting to build Java apps (I do have .NET experience) and I was trying to build a small test app whose whole code is this :

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();
    }
}

If I run the app in the IDE (IntelliJ IDEA 12.1.6 Community Edition), having the SQL Server available, the app runs fine doing exactly what it should.

The SQL Server Driver is downloaded from Microsoft and added as an External Library. I have created an artifact as JAR file :

enter image description here

Now, if I include the sqljdbc4.jar in the cliTest.jar (my JAR) the resulted JAR is fat (550kB and includes the classes in that JAR too). Or I can exclude it. Either way, running

java -jar cliTest.jar

Results in

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

I bet I'm missing something quite basic but I just can't figure out what exactly is causing this.

LE1 : I tried adding sqljdbc4.jar (although it didn't seem necessary) and sqljdbc_auth.dll in the directory containing the JAR but still no change.

Later edit 2 : Based on Nikolay's answer I've done the following :

  1. Deleted the existing artifact
  2. Created a new artifact like so :

enter image description here

enter image description here

.. and resulted this :

enter image description here

  1. Build -> Build artifacts -> cliTest.jar -> Rebuild

  2. CMD Prompt at the folder containing :

[cliTest.jar 566 KB was generated]

java -jar cliTest.jar

Now I get :

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)
like image 211
Andrei Rînea Avatar asked Nov 03 '13 19:11

Andrei Rînea


2 Answers

Use java -cp instead of java -jar and put all of you dependencies jars to classpath.

Another way is pack all of dependencies to single jar, that allowing you to run application using java -jar.

EDIT:

In Java *.jar file contains a bulk of classes. When you build your own app, typically, result jar file contains only your classes, but still have to load classes from external libraries you use (so-called dependencies).

It can be done two different ways:

  1. You create a folder for your application, for example, called lib and place your application jar and all dependencies into. Then you run application using java -cp lib:/\* com.company.Main or (thanks @NilsH, I miss this variant) you make MANIFEST.MF file and specify Main-Class and Classpath attributes inside as described here

  2. You use special tool (like maven-dependency-plugin if you use maven for build) to pack all classes, either your own, either external to single jar. You got one huge file and can run it using java -jar cliTest.jar.

Generally, first approach is preferred and using a MANIFEST.MF file is a good form.

like image 196
Nikolay Avatar answered Nov 11 '22 12:11

Nikolay


Well I should have built the JAR without the sqljdbc4.jar embedded.

The second thing I should have run the command like so :

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

.. and then all worked!

like image 6
Andrei Rînea Avatar answered Nov 11 '22 13:11

Andrei Rînea