Search code examples
javagradlejvmdependenciesnoclassdeffounderror

Including Java library built with Gradle throws NoClassDefFoundError


I am writing a Java library and I would like to build the library with Gradle and then test it from a local test project.

I would prefer using Gradle 3.3 for my objective. The library should be built for Java5 and higher.

So far my build.gradle looks like this:

plugins {
  id 'jvm-component'
  id 'java-lang'
}

repositories {
  mavenCentral()
}

model {
  components {
    main(JvmLibrarySpec) {
      sources {
        java {
          dependencies {
            module 'commons-codec:commons-codec:1.10'
            module 'org.apache.httpcomponents:httpcore:4.4.6'
            module 'org.apache.httpcomponents:httpclient:4.5.3'
          }
        }
      }

      api {
        exports 'io.simplepush'
      }

      targetPlatform 'java5'
    }
  }
}

The source code of the library is located in src/main/java/io/simplepush/Notification.java and depends on the dependencies stated in the build.gradle file.

Building the library with ./gradlew build works fine and generates build/jars/main/jar/main.jar.

However when I run a test project from IntelliJ (after including main.jar into the test project), I get the following runtime error:
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/http/HttpEntity.

It seems like the test project does not know about the runtime dependencies needed by my library.

I am not sure on what is the correct way to tell the test project about the dependencies of my library. I do not want a fat jar which includes all dependencies.
Listing all dependencies in the test project itself is also not an option.
Preferably I want the library itself to tell the test project about which dependencies it needs.


Solution

  • I solved it by changing several things.
    Thanks to @Babl for pointing me in the right direction.
    My new library build.gradle looks like this:

    plugins {
      id 'java'
      id 'maven-publish'
    }
    
    sourceCompatibility = 1.5
    
    repositories {
      mavenLocal()
      mavenCentral()
    }
    
    dependencies {
      compile 'commons-codec:commons-codec:1.10'
      compile 'org.apache.httpcomponents:httpcore:4.4.6'
      compile 'org.apache.httpcomponents:httpclient:4.5.3'
    }
    
    publishing {
      publications {
        maven(MavenPublication) {
          groupId 'io.simplepush'
          artifactId 'project1-sample'
          version '1.1'
    
          from components.java
        }
      }
    }
    

    Now I can push the library to the local maven repository with ./gradlew publishToMavenLocal.

    The build.gradle of the test project uses the application plugin and defines a main class (which is Hello in my case). Then I can run ./gradlew installDist to generate an executable file (see Application plugin docs) which puts all dependencies in the classpath and runs just fine.

    group 'com.test'
    version '1.0-SNAPSHOT'
    
    apply plugin: 'java'
    apply plugin: 'application'
    
    repositories {
      mavenLocal()
      mavenCentral()
    }
    
    dependencies {
      compile 'io.simplepush:project1-sample:1.1'
    }
    
    mainClassName = "Hello"