<!-- pom.xml -- Maven declares a dependency, and Maven handles downloading it and its own transitive dependencies -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.2</version>
</dependency>
Topics
36
Annotations
Arrays & Multidimensional Arrays
Build Tools: Maven & Gradle
Class Loading & Bytecode Verification
Collections Framework
Concurrency & Threads
Design Patterns in Java
Enums
equals(), hashCode() & toString() Contracts
Exceptions
Functional Interfaces & Method References
Garbage Collection
Generics
I/O & NIO
Inner Classes & Anonymous Classes
Interfaces & Abstract Classes
Java Date & Time API (java.time)
Java Fundamentals: Syntax, Data Types & Operators
Java Networking & HTTP Client
Java Platform Module System (JPMS)
JDBC & Database Connectivity
JVM, JRE & Memory
Logging in Java (java.util.logging, SLF4J, Log4j)
Object Cloning & Copy Semantics
OOP & Classes
Optional & Null Safety
Pattern Matching & Switch Expressions
Records & Sealed Classes
Reflection API
Regular Expressions in Java
Serialization & Deserialization
Static & Instance Initialization Blocks
Streams & Lambdas
String Handling, StringBuilder & Immutability
Unit Testing with JUnit & Mockito
Varargs, Autoboxing & Unboxing
Build Tools: Maven & Gradle
15 questions found
Build tools automate compiling source code, managing external library dependencies (downloading and resolving version conflicts automatically), running tests, packaging the application (into a JAR/WAR), and orchestrating multi-step build lifecycles consistently across every developer's machine and CI server -- without one, developers would need to manually track and download dependency JARs, manually invoke javac with correct classpaths, and manually script packaging, all error-prone and inconsistent across environments.
Real-world example
A team onboarding a new developer has them simply run `mvn clean install`, which automatically downloads all required dependencies, compiles the code, runs tests, and produces a runnable JAR -- entirely reproducible without the new developer needing to manually hunt down and configure dozens of library JARs by hand.
Java Fundamentals: Syntax
Data Types & Operators;Class Loading & Bytecode Verification
What is the Maven build lifecycle, and what do the common phases (validate, compile, test, package, install, deploy) each do?
IntermediateMaven's default lifecycle is a fixed, ordered sequence of phases, where running any given phase automatically executes all preceding phases in order: validate (checks project structure is correct), compile (compiles source code), test (runs unit tests via a test framework plugin like Surefire), package (bundles compiled code into a JAR/WAR), install (copies the package into the local ~/.m2 repository for use by other local projects), and deploy (publishes the package to a remote repository for sharing with other developers/environments) -- each phase is itself bound to specific plugin goals that do the actual work.
# Running 'mvn package' automatically runs validate, compile, and test first
mvn package
# Running 'mvn install' runs everything through package first, then installs to ~/.m2
mvn install
# Skip tests during a phase (use sparingly)
mvn package -DskipTests
Real-world example
A CI pipeline runs `mvn clean install` on every pull request, which automatically compiles, tests, and packages the code in one command, failing the build immediately if any earlier phase (like a failing unit test) doesn't succeed, preventing broken code from progressing further in the pipeline.
Testing Strategy;Deploy Checklist
How does Maven's dependency resolution algorithm handle transitive dependency version conflicts, and what is the "nearest definition wins" rule?
AdvancedWhen multiple dependencies (directly or transitively) require different versions of the same library, Maven resolves the conflict using "nearest definition wins": the version declared at the shallowest depth in the dependency tree (closest to your project's own pom.xml) takes precedence, with ties broken by declaration order -- this can silently select an unexpected or incompatible version, so Maven provides `mvn dependency:tree` to visualize the actual resolved tree and `<dependencyManagement>` or explicit `<exclusions>` to override the automatic resolution when the default nearest-wins choice is wrong for your project.
<!-- Forcing a specific version regardless of transitive resolution -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.2</version> <!-- forces this version project-wide -->
</dependency>
</dependencies>
</dependencyManagement>
# Diagnose the actual resolved dependency tree
mvn dependency:tree -Dverbose
Real-world example
A team debugging a mysterious NoSuchMethodError in production traces it to Maven's nearest-wins rule silently selecting an older, incompatible version of a transitive dependency over the newer version the team actually needed, resolved by explicitly pinning the correct version via dependencyManagement.
Diagnostics & Performance;Class Loading & Bytecode Verification
How does Gradle's build script (build.gradle / build.gradle.kts) differ structurally from Maven's declarative XML pom.xml?
IntermediateMaven's pom.xml is a purely declarative XML document describing what the project needs (dependencies, plugins, configuration), with the actual build logic entirely hidden inside Maven's plugin implementations; Gradle's build.gradle (Groovy DSL) or build.gradle.kts (Kotlin DSL) is instead an actual executable script, giving you a full general-purpose programming language to express custom build logic directly, imperative task definitions, and conditional configuration -- this makes Gradle more flexible and often more concise for complex, non-standard build requirements, at the cost of build scripts potentially becoming harder to reason about if that flexibility gets over-used.
// build.gradle.kts (Kotlin DSL)
plugins {
id("java")
}
dependencies {
implementation("com.fasterxml.jackson.core:jackson-databind:2.15.2")
testImplementation("org.junit.jupiter:junit-jupiter:5.10.0")
}
tasks.test {
useJUnitPlatform()
}
Real-world example
A team needing a custom build step (generating a version file from git commit metadata before compilation) finds this straightforward to express as arbitrary Kotlin code directly in their build.gradle.kts, whereas achieving the same thing in Maven would require writing and configuring a full custom plugin due to pom.xml's purely declarative nature.
Java Fundamentals: Syntax
Data Types & Operators;Class Loading & Bytecode Verification
How does Gradle's incremental build and build cache mechanism achieve significantly faster rebuild times compared to Maven's default behavior?
AdvancedGradle tracks fine-grained inputs and outputs for every task (source files, dependency versions, configuration), using content hashing to detect whether a task's actual inputs have changed since the last execution -- if unchanged, Gradle skips re-executing that task entirely (marking it UP-TO-DATE), and with the build cache enabled, can even reuse outputs from a previous build (potentially from a different machine or CI run) if the computed cache key matches, avoiding redundant compilation/test execution entirely; Maven's simpler execution model generally re-runs each bound goal on every invocation without this fine-grained incremental awareness, though Maven has been adding some incremental capabilities over time.
// gradle.properties -- enabling build caching
org.gradle.caching=true
org.gradle.parallel=true
// A task run twice with no source changes:
// First run: ":compileJava" executes normally
// Second run: ":compileJava UP-TO-DATE" -- skipped entirely, saving time
Real-world example
A large monorepo with hundreds of modules adopts Gradle's remote build cache shared across the team and CI, so a developer pulling the latest code and building locally can reuse compilation outputs already produced by a teammate's or CI's earlier build of the same unchanged code, cutting local build times from minutes to seconds.
Diagnostics & Performance;Deploy Checklist
What is the difference between Maven's <dependencies> scope values (compile, provided, runtime, test) and how do they affect what's included in the final packaged artifact?
Intermediatecompile (the default) is available at both compile-time and runtime, and IS included in the final packaged artifact and propagated transitively; provided is available at compile-time but expected to be supplied by the runtime environment (like servlet-api when deploying to an app server that already provides it), so it's excluded from the final package; runtime is needed only at runtime, not compile-time (like a JDBC driver implementation used only through a generic interface), and IS included in the package; test is available only during test compilation/execution and never included in the final package at all.
<dependencies>
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>6.0.0</version>
<scope>provided</scope> <!-- servlet container already provides this at runtime -->
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.0</version>
<scope>test</scope> <!-- only needed for running tests, excluded from the deployable WAR -->
</dependency>
</dependencies>
Real-world example
A WAR file deployed to an existing Tomcat server correctly excludes the servlet-api JAR (marked provided scope) from its packaged output, avoiding a classpath conflict with the version Tomcat itself already supplies, while still allowing the code to compile against those servlet APIs during the build.
Deploy Checklist;Class Loading & Bytecode Verification
How would you configure a multi-module Maven or Gradle project, and what benefits does modularizing a large codebase this way provide?
AdvancedA multi-module project has a parent pom.xml (Maven) or settings.gradle (Gradle) declaring child modules, each with its own build file but sharing common configuration/dependency versions from the parent -- this lets a large codebase be split into independently buildable, testable units (like separate api, core, and web modules) with explicit inter-module dependencies, enabling faster incremental builds (only rebuilding changed modules and their dependents), clearer architectural boundaries, and the ability to publish/version modules independently if needed.
<!-- parent pom.xml -->
<packaging>pom</packaging>
<modules>
<module>core</module>
<module>api</module>
<module>web</module>
</modules>
<!-- web/pom.xml declares a dependency on the sibling module -->
<dependency>
<groupId>com.example</groupId>
<artifactId>core</artifactId>
<version>${project.version}</version>
</dependency>
Real-world example
A large enterprise application splits into core (shared domain logic), api (REST controllers), and batch (scheduled jobs) modules within one multi-module Maven build, letting the team run and test just the core module in isolation during development while still building the entire application together for deployment.
System Design;Deploy Checklist
How do you resolve a dependency version conflict manually in Maven using exclusions, and when would this be necessary despite the automatic nearest-wins resolution?
Intermediate<exclusions> inside a <dependency> declaration explicitly prevents a specific transitive dependency from being pulled in through that particular parent dependency, useful when the automatic nearest-wins resolution selects an incompatible or vulnerable version, or when you want to substitute your own explicitly-declared version of that transitive dependency instead -- necessary in scenarios like a security vulnerability being patched in a newer version of a transitive library that the automatic resolution wouldn't otherwise select.
<dependency>
<groupId>com.example</groupId>
<artifactId>some-library</artifactId>
<version>1.0.0</version>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Now explicitly declare the desired, patched version yourself -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.3</version> <!-- patched for a known CVE -->
</dependency>
Real-world example
A security audit flags a known CVE in a transitive jackson-databind version pulled in indirectly through a third-party library, resolved by explicitly excluding that transitive dependency and declaring the patched version directly, without needing to wait for the third-party library maintainer to update their own dependency.
Security Headers
Antiforgery & CSRF Protection;Diagnostics & Performance
How would you write a custom Maven plugin or Gradle task to perform project-specific build automation not covered by existing plugins?
AdvancedA custom Maven plugin requires implementing AbstractMojo (annotated with @Mojo specifying the goal name), overriding execute() with your custom logic, packaged and installed as its own separate Maven artifact before being usable in a project's pom.xml; a custom Gradle task is comparatively lightweight, defined directly inline in build.gradle.kts by extending DefaultTask and annotating an action method with @TaskAction, without needing a separate publishing step for simple, project-local automation -- Gradle's approach is generally considered more approachable for one-off, project-specific automation, while Maven's plugin model suits more broadly reusable, formally-published automation.
// Custom Gradle task, defined directly in build.gradle.kts
abstract class GenerateVersionFile : DefaultTask() {
@TaskAction
fun generate() {
val versionFile = File(project.buildDir, "version.txt")
versionFile.writeText(project.version.toString())
}
}
tasks.register<GenerateVersionFile>("generateVersionFile")
tasks.named("build") { dependsOn("generateVersionFile") }
Real-world example
A team needing to generate a build metadata file (git commit hash, build timestamp) before packaging writes a lightweight custom Gradle task directly in their build script, avoiding the overhead of publishing a separate Maven plugin artifact just for this one project-specific, non-reusable piece of automation.
Background Tasks & Hosted Services;Class Loading & Bytecode Verification
What is a Maven BOM (Bill of Materials), and how does it help manage consistent dependency versions across a multi-module project or organization?
IntermediateA BOM is a special pom.xml (packaging type "pom") that declares a curated, consistent set of dependency versions inside <dependencyManagement> without actually including those dependencies itself -- importing a BOM via <scope>import</scope> lets your project's own dependency declarations omit explicit version numbers entirely (inheriting the BOM's version), ensuring all dependencies from a related family (like Spring Boot's own BOM covering dozens of compatible Spring ecosystem libraries) stay mutually compatible without manually tracking each version yourself.
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>3.2.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<!-- No version needed -- inherited from the imported BOM -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
Real-world example
A Spring Boot project imports the spring-boot-dependencies BOM, letting every Spring-related dependency declaration across the entire project omit explicit version numbers, guaranteeing all the interdependent Spring modules stay on mutually-tested, compatible versions as a cohesive set rather than needing manual version coordination.
Configuration & Options Pattern;Deploy Checklist
Showing 1–10 of 15