github.com-google-guava
all · 3 devs · built 2026-06-13
Repository snapshot
Monthly reports
Highlights
- Enhanced *BloomFilter* robustness with a new `readFrom` method that accepts `maxAllowedSizeInBits` to prevent out-of-memory issues from untrusted input streams, implemented in [6296a954 · Kurt Alfred Kluever].
- Extensive *test infrastructure* improvements, including running `@LargeTest` tests under Android emulators by default [74903e51 · cpovirk], migrating several I/O and concurrency tests off Mockito [10f016ed · cpovirk], and enabling more concurrency tests to run under J2KT/Native [8fa708be · cpovirk].
- Significant *code quality* and *refactoring* efforts, addressing Error Prone `ReferenceEquality` warnings across core and testlib [1c19bcbf · cpovirk], eliminating the deprecated `ImmutableSet.Indexed` class [fbd27751 · cpovirk], and modernizing collection instantiations to use direct constructors [43ad354d · cpovirk].
- Numerous *documentation improvements* were made, such as clarifying `BloomFilter` equality [5ec43b12 · cpovirk], restoring missing `@since` annotations [65fcca60 · cpovirk], and adding Javadoc summaries for `MediaType` constants [9ea94b0d · cpovirk].
- Internal *performance optimizations* were introduced, including reducing unnecessary object allocations in the *Hashing* library [5a83b928 · Chaoren Lin] and short-circuiting `TypeToken.equals` for same-instance comparisons [41f20cf6 · Patrick Strawderman].
Observations
- Overall commit volume decreased by 46% (32 commits this month vs 59-commit 2-month average).
- Total output score dropped by 65% (7 this month vs 21-score 2-month average), indicating a substantial reduction in impactful changes.
- Maintenance score decreased by 64% (7 this month vs 19-score 2-month average), aligning with the overall reduction in activity.
- The grow score remained at 0, consistent with the 2-month average, indicating no new feature development or significant enhancements contributing to this metric.
- The waste score was 0 this month, representing a 92% decrease compared to the 1-score 2-month average, suggesting highly focused and effective changes without rework.
- Development activity was almost exclusively focused on *maintenance* and *refactoring*, with 31 out of 32 commits explicitly categorized as maintenance or having zero grow/waste scores, highlighting a period of internal consolidation.
- A strong pattern of *code quality* improvements was observed, including addressing static analysis warnings (Error Prone, nullness annotations) and removing redundant code elements (e.g., `final` keywords in [1d5c444f · cpovirk], redundant annotations in [6f3f85df · cpovirk]).
- Significant investment was made in *test infrastructure* and *platform compatibility*, with updates for Android emulators, migration from Mockito, and expanded J2KT/Native test coverage.
- Despite a commit ([6296a954 · Kurt Alfred Kluever]) introducing a new capability for *BloomFilter* robustness, it did not contribute to the overall grow score, indicating that the metric might not capture all forms of 'growth' or that its impact was deemed minor by the scoring system.
Performance over time
ETV stacked by Growth, Maintenance and Fixes — 90-day moving average, normalized to ETV / month.
Average performance per developer
ETV per active developer per month — 30-day moving average.
Active developers over time
Unique developers committing each day — 90-day moving average.
Knowledge concentration
How dependent is this repo on a small number of contributors? Higher top-1 share = higher key-person risk.
cpovirk owns 88.6 % of commits.
Top contributors
Most impactful commits
Top 20 by ETV in the all-time window.
- 4.2ETVRemove unnecessary type arguments. This CL comes courtesy of IntelliJ. (I did revert a few files that ended up with errors, probably often from non-javac tools like our transpilers, and I reverted one tiny part of `OrderingTest`. I may have been able to get away with reverting less.) (previously: https://github.com/google/guava/commit/cb0e7e0cb1c62012934d998ca4d0222a758a9831, https://github.com/google/guava/commit/c1ffb313fd084c865e539c9b6dc795edade21d6a, https://github.com/google/guava/commit/35a4ccbcbb86952f1c021424acd70c7526e8964d, https://github.com/google/guava/commit/08f213923dab324b53a5ee93151a2a2c04be0784, https://github.com/google/guava/commit/274062cdc2a3819ff4b0286e57973b1bbe8c8519, which together explain why I'm not seeing hits in the prod code for packages like `collect`) RELNOTES=n/a PiperOrigin-RevId: 906444162cpovirk · b16d0611 · 2026-04-27
- 2.7ETVMark test-suite-builder suites and related code as `@AndroidIncompatible`. (Along the way, break out `SynchronizedSetTest.TestSet` into a top-level type `LockHeldAssertingSet`, which should also make it easier to run each test in an individual build target someday.) (I did also sneak in one change to the backport copy of `IteratorsTest`. It resolve a diff that we accidentally introduced in cl/613629330.) Such code is already not run when we run our tests under Android emulators. (The Android JUnit 3 runner just ignores `suite()` methods, I want to say?) However, it's still _built_ for them. Besides being a waste, this requires pulling in the whole suite-builder ecosystem, which is again causing problems when I try to bump various things related to Android version—quite possibly a sign that the Android runner starts actually using `suite()` methods, whose large numbers of tests (at least in `common.collect`) are just too much for that environment? By adding `@AndroidIncompatible`, I configure our Android test build to strip the code altogether. RELNOTES=n/a PiperOrigin-RevId: 719651707cpovirk · 1d3cbf82 · 2025-01-25
- 2.5ETVUse most of the main `AbstractFuture` implementation from J2KT and from GWT/J2CL. This CL introduces a superclass, `AbstractFutureState`, following the pattern of [`AggregateFutureState`](https://github.com/google/guava/blob/master/guava/src/com/google/common/util/concurrent/AggregateFutureState.java). That superclass contains platform-specific operations. Fixes https://github.com/google/guava/issues/2934 RELNOTES=n/a PiperOrigin-RevId: 729328833cpovirk · b15c23fb · 2025-02-21
- 2.4ETVUse `assertThrows` more. I addressed the resulting https://errorprone.info/bugpattern/AssertThrowsMinimizer warnings where I saw them in an early snapshot. But I seem to be seeing them at different places at different times, so I'm leaving some that I'll get in a future round. Also, add two missing(?) tests of `clear()` in backport copy of `MapsTest.ensureNotDirectlyModifiable`. RELNOTES=n/a PiperOrigin-RevId: 895922607cpovirk · 04098aa3 · 2026-04-07
- 2.2ETVRefactor the main `AbstractFuture` implementation to prepare for using it for more environments. That includes J2KT and [GWT/J2CL](https://github.com/google/guava/issues/2934). Changes include: - Suppress nullness at smaller scopes, fixing errors that were hidden by the old, broad suppression. - Remove `synchronized` from an override of `fillInStackTrace`. J2KT doesn't like `synchronized` except on very specific types, and we don't need it. - Introduce `rethrowIfErrorOtherThanStackOverflow` and `interruptCurrentThread`, `Platform` methods that will require different implementations for J2KT and J2CL/GWT. - Introduce helper methods like `casListeners(expect, update)` for `AtomicHelper` operations. These reduce verbosity relative to `ATOMIC_HELPER.casListeners(this, expect, update)`. They also prepare for `AbstractFuture` implementations that don't use `AtomicHelper`. - Introduce `notInstanceOfSetFuture`. This is arguably nicer than `!(localValue instanceof SetFuture)`, but the real purpose is to prepare for when code in a different file needs to check `instance SetFuture`. (I could be convinced that I should just make `SetFuture` package-private instead, even though no one outside the file should use it for anything but an `instanceof` check.) - Mysteriously move things around, increase visibility of members, and introduce and sometimes use accessors. This is to prepare for when some of the code will be moving to a separate file so that the remainder of `AbstractFuture` can be wholly shared across different platforms. - Fix a few typos in comments. Also, rename `SetFuture`. This isn't directly related, but now is as good a time as any to do it. Additional bonus: This CL probably makes [the logging at the "end" of `AbstractFuture` static initialization](https://github.com/google/guava/blob/7ec362ec68b630363231d5292cd6b2577c710be6/guava/src/com/google/common/util/concurrent/AbstractFuture.java#L210) have a better chance of actually working in the hypothetical situation that a logger uses `AbstractFuture`: Currently, `AbstractFuture` performs some further initialization _after_ that logging (such as the initialization of `NULL`). Now, it performs all that initialization before the `static` block that might log. RELNOTES=n/a PiperOrigin-RevId: 729313044cpovirk · 2dd82ad9 · 2025-02-21
- 2.0ETVUse _more_ lambdas. RELNOTES=n/a PiperOrigin-RevId: 725740741cpovirk · c282d6a6 · 2025-02-11
- 2.0ETVUse Truth in place of `assertEquals` assertions for `Enum` types. RELNOTES=n/a PiperOrigin-RevId: 899198656cpovirk · b52b8e21 · 2026-04-13
- 1.8ETVUse `assertThat(...).isEqualTo(...)` instead of `assertEquals(..., ...)` for `String` assertions. ...in `base`. RELNOTES=n/a PiperOrigin-RevId: 882875041cpovirk · 7fdb708d · 2026-03-13
- 1.7ETVStatically import members of `Funnels` and `Hashing`. ...except for `Funnels.asOutputStream`. RELNOTES=n/a PiperOrigin-RevId: 886295873cpovirk · 8e1cff49 · 2026-03-19
- 1.6ETVAddress nullness-checking errors in tests. RELNOTES=n/a PiperOrigin-RevId: 884464459cpovirk · 199848a8 · 2026-03-16
- 1.6ETVAvoid setting `final` fields in `ConcurrentHashMultiset` deserialization. This covers the first class from https://github.com/google/guava/issues/8099. As part of doing that, I needed a way to create a new `ConcurrentHashMap` instances without failing the existing `countMap.isEmpty()` check in the constructor. To do that, I moved the check out of the constructor and into the `create(ConcurrentMap)` static factory method. Then I updated all existing users of the constructor to instead call `create(ConcurrentMap)`. Along the way, I noticed that we'd never removed a TODO about exposing `create(ConcurrentMap)` in the first place, so I removed that. Plus: - I updated the comment about why we override `toArray`. (Spoiler: We probably shouldn't override one of the two overloads anymore.) I also tweaked the name of a helper method. - I added `@Serial` annotations to our serialization-related methods, and I removed one such method's `@J2ktIncompatible` annotation, which was unnecessary because the entire class is `@J2ktIncompatible`. - other tiny tweaks, including in tests (Fun fact: Back when I was discussing with Gemini the alternative of switching to using default serialization, it noticed the existing incorrect type for `deserializedCountMap`. back then, the type was worth fixing just to be pedantic, but now it actually matters.) RELNOTES=`collect`: Changed `ConcurrentHashMultiset` deserialization to [avoid mutating `final` fields](https://openjdk.org/jeps/500). In extremely unlikely scenarios in which an instance of that type contains an object that refers back to that instance, this could lead to [a broken instance](https://docs.oracle.com/en/java/javase/25/docs/specs/serialization/input.html#the-readresolve-method:~:text=in%20cases%20where%20an%20object%20being%20serialized%20nominates%20a%20replacement%20object%20whose%20object%20graph%20has%20a%20reference%20to%20the%20original%20object) that throws `NullPointerException` when used. PiperOrigin-RevId: 841920488cpovirk · 8240c7e5 · 2025-12-08
- 1.4ETVMake `UnsafeComparator` class initialization succeed even in cases in which we can't use that comparator. This accommodates some apps that eagerly initialize internal Guava classes that they've seen used in previous runs. Currently, such apps crash when `UnsafeComparator` fails to initialize, either because of `--sun-misc-unsafe-memory-access=deny` or because of `-XX:+UseCompactObjectHeaders`. This CL makes the class initialization succeed, setting a flag to indicate whether we should actually use the resulting comparator. Really, failing class initialization has always been a gross way to operate. Concretely, we've seen similar tricks cause log spam on Android (https://github.com/google/guava/commit/fb109b051c9ec48d5e77bf73b33a228ab5d57462). (Granted, we'd expect `Unsafe` to remain available for a long time under Android, so we shouldn't see that kind of issue here—at least not unless optimizers like Proguard are removing `UnsafeComparator`, in which case we'd rather make them stop doing that, rather than silence the warning as we do here....) I also found it convenient to eliminate an `unchecked` warning as part of introducing `interface LexicographicalComparator`, and I suppressed some `deprecation` warnings for `Unsafe`. Finally, I belatedly updated some documentation that was still suggesting that `Unsafe` was our preferred implementation in all environments. RELNOTES=n/a PiperOrigin-RevId: 843239216cpovirk · b64ee66f · 2025-12-11
- 1.4ETVRefactor the non-Android implementation of `HashBiMap`: - Rename `BiEntry` to `Node`, and make it not an `Entry`, since we already expose wrapper `Entry` objects to users in all cases. (Then use `equals` on it instead of `==` when we want identity comparison.) - Rename `Itr` to `BiIterator`, and make it `static` (with some `final` methods along the way). - Add a TODO about memory retention. - Add a couple "missing" `@CanIgnoreReturnValue` annotations to overrides in private, nested classes. - Make `Inverse` `static`. Also, make it use the name "obverse" instead of "forward," and rename parameters to make them match the superclass's parameters. The parameter names currently upset [OverridingMethodInconsistentArgumentNamesChecker](https://errorprone.info/bugpattern/OverridingMethodInconsistentArgumentNamesChecker). _Any_ name change from the base method upsets Kotlin builds, as we are likely already performing through J2KT. It's probably just a warning, but we may try to make it stricter someday. (Then update the Android implementation for the "observe" naming, patching up some gratuitous textual diffs between the flavors and making some members `private`, `private`, or `@LazyInit` along the way.) RELNOTES=n/a PiperOrigin-RevId: 845246988cpovirk · 20974405 · 2025-12-16
- 1.4ETVUse Truth in `IntMathTest` and `LongMathTest`. Fix an expected-actual mixup in `LongMath.testPow`. (Thanks, Gemini!) Suppress some false-positive warnings about seeming expected-actual mixups. PiperOrigin-RevId: 901341514cpovirk · e822c249 · 2026-04-17
- 1.3ETVMake `ClosingFuture` use `PhantomReference` instead of `finalize()`. Compare what https://github.com/google/guava/commit/7c6b17c0199c875ffa426c0fb0f51ba7d66f98ec did for `FileBackedOutputStream`. As in that CL, this CL adds `reachabilityFence` calls. I think that the calls are technically more necessary here than they were in `FileBackedOutputStream`, where we could probably [rely on `synchronized` to keep the object alive](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/ref/Reference.html#reachabilityFence(java.lang.Object)). Incidentally, they are equally necessary under the current `ClosingFuture` approach that uses `finalize()`. (So that gives some indication of how much they matter _in practice_: probably not much.) I had a thought at one point that maybe `reachabilityFence` was necessary only in the _terminal_ operations: Since every `ClosingFuture` pipeline should end with a terminal operation, we should be able to rely on a `reachabilityFence` in that terminal operation to keep the chain alive. However, I now think it's best to put a fence in all operations: - It's simpler. - It behaves better for broken code that lacks a terminal operation: If not for fences on intermediate operations, then such code might see its `ClosingFuture` closed by GC while it's still operating on it. And while such code is buggy, I don't think we want to cause its intermediate operations to _throw_. By putting `reachabilityFence` calls in such operations, we keep the `ClosingFuture` alive until those operations complete, at which point it can leak "properly," getting closed with no harm to anyone except the resulting log message. Finally: As a minor follow-up to https://github.com/google/guava/commit/9744861cb9b985bb832b81da91233b423b812276, I arranged for the `Finalizer` thread to always have an unobfuscated _thread name_, even when the class name of `Finalizer` gets obfuscated. RELNOTES=Migrated some prod classes from `finalize()` to `PhantomReference` in preparation for [the removal of finalization](https://openjdk.org/jeps/421). (7c6b17c) PiperOrigin-RevId: 881753103cpovirk · aeef9098 · 2026-03-11
- 1.3ETVRemove some unnecessary type arguments. This is another CL that comes courtesy of IntelliJ. RELNOTES=n/a PiperOrigin-RevId: 810092731cpovirk · 08f21392 · 2025-09-22
- 1.3ETVStatic import methods from `Executors` and `MoreExecutors`. RELNOTES=n/a PiperOrigin-RevId: 782057653cpovirk · 4c119ee1 · 2025-07-11
- 1.3ETVAddress some https://errorprone.info/bugpattern/ReferenceEquality warnings. There are many others left, but this is a start. Plus, sneak in a migration to `SimpleImmutableEntry`, which we had avoided long ago for GWT reasons. RELNOTES=n/a PiperOrigin-RevId: 922103048cpovirk · 1c19bcbf · 2026-05-27
- 1.3ETVUse some collection constructors (and a few more static imports). And address some other warnings and oddities. RELNOTES=n/a PiperOrigin-RevId: 909294379cpovirk · 43ad354d · 2026-05-02
- 1.3ETVAvoid setting `final` fields in `ImmutableMultimap` and `TreeMultiset` deserialization. Compare to what we did for `ConcurrentHashMultiset` in https://github.com/google/guava/commit/8240c7e5963ee69464e870603d2e0dac06726ebb. Fixes https://github.com/google/guava/issues/8099 RELNOTES=`collect`: Changed `ImmutableMap` and `TreeMultiset` deserialization to [avoid mutating `final` fields](https://openjdk.org/jeps/500). In extremely unlikely scenarios in which an instance of that type contains an object that refers back to that instance, this could lead to [a broken instance](https://docs.oracle.com/en/java/javase/25/docs/specs/serialization/input.html#the-readresolve-method:~:text=in%20cases%20where%20an%20object%20being%20serialized%20nominates%20a%20replacement%20object%20whose%20object%20graph%20has%20a%20reference%20to%20the%20original%20object) that throws `NullPointerException` when used. PiperOrigin-RevId: 842237977cpovirk · 04646805 · 2025-12-09