skip to content

A teammate imported your BOM but their build can't find the classes. What likely went wrong?

level: juniorimportance: should knowfreq 40%

answer

  1. import = versions only, no classpath
  2. must declare real <dependency>
  3. omit version, keep groupId/artifactId
  4. type=pom + dependencyManagement
  5. mvn dependency:tree to verify

basics

~10 s

Importing a BOM only sets versions; it does not add anything to the classpath. They still need to declare the actual dependencies in <dependencies> (without a version) to get the classes.

solid answer

~30 s

A BOM import inside `<dependencyManagement>` with `scope=import` only contributes **managed versions** — it never adds dependencies to the build. The teammate must additionally declare the libraries they want in the regular `<dependencies>` section, omitting `<version>` so the BOM supplies it. Symptom 'cannot find classes' = they imported the catalog but didn't actually depend on anything. Related mistakes: putting the import in `<dependencies>` instead of `<dependencyManagement>`, or forgetting `<type>pom</type>`. The fix is to add real `<dependency>` entries for the artifacts they use.

code

xml · 7 lines
xml
<!-- after the import, you STILL need this -->
<dependencies>
  <dependency>
    <groupId>com.acme</groupId>
    <artifactId>acme-core</artifactId>
  </dependency>
</dependencies>

go deeper

for a junior

Remember: BOM import = versions only; you still declare dependencies.

for a middle

Diagnose with dependency:tree and check import placement/type.

for a senior

Teach the distinction and spot related coordinate-mismatch errors.

for a principal

Document consumption patterns so teams avoid this recurring trap.

## The core misunderstanding People expect that importing a BOM "adds Spring" or "adds Jackson." It does **not**. `<dependencyManagement>` — including imported BOMs — only **declares versions/scopes/exclusions**. Nothing lands on the classpath until you declare an actual `<dependency>`. ## The broken setup ```xml <dependencyManagement> <dependencies> <dependency> <groupId>com.acme</groupId> <artifactId>acme-bom</artifactId> <version>1.4.0</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <!-- ...and NO <dependencies> block, so nothing is on the classpath --> ``` Compilation fails with `cannot find symbol` / `package does not exist` because no JAR was added. ## The fix ```xml <dependencies> <dependency> <groupId>com.acme</groupId> <artifactId>acme-core</artifactId> <!-- no version: comes from the imported BOM --> </dependency> </dependencies> ``` ## Other common causes of the same symptom - **Import placed in `<dependencies>` instead of `<dependencyManagement>`** — `scope=import` is only valid in dependencyManagement; elsewhere it's meaningless and the artifact (a POM) brings no classes. - **Missing `<type>pom</type>`** — resolution of the BOM itself fails. - **Declared the dependency but typo'd the groupId/artifactId** so it doesn't match a managed entry, leaving the version unset (build error about missing version). ## Quick diagnosis `mvn dependency:tree` shows what's actually on the classpath. If the library isn't in the tree, the consumer never declared it — confirming the BOM-only-manages-versions point.

  • How can the teammate verify what's actually on the classpath?
    Run mvn dependency:tree; if the library isn't listed, it was never declared as a real dependency.
  • What if they get 'dependency version not specified'?
    Their groupId/artifactId doesn't match a managed entry in the BOM (typo or not covered), so no version is supplied — fix the coordinates or add a version.

Importing a BOM is like getting a menu with prices — it doesn't bring you food. You still have to order the dishes (declare dependencies).

saying these in an interview costs you the question

  • Believing importing a BOM puts libraries on the classpath.
  • Putting scope=import inside <dependencies>.
  • Adding a version back to every dependency, defeating the BOM's purpose.

context