EqualsAndHashCode (Groovy 4.0.15)
Description: declaration: package: groovy.transform, annotation type: EqualsAndHashCode

Package groovy.transform

# Annotation Type EqualsAndHashCode

@Documented @Retention(RUNTIME) @Target(TYPE) public @interface EqualsAndHashCode
Class annotation used to assist in creating appropriate `equals()` and `hashCode()` methods.

It allows you to write classes in this shortened form:

     import groovy.transform.EqualsAndHashCode
     @EqualsAndHashCode
     class Person {
         String first, last
         int age
     }
     def p1 = new Person(first:'John', last:'Smith', age:21)
     def p2 = new Person(first:'John', last:'Smith', age:21)
     assert p1 == p2
     def map = [:]
     map[p1] = 45
     assert map[p2] == 45

The `@EqualsAndHashCode` annotation instructs the compiler to execute an AST transformation which adds the necessary equals and hashCode methods to the class.

The `hashCode()` method is calculated using Groovy's `HashCodeHelper` class which implements an algorithm similar to the one outlined in the book Effective Java.

The `equals()` method compares the values of the individual properties (and optionally fields) of the class. It can also optionally call equals on the super class. Two different equals method implementations are supported both of which support the equals contract outlined in the javadoc for `java.lang.Object`

To illustrate the 'canEqual' implementation style (see http://www.artima.com/lejava/articles/equality.html for further details), consider this class:

     @EqualsAndHashCode
     class IntPair {
         int x, y
     }

The generated `equals` and `canEqual` methods will be something like below:

     public boolean equals(java.lang.Object other)
         if (other == null) return false
         if (this.is(other)) return true
         if (!(other instanceof IntPair)) return false
         if (!other.canEqual(this)) return false
         if (x != other.x) return false
         if (y != other.y) return false
         return true
     }

     public boolean canEqual(java.lang.Object other) {
         return other instanceof IntPair
     }

If no further options are specified, this is the default style for `@Canonical` and `@EqualsAndHashCode` annotated classes. The advantage of this style is that it allows inheritance to be used in limited cases where its purpose is for overriding implementation details rather than creating a derived type with different behavior. This is useful when using JPA Proxies for example or as shown in the following examples:

     import groovy.transform.*
     @Canonical class IntPair { int x, y }
     def p1 = new IntPair(1, 2)

     // overridden getter but deemed an IntPair as far as domain is concerned
     def p2 = new IntPair(1, 1) { int getY() { 2 } }

     // additional helper method added through inheritance but
     // deemed an IntPair as far as our domain is concerned
     @InheritConstructors class IntPairWithSum extends IntPair {
         def sum() { x + y }
     }

     def p3 = new IntPairWithSum(1, 2)

     assert p1 == p2 && p2 == p1
     assert p1 == p3 && p3 == p1
     assert p3 == p2 && p2 == p3

Note that if you create any domain classes which don't have exactly the same contract as `IntPair` then you should provide an appropriate `equals` and `canEqual` method. The easiest way to achieve this would be to use the `@Canonical` or `@EqualsAndHashCode` annotations as shown below:

     @EqualsAndHashCode
     @TupleConstructor(includeSuperProperties=true)
     class IntTriple extends IntPair { int z }
     def t1 = new IntTriple(1, 2, 3)
     assert p1 != t1 && p2 != t1 && t1 != p3

The alternative supported style regards any kind of inheritance as creation of a new type and is illustrated in the following example:

     @EqualsAndHashCode(useCanEqual=false)
     class IntPair {
         int x, y
     }

The generated equals method will be something like below:

     public boolean equals(java.lang.Object other)
         if (other == null) return false
         if (this.is(other)) return true
         if (IntPair != other.getClass()) return false
         if (x != other.x) return false
         if (y != other.y) return false
         return true
     }

This style is appropriate for final classes (where inheritance is not allowed) which have only `java.lang.Object` as a super class. Most `@Immutable` classes fall in to this category. For such classes, there is no need to introduce the `canEqual()` method.

Note that if you explicitly set `useCanEqual=false` for child nodes in a class hierarchy but have it `true` for parent nodes and you also have `callSuper=true` in the child, then your generated equals methods will not strictly follow the equals contract.

Note that when used in the recommended fashion, the two implementations supported adhere to the equals contract. You can provide your own equivalence relationships if you need, e.g. for comparing instances of the `IntPair` and `IntTriple` classes discussed earlier, you could provide the following method in `IntPair`:

     boolean hasEqualXY(other) { other.x == getX() && other.y == getY() }

Then for the objects defined earlier, the following would be true:

     assert p1.hasEqualXY(t1) && t1.hasEqualXY(p1)
     assert p2.hasEqualXY(t1) && t1.hasEqualXY(p2)
     assert p3.hasEqualXY(t1) && t1.hasEqualXY(p3)

There is also support for including or excluding fields/properties by name when constructing the equals and hashCode methods as shown here:

     import groovy.transform.*
     @EqualsAndHashCode(excludes="z")
     @TupleConstructor
     public class Point2D {
         int x, y, z
     }

     assert  new Point2D(1, 1, 1).equals(new Point2D(1, 1, 2))
     assert !new Point2D(1, 1, 1).equals(new Point2D(2, 1, 1))

     @EqualsAndHashCode(excludes=["y", "z"])
     @TupleConstructor
     public class Point1D {
         int x, y, z
     }

     assert  new Point1D(1, 1, 1).equals(new Point1D(1, 1, 2))
     assert  new Point1D(1, 1, 1).equals(new Point1D(1, 2, 1))
     assert !new Point1D(1, 1, 1).equals(new Point1D(2, 1, 1))

Note: `@EqualsAndHashCode` is a transform to help reduce boilerplate in the common cases. It provides a useful implementation of `equals()` and `hashCode()` but not necessarily the most appropriate or efficient one for every use case. You should write custom versions if your scenario demands it. In particular, if you have mutually-referential classes, the implementations provided may not be suitable and may recurse infinitely (leading to a `StackOverflowError`). In such cases, you need to remove the infinite loop from your data structures or write your own custom methods. If your data structures are self-referencing, the code generated by this transform will try to avoid infinite recursion but the algorithm used may not suit your scenario, so use with caution if you have such structures. A future version of this transform may better handle some additional recursive scenarios.

More examples:

     import groovy.transform.EqualsAndHashCode

     @EqualsAndHashCode(includeFields=true)
     class User {
         String name
         boolean active
         List likes
         private int age = 37
     }

     def user = new User(name: 'mrhaki', active: false, likes: ['Groovy', 'Java'])
     def mrhaki = new User(name: 'mrhaki', likes: ['Groovy', 'Java'])
     def hubert = new User(name: 'Hubert Klein Ikkink', likes: ['Groovy', 'Java'])

     assert user == mrhaki
     assert mrhaki != hubert

     Set users = new HashSet()
     users.add user
     users.add mrhaki
     users.add hubert
     assert users.size() == 2

Since:
  1.8.0
See Also:
  - `HashCodeHelper`

- ## Optional Element Summary

  Optional Elements
  Modifier and Type
  Optional Element
  Description
  `boolean`
  `allNames`
  Whether to include all fields and/or properties in equals and hashCode calculations, including those with names that are considered internal.
  `boolean`
  `allProperties`
  Whether to include all properties (as per the JavaBean spec) in the generated constructor.
  `boolean`
  `cache`
  Whether to cache hashCode calculations.
  `boolean`
  `callSuper`
  Whether to include super in equals and hashCode calculations.
  `String[]`
  `excludes`
  List of property names (and field names if includeFields is true) to exclude from the equals and hashCode calculations.
  `boolean`
  `includeFields`
  Include fields as well as properties in equals and hashCode calculations.
  `String[]`
  `includes`
  List of property names (and field names if includeFields is true) to include within the equals and hashCode calculations.
  `boolean`
  `pojo`
  Whether to avoid using Groovy runtime methods and instead use methods like `Objects.hash(Object...)` and `Objects.equals(Object, Object)` for the generated `equals` and `hashCode` methods.
  `boolean`
  `useCanEqual`
  Generate a canEqual method to be used by equals.
  `boolean`
  `useGetters`
  Whether to access properties directly by their fields (faster) or via their getters.

- ## Element Details

  - ### excludes

    String[] excludes
    List of property names (and field names if includeFields is true) to exclude from the equals and hashCode calculations. Must not be used if 'includes' is used. For convenience, a String with comma separated names can be used in addition to an array (using Groovy's literal list notation) of String values.
    Default:
      {}

  - ### includes

    String[] includes
    List of property names (and field names if includeFields is true) to include within the equals and hashCode calculations. Must not be used if 'excludes' is used. For convenience, a String with comma separated names can be used in addition to an array (using Groovy's literal list notation) of String values. The default value is a special marker value indicating that no includes are defined; all fields and/or properties are included if 'includes' remains undefined and 'excludes' is explicitly or implicitly an empty list.
    Default:
      {"<DummyUndefinedMarkerString-DoNotUse>"}

  - ### cache

    boolean cache
    Whether to cache hashCode calculations. You should only set this to true if you know the object is immutable (or technically mutable but never changed).
    Default:
      false

  - ### callSuper

    boolean callSuper
    Whether to include super in equals and hashCode calculations.
    Default:
      false

  - ### includeFields

    boolean includeFields
    Include fields as well as properties in equals and hashCode calculations.
    Default:
      false

  - ### useCanEqual

    boolean useCanEqual
    Generate a canEqual method to be used by equals.
    Default:
      true

  - ### allProperties

    boolean allProperties
    Whether to include all properties (as per the JavaBean spec) in the generated constructor. When true, Groovy treats any explicitly created setXxx() methods as property setters as per the JavaBean specification. JavaBean properties come after any Groovy properties but before any fields for a given class (unless 'includes' is used to determine the order).
    Since:
      2.5.0
    Default:
      false

  - ### allNames

    boolean allNames
    Whether to include all fields and/or properties in equals and hashCode calculations, including those with names that are considered internal.
    Since:
      2.5.0
    Default:
      false

  - ### pojo

    boolean pojo
    Whether to avoid using Groovy runtime methods and instead use methods like `Objects.hash(Object...)` and `Objects.equals(Object, Object)` for the generated `equals` and `hashCode` methods. The generated code is more similar to what is typically used in POJO classes. The presence of the `@POJO` annotation on a class is looked for by default but this annotation attribute allows the feature to be explicitly configured if desired. NOTE: this is an incubating feature and may change in future versions.
    Since:
      4.0.0
    Default:
      false

  - ### useGetters

    boolean useGetters
    Whether to access properties directly by their fields (faster) or via their getters.
    Since:
      4.0.12
    Default:
      true