No more value classes boilerplate — The power of AutoValue.

cxr
Rock and Null
Published in
4 min readOct 12, 2016

Having an object that acts as a model for some data is a common Java/Android programming pattern. Writing this value class, as it’s called, with its getters and setters is a boring and often an error prone procedure.

I believe that this is not widely known, but there is an easy way to skip this tedious procedure and have these classes auto generated. All you have to do it define your fields and annotate your class appropriately using AutoValue by Google.

Setup AutoValue in Android Studio

To enable AutoValue in your Android project (Gradle) you need to add 4 lines into your build files. First, in your project-wide build.gradle file, add the following bold line in the appropriate section:

buildscript {
[...]
dependencies {
[...]
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
}
}

Finally, in you app-wide build.gradle file add the following:

apply plugin: 'com.neenbedankt.android-apt' // At the beginning
[...]
dependencies {
[...]
provided "com.google.auto.value:auto-value:1.2"
apt "com.google.auto.value:auto-value:1.2"

}

[Update] A useful tip by our readers @jpardogo and @egorand “Would just like to note that the Android Gradle plugin 2.2 provides out-of-the-box support for annotation processors, which means there’s no need to use android-apt anymore. There’s also a migration guide for those who are using android-apt already.”
tl;dr:
annotationProcessor replaces apt

The first 2 lines enable annotation processing in your project and the last 2 lines provide the actual AutoValue. There are setup instructions for other build systems for Java (Gradle, Maven) in AutoValue documentation.

Your first AutoValue class

@AutoValue
abstract class Film {
static Film create(String name, int year) {
return new AutoValue_Film(name, year);
}

abstract String name();
abstract int year();
}

That’s it! Create an abstract class with one abstract method for each property you want to have. Finally, create a static factory method that returns a new object of the type AutoValue_modelClassName and you are all set. If the AutoValue_Film is not recognizable in Android Studio (appears in red) just hit Build -> Rebuild project for the class to be generated.

In case your value class is an inner class, the new instance returned by the static factory method would be AutoValue_outerClassName_modelClassName. In this example, if the Film class was defined inside the FilmsActivity, the static factory method would return AutoValue_FilmsActivity_Film.

Now you can initialize your new value class using the static factory:

Film matrix = Film.create("The Matrix", 1999);

A builder to the rescue

Let’s say that you indeed start using AutoValue for your value classes and obviously they are not small example level classes with only 2 parameters. You end up having these huge create(..) init lines that do not look like the promised elegance of the previous section:

Film matrix = Film.create("The Matrix", 1999, Category.FANTASY, 8.7f, 136, releasedDate, directorsList, castList);

The solution to this initialization mess is the builder pattern that AutoValue provides as well.

@AutoValue
abstract class Film {

static Builder builder() {
return new AutoValue_Film.Builder();
}

@AutoValue.Builder
abstract static class Builder {
abstract Builder setName(String value);
abstract Builder setYear(int value);
abstract Film build();
}

abstract String name();
abstract int year();
}

Instead of providing a static factory method you provide a builder for your object and you use that to create your final value object. I only wrote setters and getters for 2 parameters but the full example at the beginning of this section would look like:

Film matrix = Film.builder()
.setName("The Matrix")
.setYear(1999)
.setCategory(Category.FANTASY)
.setRating(8.7f)
.setDuration(136)
.setReleaseDate(releasedDate)
.setDirectors(directorsList)
.setCast(castList)
.build();

This certainly looks more verbose but i believe is way more self-explained without having to look up what each parameter is for.

Android specific and beyond

You are an Android developer and the time it’s gonna come that you will need to transfer your value objects from one Activity to another. But these AutoValue classes are not Parcelable! And you are just hate writing these writeToParcel(..) and the other way around.

Fear not, AutoValue has extensions that cover a wide range of possible operations that you might need to do on your value objects. For making your classes parcelables head to AutoValue-Parcel GitHub project and include this extra dependency in you app build.gradle:

dependencies {
[...]
apt 'com.ryanharter.auto.value:auto-value-parcel:0.2.4-rc2'
}

Then just implement the Parcelable interface and you are done!

@AutoValue
abstract class Film implements Parcelable {
[...]
}

There are a lot of extensions for AutoValue available out there, like AutoValue-Gson, AutoValue-Cursor, AutoValue-With, AutoValue-Redacted to name a few.

Conclusion

AutoValue is an amazing tool that it might be simple yet it can have a significant impact on the code readability of your project. It offers you (almost) effort-free immutable objects that implement equals() and hashCode() as well. Furthermore, don’t forget that what are you providing to AutoValue is just abstract classes that you can modify by adding your own methods or use your own logic in the builder/factory (e.g. for validation before creating an object).

I would like to end with the quote AutoValue’s documentation begins with:

“AutoValue is 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

P.S. If you are like me and enjoy being productive throughout the day, check out microtasks, a task-as-undismissable-notification manager that helps you remember the small things that matter :)

--

--