skip to content

Compiler Configuration

maven-compiler-plugin: <release> versus source/target, annotation processor paths, forking, and -parameters. A frequent question because a wrong JDK level is a classic build break with a confusing error.

on this pageshow

explore

questions

6

Where in the build lifecycle does the maven-compiler-plugin run, and which goals does it execute by default?

level: juniorimportance: must knowfreq 60%

answer

  1. compile goal → compile phase
  2. testCompile goal → test-compile phase
  3. auto-bound by jar packaging
  4. target/classes vs target/test-classes
  5. add plugin only to configure

basics

~10 s

The compiler plugin's compiler:compile goal binds to the compile phase (main sources) and compiler:testCompile binds to test-compile (test sources). Maven binds these automatically for jar projects.

solid answer

~30 s

For a standard packaging like jar, Maven's default lifecycle bindings attach `maven-compiler-plugin:compile` to the `compile` phase and `maven-compiler-plugin:testCompile` to the `test-compile` phase. So when you run `mvn package`, Maven walks the phases up to package, and compilation of `src/main/java` happens at compile, then `src/main/test` (test sources) compiles at test-compile before tests run. You normally never declare these executions yourself — they come with the packaging. You only add the plugin to the `<build><plugins>` section to override its `<configuration>` (release, parameters, processor paths). The compile goal puts classes in `target/classes`; testCompile in `target/test-classes`.

code

bash · 5 lines
bash
# default bindings fire automatically:
mvn compile        # runs compiler:compile -> target/classes
mvn test           # also runs compiler:testCompile -> target/test-classes
# or invoke a goal directly:
mvn compiler:compile

go deeper

for a junior

Knows compile runs at the compile phase and tests compile at test-compile automatically.

for a middle

Knows the goals (compile/testCompile), default bindings, and output directories.

for a senior

Understands the lifecycle ordering and that plugin-level configuration applies to both default executions.

for a principal

Manages compiler config centrally in a parent POM's pluginManagement so all modules inherit consistent bindings and settings.

## Lifecycle, phases, goals Maven's **default lifecycle** is an ordered list of **phases**: ...`validate` → `compile` → `test-compile` → `test` → `package`... Running a phase runs every phase before it. A **plugin goal** (the actual unit of work) is *bound* to a phase. ## What the compiler plugin binds to For `jar` (and similar) packaging, Maven's built-in bindings automatically attach: - `maven-compiler-plugin:compile` → the **`compile`** phase — compiles `src/main/java` into `target/classes`. - `maven-compiler-plugin:testCompile` → the **`test-compile`** phase — compiles `src/test/java` into `target/test-classes`, with the test + main classpath. Because these are part of the packaging's default bindings, **you do not write `<executions>` for them**. Running `mvn compile`, `mvn test`, or `mvn package` triggers them in order. ## You only configure, not bind You add the plugin to override behaviour: ```xml <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <release>21</release> <parameters>true</parameters> </configuration> </plugin> </plugins> </build> ``` This configuration applies to both default executions (compile + testCompile) since it sits at plugin level. ## Running goals directly You can also invoke a goal ad hoc: ```bash mvn compiler:compile mvn compiler:testCompile ``` but in practice you run phases (`mvn compile`, `mvn test`) and let the bindings fire. ## Outputs - main → `target/classes` - test → `target/test-classes` These become the classpath roots downstream (test, package).

  • Do you need to declare <executions> for compile and testCompile?
    No. They are part of the default lifecycle bindings for jar/war packaging; you add the plugin only to override configuration.
  • Where do compiled main and test classes go?
    Main sources compile to target/classes; test sources to target/test-classes.

saying these in an interview costs you the question

  • Claiming you must manually bind compile/testCompile executions.
  • Confusing the compile phase (main) with test-compile (tests).
  • Thinking the plugin compiles during package — compilation already happened at the earlier compile/test-compile phases.

context

open as a page

What is the difference between configuring <release> and <source>/<target> in the maven-compiler-plugin, and which should you prefer today?

level: middleimportance: must knowfreq 75%

basics

~10 s

<source>/<target> set the language level and bytecode version separately. <release> sets both at once AND links against that JDK's API, preventing accidental use of newer APIs. Prefer <release>.

open as a page

What does the -parameters compiler flag do, and which frameworks rely on it?

level: middleimportance: should knowfreq 45%

basics

~10 s

-parameters tells javac to keep real method parameter names in the bytecode. Without it, names become arg0, arg1. Frameworks like Spring MVC and JPA queries use them via reflection.

open as a page

What does the -proc / proc:none compiler option control, and when would you disable annotation processing?

level: middleimportance: should knowfreq 40%

basics

~10 s

The -proc flag controls whether javac runs annotation processing. proc:none compiles without running any processors; proc:only runs processors but skips compilation. Disable processing to speed builds or avoid unwanted code generation.

open as a page

How do you configure annotation processors in the maven-compiler-plugin, and why is annotationProcessorPaths preferred over putting processors on the classpath?

level: seniorimportance: should knowfreq 55%

basics

~10 s

Use <annotationProcessorPaths> to list processor artifacts (like Lombok or MapStruct) separately from your project dependencies. This keeps processors off the runtime/compile classpath while still running them during compilation.

open as a page

When and why would you fork the compiler with meminitial/maxmem, and how does the plugin's incremental compilation work?

level: seniorimportance: nice to knowfreq 30%

basics

~10 s

Set <fork>true</fork> to run javac in a separate JVM, then size it with <meminitial> and <maxmem> for big modules. Incremental compilation (the default) only recompiles changed/stale classes instead of everything.

open as a page