https://github.com/google/auto/blob/master/value/userguide/index.md
immutable value class を生成してくれるライブラリ。abstract クラスを用意して @AutoValue をつけると、equals() や hashCode() などの boilerplate なコードを実装したクラスを用意してくれる。
設定
- dependencies {
- compile 'com.google.auto.value:auto-value:1.2'
- apt 'com.google.auto.value:auto-value:1.2'
- }
dependencies {
compile 'com.google.auto.value:auto-value:1.2'
apt 'com.google.auto.value:auto-value:1.2'
}
使い方
例えば
- @AutoValue
- abstract class Animal {
-
- abstract String name();
-
- abstract int numberOfLegs();
-
- }
@AutoValue
abstract class Animal {
abstract String name();
abstract int numberOfLegs();
}
のようなクラスを定義すると、
AutoValue_Animalというクラスが生成される。
- final class AutoValue_Animal extends Animal {
-
- private final String name;
- private final int numberOfLegs;
-
- AutoValue_Animal(
- String name,
- int numberOfLegs) {
- if (name == null) {
- throw new NullPointerException("Null name");
- }
- this.name = name;
- this.numberOfLegs = numberOfLegs;
- }
-
- @Override
- String name() {
- return name;
- }
-
- @Override
- int numberOfLegs() {
- return numberOfLegs;
- }
-
- @Override
- public String toString() {
- return "Animal{"
- + "name=" + name + ", "
- + "numberOfLegs=" + numberOfLegs
- + "}";
- }
-
- @Override
- public boolean equals(Object o) {
- if (o == this) {
- return true;
- }
- if (o instanceof Animal) {
- Animal that = (Animal) o;
- return (this.name.equals(that.name()))
- && (this.numberOfLegs == that.numberOfLegs());
- }
- return false;
- }
-
- @Override
- public int hashCode() {
- int h = 1;
- h *= 1000003;
- h ^= this.name.hashCode();
- h *= 1000003;
- h ^= this.numberOfLegs;
- return h;
- }
-
- }
final class AutoValue_Animal extends Animal {
private final String name;
private final int numberOfLegs;
AutoValue_Animal(
String name,
int numberOfLegs) {
if (name == null) {
throw new NullPointerException("Null name");
}
this.name = name;
this.numberOfLegs = numberOfLegs;
}
@Override
String name() {
return name;
}
@Override
int numberOfLegs() {
return numberOfLegs;
}
@Override
public String toString() {
return "Animal{"
+ "name=" + name + ", "
+ "numberOfLegs=" + numberOfLegs
+ "}";
}
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (o instanceof Animal) {
Animal that = (Animal) o;
return (this.name.equals(that.name()))
&& (this.numberOfLegs == that.numberOfLegs());
}
return false;
}
@Override
public int hashCode() {
int h = 1;
h *= 1000003;
h ^= this.name.hashCode();
h *= 1000003;
h ^= this.numberOfLegs;
return h;
}
}
コンスタクタでは name と numberOfLegs を引数に取り、equals() や hasCode() ではこれらを使った実装になっている。
immutable value class なのでコンスタクタで受け取った引数は final として保持される。
abstract クラスに static な生成メソッドを用意して利用する。
- @AutoValue
- abstract class Animal {
-
- static Animal create(String name, int numberOfLegs) {
- return new AutoValue_Animal(name, numberOfLegs);
- }
-
- abstract String name();
-
- abstract int numberOfLegs();
-
- }
@AutoValue
abstract class Animal {
static Animal create(String name, int numberOfLegs) {
return new AutoValue_Animal(name, numberOfLegs);
}
abstract String name();
abstract int numberOfLegs();
}
コンスタクタの引数は null チェックされる。これを止めたいときは abstract メソッドの戻り値に @Nullable をつける。
- @AutoValue
- abstract class Animal {
-
- @Nullable
- abstract String name();
-
- abstract int numberOfLegs();
-
- }
@AutoValue
abstract class Animal {
@Nullable
abstract String name();
abstract int numberOfLegs();
}
- final class AutoValue_Animal extends Animal {
-
- private final String name;
- private final int numberOfLegs;
-
- AutoValue_Animal(
- @Nullable String name,
- int numberOfLegs) {
- this.name = name;
- this.numberOfLegs = numberOfLegs;
- }
-
- ...
- }
final class AutoValue_Animal extends Animal {
private final String name;
private final int numberOfLegs;
AutoValue_Animal(
@Nullable String name,
int numberOfLegs) {
this.name = name;
this.numberOfLegs = numberOfLegs;
}
...
}
Builder を用意することも可能。@AutoValue をつけるクラスにインナークラスとして abstract static な Builder クラスを定義し、@AutoValue.Builder をつける。
- @AutoValue
- abstract class Animal {
-
- abstract String name();
-
- abstract int numberOfLegs();
-
- static Builder builder() {
- return new AutoValue_Animal.Builder();
- }
-
- @AutoValue.Builder
- abstract static class Builder {
- abstract Builder name(String value);
- abstract Builder numberOfLegs(int value);
- abstract Animal build();
- }
- }
@AutoValue
abstract class Animal {
abstract String name();
abstract int numberOfLegs();
static Builder builder() {
return new AutoValue_Animal.Builder();
}
@AutoValue.Builder
abstract static class Builder {
abstract Builder name(String value);
abstract Builder numberOfLegs(int value);
abstract Animal build();
}
}
- final class AutoValue_Animal extends Animal {
-
- ...
-
- static final class Builder extends Animal.Builder {
- private String name;
- private Integer numberOfLegs;
-
- Builder() {
- }
-
- Builder(Animal source) {
- this.name = source.name();
- this.numberOfLegs = source.numberOfLegs();
- }
-
- @Override
- public Animal.Builder name(String name) {
- this.name = name;
- return this;
- }
-
- @Override
- public Animal.Builder numberOfLegs(int numberOfLegs) {
- this.numberOfLegs = numberOfLegs;
- return this;
- }
-
- @Override
- public Animal build() {
- String missing = "";
- if (name == null) {
- missing += " name";
- }
- if (numberOfLegs == null) {
- missing += " numberOfLegs";
- }
- if (!missing.isEmpty()) {
- throw new IllegalStateException("Missing required properties:" + missing);
- }
- return new AutoValue_Animal(
- this.name,
- this.numberOfLegs);
- }
- }
-
- }
final class AutoValue_Animal extends Animal {
...
static final class Builder extends Animal.Builder {
private String name;
private Integer numberOfLegs;
Builder() {
}
Builder(Animal source) {
this.name = source.name();
this.numberOfLegs = source.numberOfLegs();
}
@Override
public Animal.Builder name(String name) {
this.name = name;
return this;
}
@Override
public Animal.Builder numberOfLegs(int numberOfLegs) {
this.numberOfLegs = numberOfLegs;
return this;
}
@Override
public Animal build() {
String missing = "";
if (name == null) {
missing += " name";
}
if (numberOfLegs == null) {
missing += " numberOfLegs";
}
if (!missing.isEmpty()) {
throw new IllegalStateException("Missing required properties:" + missing);
}
return new AutoValue_Animal(
this.name,
this.numberOfLegs);
}
}
}