11

I'm migrating a project to Android Studio 3 and Gradle 3.

We have multiples modules, with different dependencies. When I compile the project, everything looks fine.

I have one module with executable classes (main) to generate some internal reports. The problem is that inside it, I'm using methods from another modules, and one of them is throwing NoClassDefFoundError. It worked fine before the migration.

Here are the gradle files. Let's say that ModuleA is the executable one, ModuleB is an intermediate one, and ModuleC is the one crashing:

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

ModuleB:

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

ModuleC:

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

The class that can not be found is being used in ModuleC: com.google.common.base.Joiner and it's dependency (guava) it's being added inside it's gradle file

This is the error:

(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

Any idea what can be happening? Thanks a lot!

EDIT:

This is the dependency tree if I run gradlew. Guava is present in compile, default, runtime and so on..

 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

Edit:

We have another similar case (the same error) but with classLoader and 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
adalpari
  • 3,052
  • 20
  • 39
  • Do not use blockquote for exceptions, it messes up the formatting and makes it hard to read. Please [edit] your post and re-copy/paste the stack trace, then format as code. – Jim Garrison Nov 29 '17 at 18:00
  • Check if your Proguard setting is obfuscating the required class libraries. – CodeBulls Inc. Nov 29 '17 at 18:09
  • @CodeBullsInc. As you see in gradle code, I'm not using proguard in any of the modules. However, I'm using proguard in other module that can use the code in ModuleC, but is not keepeng com.google.common – adalpari Nov 29 '17 at 19:01
  • I might be wrong, but it seems that *com.google.guava:guava:19.0* is a transitive dependency via *com.google.inject:guice:4.1.0* Can you delete it and see if it fixes your issue. – Boris Dec 13 '17 at 11:20

5 Answers5

3

It turned out to be a bug in IntelliJ/Android Studio: https://github.com/gradle/gradle/issues/1276. The iml file created after a Gradle sync did not set the dependencies in a correct way.

Yrlec
  • 3,401
  • 6
  • 39
  • 75
2

Based on this document, this is a know issue:

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

Firebase plugin version 1.1.0 can cause a mismatch in Guava dependencies when using Android plugin 3.0.0-alpha5, resulting in the following error:

Based on the stacktrace, the issue lies around this plugin, although I do not see this as a dependency listed in your files.

But the suggested solution would be to exclude it from the classpath:

dependencies {
  classpath ('com.google.firebase:firebase-plugins:1.1.0') {
          exclude group: 'com.google.guava', module: 'guava-jdk5'
  }
}
JSONStatham
  • 353
  • 4
  • 18
1

you can check jar files used in project after build, maybe find more than one class with different version in this path

zohreh
  • 913
  • 1
  • 7
  • 9
0

As mentioned in this answer try printing the actual classpath at runtime.

It feels like you have some other version of Guava on classpath. I would also check if any of your dependencies have Class-Path attribute in their manifests. Guava may be included that way without being surfaced in Gradle dependencies.

Devstr
  • 4,431
  • 1
  • 18
  • 30
0

NoClassDefFoundError isn't caused by not finding that specific class, in which case a ClassNotFoundException would occur.

NoClassDefFoundError occurs when the class can't be loaded at runtime by the class loader. So, the class is found, but something bad happens when loading it. Typically this is some static stuff that goes wrong.

Even more typically for me, this is a class that loads a dll or a so file. Typically because the implementation of the class is native. Your jni error indicates this is what's going on. So, in this case, you'll need to find the dll or so that goes with the jar and add it to the PATH or LD_LIBRARY_PATH.

This issue seems to illustrate someone else with a similar issue, fixing his own issue some time later.: https://github.com/google/guava/issues/1533 The person isn't particularly detailed in his explain, but his/her description of the issue "As I am new in android I didn't know the libraries must be placed in the "libs" folder" is another indication to me, this is what's going bad.

Anyway, it is where NoClassDefFoundError has been bugging me in the past, especially when in combination with the jni errors.

But, as said, it's typically something that goes wrong in static code, like any uncaught exception. For instance it could well be caused by a class, in static code within that class, e.g. opening some file and not handling an exception. So, perhaps the tips listed here might also be helpful: http://javareferencegv.blogspot.be/2013/10/debugging-javalangnoclassdeffounderror.html

Johan Witters
  • 1,529
  • 11
  • 23