What is a SourceSet in Gradle's Java plugin, and what two source sets does the plugin create by default?
answer
- main + test created by java plugin
- named group of sources compiled together
- owns srcDirs, classpaths, configurations
- compileJava / processResources tasks
- test classpath includes main output
basics
~10 sA SourceSet is a named group of source files compiled together. The java plugin creates two by default: main (production code) and test (test code that depends on main's output).
solid answer
~40 sA `SourceSet` is a logical grouping of source files (Java + resources) that are compiled and processed as a unit. Applying the `java` plugin registers two source sets: `main` for production code and `test` for test code. Each source set owns its own source directories (`src/<name>/java`, `src/<name>/resources`), its own compile and runtime classpaths, and a generated `compileJava`/`processResources` task pair. The `main` source set produces the artifact that ends up in the JAR; `test` is configured so its compile and runtime classpaths include `main`'s output plus the test dependencies. Each source set also gets its own dependency configurations such as `implementation`, `testImplementation`, etc.
code
kotlin · 12 linesplugins {
java
}
// Default layout the java plugin assumes:
// src/main/java, src/main/resources
// src/test/java, src/test/resources
dependencies {
implementation("com.google.guava:guava:33.0.0-jre") // main source set
testImplementation("org.junit.jupiter:junit-jupiter:5.10.0") // test source set
}go deeper
Name main and test, know the default src/<set>/java layout, and that the java plugin creates them.
Explain the owned tasks, per-source-set configurations, and that test's classpath includes main's output.
Discuss the SourceSet as the reusable abstraction enabling extra compilation units and how configurations derive from the set name.
Frame source sets as the contract that keeps multi-unit builds consistent and explain governance implications for custom build conventions across many modules.
## What a SourceSet is A **SourceSet** is Gradle's model for a named collection of source files that are compiled together and share a classpath. It is the unit the `java` plugin uses to wire up compilation tasks, dependency configurations, and output directories. When you apply the `java` plugin (or anything that pulls it in, like `java-library` or `application`), Gradle creates a `sourceSets` container with two entries: - **`main`** — your production code. Defaults to `src/main/java` for sources and `src/main/resources` for resources. Its compiled classes go into `build/classes/java/main`. - **`test`** — your unit tests. Defaults to `src/test/java` and `src/test/resources`. Its classpath is pre-wired to include `main`'s compiled output. ## What each source set owns For a source set named `foo`, Gradle derives: - **Source directories**: a `java` `SourceDirectorySet` (`foo.java.srcDirs`) and a `resources` one (`foo.resources.srcDirs`). - **Tasks**: `compileFooJava` and `processFooResources`, plus `fooClasses` as an aggregating lifecycle task. - **Classpaths**: `foo.compileClasspath` and `foo.runtimeClasspath` — `FileCollection`s resolved from the matching configurations. - **Dependency configurations**: `fooImplementation`, `fooApi` (with `java-library`), `fooCompileOnly`, `fooRuntimeOnly`. For `main` the prefix is dropped, so you write `implementation` not `mainImplementation`. ## Why this matters The source-set abstraction is what lets Gradle support extra compilation units — integration tests, generated code, JMH benchmarks — without special-casing each one. Anything modeled as a source set automatically gets the full compile/classpath/configuration machinery. ```kotlin plugins { java } // The two defaults are already present: sourceSets { named("main") named("test") } ```
- Where do the compiled classes of the `main` source set end up by default?In `build/classes/java/main` for `.class` files and `build/resources/main` for processed resources; these directories make up `main`'s output, which feeds the `jar` task and the `test` classpath.
- Why doesn't the `main` source set's configuration prefix appear (e.g. `mainImplementation`)?By convention the `main` source set's configurations drop the name prefix, so they read as `implementation`, `api`, `compileOnly`, etc. Every other source set keeps the prefix.
Think of a source set like a separate 'room' in your project: each room has its own door (source dirs), its own furniture list (dependencies), and its own electrical circuit (classpath) — even though they all sit in the same house.
saying these in an interview costs you the question
- Saying a source set is 'just a folder' — it's a model object that owns classpaths, tasks, and configurations, not merely a directory.
- Claiming `test` automatically inherits `main`'s dependencies — it inherits `main`'s compiled output on the classpath, not `main`'s declared `implementation` dependencies unless they're on the runtime classpath.