是否可以检查哪些gradle依赖项包含给定的类?

是否可以检查哪些gradle依赖项包含给定的类?

问题描述:

最近,我们遇到了类org.apache.commons.beanutils.PropertyUtilsBean的版本不匹配问题.我们认为不匹配只是在1.8和1.9.3版中引入commons-beanutils的某些依赖项之间,但是在跟踪并排除每个传递性依赖项之后,我们仍然面临问题.

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.

事实证明,PropertyUtilsBean也包装在commons-digester3-3.2-with-deps内,而不是声明为对commons-beanutils的依赖.

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.

是否可以在gradle中搜索所有依赖项(包括可传递的依赖项)以查找特定的完全限定的类名?这样我们可以当场解决此类问题.

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.

我尝试过,可以使用一些自定义的gradle构建逻辑:

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

科特林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.

示例输出:

> 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) {}
        }
    }
  }
}