Classes of multiple source sets mixed after byte-buddy transformation
Hi,
I'm trying to apply byte buddy to classes of a test fixtures library. Here is a snippet of my build.gradle.
buildscript {
dependencies {
classpath platform('org.jmolecules:jmolecules-bom:2023.2.1')
classpath 'org.jmolecules.integrations:jmolecules-bytebuddy'
classpath 'org.jmolecules.integrations:jmolecules-jpa'
}
}
apply plugin: 'net.bytebuddy.byte-buddy-gradle-plugin'
apply plugin: 'java-test-fixtures'
dependencies {
byteBuddy platform('org.jmolecules:jmolecules-bom:2023.2.1')
byteBuddy 'org.jmolecules.integrations:jmolecules-bytebuddy'
byteBuddy 'org.jmolecules.integrations:jmolecules-jpa'
}
testFixturesByteBuddy {
transformation {
plugin = org.jmolecules.bytebuddy.JMoleculesPlugin
}
}
This creates two tasks: byteBuddy and testFixturesByteBuddy.
When I run the task byteBuddy for the first time, the raw compiled classes of my main source set are stored in build/classes/java/javaByteBuddyRaw. Then, they are transformed and copied into build/classes/java/main. So far, so good.
Then I run the testFixturesByteBuddy task, the raw compiled classes of my testFixtures source set are stored in build/classes/java/javaByteBuddyRaw as well, mixing the sources from the main and testFixtures source sets. From there, we got into trouble. The classes copied to build/classes/java/testFixtures after transformation also include the sources from the main source set. And worst, if I rerun the task byteBuddy, the compiled classes of the main source (in build/classes/java/main) now contain the testFixtures classes (and the compilation fails due to missing test dependencies).
The issue clearly comes from both tasks using the same directory for raw compiled classes. Is this a bug or an issue with my configuration?
I'm using Gradle 8.8 and version 1.17.2 of the byte-buddy plugin.
Ok I think I found the first issue in my config. The Jmolecules dependencies should be added to testFixturesByteBuddy and not byteBuddy. With this change, only a testFixturesByteBuddy task is created as no transformation is found for the main source set by auto-discovery (so no byteBuddy task). That effectively solves my problem for now.
apply plugin: 'java-test-fixtures'
apply plugin: 'net.bytebuddy.byte-buddy-gradle-plugin'
dependencies {
testFixturesByteBuddy platform('org.jmolecules:jmolecules-bom:2023.2.1')
testFixturesByteBuddy 'org.jmolecules.integrations:jmolecules-bytebuddy'
testFixturesByteBuddy 'org.jmolecules.integrations:jmolecules-jpa'
}
Also, no need to specify the transformation; auto-discovery works well.
That being said, I would be interested in other setups to run byte buddy on both the main and testFixtures (or test) source sets and there I will have the same issue. If I configure it in the following way, I'm still facing the same issue.
dependencies {
byteBuddy platform('org.jmolecules:jmolecules-bom:2023.2.1')
byteBuddy 'org.jmolecules.integrations:jmolecules-bytebuddy'
byteBuddy 'org.jmolecules.integrations:jmolecules-jpa'
testFixturesByteBuddy platform('org.jmolecules:jmolecules-bom:2023.2.1')
testFixturesByteBuddy 'org.jmolecules.integrations:jmolecules-bytebuddy'
testFixturesByteBuddy 'org.jmolecules.integrations:jmolecules-jpa'
}
I haven't dig into it too much, but ByteBuddyTaskConfiguration#configureDirectories should probably take the SourceSet as input and not the SourceDirectorySet (or both) to set the raw directory name.
I think you would need to register a custom ByteBuddyTask and bind it to the right source sets and folders. There are some limits to how one can bind the default life-cycles with Gradle, and I did loads of adjustments to cover the standard cases well. But there is no good solution when it comes to mulitiple source sets, if I recall correctly.
I attempted to modify the testFixturesByteBuddy task created by ByteBuddy to change the source directory (and the destination directory of the corresponding compile task), and it appears to work well. No more mixing of compiled classes, and the incremental build works as expected.
project.afterEvaluate {
def testFixturesByteBuddyRaw = layout.buildDirectory.dir("classes/java/testFixturesByteBuddyRaw")
tasks.compileTestFixturesJava.setDestinationDirectory testFixturesByteBuddyRaw
tasks.testFixturesByteBuddy.setSource testFixturesByteBuddyRaw
}
What would be the potential drawback of this approach?
None, but the plugin struggles to determine the order of transformations automatically. I think this is the right approach.