This guide is for the engineers, architects, and toolchain owners who integrate, govern, and build Guava — not just call it. It covers how the project is structured, how the two flavors are produced, the binary-compatibility policy you depend on, security considerations, and the build and release machinery. The companion User Guide covers day-to-day API usage.
Note
Guava is a published Java library, not a deployable service. "Operations" here means managing Guava as a dependency in your systems — version policy, compatibility, classpath hygiene, build integration, and security review — plus, for contributors, building it from source.
1. Executive Summary
Guava (Google Core Libraries for Java) is an Apache-2.0-licensed library, in development since 2010, that supplies foundational Java building blocks: immutable and extended collection types (multimap, multiset, bimap, table, ranges), a graph library, an in-memory cache, and utilities for concurrency, I/O, hashing, math, primitives, strings, networking, reflection, and escaping. It is used pervasively inside Google and broadly across the Java ecosystem.
| Attribute | Value |
|---|---|
| Group ID | com.google.guava |
| Artifact ID | guava |
| Flavors | -jre (JDK 1.8+) and -android |
| Runtime dependency | com.google.guava:failureaccess (single) |
| License | Apache License 2.0 |
| Inception | 2010 |
| Build | Maven (multi-module), with a Gradle integration-test harness |
| Source layout | Main code under guava/; mirrored Android sources under android/ |
| Javadoc | guava.dev/api |
Important
The single most important governance fact about Guava is its compatibility contract: non-
@BetaAPIs remain binary-compatible indefinitely. This is what makes Guava safe to place deep in a dependency graph — but it is conditioned on avoiding@BetaAPIs (see §5).
2. Architecture
2.1 Repository structure
Guava is a Maven multi-module project. The main library is guava/; the android/ tree is a
near-identical mirror maintained by an automated sync (contributors normally edit only the main
tree).
guava/ (repository root, Maven parent: guava-parent)
├── guava/ The JRE-flavor library → artifact "guava"
│ └── src/com/google/common/
│ ├── base/ Preconditions, Optional, Strings, Splitter, CharMatcher, ...
│ ├── collect/ Immutable collections, Multimap, Multiset, Range, Ordering, ...
│ ├── cache/ CacheBuilder, LoadingCache, CacheLoader
│ ├── util/concurrent/ ListenableFuture, Futures, Service, RateLimiter, Monitor, ...
│ ├── hash/ Hashing, HashFunction, BloomFilter, Funnels
│ ├── io/ Files, MoreFiles, ByteSource/Sink, CharSource/Sink, BaseEncoding
│ ├── net/ InternetDomainName, InetAddresses, MediaType, HostAndPort
│ ├── primitives/ Ints, Longs, ... and immutable primitive arrays
│ ├── math/ IntMath, LongMath, BigIntegerMath, Stats, Quantiles
│ ├── reflect/ TypeToken, Invokable, ClassPath
│ ├── eventbus/ EventBus, AsyncEventBus, @Subscribe
│ ├── graph/ Graph, ValueGraph, Network, builders, Traverser, Graphs
│ ├── escape/, html/, xml/ Escaper framework and implementations
│ └── annotations/ @Beta, @VisibleForTesting, @GwtCompatible, ...
├── android/ The Android-flavor mirror → artifact "guava" (-android version)
├── guava-bom/ Bill-of-materials POM for aligning versions
├── guava-testlib/ Reusable test suites for collection implementations
├── guava-tests/ The test suite and JMH-style benchmarks
├── guava-gwt/ GWT (Google Web Toolkit) super-source and bindings
├── futures/ failureaccess (the one runtime dep) + listenablefuture shims
├── proguard/ ProGuard/R8 keep-rules shipped to consumers
├── integration-tests/ Gradle-based consumption tests
├── util/ Maintainer shell scripts (snapshot deploy, doc update, reports)
└── pom.xml Parent POM (modules: guava, guava-bom, guava-gwt, testlib, tests)
2.2 Package map and relative size
The JRE source tree (guava/src/com/google/common) is dominated by the collections subsystem:
| Package | Source files | Role |
|---|---|---|
collect |
216 | Immutable + extended collections; the largest subsystem |
util/concurrent |
84 | Futures, services, executors, locks, rate limiting |
graph |
54 | Graph/ValueGraph/Network model |
base |
52 | Core utilities (preconditions, strings, functional types) |
io |
38 | Source/sink I/O abstractions |
hash |
34 | Hash functions and Bloom filters |
primitives |
26 | Per-primitive utilities and immutable primitive arrays |
cache |
22 | In-memory cache |
math |
17 | Overflow/rounding-aware arithmetic, statistics |
reflect |
17 | Generic-type reflection |
eventbus |
12 | Publish/subscribe |
escape |
11 | Escaper framework |
net |
10 | Networking value types |
annotations |
6 | Library annotations (@Beta, @GwtCompatible, ...) |
html, xml |
3 each | Escaper implementations |
2.3 The two-flavor model
Guava ships two artifacts that share a group/artifact ID and differ only by version suffix:
┌──────────────────────────────────────────────┐
guava/src ──►│ build (jvmEnvironment = standard-jvm) │──► guava:NN.N.N-jre (JDK 1.8+)
└──────────────────────────────────────────────┘
automated mirror ↓ (changes flow from guava/ into android/)
┌──────────────────────────────────────────────┐
android/src ──►│ build (jvmEnvironment = android) │──► guava:NN.N.N-android
└──────────────────────────────────────────────┘
The parent POM encodes this with variant.jvmEnvironment = standard-jvm (and the corresponding
android variant), so a Gradle consumer's variant-aware resolution can request the right flavor.
The android/ sources differ from guava/ only where Android API-level constraints require it
(for example, avoiding Java 8+ APIs unavailable on older Android).
Caution
Because both flavors publish as
com.google.guava:guava, a dependency graph that pulls both variants will hit a Gradle variant-selection conflict (see Troubleshooting). Standardize on one flavor across the entire graph.
2.4 GWT support
guava-gwt/ provides GWT "super-source" — alternative implementations of select classes that
compile to JavaScript — so a subset of Guava can run in the browser via Google Web Toolkit. This is
a niche consumer; most projects ignore it.
3. Requirements & Compatibility
| Concern | JRE flavor | Android flavor |
|---|---|---|
| Minimum runtime | JDK 1.8+ | Android (tested to API level 23) |
| Build JDK | Java 11+ may be needed to build; output runs on Java 8 | same |
| Runtime dependency | failureaccess:1.0.3 |
failureaccess:1.0.3 |
| Tested OS | Linux and Windows, across a range of OpenJDK versions | plus Android API 23 |
Warning
Some features, especially in
com.google.common.io, are validated primarily on Linux and may not behave correctly on other platforms. Test platform-sensitive file operations on your actual target OS.
3.1 Annotation-only dependencies
Beyond the single runtime dependency, Guava declares several annotation-only dependencies (used at compile time, not required at runtime), including JSpecify nullness annotations, Error Prone annotations, and (historically) JSR-305. These do not add runtime weight; if your build flags them as "used at runtime but declared as provided," that is expected.
4. Dependency Management
4.1 Aligning versions with the BOM
For multi-module builds, import the Guava BOM to keep every Guava-related artifact on the same version:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava-bom</artifactId>
<version>33.6.0-jre</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
4.2 The listenablefuture shim
Guava historically published a standalone listenablefuture artifact so that libraries depending
only on ListenableFuture need not pull all of Guava. The current Guava ships an empty
9999.0-empty-to-avoid-conflict-with-guava version of that artifact whose sole purpose is to
evict the older standalone copy from the classpath, preventing duplicate-class conflicts. You
normally never reference it directly; it is managed transitively.
4.3 failureaccess
com.google.guava:failureaccess is the one artifact Guava needs at runtime. It exists so that
AbstractFuture can access failure state across module boundaries. Keep it on the classpath at the
version Guava resolves (currently 1.0.3).
5. The Compatibility Contract (Critical Governance)
Guava's stability guarantees are the foundation of its safety as a deep dependency. Treat the following as policy.
| Rule | Detail |
|---|---|
Non-@Beta APIs are binary-compatible indefinitely |
They will not be removed. The last release to remove non-@Beta APIs was Guava 21.0. |
@Deprecated (non-@Beta) APIs are kept |
Deprecation is advisory, not a removal timer. |
@Beta APIs may change or vanish at any time |
No compatibility promise whatsoever. |
| Serialized forms are unstable | Do not persist Guava objects and expect a future version to read them, unless explicitly documented otherwise. |
Important
If your code is itself a library (used on classpaths you don't control), do not use
@BetaAPIs — a consumer pinned to a different Guava version could fail to link. Enforce this mechanically with the Guava Beta Checker, an Error Prone plugin that fails the build on@Betausage.
Tip
Application code (the top of the dependency graph, where you control the Guava version) may use
@BetaAPIs more freely, since you upgrade Guava and your own code together.
6. Security Analysis
Guava is a utility library with no network listeners, no privileged operations, and no configuration of its own. Its security surface is the behavior of its APIs when fed hostile data.
| Area | Assessment |
|---|---|
| Trust boundary | Not designed to defend against a malicious caller. Do not use Guava types as a boundary between trusted and untrusted code. |
| Deserialization | Serialized forms are version-unstable; deserializing attacker-controlled bytes is unsafe (see Bloom filter note below). |
| Weak hashes | Hashing.md5() and Hashing.sha1() are provided for legacy compatibility and are deprecated; they are cryptographically broken and must not be used for security. Prefer sha256() or stronger. |
| Escaping | HtmlEscapers/XmlEscapers ensure well-formedness, not full injection defense. Use a context-aware sanitizer for security-critical HTML. |
| Network parsing | InternetDomainName, InetAddresses, and HostAndPort parse untrusted strings safely (they validate and throw), but treat their results as untrusted input to downstream systems. |
Caution
BloomFilter.readFrom(InputStream, Funnel)and untrusted input — the serialized format encodes the backing array size, so a hostile stream can declare an enormouslongArraySizeand drive an unbounded memory allocation (reported as issue #8463). Only deserialize Bloom filters you produced yourself, or validate size bounds before reading.
Note
Guava follows OpenSSF Best Practices. Report suspected vulnerabilities through the project's standard channels rather than public issues.
6.1 ProGuard / R8 keep-rules
Guava ships consumer ProGuard configuration under proguard/ so that shrinkers do not strip
classes that are loaded reflectively or referenced only by optional code paths. Shipped rule files:
| File | Protects |
|---|---|
base.pro |
base reflective access (e.g. finalizable references, platform shims) |
collect.pro |
collect internals |
concurrent.pro |
util.concurrent (e.g. AbstractFuture atomic-helper selection) |
cache.pro |
cache internals |
hash.pro |
hash functions |
primitives.pro |
primitives |
Warning
If you use R8/ProGuard (typical on Android) and see
ClassNotFoundException,NoSuchMethodError, orAbstractFuturefalling back to a slower atomic helper at runtime, confirm Guava's bundled keep-rules are being applied. Stripping them is a common cause of shrink-related breakage.
7. Building From Source (Contributors)
7.1 Prerequisites
- A JDK (Java 11+ is recommended to build; the output remains Java 8-compatible).
- Maven — the repository includes the Maven Wrapper (
mvnw/mvnw.cmd), so no separate Maven install is required.
7.2 Common commands
# Build and run the full test suite (from the repository root):
./mvnw install
# Build without tests:
./mvnw install -DskipTests
# Run a single test class:
./mvnw test -Dtest.include="**/SplitterTest.java"
# Choose the JDK that runs the tests (toolchain), independent of the build JDK:
./mvnw test -Dsurefire.toolchain.version=21
Note
Tests run under the JDK named by
surefire.toolchain.version(defaulting to the build JDK'sjava.specification.version). Some tests need reflective access to JDK internals and the build passes--add-opensforjava.base/java.lang,java.base/java.util, andjava.base/sun.security.jcaautomatically.
7.3 Module build order
The parent POM builds modules in this order: guava → guava-bom → guava-gwt →
guava-testlib → guava-tests. The android/, futures/, and integration-tests/ trees build
through their own POMs.
7.4 Maintainer scripts (util/)
| Script | Purpose |
|---|---|
util/deploy_snapshot.sh |
Publish a 999.0.0-HEAD-*-SNAPSHOT build from master |
util/update_snapshot_docs.sh |
Refresh the snapshot Javadoc/diffs on guava.dev |
util/gradle_integration_tests.sh |
Run the Gradle consumption tests under integration-tests/ |
util/print_surefire_reports.sh |
Summarize Surefire test reports |
7.5 Contribution workflow
Important
Guava is a subset of Google's internal codebase, automatically synced to GitHub. Pull requests are not merged directly into
master. Instead, maintainers apply the change internally; when it syncs out, the original author is credited on the commit.
Key contributor rules:
- [ ] API changes require discussion first. Open an issue with concrete use cases before writing code — API design and review come before implementation.
- [ ] Significant changes need tests. The project has strong coverage; mirror existing tests.
- [ ] Sign the Google CLA (individual or corporate) before contributing.
- [ ] Apache-2.0 license header on every file, copied from an existing file.
- [ ] Format with the Google Java Style Guide.
- [ ] Do not edit
android/directly — a script mirrors changes from the main directories.
8. Operations: Managing Guava as a Dependency
Because Guava is a library, "operations" is dependency lifecycle management.
8.1 Upgrading
- [x] Track the latest release and upgrade on a
regular cadence; non-
@Betaupgrades are binary-compatible, so bumps are usually low risk. - [x] Read the snapshot API diffs (guava.dev → snapshot diffs) to see what changed between versions.
- [x] If you ship a library, keep the Beta Checker in CI so an upgrade never silently introduces a
@Betacall.
8.2 Avoiding classpath conflicts
- [x] Pin a single flavor (
-jreor-android) across the whole build. - [x] Let the empty
listenablefuture:9999.0-empty-...shim evict the old standalone artifact — don't exclude it. - [x] Keep
failureaccesson the runtime classpath at the version Guava resolves.
8.3 Monitoring & verification
- [x] Use
CacheBuilder.recordStats()and readCache.stats()(hitRate,missCount,loadExceptionCount) to observe cache effectiveness in production. - [x] For
Service/ServiceManager-based components, register aServiceManager.Listenerand exposeservicesByState()andstartupDurations()to your metrics.
9. Troubleshooting
Error: Gradle VariantSelectionByAttributesException resolving Guava
Cause: The dependency graph requests both the -jre and -android variants of
com.google.guava:guava, and Gradle cannot reconcile the jvmEnvironment attribute (issue #8398).
Resolution:
- Decide on one flavor for the whole project.
- Force it: in Gradle, add a resolution strategy forcing
com.google.guava:guava:33.6.0-jre(or the-androidequivalent); in Maven, declare Guava explicitly independencyManagement. - Run a dependency report (
./gradlew dependenciesormvn dependency:tree) to find which transitive dependency pulled the other flavor, and align it.
Error: NoSuchMethodError / ClassNotFoundException after R8/ProGuard shrinking (Android)
Cause: The shrinker removed classes or members Guava loads reflectively because the bundled keep-rules were not applied.
Resolution: Ensure the proguard/*.pro rules packaged with Guava are picked up by your build
(they are consumer rules and should apply automatically via the AAR/JAR metadata). Do not strip
them; add explicit -keep rules if your toolchain ignores bundled ones.
Problem: AbstractFuture logs a fallback to a slower atomic helper
Cause: The optimal sun.misc.Unsafe/AtomicReferenceFieldUpdater path is unavailable —
commonly because a shrinker removed it or the runtime restricts reflective access.
Resolution: Apply proguard/concurrent.pro; on a module path, ensure required --add-opens
are present for tests/tools that need reflective access.
Problem: Duplicate-class errors mentioning ListenableFuture
Cause: Both modern Guava and the old standalone listenablefuture artifact are on the
classpath.
Resolution: Let Guava's empty listenablefuture shim win (don't exclude it); run a dependency
tree to confirm only the 9999.0-empty-... version is resolved.
Problem: A build flags Guava's annotation dependencies as "used but undeclared"
Cause: JSpecify/Error Prone/JSR-305 annotations are compile-time only.
Resolution: This is expected; mark them as provided/optional or ignore the warning. They are not needed at runtime.
10. Quick Reference
10.1 Coordinates
<!-- JRE -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>33.6.0-jre</version>
</dependency>
implementation("com.google.guava:guava:33.6.0-jre") // or -android
10.2 Key facts
| Fact | Value |
|---|---|
| Group / artifact | com.google.guava / guava |
| Flavors | -jre (JDK 1.8+), -android |
| Runtime dependency | failureaccess:1.0.3 (only) |
| License | Apache 2.0 |
| Compatibility | Non-@Beta APIs stable indefinitely; last removal in 21.0 |
| Beta enforcement | Guava Beta Checker |
| BOM | com.google.guava:guava-bom |
| Javadoc | guava.dev/api, guava.dev/{ClassName} |
| Build | ./mvnw install (Maven Wrapper included) |
10.3 Subsystem owners' map
| If you need… | Look in package |
|---|---|
| Argument checks, strings, functional types | base |
| Immutable / extended collections, ranges | collect |
| In-memory cache | cache |
| Futures, services, executors, rate limiting | util.concurrent |
| Hashing, Bloom filters | hash |
| File / stream / encoding I/O | io |
| Domain names, IPs, media types | net |
| Primitive utilities | primitives |
| Overflow-safe math, statistics | math |
| Generic-type reflection, classpath scanning | reflect |
| Publish/subscribe | eventbus |
| Graph / network modeling | graph |
| HTML/XML/URL escaping | escape, html, xml, net |
10.4 Governance checklist for adopting Guava
- [ ] Pick a flavor (
-jre/-android) and pin it project-wide. - [ ] Import
guava-bomif you have multiple Guava artifacts. - [ ] Add the Beta Checker if you ship a library.
- [ ] Apply Guava's ProGuard rules if you shrink (Android).
- [ ] Avoid deserializing Guava objects from untrusted input.
- [ ] Replace any
md5()/sha1()security usage withsha256()+. - [ ] Schedule periodic version upgrades; review API diffs each time.