Gradle Kotlin FileCollection JavaExec classpath

Viewed 9

I'm attempting to create a gradle kotlin based SoapUI launcher of sorts sans plugins using native gradle functionality for incorporating SoapUI tests into our ci/cd pipeline. So far I have the following:

val soapui: Configuration by configurations.creating

dependencies {
    // Old version is intentional
    soapui("com.smartbear.soapui:soapui:5.4.0")
}

var clazzpath: List<Any> = mutableListOf()
var files: FileCollection = project.files()

task("soapui", JavaExec::class) {
    doFirst {
        // Validating iteration causes resolution
        soapui.forEach { clazzpath += it }

        // Validating contents of List
        //clazzpath.forEach { println(it) }

        // Creating a FileCollection from my List
        files = project.files(clazzpath)

        // Validating contents of my FileCollection
        //files.forEach { println(it) }
    }

    // My first thought which does not work
    //classpath = soapui

    // My second thought which also does not work
    //classpath = project.files(clazzpath)

    // My third thought which also does not work
    classpath = files

    systemProperties = mapOf(
        "soapui.properties.MyProject" to "src/test/integration/environments/my.properties")
    main = "com.eviware.soapui.SoapUI"

    // Will be invoked for automated test runs
    //main = "com.eviware.soapui.tools.SoapUITestCaseRunner"

    args = listOf("src/test/integration/my_project.xml")
}

I've found that iterating over a configuration causes gradle to resolve the configuration allowing for all the transitive dependencies to be discovered. The commented println statements validate that.

When using classpath = soapui, the SoapUI main jar file is put on the classpath, the main class is found, and the SoapUI GUI starts up fine. However, none of it's transient dependencies end up on the classpath and test cases fail when their assertions are performed.

When I try constructing the classpath explicitly, nothing ends up on the classpath and the SoapUI GUI fails to load because the main class is not found.

> Task :soapui FAILED
Picked up _JAVA_OPTIONS: -Djava.net.preferIPv4Stack=true
Error: Could not find or load main class com.eviware.soapui.SoapUI
Caused by: java.lang.ClassNotFoundException: com.eviware.soapui.SoapUI

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':soapui'.
> Process 'command 'C:\<path to JDK\bin\java.exe'' finished with non-zero exit value 1

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 1s
1 actionable task: 1 executed
<list of transitive dependencies on one line with no path separation characters (;)>

That last line of output may be what was used as the classpath, which consists of a list of all the transitive dependencies printed one after another without any path separation characters (semicolons).

Based off of my investigation and reading of the documentation, I'm clearly misunderstanding how this is supposed to work. What am I missing?

1 Answers

Time for me to publicly eat some crow. Turns out, the error I'm investigating has nothing to do with gradle or my understanding of it. Firstly, in the question I mention that the last line of output is a list of all the SoapUI 5.4.0 dependencies on one line without any path separators. It turns out that was being caused by my lack of experience with gradle. In the gradle build file I was working with, I had the following task defined as part of my investigation of gradle.

task("soapuiDependencies") {
    soapui.forEach { print(it.toString()) }
}

Since the code is not inside a doFirst {} or doLast{} block, it is executed when the task is realized, and does not need to be called explicitly for the output to be sent to the console. Lesson learned. What I should have had was

task("soapuiDependencies") {
    doLast {
        soapui.forEach { print(it.toString()) }
    }
}

Or some such. Second lesson has to do with dependency versions. Soapui 5.4.0 is packaged with json-path-0.9.1.jar (yikes, that's old) which contains the file

com/jayway/jsonpath/spi/JsonProvider.class

while gradle is pulling in as a dependency json-path-2.7.0.jar which contains the file

com/jayway/jsonpath/spi/json/JsonProvider.class.

Causing a ClassNotFoundException on the JsonProvider class when invoked via gradle. This is the root of my problem and has nothing to do with my understanding of how gradle FileCollections, JavaExec, or classpath parameters work. I know I'm treading with dinosaurs, but hopefully the lessons learned will be of help to someone else.

Related