CHALLENGE: Multi project gradle build - During compile of project B invoke method of class found in project A


#1

Hello,

I need so suggestions to solve the following multi project built

In project A I have a class of this kind used create web service stubs:

/src/main/java/com/mycompany/GenerateWSStubs.java

The class has a method:
public static void main(String[] args) throws Exception
that connects to some webservices and generate java classes based on them

In project B I have a class than needs the classes generated by project A

/src/main/java/com/mycompany/Client.java

My challenge is to be able to:

  1. Compile A before B (easy)
  2. Make available com.mycompany.GenerateWSStubs.class to project B (don’t know how)
  3. From project B build, invoke com.mycompany.GenerateWSStubs.main(’’) before B dependencies are resolved. (I know how to do it, but not before dependencies are resolved)
    This will output some classes to a package com/mycompany/ws/… I just need to make this availble to B before compile
  4. Compile and package to jar, project B including both: (don’t know how)
    com/mycompany/ws/… (the class generated by running com.mycompany.GenerateWSStubs.main(’’))
    com/mycompany/Client.class

What I have tried so far:

A.gradle

apply plugin: 'java-library'
dependencies {	
	implementation group: 'junit', name: 'junit', version: '4.12'
	implementation group: 'org.apache.axis2', name: 'axis2-adb-codegen', version: '1.7.6'
}

B.gradle

    buildscript {
       dependencies {
     //the following seems working but is terrible way to specifying  this inclusion, and the jar might not be there if I did a clean
          classpath files("../A/build/libs/A.jar")
       }
    }
    apply plugin: 'java-library'
    dependencies {	
    	implementation group: 'junit', name: 'junit', version: '4.12'
    	implementation group: 'org.apache.axis2', name: 'axis2-adb-codegen', version: '1.7.6'
       // The following does not seems to allow adding com.mycompany.GenerateWSStubs to the compile path to allow me running main
        compileClasspath project(':A')
    }

compileJava {
        // This should ensure that A.jar is built
	dependsOn ':A:build'
	doFirst {
           def obj = new com.mycompany.GenerateWSStubs()
	   obj.main('someparameters')
	}
}

Questions:

  1. Unless I use buildscript def obj = new com.mycompany.GenerateWSStubs() fails. How can I create an object based on a class to be compiled in another project without statically referring to the jar as I did?
  2. com.mycompany.GenerateWSStubs.main() accept several parameter to know how to read some URL and where to store the stub classes.
    a) What variable to I use in gradle to refer to standard resources location (src/main/resources)
    b) where should I output my classes generated by com.mycompany.GenerateWSStubs.main() to be sure that they are used for dependencies in project B and packed in B.jar?

Thank a lot


(Sterling Greene) #2

You don’t need projectA’s classes on projectB’s buildscript’s classpath.

Try something like (I haven’t tried this, but hopefully it’ll give you the right direction/ideas):

configurations {
    generator
}

dependencies {
    generator project(":projectA")
}

task generateWSStubs(type: JavaExec) {
    outputs.upToDateWhen { false }

    def generatedSources = "$buildDir/generated-sources/main"
    outputs.dir generatedSources

    classpath = configurations.generator
    main = "com.mycompany.GenerateWSStubs"
    args 'some', 'parameters', generatedSources.absolutePath
}

sourceSets {
    main {
        srcDir tasks.generateWSStubs
    }
}

This assumes that GenerateWSStubs creates .java files. If you’re directly creating .class files, you need to use something more like the example here for generated resources: https://docs.gradle.org/current/dsl/org.gradle.api.tasks.SourceSetOutput.html


#3

Thanks!
Sounds like a great approach!

I will try and publish the complete solutions if it works