1

I am painfully aware of the number of posts on this subject, but trawling through them hasn't helped me so far.

I have a maven project that uses a sqlite3 database. This runs successfully from within intelliJ. But I wanted to check that it was also capable of running as a jar by running this command:

    Bradleys-MBP:general-state-machine atkinsb$ java -cp target/general-state-machine-1.0-SNAPSHOT.jar com.bradley.atkins.state.GeneralStateMachine
No suitable driver found for jdbc:sqlite:/Users/atkinsb/.general_state_machine/default/20171112105601/database/sm.db
Exception in thread "main" java.lang.ClassNotFoundException: org.sqlite.JDBC
        at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
        at java.lang.Class.forName0(Native Method)
        at java.lang.Class.forName(Class.java:264)
        at com.bradley.atkins.state.StateMachineDb.executeSqlStatement(StateMachineDb.java:82)
        at com.bradley.atkins.state.StateMachineDb.createTables(StateMachineDb.java:33)
        at com.bradley.atkins.state.StateMachineInit.prepareDatabase(StateMachineInit.java:54)
        at com.bradley.atkins.state.StateMachineInit.prepare(StateMachineInit.java:12)
        at com.bradley.atkins.state.GeneralStateMachine.main(GeneralStateMachine.java:12)

I'm fairly inexperienced with Java and am struggling to understand why this fails. Possible answers that have come up while googling around are:

  • I need to somehow include the sqlite3 jar itself into my project. Perhaps making this a "fat jar" instead of relying on maven pulling it in as a dependency?
  • I need to add the sqlite3 jar to my class path in intelliJ. I don't know how to explicitly set this...
  • Explicitly load the jar from code like this:

    Class.forName("org.sqlite.JDBC");

just prior to establishing a connection...

  • I am trying to run the jar directly from the command line and need to set the path to sqlite3?

My maven setting for the dependency is:

  <dependency>
      <groupId>org.xerial</groupId>
      <artifactId>sqlite-jdbc</artifactId>
      <version>3.20.1</version>
  </dependency>

While my method looks like:

public static void executeSqlStatement(String sql) throws ClassNotFoundException {

Connection conn = null;

Class.forName("org.sqlite.JDBC");

try {
  conn = DriverManager.getConnection(url);
  Statement stmt = conn.createStatement();
  stmt.execute(sql);
} catch (SQLException e) {
  System.out.println(e.getMessage());
} finally {
  try {
    if (conn != null) {
      conn.close();
    }
  } catch (SQLException ex) {
    System.out.println(ex.getMessage());
  }
}

}

Like I said, this all works ok form within IntelliJ but am I going about confirming it will work as a standalone jar in the right way? I hope to eventually compile this project as a jar that other projects can pull in as an import.

Any advice on how to ensure I can get to that point would be much appreciated.

Thanks

Bradley

Kaliklipper
  • 355
  • 5
  • 19

1 Answers1

1

Your class is missing from the classpath (but you already know it obviously). The problem is caused by how you handle the packaging of your JAR and how you are trying to run your app.

When you run your program from InteliJ (or most IDE with Maven integration), it automatically includes on the classpath all the required JARs and dependencies Maven defined, and everything works fine. However when you run your app using the command line such as java -cp ..., Maven dependencies won't be appended to your classpath unless you speficically add them. As your class does not seem to be packaged in your JAR either, it is not on your classpath when you run the app.

If you were to run your program using the command line to reproduce exactly how it is run with IntelliJ, it would be a very long command with your target/classes directory and all your dependencies included with the cp option such as

java -cp C:/myproject/target/classes/;C:/somewhere/.m2/repository/org/xerial/sqlite-jdbc/3.20.1/sqlite-jdbc-3.20.1/sqlite-jdbc-3.20.1.jar; ... [lots of dependencies] ... ;C:/somewhere/.m2/repository/org/somepackage/someartifact.jar

I need to somehow include the sqlite3 jar itself into my project. Perhaps making this a "fat jar"

I think this is the right approach, with a little nuance. You'll probably want to create an executable jar if your want your JAR to be run as a standalone application using java command. Take a look at the Maven Shade Plugin or the Maven Assembly Plugin. A bit of Googling will tell you how to create your JAR with your dependencies.

I hope to eventually compile this project as a jar that other projects can pull in as an import.

If you want other projects to pull in your project as dependency using Maven you may not want to make your JAR executable or "fat jar". (it may cause various issues such as class overlapping) For example if your JAR is supposed to be a library or helper for other projects, you can deploy your app on a Maven repo and reference it in other projects using the same <dependency> mechanism.

When you define a dependency, Maven will pull any transitive dependencies as well (dependencies-of-dependencies). Try to run mvn dependency:tree -Dverbose to see all the dependencies used by your current app.

I don't know your level of familiarity with Maven, if any precision is needed comment it I'll edit my answer accordingly ;)

Pierre B.
  • 11,612
  • 1
  • 37
  • 58
  • Thanks very much, Pierre. That's very helpful. Yes I have limited experience with maven, I've been working on a maven project at work for the past couple of months and have learned a lot, but have no previous experience. You have clarified this for me quite a bit, and got me thinking about how I want to deploy this going forward. Once again, thanks! :) – Kaliklipper Nov 12 '17 at 15:04
  • Glad to help! If this answer helped you feel free to upvote and/or accept it ;) – Pierre B. Nov 12 '17 at 15:47