MxLDevs
MxLDevs

Reputation: 19546

ClassNotFoundException from libraries that use other libraries

An overview of the problem: I have a CSVFile class in a Utils project that uses openCSV's CSVReader internally to load csv files.

Now I create a new project called MyTester and added Utils onto its classpath with the intention of using the CSVFile to work with csv files.

This is how it looks so far

MyTester
  src
    Tester.java

Utils
  src
    CSVFile.java
  lib
    opencsv.jar

Instantiating a CSVFile and passing in a file path will have it simply load the csv file:

import au.com.bytecode.opencsv.CSVReader;

public class CSVFile {

    public CSVFile(String filename) {
       CSVReader reader = new CSVReader( ... );
       // read CSV file
    }
}

This works fine.

So now I want to load a csv file in a separate project. I use the CSVFile as that is its purpose.

import CSVFile;

class Tester {
    public static void main(String[] args) {
       CSVFile reader = new CSVFile("test.csv");
    }
}

When I run Tester, I get a ClassNotFoundException while looking for CSVReader. The top of the stacktrace points to the line in the CSVFile constructor, so at least my code is doing what I expect it to do.

I am familiar with classpath related issues where I forget to add a required jar, so when I added the required jar to MyTester project, it works as expected.

But I don't understand why I need to do this.

If I'm using a class or method defined in a 3rd party library, I should not have to know anything about its implementation. However in this example, my Tester class needs opencsv.jar, which doesn't make sense to me. What could be causing the problem?

Upvotes: 0

Views: 44

Answers (1)

Alex
Alex

Reputation: 13961

If I'm using a class or method defined in a 3rd party library, I should not have to know anything about its implementation.

This is true when compiling code using a third-party library (in most cases) - if my project A depends on B.jar, which is provided by a project that in turn has a dependency on C.jar, then I don't usually need C.jar on my classpath to compile project A.

At runtime it's a different story. The first time some code in my project A accesses a method in a class from B.jar, the JVM will load they bytecode for that class from B.jar, initialize the class, and proceed to execute the method in question. Similarly, if during the course of executing the method from project B, there is a method call to a class defined in C.jar, the JVM will load that bytecode as well. So, C.jar needs to be on your classpath at runtime, but not necessarily at compile-time.

This is why tools such as Maven are so popular - they handle transitive project dependencies and automatically set up your classpath for you, based on a declarative description of your project's dependencies.

Upvotes: 1

Related Questions