Build path for java classes changed from 3.x to 4.x


(Steve Cohen) #1

I have some gradle buildscript code that wants to compile a bunch of files in one subproject and include them in other subprojects. I have noticed that in version 3.x gradle put such files under build/classes/main and in 4.x at build/classes/java/main..

This is very annoying. It’s not expected behaviour to have builds break due to changing gradle versions, and I don’t think you would want that as it would make users shy of upgrading.

And also, it’s non-analogous to the source path which is, of course src/main/java so the analog would be build/classes/main/java, not build/classes/java/main.


(Benjamin Muschko) #2

I have some gradle buildscript code that wants to compile a bunch of files in one subproject and include them in other subprojects.

It sounds like you are referencing those paths by hard-coding then. It would be better (and not error-prone) to ask the source set about it.

It’s not expected behaviour to have builds break due to changing gradle versions, and I don’t think you would want that as it would make users shy of upgrading.

We made that change with a major version. Based on semantic versioning that means that some of the changes might be breaking changes. It was a required change so we could make other optimizations.


(Steve Cohen) #3

Thanks.

Please explain “ask the source set”. Not sure what you mean. It sounds good but I’m not familiar with that construct.

Our use case is kind of an edge case. We wish to build two rpm files which contain a war file with the same classes, but have some differences. We want to compile the code in one place and include it in the war and not as a jar file but as class files.

Why did you choose build/classes/java/main rather than build/classes/main/java which would be more analogous to the source tree?


(Benjamin Muschko) #4

Please explain “ask the source set”.

apply plugin: 'java'

task printSourceSetOutputDir {
    doLast {
        println sourceSets.main.java.outputDir
    }
}

Why did you choose build/classes/java/main rather than build/classes/main/java which would be more analogous to the source tree?

Not quite sure. I was not involved in that change. @Stefan_Wolf @sterling Do you know by any chance?


(Steve Cohen) #5

thanks. Always some new tricks, though it’s probably old hand to you.
Oh, and it works like a charm!


(Benjamin Muschko) #6

The source set concept has been around for a long time. I think this use case clearly demonstrated the benefit of Gradle’s model. You can ask domain objects for their runtime value.

I suggest sitting in on one of the free Gradle trainings where we definitely discuss source sets and their use. We are also planning to write a guide on it.


(Mark Vieira) #7

This is the logical structure: build directory > output type > source set > language.

We certainly could switch the last two but it makes more sense to group output by source set than by language. I want all my main code in one directory, and all my test code in another, rather that split. In the end it doesn’t really matter how the stuff is arranged in the build directory.

By the way, this change was introduced to support multiple output directories per source set. So we now separate Java and Groovy classes. You should be calling sourceSets.main.output.classesDirs to get this information since you might have multiple directories with .class files in them if you use both Java and Groovy.


(Sterling Greene) #8

The reason we went with build/classes/java/main vs build/classes/main/java is that it was less likely to break in strange ways with builds and plugins that hardcoded the path to build/classes/main or snuck outputs into build/classes/main.

If we used build/classes/main/java and had tasks that put things into build/classes/main or read things from build/classes/main, it might look like you had classes with the package java.your.package.structure because of the nesting.