How To Use @Data Annotation With Project Lombok in Java Applications

@Data is an "all-in-one" special annotation that groups functionalities from multiple annotations namely:-

  1. @Getter.
  2. @Setter.
  3. @RequiredArgsConstructor.
  4. @ToString.
  5. @EqualsAndHashCode.

# Dev Environment:

  • Apache maven (v3.6.1)
  • maven-compiler-plugin (v3.8.1)
  • lombok (v1.18.8)
  • Apache Netbeans (v10.0)

TIP: For those who would like to follow along with this blog, just clone my repository git clone https://github.com/steven7mwesigwa/java-tutorials.git and navigate to java-tutorials\project-lombok\data. In there, you should be able to play around with all the source code used in this blog post.

# Demonstration : (Without Lombok)

Before we move on, let's look at how we would normally type out code for a regular Java object without using any lombok specific annotations.

Let's create a Person class that will have a manual implementation of @Data annotation. Full code here


//demo1			
package com.stevenmwesigwa.data.demo1;

import java.util.Objects;

public class Person {

    private String firstname;
    private String lastname;

    public Person() {
    }

    public String getFirstname() {
        return firstname;
    }

    public String getLastname() {
        return lastname;
    }

    public void setFirstname(String firstname) {
        this.firstname = firstname;
    }

    public void setLastname(String lastname) {
        this.lastname = lastname;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 17 * hash + Objects.hashCode(this.firstname);
        hash = 17 * hash + Objects.hashCode(this.lastname);
        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Person other = (Person) obj;
        if (!Objects.equals(this.firstname, other.firstname)) {
            return false;
        }
        if (!Objects.equals(this.lastname, other.lastname)) {
            return false;
        }
        return true;
    }

    protected boolean canEqual(final Object other) {
        return other instanceof Person;
    }

    @Override
    public String toString() {
        return "Person{" + "firstname=" + firstname + ", lastname=" + lastname + '}';
    }

}

As you would notice, this is a lot of boilerplate code for just 2 fields in our Person class.

It was actually even more painful for me to paste it here, but i had no choice but to show you how big your code can get.

For those who aren't familiar with what's going on, am basically providing:-

  • getters - To be able to return field values.
  • setters - To be able to set field values.
  • toString method - To return a more readable string representation of our object.
  • equals method - To check if 2 objects are equal.
  • hashCode method - Simply returns a hash code value for the object.
  • canEqual method - Explained in this equality method paper.
  • A "required args constructor" - A special constructor that takes one parameter for each final or non-null field with no initial value. Since we don't have any final / non-null fields, we don't have any parameters for our constructor.

Now, enough with the manual implementation. Let's try out some magic provided by Lombok specific annotations.

# Using @Data Annotation From Project Lombok Library : (Lombok)

The project Lombok authors decided to work on a quick solution to eliminate all this boilerplate code with just one annotation.

Adding @Data annotation right on top of your class informs Lombok to automatically generate:-

  • Equals and hashCode methods.
  • Setters for each non-final field.
  • A toString method.
  • A constructor that takes one parameter for each final or non-null field with no initial value.
  • Getters for each field.

Let's create a Person class, but this time making use of @Data annotation... Full code here


//demo2			
package com.stevenmwesigwa.data.demo2;

import lombok.Data;

@Data
public class Person {

    private String firstname;
    private String lastname;
}

Imagine if i had told you that by annotating my class with @Data annotation, Lombok would generate all the functionalities we had manually implemented in our previous example.

You can now see how small our code looks. As they say, less code less bugs, this allows us to focus on more important parts of our logic.

# How To Include Other Lombok Specific Annotations On Top Of @Data annotation

Now let's move on to the tricky parts. I know some of you're having several questions like:-

Truthfully speaking, we don't have special parameters for @Data annotation to cater for those use cases.

Though all hope is not lost, You can easily explicitly add other Lombok specific annotations to individually cater for each of those options.

The good news is, the implementation of these other Lombok specific annotations takes precedence over @Data annotation.

For example, in addition to @Data annotation, you could add :-

  1. @Setter(AccessLevel.NONE) annotation. To make the class read only.
  2. @Getter(AccessLevel.NONE) annotation. To make the class write-only.
  3. @AllArgsConstructor annotation. To have an "all args constructor" instead of a "required args constructor".
  4. @ToString(includeFieldNames=false) annotation. To inform Lombok not to display non-static field names and simply return a list of all non-static field values separated by commas.
  5. etc...

As you can see, this makes @Data annotation more flexible to specific requirements.

Let's create a Person class to demonstrate this behaviour. Full code here


//demo3			
package com.stevenmwesigwa.data.demo3;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.ToString;

@AllArgsConstructor
@ToString(includeFieldNames = false)
@Data
public class Person {

    private String firstname;
    private String lastname;
}

On top of what @Data annotation does, @AllArgsConstructor annotation provides us with an "all args constructor" and @ToString(includeFieldNames = false) annotation provides us with a string representation of our object that lucks 'field names'.

Feel free to play with other options you may have at your disposal.

# Make Lombok Generate A Private Constructor And A Public Static Factory Method

There're cases when you don't want your client to have direct access to call your constructor.

For a case like this, You normally want to make the constructor private and provide a public static factory method wrapper to the client so that they're still able to set field values.

This can be achieved with @AllArgsConstructor(staticName="of") or @RequiredArgsConstructor(staticName="of") annotation depending on your use case.

This is cool and fine, though you probably should keep in mind that we're able to achieve the same result by passing a staticConstructor parameter to @Data annotation. i.e @Data(staticConstructor="of").

NOTE: You're free to provide your own "staticConstructor" value, though a lot of developers prefer to use "of".

Let's create a Person class to demonstrate this behaviour. Full code here


//demo4	
package com.stevenmwesigwa.data.demo4;

import lombok.Data;

@Data(staticConstructor="of")
public class Person {

    private String firstname;
    private String lastname;
}

With the setup above, the client can easily create a new instance of the class like this Person.of()

When we create and run an App.java class that makes use of this Person class Full code here, we have successfully returned a string representation of our Person object. i.e Person(firstname=Steven, lastname=Mwesigwa)

I hope you learn a thing or two from this blog. Thanks for checking it out.

If anything is unclear or you wish to make any corrections, don't hesitate to leave a comment. Your feedback is greatly appreciated.

Sharing is caring. Share this blog to help out others getting started with 'project Lombok' library for Java applications.

Au revoir!

About The Author   

Steven Mwesigwa

Software Engineer at Vogue Book Consultancy Services Ltd


Picture Of Steven Mwesigwa

Steve is currently a software developer at Vogue Book Consultancy Services Ltd and a technology author. He holds a Dip. in civil engineering from Kyambogo University. He founded and maintains stevenmwesigwa.com a website that receives more than 1.5 thousand visits per month. Steve can be reached on Twitter at @steven7mwwesigwa