Gradle exclude java class from lib replaced by own class to avoid duplicate

issue: when linking your app the linker finds two versions

  • org.luaj:luaj-jse:3.0.1:org.luaj.vm2.lib.jse.JavaMethod and
  • {localProject}:org.luaj.vm2.lib.jse.JavaMethod

howto fix: tell gradle to exclude org.luaj:luaj-jse:3.0.1:org.luaj.vm2.lib.jse.JavaMethod from building

android {
    packagingOptions {
        exclude '**/JavaMethod.class'
    }
}

I have not tried this with "exclude class" but it works for removing duplicate gpl license files a la "COPYING".

If this "exclude" does not work you can

  • download the lib org.luaj:luaj-jse:3.0.1 to the local libs folder,
  • open jar/aar with a zip-app and manually remove the duplicate class.
  • remove org.luaj:luaj-jse:3.0.1 from dependencies since this is now loaded from lib folder

I am not completely sure I understand your problem; however, it sounds like a classpath ordering issue, not really a file overwrite one.

AFAIK, gradle does not make a 'guarantee' on the ordering from a 'dependencies' section, save for that it will be repeatable. As you are compiling a version of file that you want to customize, to make your test/system use that file, it must come earlier in the classpath than the jar file it is duplicated from.

Fortunately, gradle does allow a fairly easy method of 'prepending' to the classpath:

sourceSets.main.compileClasspath = file("path/to/builddir/named/classes") + sourceSets.main.compileClasspath

I don't know enough about your system to define that better. However, you should be able to easily customize to your needs. That is, you can change the 'compile' to one of the other classpath (runtime, testRuntime, etc) if needed. Also, you can specify the jarfile you build rather than the classes directory if that is better solution. Just remember, it may not be optimal, but it is fairly harmless to have something specified twice in the classpath definition.


This is rather convoluted but it is technically feasible. However it's not a single task as asked by the poster:

  1. Exclude said dependency from build.gradle and make sure it's not indirectly included by another jar (hint: use ./gradlew dependencies to check it)
  2. create a gradle task that downloads said dependency in a known folder
  3. unpack such jar, remove offending .class file
  4. include folder as compile dependency

If it's safe to assume that you're using Linux/Mac you can run a simple command line on item 3, it's only using widely available commands:

mkdir newFolder ; cd newFolder ; jar xf $filename ; rm $offendingFilePath

If you don't care about automatic dependency management you can download the jar file with curl, which I believe to be widely available on both linux and mac.

curl http://somehost.com/some.jar -o some.jar

For a more robust implementation you can substitute such simple command lines with groovy/java code. It's interesting to know that gradle can be seen as a superset of groovy, which is arguable a superset of java in most ways. That means you can put java/groovy code pretty much anywhere into a gradle.build file. It's not clean but it's effective, and it's just another option.

For 4 you can have something along either

sourceSets.main.java.srcDirs += ["newFolder/class"]

at the root level of build.gradle, or

dependencies {
. . . 
   compile fileTree(dir: 'newFolder', include: ['*.class'])
. . .