Skip to content

Instantly share code, notes, and snippets.

@rock3r
Last active July 19, 2021 18:29
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save rock3r/cf243af5d4e6482f784396b01f04b7ac to your computer and use it in GitHub Desktop.
Save rock3r/cf243af5d4e6482f784396b01f04b7ac to your computer and use it in GitHub Desktop.
Utility Gradle task to find where duplicate classes come from (for Gradle 4.1+)
// H/t to https://github.com/ethankhall/scripts/blob/master/gradle/find-file.gradle for the idea;
// this re-written version actually works in modern Gradle and Android Gradle plugins.
task findInDependencies {
doLast {
println()
def resolvableConfigs = project.getConfigurations()
.stream()
.filter { it.isCanBeResolved() }
resolvableConfigs.each { config ->
config.resolve()
.stream()
.filter {
//noinspection GroovyPointlessBoolean
zipTree(it)
.filter { it.name.startsWith 'Nonnegative' } // TODO replace `Nonnegative` with what you are looking for
.each { println " Match: $it.path" }
.toList()
.isEmpty() == false
}
.each {
println "Found in `$config.name: $it.name`\n"
}
}
}
}
@rock3r
Copy link
Author

rock3r commented Jul 14, 2017

This is useful for when your build breaks because of errors such as com.android.dex.DexException: Multiple dex files define L...;.

Common culprits are Findbugs 3.0.1 and its annotations that include the JSR305 annotations, such as javax/annotation/Nonnegative etc. In these cases you need to manually exclude those transitive dependencies from the all those that declare them, and re-declare them explicitly yourself. The dependencies task can be very useful to determine what top-level dependencies transitively include them.

@saket
Copy link

saket commented Mar 29, 2018

LeftShift has been deprecated and will no longer work with Gradle v5. This can be fixed by using this instead:

task findInDependencies {
  doLast {
    println()

    def resolvableConfigs = project.getConfigurations()
        .stream()
        .filter { it.isCanBeResolved() }

    resolvableConfigs.each { config ->
      config.resolve()
          .stream()
          .filter {
        //noinspection GroovyPointlessBoolean
        zipTree(it)
            .filter { it.name.startsWith 'Nonnegative' }        // TODO replace `Nonnegative` with what you are looking for
            .each { println "    Match: $it.path" }
            .toList()
            .isEmpty() == false
      }
      .each {
        println "Found in `$config.name: $it.name`\n"
      }
    }
  }
}

@rock3r
Copy link
Author

rock3r commented Aug 7, 2018

Thanks, I have incorporated it in the main gist

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment