@Data

Overview

@Data is a convenient shortcut annotation that bundles the features of @ToString, @EqualsAndHashCode, @Getter / @Setter and @RequiredArgsConstructor together: In other words, @Data generates all the boilerplate that is normally associated with simple POJOs (Plain Old Java Objects) and beans: getters for all fields, setters for all non-final fields, and appropriate toString, equals and hashCode implementations that involve the fields of the class, and a constructor that initializes all final fields, as well as all non-final fields with no initializer that have been marked with @NonNull, in order to ensure the field is never null.

@Data is like having implicit @Getter, @Setter, @ToString, @EqualsAndHashCode and @RequiredArgsConstructor annotations on the class. However, the parameters of these annotations (such as callSuper, includeFieldNames and exclude) cannot be set with @Data. If you need to set non-default values for any of these parameters, just add those annotations explicitly; @Data is smart enough to defer to those annotations.

All generated getters and setters will be public. To override the access level, annotate the field or class with an explicit @Setter and/or @Getter annotation. You can also use this annotation (by combining it with AccessLevel.NONE) to suppress generating a getter and/or setter altogether.

All fields marked as transient will not be considered for hashCode and equals. All static fields will be skipped entirely (not considered for any of the generated methods, and no setter/getter will be made for them).

If the class already contains a method with the same name and parameter count as any method that would normally be generated, that method is not generated, and no warning or error is emitted. For example, if you already have a method with signature equals(AnyType param), no equals method will be generated, even though technically it might be an entirely different method due to having different parameter types. The same rule applies to the constructor (any explicit constructor will prevent @Data from generating one), as well as toString, equals, and all getters and setters. You can mark any constructor or method with @lombok.experimental.Tolerate to hide them from lombok.

@Data can handle generics parameters for fields just fine. In order to reduce the boilerplate when constructing objects for classes with generics, you can use the staticConstructor parameter to generate a private constructor, as well as a static method that returns a new instance. This way, javac will infer the variable name. Thus, by declaring like so: @Data(staticConstructor="of") class Foo<T> { private T x;} you can create new instances of Foo by writing: Foo.of(5); instead of having to write: new Foo<Integer>(5);.

With Lombok

01 import lombok.AccessLevel;
02 import lombok.Setter;
03 import lombok.Data;
04 import lombok.ToString;
05 
06 @Data public class DataExample {
07   private final String name;
08   @Setter(AccessLevel.PACKAGEprivate int age;
09   private double score;
10   private String[] tags;
11   
12   @ToString(includeFieldNames=true)
13   @Data(staticConstructor="of")
14   public static class Exercise<T> {
15     private final String name;
16     private final T value;
17   }
18 }

Vanilla Java

001 import java.util.Arrays;
002 
003 public class DataExample {
004   private final String name;
005   private int age;
006   private double score;
007   private String[] tags;
008   
009   public DataExample(String name) {
010     this.name = name;
011   }
012   
013   public String getName() {
014     return this.name;
015   }
016   
017   void setAge(int age) {
018     this.age = age;
019   }
020   
021   public int getAge() {
022     return this.age;
023   }
024   
025   public void setScore(double score) {
026     this.score = score;
027   }
028   
029   public double getScore() {
030     return this.score;
031   }
032   
033   public String[] getTags() {
034     return this.tags;
035   }
036   
037   public void setTags(String[] tags) {
038     this.tags = tags;
039   }
040   
041   @Override public String toString() {
042     return "DataExample(" this.getName() ", " this.getAge() ", " this.getScore() ", " + Arrays.deepToString(this.getTags()) ")";
043   }
044   
045   protected boolean canEqual(Object other) {
046     return other instanceof DataExample;
047   }
048   
049   @Override public boolean equals(Object o) {
050     if (o == thisreturn true;
051     if (!(instanceof DataExample)) return false;
052     DataExample other = (DataExampleo;
053     if (!other.canEqual((Object)this)) return false;
054     if (this.getName() == null ? other.getName() != null : !this.getName().equals(other.getName())) return false;
055     if (this.getAge() != other.getAge()) return false;
056     if (Double.compare(this.getScore(), other.getScore()) != 0return false;
057     if (!Arrays.deepEquals(this.getTags(), other.getTags())) return false;
058     return true;
059   }
060   
061   @Override public int hashCode() {
062     final int PRIME = 59;
063     int result = 1;
064     final long temp1 = Double.doubleToLongBits(this.getScore());
065     result = (result*PRIME(this.getName() == null this.getName().hashCode());
066     result = (result*PRIMEthis.getAge();
067     result = (result*PRIME(int)(temp1 ^ (temp1 >>> 32));
068     result = (result*PRIME+ Arrays.deepHashCode(this.getTags());
069     return result;
070   }
071   
072   public static class Exercise<T> {
073     private final String name;
074     private final T value;
075     
076     private Exercise(String name, T value) {
077       this.name = name;
078       this.value = value;
079     }
080     
081     public static <T> Exercise<T> of(String name, T value) {
082       return new Exercise<T>(name, value);
083     }
084     
085     public String getName() {
086       return this.name;
087     }
088     
089     public T getValue() {
090       return this.value;
091     }
092     
093     @Override public String toString() {
094       return "Exercise(name=" this.getName() ", value=" this.getValue() ")";
095     }
096     
097     protected boolean canEqual(Object other) {
098       return other instanceof Exercise;
099     }
100     
101     @Override public boolean equals(Object o) {
102       if (o == thisreturn true;
103       if (!(instanceof Exercise)) return false;
104       Exercise<?> other = (Exercise<?>o;
105       if (!other.canEqual((Object)this)) return false;
106       if (this.getName() == null ? other.getValue() != null : !this.getName().equals(other.getName())) return false;
107       if (this.getValue() == null ? other.getValue() != null : !this.getValue().equals(other.getValue())) return false;
108       return true;
109     }
110     
111     @Override public int hashCode() {
112       final int PRIME = 59;
113       int result = 1;
114       result = (result*PRIME(this.getName() == null this.getName().hashCode());
115       result = (result*PRIME(this.getValue() == null this.getValue().hashCode());
116       return result;
117     }
118   }
119 }

Supported configuration keys:

lombok.data.flagUsage = [warning | error] (default: not set)
Lombok will flag any usage of @Data as a warning or error if configured.

Small print

See the small print of @ToString, @EqualsAndHashCode, @Getter / @Setter and @RequiredArgsConstructor.

Any annotations named @NonNull (case insensitive) on a field are interpreted as: This field must not ever hold null. Therefore, these annotations result in an explicit null check in the generated constructor for the provided field. Also, these annotations (as well as any annotation named @Nullable) are copied to the constructor parameter, in both the true constructor and any static constructor. The same principle applies to generated getters and setters (see the documentation for @Getter / @Setter)

By default, any variables that start with a $ symbol are excluded automatically. You can include them by specifying an explicit annotation (@Getter or @ToString, for example) and using the 'of' parameter.