Dependency Management
Apache Juneau ships two packaging aids that make it easy to depend on a coherent, version-aligned slice
of the framework without hand-maintaining a long list of <version> tags:
- A Bill of Materials (BOM) —
org.apache.juneau:juneau-bom— for version alignment. - A small set of curated dependency bundles — one per deployment shape — that transitively pull a coherent module set.
Both are deliberately dependency-only aids. They register nothing and discover nothing at runtime (see Explicit over magic below).
The BOM
The ${juneau.version} property is 10.0.0-SNAPSHOT for these docs; the latest release on Maven Central is 9.2.0. See Install Juneau.
The BOM is a 10.0 artifact; it is not published for 9.2.0.
Import juneau-bom (scope import, type pom) in your <dependencyManagement> and then drop the
explicit versions from every Juneau dependency — the BOM supplies them:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.juneau</groupId>
<artifactId>juneau-bom</artifactId>
<version>${juneau.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- No <version> needed - the BOM aligns it. -->
<dependency>
<groupId>org.apache.juneau</groupId>
<artifactId>juneau-marshall</artifactId>
</dependency>
<dependency>
<groupId>org.apache.juneau</groupId>
<artifactId>juneau-rest-server</artifactId>
</dependency>
</dependencies>
The BOM enumerates the consumer-facing Juneau modules (juneau-core marshalling/config, juneau-rest,
juneau-microservice, juneau-bean, juneau-sc), the test-support modules (juneau-bct,
juneau-microservice-test, juneau-rest-mock), and the curated *-bundle POMs themselves. It excludes
aggregate/non-library artifacts (juneau-shaded/*, juneau-examples, juneau-petstore,
juneau-distrib) and the juneau-terminal build tooling.
BOM module catalog
Every module below is version-managed by juneau-bom. See the
Ecosystem Overview for what each one does and what it requires.
| Area | Managed artifacts |
|---|---|
| Core | juneau-commons, juneau-config, juneau-marshall, juneau-marshall-rdf, juneau-beanquery-sql, juneau-beanquery-postgres, juneau-bct |
| Secrets | juneau-secret-macos-keychain |
| Beans | juneau-bean-atom, juneau-bean-common, juneau-bean-hal, juneau-bean-html5, juneau-bean-jsonapi, juneau-bean-jsonpatch, juneau-bean-jsonrpc, juneau-bean-jsonschema, juneau-bean-mcp-v20250618, juneau-bean-mcp-v20260728, juneau-bean-openapi-v3, juneau-bean-rfc7807, juneau-bean-swagger-v2 |
| REST common and mock | juneau-rest-common, juneau-rest-common-classic, juneau-rest-mock |
| REST server | juneau-rest-server, juneau-rest-server-rdf, juneau-rest-server-springboot, juneau-rest-server-management-logging, juneau-rest-server-reactive, juneau-rest-server-reactive-reactor |
| REST server: MCP | juneau-rest-server-mcp, juneau-rest-server-mcp-v20250618, juneau-rest-server-mcp-v20260728 |
| REST server: auth | juneau-rest-server-auth-jwt, juneau-rest-server-auth-saml, juneau-rest-server-auth-oauth, juneau-rest-server-auth-oidc-rp, juneau-rest-auth-oauth-flow |
| REST server: observability | juneau-rest-server-metrics-micrometer, juneau-rest-server-tracing-otel |
| REST server: view engines | juneau-rest-server-view-freemarker, juneau-rest-server-view-jsp, juneau-rest-server-view-mustache, juneau-rest-server-view-thymeleaf |
| REST server: console UI and views | juneau-console, juneau-console-freemarker, juneau-console-datatables, juneau-console-views, juneau-console-views-markdown, juneau-console-widgets, juneau-terminal-report |
| REST client | juneau-rest-client, juneau-rest-client-classic, juneau-rest-client-apache-httpclient-45, juneau-rest-client-apache-httpclient-50, juneau-rest-client-okhttp, juneau-rest-client-jetty |
| REST client: MCP | juneau-rest-client-mcp, juneau-rest-client-mcp-v20250618, juneau-rest-client-mcp-v20260728, juneau-rest-client-mcp-auth |
| Microservice | juneau-microservice, juneau-microservice-jetty, juneau-microservice-tomcat, juneau-microservice-test |
| Server config | juneau-sc-server |
| Bundles | juneau-microservice-jetty-bundle, juneau-microservice-tomcat-bundle, juneau-springboot-bundle, juneau-observability-otlp-bundle |
Beyond Juneau's own modules, the BOM also pins the small set of starter-relevant third-party versions the
bundles need to stay coherent — Micrometer (micrometer-core, micrometer-registry-otlp), OpenTelemetry
(opentelemetry-api, opentelemetry-sdk, opentelemetry-exporter-otlp,
opentelemetry-sdk-extension-autoconfigure), and Jakarta (jakarta.servlet-api,
jakarta.validation-api). It is not a whole-world third-party BOM (unlike Spring Boot's), so it won't
collide with a third-party BOM you import yourself.
The bundles
Juneau also publishes bundle artifacts — <packaging>pom</packaging> Maven coordinates that pull a
curated, version-aligned set of Juneau modules (and their transitive dependencies) in a single declaration.
Each bundle targets one deployment shape: depend on a single bundle and you transitively pull a coherent
module set plus the REST client.
Bundles are dependency aggregators only: they contain no code, register no configurations, and perform
no classpath auto-discovery. Every bean, server, and resource still needs to be wired explicitly, exactly as
if you had listed the individual modules yourself. Because each bundle internally imports juneau-bom, the
modules it pulls are already version-aligned.
Bundle vs. starter. These
*-bundlePOMs are dependency aggregators — add one dependency, get a coherent module set. They are not to be confused with the clone-and-go starter project templates on dedicatedapache/juneaubranches (microservice-*-starter), which are full runnable project templates.
Bundles vs shaded JARs vs individual modules
| Approach | What it is | Best for |
|---|---|---|
| Bundle | A POM-type dependency that pulls a curated module set transitively | Applications where you control the full classpath and want a quick start |
| Shaded JAR | A single fat JAR with Juneau modules merged in | Bazel builds or environments that need a single-artifact classpath; see Juneau Shaded Artifacts |
| Individual modules | Each Juneau JAR declared explicitly | Libraries and frameworks that want fine-grained transitive dependency control |
Available bundles
| Artifact | Use when |
|---|---|
juneau-microservice-jetty-bundle | Building an embedded-Jetty microservice |
juneau-microservice-tomcat-bundle | Building an embedded-Tomcat microservice |
juneau-springboot-bundle | Adding Juneau REST resources to Spring Boot |
juneau-observability-otlp-bundle | Exporting metrics + traces over OTLP in one dependency |
juneau-microservice-jetty-bundle
<dependency>
<groupId>org.apache.juneau</groupId>
<artifactId>juneau-microservice-jetty-bundle</artifactId>
<version>${juneau.version}</version>
<type>pom</type>
</dependency>
Pulls the full embedded-Jetty microservice stack for a standalone service process:
| Direct dependency | What it brings |
|---|---|
juneau-microservice-jetty | Embedded-Jetty launcher, juneau-microservice lifecycle, juneau-rest-server, juneau-marshall, juneau-config, juneau-commons, and the Jetty embedded-server JARs at the tested compatible version |
juneau-rest-client | REST client for typical service-to-service calls |
Use this when starting a new Jetty-based microservice and you want a single dependency to bootstrap the
project. Wire your servers explicitly via Microservice.Builder.configurations(...) — the bundle performs
no auto-configuration.
See juneau-microservice-jetty for setup instructions.
juneau-microservice-tomcat-bundle
<dependency>
<groupId>org.apache.juneau</groupId>
<artifactId>juneau-microservice-tomcat-bundle</artifactId>
<version>${juneau.version}</version>
<type>pom</type>
</dependency>
The Tomcat equivalent of juneau-microservice-jetty-bundle:
| Direct dependency | What it brings |
|---|---|
juneau-microservice-tomcat | Embedded-Tomcat launcher, juneau-microservice lifecycle, juneau-rest-server, juneau-marshall, juneau-config, juneau-commons, and the Tomcat embedded-server JARs at the tested compatible version |
juneau-rest-client | REST client for typical service-to-service calls |
Wire your servers explicitly via Microservice.Builder.configurations(...).
See juneau-microservice-tomcat for setup instructions.
juneau-springboot-bundle
<dependency>
<groupId>org.apache.juneau</groupId>
<artifactId>juneau-springboot-bundle</artifactId>
<version>${juneau.version}</version>
<type>pom</type>
</dependency>
Pulls the Juneau REST server stack for a Spring Boot application:
| Direct dependency | What it brings |
|---|---|
juneau-rest-server-springboot | Spring Boot bridge, juneau-rest-server, spring-boot-starter-web, and the shared juneau-rest-common types |
juneau-rest-client | REST client for typical service-to-service calls |
Wire your @Rest-annotated resources explicitly in your Spring @Configuration classes — the bundle performs
no classpath auto-discovery.
See juneau-rest-server-springboot for Spring Boot integration details.
juneau-observability-otlp-bundle
<dependency>
<groupId>org.apache.juneau</groupId>
<artifactId>juneau-observability-otlp-bundle</artifactId>
<version>${juneau.version}</version>
<type>pom</type>
</dependency>
Pulls both Juneau observability bridges plus a coherent, version-aligned OTLP exporter stack in one dependency:
| Direct dependency | What it brings |
|---|---|
juneau-rest-server-metrics-micrometer | MicrometerMetricsRecorder — the MetricsRecorder SPI implementation |
juneau-rest-server-tracing-otel | OtelTracerHook — the TracerHook SPI implementation |
opentelemetry-exporter-otlp | OTLP span exporter |
opentelemetry-sdk | OpenTelemetry SDK (satisfies the provided OTel API dependency of the tracing bridge) |
opentelemetry-sdk-extension-autoconfigure | SDK auto-configure extension |
micrometer-registry-otlp | Micrometer OTLP registry (satisfies the provided Micrometer dependency of the metrics bridge) |
The bundle covers metrics and traces; OTLP log export is not included in v1.
Because the bundle is a dependency aggregator only, you still register the beans explicitly:
@Configuration
public class ObservabilityConfig {
@Bean MeterRegistry registry() {
// OtlpMeterRegistry is the Micrometer OTLP registry pulled by the bundle.
return new OtlpMeterRegistry(OtlpConfig.DEFAULT, Clock.SYSTEM);
}
@Bean MetricsRecorder recorder(MeterRegistry r) {
return new MicrometerMetricsRecorder(r);
}
@Bean TracerHook tracer() {
// Uses GlobalOpenTelemetry, typically wired by the OTel Java agent or SDK autoconfigure.
return new OtelTracerHook();
}
}
See Observability — Micrometer + OpenTelemetry for the full
configuration guide including per-operation controls, W3C trace-context propagation, and custom
MetricsRecorder / TracerHook implementations.
When to use a bundle vs building your own assembly
Use a bundle when:
- Starting a new application — one dependency gets you a working, version-aligned stack.
- You control the full classpath — no other dependency manager can conflict with the bundle's transitive pulls.
- You want the versions the Juneau team tested — bundle dependencies are pinned against the
juneau-bomso all Juneau sub-modules and their third-party peers are mutually compatible.
Build your own assembly when:
- Writing a library — declare only the modules your library's API surface requires; don't force your consumers to pull a full microservice stack.
- Mixing with an existing framework — if your project already declares Jetty or Spring Boot at a specific version, depend on the individual Juneau modules and let your build tool resolve the container version.
- Minimizing JAR footprint — a single microservice module is smaller than the full microservice bundle when you know exactly which Juneau features you use.
Explicit over magic (no auto-configuration)
A bundle gives you the classpath for a deployment shape. It does not wire anything up for you. Juneau
keeps configuration registration explicit — you register your configuration classes yourself through
Microservice.Builder.configurations(Class<?>...). There is no ServiceLoader / META-INF/services
scan and no @ConditionalOnClass-style classpath auto-discovery that decides what to activate based on
what happens to be on the classpath.
This is a deliberate design choice, not a missing feature. In the maintainer's words:
"No, we want an explicit classpath-driven solution. I actually see auto-configuration as a weakness in Spring Boot that leads to applications with long startup times and impossible-to-understand architectures. We should make this distinction clear in our docs."
The two costs called out there are exactly what the explicit model avoids:
- Startup time. No classpath scanning for conditional configuration to evaluate at boot. What you register is what runs.
- Comprehensibility. The set of active configurations is the literal list you passed to
configurations(...)— readable in one place, with no implicit behavior toggled on by a transitive dependency you didn't realize was present.
So the division of labor is clean: the BOM aligns versions, the bundles assemble a coherent classpath, and you stay in explicit control of what gets wired up.
See also
- Juneau Shaded Artifacts — fat JARs as an alternative to bundles (Bazel-friendly)
- Starter projects — clone-and-go runnable project templates
- Observability — Micrometer + OpenTelemetry — full guide for
juneau-observability-otlp-bundle
In This Section
📄️ 6.1.1. GraalVM Native Image & Docker Layering
This page covers two packaging concerns for Juneau applications: Docker image layering (a concrete recommendation you can apply today) and GraalVM native-image support (a feasibility assessment with a forward plan).