Overview

Lombok project has taken constructors generation to the next level by providing a list of handy ready-to-use annotations: @AllArgsConstructor, @NoArgsConstructor, and @RequiredArgsConstructor.

Despite the fact that all of them can be used to generate the boilerplate code required to create constructors, they are quite different.

In this quick tutorial, we’re going to highlight Lombok constructor annotations and explore in detail how each one works under-the-hood.

Lombok @AllArgsConstructor Annotation

In short, @AllArgsConstructor, as the name implies, is mainly introduced to generate an All-Args constructor for the decorated class.

Basically, an all-args constructor provides a parameter for each field of the class.

@Builder is another Lombok annotation that generates an all-args constructor.

To understand the importance of @AllArgsConstructor annotation, we’re going to use it in a simple example.

First, we’ll create a simple POJO class - Employee.java:

    
        @AllArgsConstructor
        public class Employee {
            
            private int id;
            private String firstName;
            private String lastName;
            private double salary;
            
            public int getId() {
                return id;
            }
            
            public void setId(int id) {
                this.id = id;
            }
            
            public String getFirstName() {
                return firstName;
            }
            
            public void setFirstName(String firstName) {
                this.firstName = firstName;
            }
            
            public String getLastName() {
                return lastName;
            }
            
            public void setLastName(String lastName) {
                this.lastName = lastName;
            }
            
            public double getSalary() {
                return salary;
            }
            
            public void setSalary(double salary) {
                this.salary = salary;
            }
        }
    

Now, let’s de-lombok our Employee class and see what @AllArgsConstructor generates for us:

    
        public class Employee {
            private int id;
            private String firstName;
            private String lastName;
            private double salary;
            // Standard Getters + Setters
            @java.beans.ConstructorProperties({"id", "firstName", "lastName", "salary"})
            public Employee(final int id, final String firstName, final String lastName, final double salary) {
                this.id = id;
                this.firstName = firstName;
                this.lastName = lastName;
                this.salary = salary;
            }
        }
    

As we can see, the generated constructor is by default public and annotated with @ConstructorProperties to make sure that the parameters correspond to the constructed object’s getter methods.

As a matter of fact, @AllArgsConstructor annotation generates all the necessary code required to create an all arguments constructor. The annotation itself is self-explanatory and makes our code well optimized.

Note that, @AllArgsConstructor is among annotations that are implicitly included in @Value.

Create a Static Factory Method with @AllArgsConstructor

@AllArgsContstructor offers a handy attribute - staticName - that can be used to generate a static factory method.

                  
        @AllArgsConstructor(staticName = "of")
        public class User {
            
            private int id;
            private String userName;
            private String password;

        }
    

When staticName is used, Lombok marks the generated constructor as private and creates a static factory method - of() in our case - that will be used to construct all User objects.

                  
        public class User {
            private int id;
            private String userName;
            private String password;

            @java.beans.ConstructorProperties({"id", "userName", "password"})
            private User(final int id, final String userName, final String password) {
                this.id = id;
                this.userName = userName;
                this.password = password;
            }

            public static User of(final int id, final String userName, final String password) {
                return new User(id, userName, password);
            }
        }
    

Simply put, the factory method of() acts as a wrapper for the private constructor: User(id, userName, password).

@AllArgsConstructor with Initialized Final Field

In this section, we’ll take a close look at how @AllArgsConstructor will behave in the presence of an initialized final field.

First, let’s create a Java class - Address.java - with a final variable and annotate it with @AllArgsConstructor:

                  
        @AllArgsConstructor
        public class Address {

            private String streetName;
            private String zipCode;
            private String city;
            private final String country = "United States";

        }
    

Next, let’s take a look at the lombok-generated constructor:

    
        public class Address {
            private String streetName;
            private String zipCode;
            private String city;
            private final String country = "United States";

            @java.beans.ConstructorProperties({"streetName", "zipCode", "city"})
            public Address(final String streetName, final String zipCode, final String city) {
                this.streetName = streetName;
                this.zipCode = zipCode;
                this.city = city;
            }
        }
    

As shown above, the generated constructor doesn’t include a parameter for our initialized final field country.

As a matter of fact, @AllArgsConstructor annotation skips final fields as long they are initialized.

@AllArgsConstructor with static Field

In short, Lombok AllArgsConstructor annotation simply ignores all static fields and does not include them in the parameters list.

The main reason behind this behavior is that all static variables are bound to the class and they have nothing to do with the class instances.

Note that, in case we want to define a constructor with a static field, we need to do it explicitly.

Writing an explicit constructor will not stop Lombok from generating the All-Args one. However, the compiler will complain in case we write a custom constructor with the same signature as the one generated by @AllArgsConstructor.

Lombok @RequiredArgsConstructor Annotation

@RequiredArgsConstructor belongs to the Lombok constructor annotations list. As the name indicates, its main purpose is creating a constructor with required arguments.

According to the docs, a required argument is a field declared final or has some constraints such as @NonNull.

To exemplify @RequiredArgsConstructor, we’re going to create a simple POJO class - Article.java:

                  
        @RequiredArgsConstructor
        public class Article {
            
            @NonNull
            private int reference;
            private final String title;
            private final String link;
            private String description;
            
        }
    

The de-lomboked version of Article.java looks like the following:

    
        public class Article {
            @NonNull
            private int reference;
            private final String title;
            private final String link;
            private String description;

            @java.beans.ConstructorProperties({"reference", "title", "link"})
            public Article(@NonNull final int reference, final String title, final String link) {
                this.reference = reference;
                this.title = title;
                this.link = link;
            }
        }
    

As we can see, @RequiredArgsConstructor generates a constructor with a parameter for each required field!

In general, Lombok @RequiredArgsConstructor annotation will not generate an argument for:

  • Non-final fields.

  • Initialized final fields.

  • Initialized fields decorated with @NonNull.

  • Static fields.

It’s worth mentioning that, @RequiredArgsConstructor is included in @Data annotation.

Create a Static Factory Method with @RequiredArgsConstructor

We can also create a static factory method with @RequiredArgsConstructor! To do so, we need just to specify the name of the method using staticName attribute: staticName = “methodname”.

                  
        @RequiredArgsConstructor(staticName = "newInstance")
        public class Car {
            private final String type;
            private final String model;
            private final String color;
        }
    

Behind the scenes, Lombok generates the following code:

                  
        public class Car {
            private final String type;
            private final String model;
            private final String color;
            @java.beans.ConstructorProperties({"type", "model", "color"})
            private Car(final String type, final String model, final String color) {
                this.type = type;
                this.model = model;
                this.color = color;
            }
            public static Car newInstance(final String type, final String model, final String color) {
                return new Car(type, model, color);
            }
        }
    

When using staticName attribute, @RequiredArgsConstructor marks the required arguments constructor private and creates an additional factory method with the name specified by staticName attribute.

In our example, the name of the factory method is newInstance. As shown above, newInstance wraps the private constructor! This means, all Car instances will be created using newInstance method instead of the classic new operator.

Lombok @NoArgsConstructor Annotation

@NoArgsConstructor is a self-explanatory and straightforward annotation, introduced to generate the default no-args constructor for the annotated class. By default, the access modifier of the generated constructor is public.

                  
        @NoArgsConstructor
        public class Singer {
            private Long id;
            private String firstName;
            private String lastName;
            private List<String> albums;
        }
    

When we look at the de-lomboked version of Singer class, we can see that Lombok creates a no-args constructor:

                  
        public class Singer {
            private Long id;
            private String firstName;
            private String lastName;
            private List<String> albums;
            public Singer() {
            }
        }
    

It’s worth noting that, @NoArgsConstructor, like other Lombok constructor annotations, provides staticName attribute.

When set, Lombok generates a static factory method and change the access scope of the default constructor to private.

@NoArgsConstructor with Final Fields

Basically, @NoArgsConstructor will generate an error message in case the annotated class has uninitialized final fields.

@NoArgsConstructor with Final Fields

The compiler will complain about the unassignable final field, unless we set force attribute to true. That way, we tell Lombok to initialize all the final fields with their default values.

Access Level For Lombok Generated Constructors

All Lombok constructor annotations (@AllArgsConstructor, @RequiredArgsConstructor, and @NoArgsConstructor) offers access attribute to help us easily set the access level of the generated constructors.

Let’s see how we can use access attribute to customize the access modifier - which is generally public - of a default generated constructor:

                  
        @NoArgsConstructor(access = AccessLevel.PROTECTED)
        public class Singer {
            // fields
        }
    

Basically, Lombok provides AccessLevel enum to allow us to specify the desired access level.

                  
        public class Singer {
            // fields
            protected Singer() {
            }
        }
    

As shown above, the no-args constructor is generated with the protected modifier.

Call Super Constructor in Lombok

In this section, we’re going to investigate if it’s possible to call a super constructor from a subclass in Lombok.

Firstly, let’s create a superclass - Animal.java - with an all-args constructor:

                  
        public class Animal {
            private String name;
            public Animal(String name) {
                this.name = name;
            }
            public String getName() {
                return name;
            }
            public void setName(String name) {
                this.name = name;
            }
        }
    

Secondarily, we’ll create another class, Cat.java, that extends the Animal class.

                  
        public class Cat extends Animal {
            private String color;
            public Cat (String name, String color) {
                super(name);
                this.color = color;
            }
            public String getColor() {
                return color;
            }
            public void setColor(String color) {
                this.color = color;
            }
        }
    

If we decorate Cat class with Lombok @AllArgsConstructor annotation, the compiler will simply complain because the implicit super constructor Animal() is undefined.

Call Super Constructor in Lombok

In the case of inheritance, Lombok can’t generate automatically a constructor that calls a super constructor with parameters for a subclass.

Conclusion

In this tutorial, we covered in-depth all Lombok constructor annotations and highlighted the difference between them.

As always, the full source code of the article is available over on this Github repository.