Is it possible to check which gradle dependencies contains given class?

佐手、 提交于 2021-02-07 12:03:31

问题


Recently we had a version mismatch problem with a class org.apache.commons.beanutils.PropertyUtilsBean. We thought that mismatch is just between some dependency that brings commons-beanutils in versions 1.8 and 1.9.3 but after tracking and excluding each transitive dependency we were still facing an issue.

It turns out that the the PropertyUtilsBean was also packed inside the commons-digester3-3.2-with-deps instead declared as dependency to commons-beanutils.

Is it possible in gradle to search all dependencies (including transitive ones) for specific fully qualified classname? That way we could resolve such problems on the spot.


回答1:


I tried it and it is possible using some custom gradle build logic:

Kotlin DSL

tasks {
  val searchClass by creating {
    doLast {
      configurations.forEach {    // check all configurations
        if (it.isCanBeResolved) { 
          try {
            val classLoader = configToClassloader(it)
            // replace here class you are looking for
            val cl = Class.forName("arrow.core.Either", false, classLoader)
            println("found in Configuration $it")
            println(cl.protectionDomain.codeSource.location)
          } catch (e: Exception) {}
        }
      }
    }
  }
}

// Helper function: convert a gradle configuration to ClassLoader
fun configToClassloader(config: Configuration) = 
  URLClassLoader(
    config.files.map {
      it.toURI().toURL()
    }.toTypedArray())

This could be further enhanced by replacing the hard coded classname with some parameter mechanism.

Sample output:

> Task :searchClass
Configuration configuration ':domain:apiDependenciesMetadata'
file:/Users/abendt/.gradle/caches/modules-2/files-2.1/io.arrow-kt/arrow-core-data/0.9.0/a5b0228eebd5ee2f233f9aa9b9b624a32f84f328/arrow-core-data-0.9.0.jar   

Groovy DSL

def configToClassloader(config) {
  return new URLClassLoader(
          *config.files.collect {
              it.toURI().toURL()
          }.toArray())
}

task searchClass {
  doLast {
    configurations.forEach {    // check all configurations
        if (it.canBeResolved) {
            try {
                def classLoader = configToClassloader(it)
                // replace here class you are looking for
                def cl = Class.forName("arrow.core.Either", false, classLoader)
                println("found in Configuration $it")
                println(cl.protectionDomain.codeSource.location)
            } catch (e) {}
        }
    }
  }
}



回答2:


You could do this

task findJarsForClass {
   doLast {
      def findMe = 'org/apache/commons/beanutils/PropertyUtilsBean.class'
      def matches = configurations.runtime.findAll { f ->
         f.name.endsWith('.jar') && 
            !(zipTree(f).matching { include findMe }.empty) 
      }
      println "Found $findMe in ${matches*.name}"
   } 
}



回答3:


Just ctrl+left click class name which was imported, then you can see the jar on your ide(eclipse has that feature, probably IntelliJ has as well)




回答4:


Try using the task dependencyInsight :

gradle -q dependencyInsight --configuration compile --dependency commons-beanutils

Every Gradle project provides the task dependencyInsight to render the so-called dependency insight report from the command line. Given a dependency in the dependency graph you can identify the selection reason and track down the origin of the dependency selection.



来源:https://stackoverflow.com/questions/49692122/is-it-possible-to-check-which-gradle-dependencies-contains-given-class

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!