Maven/Gradle Dependencies - Java

  1. Which command best satisfies the requirement?
    Answer: Run mvn clean package -DskipTests, which compiles the tests, skips their execution, and continues to the package phase. When working with Maven's build lifecycle, you need to distinguish between skipping test compilation and skipping test execution — these are two different things controlled by different flags. The -DskipTests flag tells Maven: "compile the test sources, but don't run them." This is exactly what the scenario demands — the developer needs test sources compiled (perhaps because other code depends on them) but doesn't want the failing assertion to block the build. Combined with the package phase, mvn clean package -DskipTests compiles both production and test sources, skips test execution, and produces the JAR. That makes A the correct answer. B is a common trap. -Dmaven.test.skip=true goes further — it skips both compilation and execution of tests. This violates the requirement that test sources must still compile, so B is wrong despite also reaching the package phase. C uses the compile phase instead of package. The compile phase only compiles production sources and stops before packaging, so no JAR is produced. Even with -DskipTests, you never reach the packaging step, making C incorrect. D misunderstands the Maven lifecycle. Running mvn clean test with -DskipTests skips test execution, but test is an intermediate phase — it does not automatically continue to package. Maven only advances to phases you explicitly invoke, so no JAR is created. A useful rule of thumb: reach for -DskipTests when you want tests compiled but not run, and reserve -Dmaven.test.skip=true for situations where you want to completely ignore the test sources altogether.
  2. Which change most directly fixes the dependency-resolution failure?
    Answer: Add repositories { mavenCentral() } so Gradle knows which repository should supply the declared module. Whenever you see a Gradle dependency-resolution failure, think about the two things Gradle needs: a declaration of what you want (the dependencies block) and a location to fetch it from (the repositories block). The build file in this question has only the first piece. Gradle does not search any repository by default — you must explicitly tell it where to look. Adding repositories { mavenCentral() } (choice A) registers Maven Central as a source, which is exactly where com.google.guava:guava lives. With that block in place, Gradle can resolve, download, and cache the artifact, and the build succeeds. This is the most direct fix because it addresses the root cause: no repository was configured. Choice B is wrong because gradlePluginPortal() is designed for Gradle plugins (things declared in the plugins {} block), not for application libraries like Guava. Pointing Gradle there for a regular dependency would still fail to find it. Choice C reflects a common misconception — clean simply deletes the build/ output directory. It has nothing to do with configuring or creating repositories, so running clean build would repeat the same failure on a fresh slate. Choice D is wrong because switching from implementation to compileOnly changes classpath scoping, not resolution behavior. Gradle still needs a repository to download the artifact regardless of which configuration you use, so the resolution error would persist. The study tip: whenever a Gradle build can't resolve a dependency, check for a repositories block before questioning the dependency declaration itself — a missing repository is one of the most common beginner mistakes.
  3. Which dependency configuration best matches this requirement?
    Answer: Declare JUnit with testImplementation, limiting its compile and runtime availability to the test source set. When working with Gradle dependency configurations, the key question to ask yourself is: which source sets need this dependency, and at which phase (compile vs. runtime)? Gradle gives you fine-grained control through configurations designed for exactly this purpose. Since JUnit belongs exclusively to tests, you need a configuration that scopes it to the test source set for both compilation and execution. That's precisely what testImplementation does — it makes the dependency available when src/test/java compiles and when the test task runs, while keeping it completely invisible to production code. D is the correct answer. Here's why the other options fall short. A (implementation) places JUnit on the compile and runtime classpaths for all source sets, meaning your production classes could accidentally import JUnit types — a design smell that blurs the line between production and test code. B (compileOnly) exposes the dependency only during production compilation and explicitly excludes it at runtime, which is the opposite of what you need; tests would fail because JUnit wouldn't be on the runtime classpath when they execute. C (runtimeOnly) is closer but still wrong: it makes the dependency available at runtime but not during compilation, so your test source files couldn't even reference JUnit's @Test annotation or assertion methods without compiler errors. A handy mental model: prefix test to scope something to tests, and remember that implementation covers both compile and runtime. Combining them gives you testImplementation — compile-time and runtime availability, test source set only.
  4. Which change and command correctly add Guava as a normal application dependency and build the project?
    Answer: Add Guava under <dependencies> with its group, artifact, and version, then run mvn package to build the application. When working with Maven, it helps to clearly separate two concerns: project dependencies (libraries your code uses at runtime/compile time) and build plugins (tools that assist the build process itself). Guava is a library your application code imports, so it belongs in the dependencies section, not anywhere related to plugins or build tooling. The correct approach — answer C — is to declare Guava inside the <dependencies> block within your pom.xml, providing the <groupId> (com.google.guava), <artifactId> (guava), and <version>. Once declared, running mvn package triggers the full lifecycle: it compiles your sources (resolving Guava from Maven Central), runs tests, and packages the output into a JAR. This directly fixes the missing-package error and produces a build artifact. A is wrong because <plugin> entries under <build> are for build tools like the compiler plugin or Shade plugin — not application libraries. Putting Guava there would have no effect on compilation classpath. B is wrong on two counts: <dependency> placed directly under <project> is invalid XML structure — dependencies must nest inside <dependencies>. Additionally, mvn dependency:resolve only downloads dependencies; it doesn't compile or build anything. D is wrong because <pluginManagement> is used to pre-configure plugins for child modules, not to declare application libraries. Guava declared there would never appear on your compile classpath. As a study tip, remember Maven's structure like concentric zones: <dependencies> is for your app's libraries, <plugins> is for build tools, and <pluginManagement> is for inherited plugin configuration — mixing these up is a classic exam trap.
  5. Which dependency change most directly produces the intended runtime dependency set?
    Answer: Exclude slf4j-simple within the old-client dependency declaration and keep logback-classic as a direct dependency. When working with Maven dependency management, the key concept here is transitive dependency exclusion — controlling which libraries get pulled in indirectly through your dependencies. Whenever you see a conflict between logging providers on the classpath, your goal is to keep exactly one provider while preserving the dependency that brought in the unwanted one. In this scenario, old-client is still needed, but its transitive dependency slf4j-simple conflicts with logback-classic. The cleanest solution is to exclude slf4j-simple directly inside the old-client declaration using Maven's <exclusions> block. This surgically removes the conflicting provider while keeping old-client fully on the classpath. logback-classic remains your sole SLF4J provider, and the warning disappears. That's exactly what C does, making it correct. A is wrong because marking old-client as provided tells Maven the runtime environment will supply it — it omits the artifact and its transitive dependencies entirely from the final artifact. This would break the application since old-client is genuinely needed at runtime, not just compile time. B is wrong because adding a direct dependency on slf4j-simple doesn't remove it — it just potentially changes which version Maven resolves. You'd still have two SLF4J providers on the classpath, which is the exact problem you're trying to solve. D is wrong because old-client is not a transitive dependency of logback-classic. Excluding it from Logback's declaration has no effect whatsoever — you're excluding something that was never brought in through that path. As a study tip: when you see classpath conflicts involving transitive libraries, think exclusion on the dependency that brings in the unwanted artifact, not on unrelated dependencies.
  6. Which action most reliably builds the project with the version selected by the repository?
    Answer: Run ./gradlew build; the wrapper obtains Gradle 8.7 if necessary and then executes the build. When you see a question about build tools and project setup in Java, focus on version consistency — the whole point of the Gradle Wrapper is to ensure everyone on a team builds with the exact same Gradle version, regardless of what's installed locally. The Gradle Wrapper (gradlew/gradlew.bat) is a shell script bundled with the project. When you run ./gradlew build, it reads gradle/wrapper/gradle-wrapper.properties, checks whether Gradle 8.7 is cached locally, downloads it from Gradle's distribution servers if needed, and then executes the build using that specific version. No global Gradle installation is required — that's precisely the wrapper's purpose. B is correct because it uses the wrapper exactly as intended. A is wrong because gradle build invokes a globally installed Gradle binary, which bypasses the wrapper entirely. If no global Gradle is installed, this command simply fails. Even if one were installed, it might be a different version, breaking the reproducibility guarantee. C is wrong because Maven and Gradle are completely separate build systems with no awareness of each other. Running mvn package would look for a pom.xml, not a Gradle wrapper, and would fail entirely. Maven never "delegates" to Gradle. D is wrong because deleting the wrapper files defeats the repository's version-pinning strategy. Installing the newest Gradle globally introduces exactly the version drift the wrapper was designed to prevent. A useful mental shortcut: the wrapper wraps a specific Gradle version for portability — always prefer ./gradlew over gradle in any project that ships wrapper files.
  7. Which declaration should be added to the dependencies block of the app subproject?
    Answer: Use implementation project(':core') so Gradle builds core and places its output on app's relevant classpaths. When working with multi-project Gradle builds, the key concept to understand is project dependencies — a mechanism that lets one subproject depend directly on another without publishing artifacts to a Maven repository. Gradle handles the wiring automatically, putting the dependency's compiled output on the appropriate classpaths. implementation project(':core') is the correct choice (D) because implementation places core on both the compile classpath and the runtime classpath of app, which is exactly what you need when app imports classes from core. The project(':core') notation tells Gradle to resolve the dependency by building the sibling subproject directly from source — no external repository required. Each wrong answer has a specific flaw worth understanding. A uses testImplementation, which scopes the dependency only to test sources — your production code in app won't compile against core at all. B uses a module coordinate string ('core:core:latest') instead of a project reference, so Gradle would search Maven/Ivy repositories for an artifact named core, which the passage explicitly says doesn't exist — the build would fail. C uses runtimeOnly, which intentionally excludes the dependency from the compile classpath. That means app's source code can't reference core's classes at compile time, causing compilation errors — the opposite of what you want. A handy tip: whenever you see a Gradle multi-project scenario where one subproject consumes another's production classes and no repository is involved, reach for implementation project(':subprojectName'). Match the configuration scope (implementation, testImplementation, runtimeOnly) to when the dependency is actually needed — compile time, test time, or runtime only.
  8. What is the expected result, and what is the appropriate next step?
    Answer: The build fails because offline mode cannot download the uncached dependency; rerun without -o to populate the local repository. Whenever you see a question involving mvn -o, you need to focus on one core concept: the -o flag stands for offline mode, which tells Maven to use only what is already cached in the local repository (~/.m2/repository). It will not reach out to any remote repository, even if internet access is fully available. On a fresh machine with an empty local repository, running mvn -o package means Maven immediately hits a wall — the declared dependency simply doesn't exist locally, and offline mode strictly forbids downloading it. The build fails with an artifact resolution error. The correct fix is to first run mvn package (without -o) so Maven can reach Maven Central, download the dependency, and cache it locally. Once it's cached, future offline builds will succeed. This makes B the right answer. A is wrong because offline mode does not permit downloads of any kind — it's an all-or-nothing restriction. The claim that it "prevents checks for newer versions" while still allowing downloads misrepresents what -o does entirely. C is wrong on two counts: mvn package absolutely resolves dependencies as part of its lifecycle (during the initialize and validate through compile phases), and you don't need to run dependency:resolve as a mandatory prerequisite — that goal is a diagnostic convenience, not a required step. D is wrong because Maven doesn't front-load dependency downloads before applying the offline restriction. The -o flag takes effect from the start; there's no pre-download phase that bypasses it. A quick mental rule: **-o = local cache only, always.** If the artifact isn't cached, the build fails regardless of internet access.
  9. What is the minimal correct change to the child module?
    Answer: Add formatter under the child's <dependencies> without a version, allowing the parent management entry to supply version 2.4. When you see a Maven question about missing dependencies, focus on the two-step system Maven uses: <dependencyManagement> declares available versions centrally, but it does not add anything to the classpath. A child module must still explicitly declare the dependency under <dependencies> to actually use it — the management entry just means you can omit the version tag. That's exactly why A is correct. The parent's <dependencyManagement> block already registers formatter at version 2.4. The child simply needs to declare formatter inside its own <dependencies> section — without specifying a version — and Maven will inherit 2.4 from the parent. This is the minimal, idiomatic fix. B is wrong because copying <dependencyManagement> into the child doesn't help at all. Management sections never add libraries to the classpath regardless of where they appear; they only govern version resolution when a matching <dependencies> entry exists. You'd still be missing that entry. C is wrong on two counts: the <build> section is for plugins and build configuration, not for library dependencies. Placing a library there is structurally invalid and wouldn't resolve compile-time imports. D is wrong because mvn dependency:resolve is a diagnostic/reporting goal — it resolves and lists dependencies but doesn't modify any POM or permanently add anything to a module's classpath. Running it changes nothing about the build outcome. As a study tip, remember the Maven mantra: management = version control, dependencies = classpath inclusion. Questions that conflate the two are a classic Maven trap on Java certification exams.
  10. Which POM change satisfies both the compilation and runtime requirements?
    Answer: Remove the scope element, giving the library the default compile scope for main, test, and runtime classpaths. When working with Maven dependency scopes, think about which classpaths each scope covers: compile (main sources), test (test sources), and runtime (packaged application execution). The bug here is that <scope>test</scope> restricts a dependency to the test classpath only — main sources and the final packaged artifact never see it. Removing the <scope> element entirely gives the dependency the default compile scope, which is exactly what this scenario needs. Compile scope places the library on all three classpaths: main source compilation, test compilation, and runtime execution. That single change satisfies both requirements the question describes. A is wrong because runtime scope explicitly excludes the compile classpath for main sources — it's designed for libraries you reference only through interfaces or reflection at compile time but need present at runtime. Main source compilation would still fail. C is wrong because provided scope covers compilation but assumes the runtime container (like a servlet container) will supply the library — it is not bundled into the packaged artifact. Since the question says the packaged application must use the library at runtime, provided would break at runtime. D is wrong for two reasons: test scope still doesn't reach main sources, and Maven doesn't support declaring the same artifact twice with different scopes in a meaningful way — the second declaration would typically override or conflict with the first. B is the correct answer. As a study tip, memorize Maven's four common scopes as a table mapping each to its classpath coverage — knowing which classpaths compile, test, provided, and runtime include will quickly eliminate distractors on any Maven scope question.

Start this quiz