包含使用Gradle构建的Java库会抛出NoClassDefFoundError

时间:2017-02-14 19:37:45

标签: java gradle jvm dependencies noclassdeffounderror

我正在编写一个Java库,我想用Gradle构建库,然后从本地测试项目中测试它。

我更倾向于使用Gradle 3.3作为我的目标。 该库应该为Java5及更高版本构建。

到目前为止,我的build.gradle看起来像这样:

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'
    }
  }
}

该库的源代码位于src/main/java/io/simplepush/Notification.java,取决于build.gradle文件中所述的依赖项。

使用./gradlew build构建库可以正常工作并生成build/jars/main/jar/main.jar

然而,当我从IntelliJ运行测试项目(包括main.jar之后进入测试项目)时,我收到以下运行时错误:
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/http/HttpEntity

似乎测试项目不知道我的库所需的运行时依赖性。

我不确定告诉测试项目关于我的库的依赖关系的正确方法是什么。 我不想要一个包含所有依赖关系的胖罐子 列出测试项目本身中的所有依赖项也不是一种选择 我希望库本身能够告诉测试项目它需要哪些依赖项。

3 个答案:

答案 0 :(得分:5)

您创建的库jar不包含IDE / Gradle随后可以解析的任何依赖性信息,以便能够编译/运行测试项目。我看到你正在使用maven中央存储库,所以你需要做的是将你的库发布到你的本地maven存储库,在测试项目中只需添加一个依赖信息(不仅仅是普通的jar文件)。

因此,在库和测试项目build.gradle中添加maven本地存储库配置。

repositories {
   mavenLocal()
   mavenCentral()
}

现在您需要将库发布到本地存储库。在使用gradle 3.3时,您可以使用Maven Publishing

因此,在库build.gradle中添加maven发布信息。

publishing {
    publications {
        maven(MavenPublication) {
            groupId 'io.simplepush'
            artifactId 'project1-sample'
            version '1.1'

            from components.java
        }
    }
}

Gradle“maven-publish”插件可以轻松地将其发布到本地存储库,自动创建PublishToMavenLocal任务。 所以你可以运行

  

gradle publishToMavenLocal

将把包含所有相关性信息的库发布到本地maven存储库中。

然后您只需要向测试项目build.gradle

添加库信息
dependencies {
        // other dependencies .....
        module 'io.simplepush:project1-sample:1.1'
}

答案 1 :(得分:2)

我通过改变几件事来解决它 感谢@Babl让我指向了正确的方向 我的新图书馆build.gradle看起来像这样:

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
    }
  }
}

现在我可以使用./gradlew publishToMavenLocal将库推送到本地maven存储库。

测试项目的build.gradle使用application插件并定义一个主类(在我的例子中是Hello)。然后我可以运行./gradlew installDist来生成一个可执行文件(参见Application plugin docs),它将所有依赖项放在类路径中并运行得很好。

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"

答案 2 :(得分:0)

这指定要检查的存储库以从

获取依赖项
repositories {
  mavenCentral()
}

因此,dependecies{}中的任何内容都将从上面的内容中获取。

如果测试项目没有与库项目结合,(@ RaGe示例)新测试项目需要知道从哪里获取依赖项 - 您需要使用首选方法发布它。

之后,您的新测试项目需要在build.gradle dependencies{}

中指定具有首选配置(编译...运行时等)的库

之后,根据IDE,您需要刷新类路径并从指定的存储库中下载依赖项,库依赖项中指定的传递依赖项(在本例中)将从测试项目repositories{}中获取

Library build.gradle

repositories {
  mavenCentral()
}

dependencies {
  module 'commons-codec:commons-codec:1.10'
  module 'org.apache.httpcomponents:httpcore:4.4.6'
  module 'org.apache.httpcomponents:httpclient:4.5.3'
}

测试项目build.gradle

repositories {
  mavenCentral() repository to fetch transitives
  mavenLocal() or any other repo that you published the library to
}

dependencies {
  pref-conf librarygroup:name:version
}

您可以在gradle中使用idea或eclipse插件来执行gradle ideagradle eclipseClasspath任务,以使用新添加的依赖项刷新它。

使用此解决方案,您不需要在库中打包传递依赖项

PS。在你说你想要可执行jar之后我很困惑。