問題
lombokでEqualsAndHashCodeを使えば自動的にhashCodeとequalsメソッドを実装してくれる。デフォルトでは、staticではなく、transientでないフィールドはすべて評価の対象となる。特定の対象のみを評価したい場合には、メソッドの前に下記のアノテーションを付ける。
@EqualsAndHashCode
public class Data {
@EqualsAndHashCode.Include
String key;
int value;
}
この場合は、keyのみを評価対象とするhashCodeとequalsメソッドができるのを期待する。ネット上に上がっているサンプル例では、このように書いてあるケースもある。しかし、このままでは期待通りに動かない。どうもIncludeが適用されずに、keyもvalueも評価対象になっている。
lombokが生成しているコードを下記コマンドを実施して確認してみる。
java -jar lombok.jar delombok -p {対象のファイル名}.java
先ほどのコードから生成されたコードを確認すると、
public class Data {
String key;
int value;
@java.lang.Override
@java.lang.SuppressWarnings("all")
public boolean equals(final java.lang.Object o) {
if (o == this) return true;
if (!(o instanceof Data)) return false;
final Data other = (Data) o;
if (!other.canEqual((java.lang.Object) this)) return false;
if (this.value != other.value) return false;
final java.lang.Object this$key = this.key;
final java.lang.Object other$key = other.key;
if (this$key == null ? other$key != null : !this$key.equals(other$key)) return false;
return true;
}
@java.lang.SuppressWarnings("all")
protected boolean canEqual(final java.lang.Object other) {
return other instanceof Data;
}
@java.lang.Override
@java.lang.SuppressWarnings("all")
public int hashCode() {
final int PRIME = 59;
int result = 1;
result = result * PRIME + this.value;
final java.lang.Object $key = this.key;
result = result * PRIME + ($key == null ? 43 : $key.hashCode());
return result;
}
}
やはり、keyもvalueも評価対象となっている。
解決方法
EqualsAndHashCodeアノテーションの変数onlyExplicitlyIncludedをtrueにする。
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
public class Data {
@EqualsAndHashCode.Include
String key;
int value;
}
これで期待通り、keyのみが評価されるメソッドが生成される。
public class Data {
String key;
int value;
@java.lang.Override
@java.lang.SuppressWarnings("all")
public boolean equals(final java.lang.Object o) {
if (o == this) return true;
if (!(o instanceof Data)) return false;
final Data other = (Data) o;
if (!other.canEqual((java.lang.Object) this)) return false;
final java.lang.Object this$key = this.key;
final java.lang.Object other$key = other.key;
if (this$key == null ? other$key != null : !this$key.equals(other$key)) return false;
return true;
}
@java.lang.SuppressWarnings("all")
protected boolean canEqual(final java.lang.Object other) {
return other instanceof Data;
}
@java.lang.Override
@java.lang.SuppressWarnings("all")
public int hashCode() {
final int PRIME = 59;
int result = 1;
final java.lang.Object $key = this.key;
result = result * PRIME + ($key == null ? 43 : $key.hashCode());
return result;
}
}
公式サイトをよく見ると、一番最初にちゃんと書いてある。やはり公式をちゃんと読むことが大事。
you can specify exactly which fields or methods you wish to be used by marking them with @EqualsAndHashCode.Include and using @EqualsAndHashCode(onlyExplicitlyIncluded = true).
なお、onlyExplicitlyIncludedという名称だが、EqualsAndHashCode.Includeではなく、特定のフィールドだけ評価から除外するEqualsAndHashCode.Excludeを使用する場合も同じ。