Egalité avec Lombox

De EjnTricks

Lors de l'utilisation de POJO dans le projet Java, il est parfois nécessaire de comparer deux instances sur les variables déclarées. Lorsqu'elles sont en nombres, le code est considérablement allourdi, car il faut tester les valeurs null et les égalités.

Lombok permet de s'affranchir de tout ceci à l'aide de l'annotation EqualsAndHashCode, qui va créer la fonction equals et également hashCode.

Le code source est disponible à l'adresse suivante: http://www.jouvinio.net/svn/study/trunk/lombok/, et en particulier les classes du package fr.ejn.tutorial.java.lombok.equals.


Hand-icon.png Votre avis

Nobody voted on this yet

 You need to enable JavaScript to vote


Add-icon.png Toutes variables

L'utilisation basique de l'annotation EqualsAndHashCode permet donc de comparer toutes les valeurs. La classe DataObject contient les deux variables suivantes.

  • name;
  • surname.
package fr.ejn.tutorial.java.lombok.equals;

import lombok.EqualsAndHashCode;
import lombok.Setter;

/**
 * Tutorial class to illustrate equals generation on class.
 *
 * @author Etienne Jouvin
 *
 */
@EqualsAndHashCode
@Setter
public class DataObject {

  private String name;
  private String surname;

}

A noter que seule l'annotation Setter est utilisée, aucun getter n'est mis à disposition.

Le test unitaire DataObjectTest permet de démontrer que l'égalité s'effectue bien sur toutes les variables.

package fr.ejn.tutorial.java.lombok.equals;

import static org.assertj.core.api.Assertions.assertThat;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

public class DataObjectTest {

  @BeforeClass
  public static void setUpBeforeClass() throws Exception {
  }

  @AfterClass
  public static void tearDownAfterClass() throws Exception {
  }

  @Before
  public void setUp() throws Exception {
  }

  @After
  public void tearDown() throws Exception {
  }

  @Test
  public void testEquals() throws Exception {
    DataObject actual = new DataObject();
    actual.setName("data name");
    actual.setSurname("data surname");
    actual.setId("data id");

    DataObject otherData = new DataObject();
    otherData.setName("data name");
    otherData.setSurname("data surname");
    assertThat(actual.equals(otherData)).isTrue();

    otherData = new DataObject();
    otherData.setName("other data name");
    otherData.setSurname("data surname");
    assertThat(actual.equals(otherData)).isFalse();

    otherData = new DataObject();
    otherData.setName("data name");
    otherData.setSurname("other data surname");
    assertThat(actual.equals(otherData)).isFalse();
  }

}


Multiples-icon.png Héritage classe

Lorsqu'une classe étend une classe parente, l'annotation peut être configurée pour utiliser ou non les variables parentes lors de la vérification d'égalité. Pour cela, il faut ajouter l'argument callSuper.

La classe ChildDataWithoutSuperObject montre comment ajouter la vérification d'égalité uniquement sur les variables de la classe, et sans la parente, en passant la valeur false à l'argument callSuper.

package fr.ejn.tutorial.java.lombok.equals;

import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;

/**
 * Tutorial class to illustrate equals generation with only class variables, and not on parent class
 * variables.
 *
 * @author Etienne Jouvin
 *
 */
@EqualsAndHashCode(callSuper = false)
@Getter
@Setter
public class ChildDataWithoutSuperObject extends DataObject {

  private String id;

}

Le test unitaire associé ChildDataWithoutSuperObjectTest confirme le comportement en modifiant les différentes variables.

package fr.ejn.tutorial.java.lombok.equals;

import static org.assertj.core.api.Assertions.assertThat;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

public class ChildDataWithoutSuperObjectTest {

  @BeforeClass
  public static void setUpBeforeClass() throws Exception {
  }

  @AfterClass
  public static void tearDownAfterClass() throws Exception {
  }

  @Before
  public void setUp() throws Exception {
  }

  @After
  public void tearDown() throws Exception {
  }

  @Test
  public void testEquals() throws Exception {
    ChildDataWithoutSuperObject actual = new ChildDataWithoutSuperObject();
    actual.setName("data name");
    actual.setSurname("data surname");
    actual.setId("data id");

    ChildDataWithoutSuperObject otherData = new ChildDataWithoutSuperObject();
    otherData.setName("data name");
    otherData.setSurname("data surname");
    otherData.setId("data id");
    assertThat(actual.equals(otherData)).isTrue();

    otherData = new ChildDataWithoutSuperObject();
    otherData.setName("other data name");
    otherData.setSurname("data surname");
    otherData.setId("data id");
    assertThat(actual.equals(otherData)).isTrue();

    otherData = new ChildDataWithoutSuperObject();
    otherData.setName("data name");
    otherData.setSurname("data surname");
    otherData.setId("other data id");
    assertThat(actual.equals(otherData)).isFalse();
  }

}

A l'inverse, en spécifiant la valeur true dans l'argument callSuper, les variables de la classe parente sont prises en compte comme cela est implémenté dans la classe ChildDataWithSuperObject.

package fr.ejn.tutorial.java.lombok.equals;

import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;

/**
 * Tutorial class to illustrate equals generation with class and parent class variables.
 *
 * @author Etienne Jouvin
 *
 */
@EqualsAndHashCode(callSuper = true)
@Getter
@Setter
public class ChildDataWithSuperObject extends DataObject {

  private String id;

}

Le test unitaire associé ChildDataWithSuperObjectTest confirme ce comportement.

package fr.ejn.tutorial.java.lombok.equals;

import static org.assertj.core.api.Assertions.assertThat;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

public class ChildDataWithSuperObjectTest {

  @BeforeClass
  public static void setUpBeforeClass() throws Exception {
  }

  @AfterClass
  public static void tearDownAfterClass() throws Exception {
  }

  @Before
  public void setUp() throws Exception {
  }

  @After
  public void tearDown() throws Exception {
  }

  @Test
  public void testEquals() throws Exception {
    ChildDataWithSuperObject actual = new ChildDataWithSuperObject();
    actual.setName("data name");
    actual.setSurname("data surname");
    actual.setId("data id");

    ChildDataWithSuperObject otherData = new ChildDataWithSuperObject();
    otherData.setName("data name");
    otherData.setSurname("data surname");
    otherData.setId("data id");
    assertThat(actual.equals(otherData)).isTrue();

    otherData = new ChildDataWithSuperObject();
    otherData.setName("other data name");
    otherData.setSurname("data surname");
    otherData.setId("data id");
    assertThat(actual.equals(otherData)).isFalse();

    otherData = new ChildDataWithSuperObject();
    otherData.setName("data name");
    otherData.setSurname("data surname");
    otherData.setId("other data id");
    assertThat(actual.equals(otherData)).isFalse();
  }

}


Vues-icon.png Sélection variables

Parfois, le test d'égalité ne doit pas impliquer toutes les variables de la classe. L'argument exclude de l'annotation permet de fournir la liste des variables devant être exclues.

Dans la classe DataWithSpecificFieldsObject, seule la variable id est utilisée et les variables name et surname sont exclues.

package fr.ejn.tutorial.java.lombok.equals;

import lombok.EqualsAndHashCode;
import lombok.Setter;

/**
 * Tutorial class to illustrate equals generation based on specific variables.
 *
 * @author Etienne Jouvin
 *
 */
@EqualsAndHashCode(exclude = { "name", "surname" })
@Setter
public class DataWithSpecificFieldsObject {

  private String id;
  private String name;
  private String surname;

}

Dans le test unitaire DataWithSpecificFieldsObjectTest, les variables sont modifiées pour montrer que seule une valeur identique sur id valide l'égalité.

package fr.ejn.tutorial.java.lombok.equals;

import static org.assertj.core.api.Assertions.assertThat;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

public class DataWithSpecificFieldsObjectTest {

  @BeforeClass
  public static void setUpBeforeClass() throws Exception {
  }

  @AfterClass
  public static void tearDownAfterClass() throws Exception {
  }

  @Before
  public void setUp() throws Exception {
  }

  @After
  public void tearDown() throws Exception {
  }

  @Test
  public void testEquals() throws Exception {
    DataWithSpecificFieldsObject actual = new DataWithSpecificFieldsObject();
    actual.setName("data name");
    actual.setSurname("data surname");
    actual.setId("data id");

    DataWithSpecificFieldsObject otherData = new DataWithSpecificFieldsObject();
    otherData.setName("data name");
    otherData.setSurname("data surname");
    otherData.setId("data id");
    assertThat(actual.equals(otherData)).isTrue();

    otherData = new DataWithSpecificFieldsObject();
    otherData.setName("other data name");
    otherData.setSurname("data surname");
    otherData.setId("data id");
    assertThat(actual.equals(otherData)).isTrue();

    otherData = new DataWithSpecificFieldsObject();
    otherData.setName("data name");
    otherData.setSurname("data surname");
    otherData.setId("other data id");
    assertThat(actual.equals(otherData)).isFalse();
  }

}


Viewer icon.png Voir aussi

Documentation officielle: https://projectlombok.org/features/EqualsAndHashCode