gradlegradle-multi-project-build

How can I call code from one subproject in a gradle tasks of another subproject?


I have a project with two subprojects.

One of these subprojects, "A", contains code that is being published to an artifact.

The other subproject, "B", has a task that needs to do exactly what one of the methods in A's code does. I can replicate the logic in groovy, but is there any way I can actually have my task in subproject B call the code that was compiled as part of subproject A?

I'd tried adding a buildscript block in B that added the artifact from A to the classpath:

buildscript {
    dependencies {
        classpath project(':subproject-a')
    }
}

...but this gave me an error:

Cannot use project dependencies in a script classpath definition.

I don't believe I can move subproject-a to buildSrc, as I'm also publishing its artifact to a maven repository for other projects to use.


Solution

  • You have a chicken or egg problem where all of the Gradle project classloaders are resolved before any classes are compiled. This can be resolved using a custom configuration and a Classloader

    Eg:

    configurations {
       custom 
    } 
    dependencies {
       custom project(':subproject-a')
    } 
    task customTask {
       doLast {
          def urls = configurations.custom.files.collect { it.toURI().toURL() } 
          ClassLoader cl = new java.net.URLClassLoader(urls as URL[]) 
          Class myClass = cl.loadClass('com.foo.MyClass')
    
          // assuming zero args constructor 
          Object myObject = myClass.newInstance()
    
          // assuming method which accepts single String argument 
          java.lang.reflect.Method myMethod = myClass.getMethod('myMethodName', String.class)  
          myMethod.invoke(myObject, 'methodArg')
       } 
    }