cswork / libraryOpen practice workspace

Articles

Maven Interview Questions: Dependency Mediation, Scopes, and Reproducible Builds

Prepare for Maven interview questions on dependency mediation, scopes, dependency management, CI failures, and reproducible builds with verified examples.

A Java service compiles on your laptop, fails with a missing method in CI, and produces a different JAR checksum when rebuilt. “Run Maven clean” is an action, but it does not explain any of those symptoms. A useful Maven interview answer connects the dependency graph, the classpath used at each stage, and the inputs that determine the artifact's bytes.

This guide targets Maven 3.x behavior and uses official Apache documentation. The original fixtures were executed with Maven 3.9.16 and Java 26.0.2.1, compiling a small class with release 17. The dependency versions are fixed practice inputs, not production upgrade recommendations. No candidate reports are used or implied.

For application-level Java topics, see the Spring Boot interview guide. Here, the thesis is narrower: inspect what Maven resolved and executed before reasoning about what the build guarantees.

Which version wins when two dependency paths disagree?

Official fact: Maven dependency mediation normally selects the nearest definition. At equal depth, the first declaration wins. This is not a rule that automatically chooses the newest version. Dependency mechanism.

Our first executed fixture declares commons-text:1.10.0 and a direct commons-lang3:3.14.0 dependency. The text library introduces commons-lang3:3.12.0 transitively. The observed tree, abbreviated to the relevant coordinates, was:

example:mediation:1.0.0
+- commons-text:1.10.0
|  \- commons-lang3:3.12.0
|     (omitted for conflict with 3.14.0)
\- commons-lang3:3.14.0

The direct path wins because it is shorter. The observed result does not establish that the selected library is compatible with every consumer. Resolution chooses an artifact; it does not prove that every method call in every library will link successfully at runtime.

A good follow-up is to remove the direct declaration and predict the new graph before running the command. Then ask what changes if another direct library introduces a competing version at the same depth. State the declaration order, rather than claiming that Maven detects the “best” version.

For diagnosis, the dependency plugin's tree goal can include omitted nodes and filter coordinates. That is more useful than scanning a long unfiltered log for a filename. Dependency tree goal.

mvn org.apache.maven.plugins:maven-dependency-plugin:3.8.1:tree \
  -Dverbose -Dincludes=org.apache.commons:commons-lang3

In an interview, preserve the conflicting paths in your explanation. Saying only “version 3.14.0 is present” omits why it appeared and which dependency will be affected by changing it.

Does dependencyManagement add a library to the classpath?

Official fact: Dependency management supplies dependency information when a dependency is encountered; it does not, by itself, add that dependency to the project's dependencies. A BOM import supplies managed entries through a POM import. Maven POM reference.

The second executed fixture removed the direct language-library dependency and managed its version instead:

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-lang3</artifactId>
      <version>3.14.0</version>
    </dependency>
  </dependencies>
</dependencyManagement>

With commons-text still declared, the observed transitive language-library version became 3.14.0, and the tree identified it as managed from 3.12.0. In the third fixture, removing all actual dependencies while retaining this management block produced a dependency tree containing only the project.

Those two results separate a version policy from inclusion. My interview explanation would describe management as an instruction for an applicable dependency, then point to the declaration or transitive path that actually introduces it.

A BOM is therefore not a request to download and attach every library it lists. After importing one, check the effective model and resolved graph to determine what the application uses. Also keep project dependency management separate from the dependencies of build plugins; a policy for the application graph is not automatically a policy for every tool executing during the build.

Which dependency scope matches the runtime contract?

Official fact: compile is the default scope. provided participates in compilation and tests but expects the runtime environment to supply the library. runtime is absent from the main compile classpath but present for execution and tests. test is limited to test compilation and execution. Maven scope definitions.

Use this decision table as a practice exercise, not a substitute for checking your packaging and deployment model.

SituationScope to evaluateQuestion that can overturn the choice
Main source imports a library's classescompileIs the environment contract explicitly supplying those classes?
A deployed container supplies an APIprovidedDoes the actual production container include the required compatible API?
A driver is discovered only at executionruntimeDoes main source also import implementation-specific classes?
Assertions and test helpers are only in teststestHas production code accidentally started depending on them?

A common debugging trap is to treat a passing test as proof of the deployment classpath. Tests can see dependencies that are intentionally unavailable in the application's normal runtime scope. Conversely, an IDE may add libraries in ways that differ from the packaged application's launcher.

My proposed missing-class investigation records three separate views: the source-level dependency declaration, the resolved scope, and the contents or classpath of the artifact that actually runs. A regular JAR does not automatically become a self-contained application merely because dependencies appear in the POM.

Explain who supplies each required class. “Maven knows the dependency” is not enough if the deployment step leaves its JAR behind or the container supplies an incompatible version.

When should you use exclusions or optional dependencies?

Official fact: An exclusion applies to a dependency path. An optional dependency allows the producing project to use a dependency without automatically passing it to consumers. Another path can still introduce an excluded artifact. Optional dependencies and exclusions.

Suppose one library brings an unwanted logging implementation while another independently brings the same artifact. Excluding it from only the first path does not establish absence from the final graph. Re-run the tree and inspect the packaged runtime after the change.

Explain why removal is safe. Perhaps the application deliberately provides a different implementation through a supported interface. Perhaps the excluded feature is never used. Without that justification, an exclusion can transform a version conflict into a missing-class failure that appears much later.

For a reusable library, optionality communicates a consumer choice. If a consumer uses the optional feature, that consumer may need to declare the corresponding dependency. Describe the feature boundary so the next engineer can understand why a dependency is optional instead of treating the flag as a generic way to make a tree shorter.

How do you diagnose a build that differs in CI?

Official fact: The help plugin's effective-POM goal exposes the resulting project model after inheritance and active profiles are applied. Verbose output can show where model elements originate. Effective POM documentation.

Start with the same commit, command, module selection, profiles, and property values. Then compare the effective model, dependency tree, Java runtime, Maven version, repository configuration, and actual launch artifact. A parent POM or activated profile may explain a version that is absent from the file someone initially opened.

mvn org.apache.maven.plugins:maven-help-plugin:3.5.2:effective-pom \
  -Dverbose -Doutput=effective-pom.xml
mvn -version

The second command reports the runtime used to launch Maven. Compiler toolchains may select a different JDK for participating tools. Apache documents toolchains as a way to separate tool selection from the JVM running Maven. Using toolchains.

My debugging sequence would first make the difference observable in one report, then change one input. Deleting every local cache at the start discards evidence and may only hide a dependency on unpublished local artifacts. A clean, controlled repository can be a useful later experiment, once the original resolution paths have been saved.

For a missing-method failure, record the class and method signature, then identify the JAR that supplies that class in the failing runtime. Matching filenames are not enough: dependency resolution, packaging, shading, and container loading can each change what executes.

Does a successful package mean the build is reproducible?

Official fact: Maven phases execute their preceding phases within the same lifecycle. package and verify are different points in that lifecycle; checks bound later than packaging require reaching those later phases. The clean lifecycle is separate. Build lifecycle.

There are at least three questions to separate in an interview. Did this command succeed? Does the application behave correctly with the selected dependencies? Can controlled rebuilds produce the same artifact bytes? A “yes” to the first question supplies little evidence for the other two.

Official fact: Apache's reproducible-build guidance recommends supported plugin versions and an output timestamp for Maven 3 builds. It also warns that a local comparison does not prove a third party can reproduce the artifact in a different environment. Reproducible builds guide.

Our fixture fixed the compiler release, source encoding, output timestamp, and plugin versions. Two clean verify runs produced JARs with identical SHA-256 hashes in the same local environment. That observation is deliberately narrow: the fixture did not exercise another operating system, another JDK, network-generated sources, or a production release pipeline.

<properties>
  <maven.compiler.release>17</maven.compiler.release>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  <project.build.outputTimestamp>2026-01-01T00:00:00Z</project.build.outputTimestamp>
</properties>

A fixed timestamp alone cannot neutralize every source of nondeterminism. My next experiment would rebuild in a separate directory and controlled environment, preserving the first artifact outside target before cleaning. Compare bytes, then inspect archive entries and generated resources when hashes differ.

What should a reproducibility review actually record?

Record the source revision, resolved dependency graph, active profiles, Maven distribution, participating JDKs, plugin versions, and relevant environment inputs. For generated content, name the generator and whether its output depends on wall-clock time, machine paths, locale, or external services. These are proposed review inputs, not a claim that every Maven project uses them.

Official fact: Maven Wrapper lets a project specify and bootstrap a Maven distribution. It does not by itself define the entire build environment. Maven Wrapper.

Official fact: Plugin versions should be explicitly defined for reproducibility. Plugin management supplies configuration for applicable plugins; it should not be mistaken for an instruction that every listed goal runs. Configuring plugins.

A further distinction is dependency convergence. The Enforcer rule can report conflicting dependency paths even when ordinary mediation chooses a winner. This turns a team policy into a build check, but a convergent graph is still not a compatibility test. Dependency convergence rule.

For the exercise, explain what each check can falsify. A tree reveals an unexpected version. A runtime test can expose an incompatible method call. A checksum comparison reveals differing bytes. None of these should be promoted into a broader guarantee without the supporting experiment.

Sources and Further Reading