blob: 06326b9a98219458a3a6de40645a53e988c22d06 [file] [view]
AutoValue
=========
*Immutable value-type code generation for Java 1.6+* <br />
***Kevin Bourrillion, Éamonn McManus*** <br />
**Google, Inc.**
> "AutoValue may sound like a cheesy newspaper for
> unloading your jalopy on an unsuspecting stranger,
> but it's actually a great tool for eliminating the
> drudgery of writing mundane value classes in Java.
> It encapsulates much of the advice in Effective
> Java Chapter 2, and frees you to concentrate on
> the more interesting aspects of your program.
> The resulting program is likely to be shorter,
> clearer, and freer of bugs. Two thumbs up."
>
> -- Joshua Bloch, author, Effective Java
Contents
------------------
<!-- generated with http://doctoc.herokuapp.com/ -->
- [Background](#background)
- [Design goals](#design-goals)
- [How to use AutoValue](#how-to-use-autovalue)
- [In Example.java](#in-examplejava)
- [In ExampleTest.java](#in-exampletestjava)
- [In pom.xml](#in-pomxml)
- [What's going on here?](#whats-going-on-here)
- [Builders](#builders)
- [Optional "features"](#optional-features)
- [Data hiding](#data-hiding)
- [Multiple creation paths](#multiple-creation-paths)
- [Default values with builders](#default-values-with-builders)
- [Nullability](#nullability)
- [JavaBeans-style prefixes are optional](#javabeans-style-prefixes-are-optional)
- [Other preconditions or preprocessing](#other-preconditions-or-preprocessing)
- [Custom implementations](#custom-implementations)
- [Nesting](#nesting)
- [Derived fields](#derived-fields)
- [Generics](#generics)
- [Converting back to a builder](#converting-back-to-a-builder)
- [Serialization](#serialization)
- [Warnings](#warnings)
- [Restrictions and non-features](#restrictions-and-non-features)
- [Best practices](#best-practices)
- [Alternatives](#alternatives)
Background
------------------
Classes with value semantics are extremely common in Java.
These are classes for which object identity is irrelevant,
and instances are considered interchangeable based only on
the equality of their field values. We will refer to these
classes as value types in this document.
To implement a value type safely and properly requires
implementing `equals`, `hashCode` and `toString` in a bloated,
repetitive, formulaic yet error-prone fashion. These methods
are not especially time-consuming to write, especially with
the aid of IDE templates and a few Guava helpers, but they
are a continual burden to reviewers, editors and future
readers. Their wide expanses of boilerplate sharply decrease
the signal-to-noise ratio of your code, and constitute
probably the single greatest violation of the DRY (Don't
Repeat Yourself) principle we are ever forced to commit.
AutoValue provides an easier way to create immutable value
types, with less code and less room for error, while **not
restricting your freedom** to code any aspect of your class
just the way you want it.
Design goals
------------------
AutoValue is the only solution to the value types problem in
Java (that we are aware of) having all of the following
characteristics:
* Usage is **API-invisible** (callers cannot become
dependent on your choice to use it, or generally
even tell the difference)
* No required runtime dependencies
* No performance penalty vs. hand-written code.
* Virtually no limitations on what you can do with your
class (private accessors, implementing interfaces,
custom `hashCode()`, etc. See the "optional features"
section.)
* Minimal extralinguistic magic
How to use AutoValue
------------------
The way to use AutoValue is a little surprising at first!
Create your value type as an abstract class, containing
an abstract accessor method for each desired field. This
accessor can be any non-void, parameterless method. Add
the @AutoValue annotation to your class, and AutoValue will
automatically generate an implementing class.
### In `Example.java`
```java
import com.google.auto.value.AutoValue;
class Example {
 @AutoValue
 abstract static class Animal {
   static Animal create(String name, int numberOfLegs) {
     return new AutoValue_Example_Animal(name, numberOfLegs);
// (or just AutoValue_Animal if this is not nested)
   }
   abstract String name();
   abstract int numberOfLegs();
 }
}
```
That's it! (In real life, some classes and methods would
presumably be public and have Javadoc.)
The central idea behind AutoValue is: if you can create
an abstract class that has one "obvious" reasonable
implementation, a tool ought to be able to write that
implementation for you. And now it does.
### In `ExampleTest.java`
To a consumer, this looks and functions like any other object.
The simple test below illustrates that behavior. Note that in
real life, you would write tests that actually **do something
interesting** with the object, instead of just checking field
values going in and out.
```java
public void testAnimal() {
Animal dog = Animal.create("dog", 4);
assertEquals("dog", dog.name());
assertEquals(4, dog.numberOfLegs());
// You really don't need to write tests like these; just illustrating.
assertTrue(Animal.create("dog", 4).equals(dog));
assertFalse(Animal.create("cat", 4).equals(dog));
assertFalse(Animal.create("dog", 2).equals(dog));
assertEquals("Animal{name=dog, numberOfLegs=4}", dog.toString());
}
```
### In `pom.xml`
add the following to your Maven configuration:
```xml
<dependency>
<groupId>com.google.auto.value</groupId>
<artifactId>auto-value</artifactId>
<version>1.0</version>
<scope>provided</scope>
</dependency>
```
### What's going on here?
AutoValue runs as a standard annotation processor in javac.
It generates source code, in your package, for a *package-private*
implementation class called **`AutoValue_Example_Animal`**. The generated
class contains a field for each abstract accessor method, and
the generated constructor sets these fields. It implements the
accessor methods to simply return those references/values. It
implements equals to compare these values in the standard
fashion, and implements an appropriate corresponding `hashCode`.
It implements `toString` to return an unspecified string
representation of the class.
Consumers of your value type don't need to know any of this.
They just invoke your provided factory method and get a
well-behaved instance back.
### Builders
You may prefer to construct some objects through _builders_. If there
is a nested interface or abstract class that is annotated with
`@AutoValue.Builder`, then AutoValue will implement it to make it a
builder class. The `@AutoValue.Builder` interface or class is conventionally
called `Builder`. It must have method for every property to set the
value of the property, and a build method. Here is the example above
written using builders.
```java
import com.google.auto.value.AutoValue;
class Example {
 @AutoValue
 abstract static class Animal {
static Builder builder() {
return new AutoValue_Example_Animal.Builder();
}
   abstract String name();
   abstract int numberOfLegs();
@AutoValue.Builder
interface Builder {
Builder name(String s);
Builder numberOfLegs(int n);
Animal build();
}
 }
}
```
Now client code can look something like this:
```java
Animal dog = Animal.builder().name("dog").numberOfLegs(4).build();
```
Optional "features"
------------------
Many of the following are not even features of AutoValue itself,
just features of the Java language which (unlike some other
solutions to the value types problem) AutoValue doesn't get in
the way of.
### Data hiding
Your accessors don't have to be public! They do have to be at
least package-private. The fields themselves cannot be directly
accessed.
### Multiple creation paths
You can offer as many static creation methods as you need, named
descriptively, to cover different combinations of parameters.
They do not need to be named `create` as in the example.
### Default values with builders
Generated builders require every property to be set, except
`@Nullable` properties. If you want to define a default value for a
property, set it in the `builder()` method before returning. Here's
how to define that animals have 4 legs by default:
```java
class Example {
 @AutoValue
 abstract static class Animal {
static Builder builder() {
return new AutoValue_Example_Animal.Builder()
.numberOfLegs(4);
}
// ...remainder as before...
 }
}
```
### Nullability
By default, AutoValue inserts a not-null check for each non-primitive
parameter passed to the generated constructor. If your class has a
property that is allowed to be null, apply `@Nullable` to the
corresponding accessor method and factory parameter. This has two
effects: AutoValue will skip the null check, and generate null-friendly
code for `equals` and `hashCode`. The `@Nullable` annotation can be
`javax.annotation.Nullable` or a `Nullable` annotation defined in
any other package.
### JavaBeans-style prefixes are optional
In the example above, we used the `name()` and `numberOfLegs()`
methods to define the properties of the object. If you prefer, you can
use JavaBeans-style method names, like `getName()` and
`getNumberOfLegs()` to achieve the same effect. The property names
will still be `name` and `numberOfLegs`, for example in the result of
`toString()`. This applies only if every abstract method looks like
`getX()` or `boolean isX()` for some non-empty string X.
Similarly, in a builder you can use methods like `name(String s)` and
`numberOfLegs(int n)` or methods like `setName(String s)` and
`setNumberOfLegs(int n)`. Again, every abstract method must follow the
same one of the two conventions.
### Other preconditions or preprocessing
If you need to check preconditions or perform any other preparatory
steps, insert the code to do so into your static factory method before
invoking the generated constructor. Remember that null checks are
already present in the generated constructor.
When using builders, you can validate using a method annotated with
`@AutoValue.Validate`. The method will be called immediately after a
new instance is constructed by the build method and before that
instance is returned to the client. It can throw an exception if
validation fails. Here's how our example might be validated:
```java
class Example {
 @AutoValue
 abstract static class Animal {
@AutoValue.Validate
void validate() {
if (numberOfLegs() < 0) {
throw new IllegalStateException("Negative legs");
}
}
// ...remainder as before...
 }
}
```
### Custom implementations
Don't like the `equals`, `hashCode` or `toString` method AutoValue
generates? You can underride it! Just write your own, directly in your
abstract class; AutoValue will see this and skip generating its own.
### Nesting
Your hand-written abstract value type can be nested at any level. The
generated implementation class is named `AutoValue_` plus each
component of the class named separated by underscores. For example,
for the abstract class `Foo.Bar.Qux`, the generated implementation
class is `AutoValue_Foo_Bar_Qux`, in the same package.
### Derived fields
If a field exists to cache a derived value, and should be ignored in
`equals`, `hashCode` and `toString`, define it directly in your class
instead of providing an abstract accessor for it. AutoValue will know
nothing of it.
You may have fields you wish to ignore in equals for other reasons.
We're sorry: AutoValue doesn't work for these cases, since there's no
way to pass the extra parameter "through" the generated class
constructor.
### Generics
An `@AutoValue` class can have type parameters, as illustrated in these
examples:
```java
@AutoValue
abstract class MapEntry<K extends Comparable<K>, V> implements Map.Entry<K, V> {
static <K extends Comparable<K>, V> MapEntry<K, V> create(K key, V value) {
return new AutoValue_MapEntry<K, V>(key, value);
}
...
}
```
or
```java
@AutoValue
abstract class MapEntry<K extends Comparable<K>, V> implements Map.Entry<K, V> {
static <K extends Comparable<K>, V> Builder<K, V> builder() {
return new AutoValue_MapEntry.Builder<K, V>();
}
interface Builder<K extends Comparable<K>, V> {
Builder setKey(K key);
Builder setValue(V value);
MapEntry<K, V> build();
}
...
}
```
### Converting back to a builder
An `@AutoValue` class with a builder can optionally have an abstract
method that returns the builder type. It will be implemented by
initializing the builder with the values of the properties. This can
be exposed directly to clients, or used to implement "wither" methods
that return a new object that is the same as the original one except
for one changed property. Here is an example:
```java
class Example {
 @AutoValue
 abstract static class Animal {
static Builder builder() {
return AutoValue_Example_Animal.Builder();
}
abstract Builder toBuilder();
Animal withNumberOfLegs(int n) {
return toBuilder().numberOfLegs(n).build();
}
// ...remainder as before...
 }
}
```
### Serialization
The generated class will be serializable if your abstract class
implements `Serializable`. It will be GWT-serializable if your
abstract class is annotated with `@GwtCompatible(serializable = true)`
(any annotation with that name and field will do, such as the one
included in [Guava][1]).
(Ordinarily, abstract types should not be serializable, but in this
case it's harmless, since we truly expect no other implementations to
ever exist.)
There is no way to mark individual fields as transient or customize
the serialization behavior.
Warnings
------------------
Use of AutoValue has one serious **negative consequence**: certain
formerly safe refactorings could now break your code, and be caught
only by your tests.
If you are not using builders, you must ensure that parameters are
passed to the auto-generated constructor in the ***same order*** the
corresponding accessor methods are defined in the file. **Your tests
must be sufficient** to catch any field ordering problem. In most
cases this should be the natural outcome from testing whatever actual
purpose this value type was created for! In other cases a very simple
test like the one shown above is enough.
We reserve the right to **change the `hashCode` implementation**
at any time. Do not depend on the order your objects appear in
hash maps (use `ImmutableMap` or `LinkedHashMap`!), and never
persist these hash codes.
Restrictions and non-features
------------------
* Using AutoValue limits your public creation API to static
factory methods, not constructors. See *Effective Java* Item 1
for several reasons this is usually a good idea anyway.
* AutoValue does not and will not support creating *mutable*
value types. (We may consider adding support for
`withField`-style methods, which return a new immutable
copy of the original instance with one field value changed.)
* One `@AutoValue` class may not extend another. As explained in
*Effective Java*, inheritance of value types simply doesn't work.
* Object arrays are not and will not be supported, including
multidimensional primitive array types. Use a `Collection` type
instead, such as `ImmutableList`.
* Your accessor methods may not be `private` -- but they may be
package-private. The same is true for your `@AutoValue` class
itself.
* We don't generate `compareTo`, because we feel you need the
expressiveness that [ComparisonChain][2] provides, and we can't beat
it at its own game. If we find later that a large minority of
AutoValue classes are implementing compareTo by the exact same
formula, we will reconsider this feature.
* AutoValue currently doesn't inspect the `new AutoValue_Foo`
line to issue warnings on parameter order. (There are
certain technical issues with doing so.) As stated above
in Warnings, you had better have some test somewhere that
will catch such problems. Or you can use builders to avoid having
a parameter order at all.
* It might seem convenient to use AutoValue to implement annotation
interfaces, which frameworks such as [Guice][3] occasionally
require. But in fact such interfaces must obey the contracts for
`equals` and `hashCode` specified by
java.lang.annotation.Annotation, and the implementations of those
methods that AutoValue would generate do not. Instead, the
com.google.auto.value package includes another annotation
`@AutoAnnotation` specifically for this case. See its documentation
for more details.
Best practices
------------------
You should add a **package-private constructor** to your abstract
class, although we have omitted it for brevity in our examples.
This accomplishes two things: it prevents an undocumented public
constructor (that no one can even call) from appearing in your
javadoc, and it prevents users outside your package from creating
their own subclasses (and potentially subverting your
immutability).
In fact, **you should virtually never need an alternative
implementation of your hand-written abstract class**, whether
hand-written or generated by a mocking framework. Your class can
and should contain simple intrinsic behavior, but if that behavior
has enough complexity or enough dependencies that it actually needs
to be mocked or faked, split it into a separate type that is *not*
a value type. Otherwise it permits an instance with "real" behavior
and one with "mock/fake" behavior to be `equals`, which does not
make sense. Keep your value types straightforward.
Other code in the same package will be able to directly access
the generated class, *but should not*. It's best if each generated
class has **one and only one reference** from your source code.
If you have multiple creation methods, have them all call through
to the same point, so there is still one call to the generated file,
and one place to insert preconditions, etc.
**Avoid mutable field types**, especially if you make your
accessor methods `public`. The generated accessors won't copy the
field value on its way out, so you'd be exposing your internal
state. This doesn't mean your factory method can't *accept*
mutable types as input parameters. Example:
```java
@AutoValue
public abstract class ListExample {
abstract ImmutableList<String> names();
public static ListExample create(List<String> mutableNames) {
return new AutoValue_ListExample(ImmutableList.copyOf(mutableNames));
}
}
```
Primitive arrays are arguably an exception to this, as in this
case only AutoValue does return a copy of the internal array
from the generated accessor. It does not automatically copy the
data on its way in, however, so your static factory method should
pass `array.clone()` in to the generated constructor instead of
the input `array` itself. If you are using builders, arrays will
be cloned in the generated builder.
Finally, if you choose to provide an explicit `equals`, `hashCode`
or `toString` implementation, please make it **`final`**, so readers
don't have to wonder whether AutoValue is overriding it.
Alternatives
------------------
[This slide presentation][4]
walks through several competing solutions to this problem and shows
why we considered them insufficient.
[1]: http://guava-libraries.googlecode.com
[2]: http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/ComparisonChain.html
[3]: https://github.com/google/guice/wiki/BindingAnnotations#user-content-binding-annotations-with-attributes
[4]: https://docs.google.com/presentation/d/14u_h-lMn7f1rXE1nDiLX0azS3IkgjGl5uxp5jGJ75RE/edit