Software Development Notions

Lombok annotations

April 21, 2020

Lombok es una biblioteca Java que nos permite reemplazar las líneas de código que creamos para los constructores, getter y setter, entre otros, por unas simple anotaciones, por lo que cuando creamos una clase solo definimos las propiedades y ésta librería hace el resto.

Con una simple anotación(@Data), Lombok inyectará los métodos getter y setter para cada propiedad, además de un equals, hashCode y toString.

https://1.bp.blogspot.com/--CYarvynlTU/Xp24u-wh6zI/AAAAAAAAAKE/-pW3SGJ7qokEtPL93HgN911_hjvzZCnnQCLcBGAsYHQ/s400/28ae0b5bfcf57c9972db8ecc6f9df091_f652.png

@Getter y Setter

Se usan para generar un getter y setter para un atributo específico.

/*BEFORE*/
public boolean isEmployed() {
    return employed;
}
 
public void setEmployed(final boolean employed) {
    this.employed = employed;
}

/*AFTER*/
@Getter @Setter private boolean employed;

@NonNull

Cuando se coloca en un atributo para el que Lombok está generando un método de establecimiento, se generará una comprabación que dará como resultado un NullPointerException, si se proporciona un valor nulo.

/*BEFORE*/
public class Family{

  private List<Person> members;
 
  public Family(List<Person> members) {
    if (members == null) throw new 
  java.lang.NullPointerException("members");
    this.members = members;
  }
 
  public void setMembers(List<Person> members) {
    if (members == null) throw new java.lang.NullPointerException("members");
    this.members = members;
  }
}

/*AFTER*/
@Setter @NonNull
private List<Person> members;

@ToString

Genera una implementación del método toString. Imprimirá todos los atributos en forma de clave-valor, para todos los campos que no sean estáticos. Podemos personalizar su funcionamiento mediante los siguientes parámetros:

  • includeFieldNames = false → No incluye el nombre de los atributos (clave)
  • exclude=“nombreDeAtributo” → No incluye el atributo especificado
  • of → Lista de atributos a imprimir
  • callSuper = true → Junta el toString de la clase actual con el de la clase de la que extiende
/*BEFORE*/
public class Foo extends Bar {
    private boolean someBoolean = true;
    private String someStringField;
    private float someExcludedField;
 
    @java.lang.Override
    public java.lang.String toString() {
        return "Foo(super=" + super.toString() +
            ", someBoolean=" + someBoolean +
            ", someStringField=" + someStringField + ")";
    }
}

/*AFTER*/
@ToString(callSuper=true,exclude="someExcludedField")
public class Foo extends Bar {
    private boolean someBoolean = true;
    private String someStringField;
    private float someExcludedField;
}

@EQUALSANDHASHCODE

Generará una implementación de los métodos equals y hashCode, para comparar un objeto de la clase con otro. Le podemos especificar una serie de parámetros:

  • exclude=“nombreDeAtributo” → No compara por el atributo especificado
  • of → Lista de atributos a comparar
  • callSuper = true → Compara también por la clase de la que extiende
/*BEFORE*/
public class Person extends SentientBeing {
 
    enum Gender {
        /*public static final*/ Male /* = new Gender() */,
        /*public static final*/ Female /* = new Gender() */;
    }
    @NonNull
    private String name;
    @NonNull
    private Gender gender;
    private String ssn;
    private String address;
    private String city;
    private String state;
    private String zip;
 
    @java.lang.Override
    public boolean equals(final java.lang.Object o) {
        if (o == this) return true;
        if (o == null) return false;
        if (o.getClass() != this.getClass()) return false;
        if (!super.equals(o)) return false;
        final Person other = (Person)o;
        if (this.name == null ? other.name != null : !this.name.equals(other.name)) return false;
        if (this.gender == null ? other.gender != null : !this.gender.equals(other.gender)) return false;
        if (this.ssn == null ? other.ssn != null : !this.ssn.equals(other.ssn)) return false;
        return true;
    }
 
    @java.lang.Override
    public int hashCode() {
        final int PRIME = 31;
        int result = 1;
        result = result * PRIME + super.hashCode();
        result = result * PRIME + (this.name == null ? 0 : this.name.hashCode());
        result = result * PRIME + (this.gender == null ? 0 : this.gender.hashCode());
        result = result * PRIME + (this.ssn == null ? 0 : this.ssn.hashCode());
        return result;
    }
}

/*AFTER*/
@EqualsAndHashCode(callSuper=true,exclude={"address","city","state","zip"})
public class Person extends SentientBeing {
    enum Gender { Male, Female }
 
    @NonNull private String name;
    @NonNull private Gender gender;
 
    private String ssn;
    private String address;
    private String city;
    private String state;
    private String zip;
}

@Data

Combina la funcionalidad de @ToString, @EqualsAndHashCode, @Getter, y @Setter, todo lo que un Plain Old Java Object (POJO) necesita. También se le pueden especificar parámetros como:

  • staticConstructor = “metodoFactoria” → El constructor se vuelve privado y se crea un método factoría con el nombre especificado.
/*BEFORE*/
public class Company {
    private final Person founder;
    private String name;
    private List<Person> employees;
 
    private Company(final Person founder) {
        this.founder = founder;
    }
 
    public static Company of(final Person founder) {
        return new Company(founder);
    }
 
    public Person getFounder() {
        return founder;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(final String name) {
        this.name = name;
    }
 
    public List<Person> getEmployees() {
        return employees;
    }
 
    public void setEmployees(final List<Person> employees) {
        this.employees = employees;
    }
 
    @java.lang.Override
    public boolean equals(final java.lang.Object o) {
        if (o == this) return true;
        if (o == null) return false;
        if (o.getClass() != this.getClass()) return false;
        final Company other = (Company)o;
        if (this.founder == null ? other.founder != null : !this.founder.equals(other.founder)) return false;
        if (this.name == null ? other.name != null : !this.name.equals(other.name)) return false;
        if (this.employees == null ? other.employees != null : !this.employees.equals(other.employees)) return false;
        return true;
    }
 
    @java.lang.Override
    public int hashCode() {
        final int PRIME = 31;
        int result = 1;
        result = result * PRIME + (this.founder == null ? 0 : this.founder.hashCode());
        result = result * PRIME + (this.name == null ? 0 : this.name.hashCode());
        result = result * PRIME + (this.employees == null ? 0 : this.employees.hashCode());
        return result;
    }
 
    @java.lang.Override
    public java.lang.String toString() {
        return "Company(founder=" + founder + ", name=" + name + ", employees=" + employees + ")";
    }
}

/*AFTER*/
@Data(staticConstructor="of")
public class Company {
    private final Person founder;
    private String name;
    private List<Person> employees;
}

@Builder

Usaremos el patrón Builder sin necesidad de implementar código para ello, bastante útil también en la ejecución de test (unit test por ejemplo) en donde debemos crear el objeto con atributos válidos o por defecto.

@Getter
@Builder
public class Widget {
    private final String name;
    private final int id;
}
/************************************/
Widget testWidget = Widget.builder()
  .name("foo")
  .id(1)
  .build();
 
assertThat(testWidget.getName())
  .isEqualTo("foo");
assertThat(testWidget.getId())
  .isEqualTo(1);

Welcome to my blog about Software Development! I would like to invite you to learning with me 👨‍💻

Search all posts