运行时出现NoClassDefFoundError错误

11

我正在将一个项目迁移到 Android Studio 3Gradle 3

我们有多个模块,具有不同的依赖关系。当我编译项目时,一切看起来都很好。

我有一个包含可执行类(主类)以生成一些内部报告的模块。问题在于,在其中我使用了另一个模块的方法,其中一个模块抛出了NoClassDefFoundError。在迁移之前它是正常工作的。

以下是gradle文件。假设ModuleA是可执行的模块,ModuleB是中间模块,而ModuleC是崩溃的模块:

ModuleA:

dependencies {
    compile project(':ModuleB')
    compile group: 'com.googlecode.protobuf-rpc-pro', name: 'protobuf-rpc-pro-duplex', version: '3.3'
    testCompile "junit:junit:4.12"
}
sourceSets {
    test {
        java {
            srcDirs = ['test']
        }
        resources {
            srcDirs = ['test']
        }
    }
}
test {
    afterTest { desc, result ->
        println "Executing test ${desc.name} [${desc.className}] with result: ${result.resultType}"
    }
    workingDir = new File(rootProject.projectDir, '/Output')
    jvmArgs "-Xmx1536m"
}

模块B:

dependencies {
  compile project(':ModuleC')
  compile project(':AnotherModule')
    compile group: 'com.h2database', name: 'h2', version:'1.3.176'
    compile group: 'com.google.code.gson', name: 'gson', version:'2.7'
    compile group: 'org.json', name: 'json', version:'20080701'
}

模块C:

dependencies {
    compile project(':AnotherModule')
    compile project(':AnotherModule')
    compile project(':AnotherModule')
    compile group: 'org.slf4j', name: 'log4j-over-slf4j', version:'1.7.25'
    compile group: 'org.slf4j', name: 'jul-to-slf4j', version:'1.7.25'
    compile group: 'com.google.protobuf', name: 'protobuf-java', version:'2.6.1'
    compile(group: 'com.google.inject', name: 'guice', version:'4.1.0', classifier:'no_aop') {
        exclude(module: 'aopalliance')
    }
    compile(group: 'com.mortennobel', name: 'java-image-scaling', version:'0.8.6') {
      exclude group: 'com.squareup.retrofit2', module: 'retrofit'
    }
    compile group: 'com.google.guava', name: 'guava', version: '19.0'
}

ModuleC中正在使用找不到的类:com.google.common.base.Joiner,而它的依赖(guava)被添加在它的gradle文件中。

这是错误信息:

(1/124) RUNNING 'Internal check xxx'... 
Exception in thread "main" java.lang.NoClassDefFoundError: com/google/common/base/Joiner  
at com.degoo.util.FirebaseAnalyticsUtil.adjustTestKeyForFirebase(FirebaseAnalyticsUtil.java:35)   
at com.degoo.util.FirebaseAnalyticsUtil.adjustPropertyString(FirebaseAnalyticsUtil.java:16)   
at com.degoo.splittestrunner.SplitTestRunner.getQuery(SplitTestRunner.java:109)   
at com.degoo.splittestrunner.SplitTestRunner.run(SplitTestRunner.java:67)   
at com.degoo.splittestrunner.SplitTestRunner.main(SplitTestRunner.java:50) 
Caused by: java.lang.ClassNotFoundException: com.google.common.base.Joiner   
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)  ... 5 more

有什么想法可能会发生了什么? 非常感谢!

编辑:

如果我运行 gradlew,这是依赖树。 Guava 存在于编译,默认,运行时等。

 runtime - Runtime dependencies for source set 'main' (deprecated, use 'runtimeOnly ' instead).
 +--- project :ProjectBackup
 |    +--- com.myapp:PackJPG:1.5
 |    +--- com.myapp:xz:1.2
 |    +--- org.ocpsoft.prettytime:prettytime:2.1.2.Final
 |    +--- joda-time:joda-time:2.1
 |    +--- project :ProjectCommon
 |    |    +--- project :Utilities
 |    |    +--- project :ProcessPriority
 |    |    |    +--- com.nativelibs4java:bridj:0.6.2
 |    |    |    |    \--- com.google.android.tools:dx:1.7
 |    |    |    +--- net.java.dev.jna:jna:4.1.0
 |    |    |    +--- net.java.dev.jna:jna-platform:4.1.0
 |    |    |    |    \--- net.java.dev.jna:jna:4.1.0
 |    |    |    +--- org.tinylog:slf4j-binding:1.2
 |    |    |    |    +--- org.tinylog:tinylog:1.2
 |    |    |    |    \--- org.slf4j:slf4j-api:[1.6,1.8) -> 1.7.25
 |    |    |    \--- project :Utilities
 |    |    +--- project :ProjectHttp
 |    |    |    +--- commons-logging:commons-logging:1.2
 |    |    |    +--- org.tinylog:jcl-binding:1.2
 |    |    |    |    +--- org.tinylog:tinylog:1.2
 |    |    |    |    \--- commons-logging:commons-logging:[1.2,1.3) -> 1.2
 |    |    |    \--- commons-codec:commons-codec:1.10
 |    |    +--- org.slf4j:log4j-over-slf4j:1.7.25
 |    |    |    \--- org.slf4j:slf4j-api:1.7.25
 |    |    +--- org.slf4j:jul-to-slf4j:1.7.25
 |    |    |    \--- org.slf4j:slf4j-api:1.7.25
 |    |    +--- com.google.protobuf:protobuf-java:2.6.1
 |    |    +--- com.google.inject:guice:4.1.0
 |    |    |    +--- javax.inject:javax.inject:1
 |    |    |    \--- com.google.guava:guava:19.0
 |    |    +--- org.bouncycastle:bcprov-jdk16:1.46
 |    |    +--- com.mortennobel:java-image-scaling:0.8.6
 |    |    |    \--- com.jhlabs:filters:2.0.235
 |    |    +--- com.google.guava:guava:19.0
 |    |    \--- com.drewnoakes:metadata-extractor:2.9.1
 |    |         \--- com.adobe.xmp:xmpcore:5.1.2
 |    +--- project :PackJPGInterFileCompression
 |    |    +--- project :ProjectCommon (*)
 |    |    \--- com.myapp:PackJPG:1.5
 |    +--- com.h2database:h2:1.3.176
 |    +--- com.google.code.gson:gson:2.7
 |    +--- org.json:json:20080701
 |    \--- itadaki:jbzip2:0.9.1
 \--- com.googlecode.protobuf-rpc-pro:protobuf-rpc-pro-duplex:3.3
      +--- com.google.protobuf:protobuf-java:2.6.1
      +--- io.netty:netty-transport:4.0.23.Final
      |    \--- io.netty:netty-buffer:4.0.23.Final
      |         \--- io.netty:netty-common:4.0.23.Final
      +--- io.netty:netty-common:4.0.23.Final
      +--- io.netty:netty-handler:4.0.23.Final
      |    +--- io.netty:netty-buffer:4.0.23.Final (*)
      |    +--- io.netty:netty-transport:4.0.23.Final (*)
      |    \--- io.netty:netty-codec:4.0.23.Final
      |         \--- io.netty:netty-transport:4.0.23.Final (*)
      +--- io.netty:netty-codec:4.0.23.Final (*)
      \--- org.slf4j:slf4j-api:1.7.2 -> 1.7.25

编辑:

我们有另一个类似的情况(相同的错误),但涉及classLoader和tinyLog。

Error: A JNI error has occurred, please check your installation and try again
Exception in thread "main" java.lang.NoClassDefFoundError: org/pmw/tinylog/writers/Writer
    at java.lang.Class.getDeclaredMethods0(Native Method)
    at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
    at java.lang.Class.privateGetMethodRecursive(Class.java:3048)
    at java.lang.Class.getMethod0(Class.java:3018)
    at java.lang.Class.getMethod(Class.java:1784)
    at sun.launcher.LauncherHelper.validateMainClass(LauncherHelper.java:544)
    at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:526)
Caused by: java.lang.ClassNotFoundException: org.pmw.tinylog.writers.Writer
    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)
    ... 7 more

请勿使用块引用来处理异常,这会破坏格式并使其难以阅读。请编辑您的帖子,重新复制/粘贴堆栈跟踪,然后将其格式化为代码。 - Jim Garrison
检查一下你的Proguard设置是否混淆了所需的类库。 - CodeBulls Inc.
@CodeBullsInc。正如您在Gradle代码中所看到的,我没有在任何模块中使用Proguard。但是,我在其他模块中使用了Proguard,这些模块可以使用ModuleC中的代码,但不保留com.google.common。 - adalpari
我可能错了,但似乎 com.google.guava:guava:19.0 是通过 com.google.inject:guice:4.1.0 的传递依赖关系。你能删除它并查看是否解决了你的问题吗? - Boris
5个回答

3

2
根据这份文档,这是一个已知问题:

https://developer.android.com/studio/build/gradle-plugin-3-0-0.html

Firebase插件版本1.1.0在使用Android插件3.0.0-alpha5时可能会导致Guava依赖项不匹配,从而导致以下错误:
根据堆栈跟踪,问题出现在该插件周围,尽管我没有在您的文件中看到它作为依赖项列出。
但建议的解决方案是从类路径中排除它:
dependencies {
  classpath ('com.google.firebase:firebase-plugins:1.1.0') {
          exclude group: 'com.google.guava', module: 'guava-jdk5'
  }
}

我已经做了那个更改。我认为这与此无关,因为它在另一个模块中。 - adalpari

1
在构建后,您可以检查项目中使用的jar文件,可能会在此路径中找到多个带有不同版本的类。

0

就像在这个答案中提到的那样,在运行时尝试打印实际的类路径。

感觉您的类路径上有其他版本的Guava。 我还会检查是否有任何依赖项在它们的清单中具有Class-Path属性。Guava可能以此方式被包含,而不会出现在Gradle依赖项中。


0

NoClassDefFoundError并不是由于找不到特定的类而引起的,否则会出现ClassNotFoundException。

NoClassDefFoundError发生在类加载器无法在运行时加载类时。因此,找到了该类,但在加载它时发生了一些错误。通常这是一些静态内容出了问题。

对我来说更典型的情况是,这是一个加载dll或so文件的类。通常是因为该类的实现是本地的。您的jni错误表明正在发生这种情况。因此,在这种情况下,您需要找到与jar相对应的dll或so,并将其添加到PATH或LD_LIBRARY_PATH中。

这个问题似乎说明了其他人有类似的问题,后来解决了自己的问题:https://github.com/google/guava/issues/1533 这个人没有详细说明他的问题,但他/她对问题的描述“由于我是新手,我不知道库必须放在“libs”文件夹中”是另一个提示,这就是出了问题的原因。

总之,NoClassDefFoundError过去一直困扰着我,特别是与jni错误结合使用时。

但是,正如所说的那样,通常是在静态代码中出现问题,例如任何未捕获的异常。例如,它可能是由一个类在该类的静态代码中引起的,例如打开某个文件并未处理异常。因此,这里列出的提示也可能会有所帮助:http://javareferencegv.blogspot.be/2013/10/debugging-javalangnoclassdeffounderror.html


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接