AutoValue → Java records
Once you are on Java 17+, many @AutoValue abstract classes can become records — getting equals/hashCode/toString for free and dropping the annotation processor. Watch for builders, factory methods, and cases where records' immutability or lack of inheritance doesn't fit.
Last verified · Updated May 22, 2026
Converting Google AutoValue value types to Java records is a low-risk modernization available once you are on Java 17+. A record gives you automatic equals/hashCode/toString and a canonical constructor, letting you delete the @AutoValue abstract class and its generated subclass. The work is in builders, factory methods, and the cases where records don't fit.
Why migrate
AutoValue generates an immutable value class at compile time via an annotation processor. Records are the language-native version of the same idea: a compact, immutable carrier with structural equals/hashCode/toString. Replacing AutoValue removes a build dependency and an annotation-processing step.
Transformation rules
| AutoValue pattern | Record equivalent |
|---|---|
| @AutoValue abstract class with abstract getters | record with components for each getter |
| Generated equals/hashCode/toString | Provided automatically by the record |
| static create(...) factory | Canonical constructor, or a static factory kept as a convenience |
| @AutoValue.Builder | No native builder — keep a hand-written builder or use the canonical constructor |
| @Nullable / validation in create() | Validation in a compact canonical constructor |
// Before: Google AutoValue
@AutoValue
abstract class Point {
abstract int x();
abstract int y();
static Point create(int x, int y) { return new AutoValue_Point(x, y); }
}
// After: Java record
record Point(int x, int y) {
// optional: validation in the compact canonical constructor
Point {
if (x < 0 || y < 0) throw new IllegalArgumentException("negative");
}
}When the pattern applies
- Simple immutable value types whose only logic is accessors plus equals/hashCode/toString.
- Types you are already touching during a Java 17+ upgrade.
- Value types without a builder, or with a builder you are willing to hand-write.
When records don't fit
- Types that need mutability — records are shallowly immutable.
- Types that rely on inheritance — records cannot extend a class.
- Heavy @AutoValue.Builder usage where dropping the builder would churn many call sites.
- Value types whose generated subclass is referenced by name elsewhere (e.g. AutoValue_Point).
If call sites use Point.create(...), keep a static factory on the record that delegates to the canonical constructor. That lets you migrate the type without touching every caller in the same change.
Review guidance
- Component order matches the old getter/constructor order
- Validation moved into the compact canonical constructor
- Builders and factory methods preserved or intentionally removed
- No remaining references to generated AutoValue_* classes
Related paths
Official sources
Backs the breaking-change and migration-step claims.