Jesse A. Green / notebook

Guava Admin & Architecture Guide

Generated June 2026 from google/guava at 9a5d60d

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

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-@Beta APIs remain binary-compatible indefinitely. This is what makes Guava safe to place deep in a dependency graph — but it is conditioned on avoiding @Beta APIs (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 @Beta APIs — 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 @Beta usage.

Tip

Application code (the top of the dependency graph, where you control the Guava version) may use @Beta APIs 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 enormous longArraySize and 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, or AbstractFuture falling 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's java.specification.version). Some tests need reflective access to JDK internals and the build passes --add-opens for java.base/java.lang, java.base/java.util, and java.base/sun.security.jca automatically.

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-@Beta upgrades 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 @Beta call.

8.2 Avoiding classpath conflicts

  • [x] Pin a single flavor (-jre or -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 failureaccess on the runtime classpath at the version Guava resolves.

8.3 Monitoring & verification

  • [x] Use CacheBuilder.recordStats() and read Cache.stats() (hitRate, missCount, loadExceptionCount) to observe cache effectiveness in production.
  • [x] For Service/ServiceManager-based components, register a ServiceManager.Listener and expose servicesByState() and startupDurations() 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:

  1. Decide on one flavor for the whole project.
  2. Force it: in Gradle, add a resolution strategy forcing com.google.guava:guava:33.6.0-jre (or the -android equivalent); in Maven, declare Guava explicitly in dependencyManagement.
  3. Run a dependency report (./gradlew dependencies or mvn 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-bom if 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 with sha256()+.
  • [ ] Schedule periodic version upgrades; review API diffs each time.