Constructor Injection in Spring with Lombok

1. Introduction

Lombok is an extremely useful library overcoming boilerplate code. If you are not familiar with it yet, I highly recommend taking a look at the previous tutorial – Introduction to Project Lombok.

In this article, we’ll demonstrate its usability when combined with Spring’s Constructor-Based Dependency Injection.

2. Constructor-Based Dependency Injection

A good way to wire dependencies in Spring using constructor-based Dependency Injection. This approach forces us to explicitly pass component’s dependencies to a constructor.

As opposed to Field-Based Dependency Injection, it also provides a number of advantages:

  • no need to create a test-specific configuration component – dependencies are injected explicitly in a constructor
  • consistent design – all required dependencies are emphasized and looked after by constructor’s definition
  • simple unit tests – reduced Spring Framework’s overhead
  • reclaimed freedom of using final keywords

However, due to the need for writing a constructor, it uses to lead to a significantly larger code base. Consider the two examples of GreetingService and FarewellService:

@Component
public class GreetingService {

    @Autowired
    private Translator translator;

    public String produce() {
        return translator.translate("hello");
    }
}
@Component
public class FarewellService {

    private final Translator translator;

    public FarewellService(Translator translator) {
        this.translator = translator;
    }

    public String produce() {
        return translator.translate("bye");
    }
}

Basically, both of the components do the same thing – they call a configurable Translator with a task-specific word.

The second variation, though, is much more obfuscated because of the constructor’s boilerplate which doesn’t really bring any value to the code.

In the newest Spring release, it’s constructor does not need to be annotated with @Autowired annotation.

3. Constructor Injection With Lombok

With Lombok, it’s possible to generate a constructor for either all class’s fields (with @AllArgsConstructor) or all final class’s fields (with @RequiredArgsConstructor). Moreover, if you still need an empty constructor, you can append an additional @NoArgsConstructor annotation.

Let’s create a third component, analogous to the previous two:

@Component
@RequiredArgsConstructor
public class ThankingService {

    private final Translator translator;

    public String produce() {
        return translator.translate("thank you");
    }
}

The above annotation will cause Lombok to generate a constructor for us:

@Component
public class ThankingService {

    private final Translator translator;

    public String thank() {
        return translator.translate("thank you");
    }

    /* Generated by Lombok */
    public ThankingService(Translator translator) {
        this.translator = translator;
    }
}

4. Multiple Constructors

A constructor doesn’t have to be annotated as long as there is only one in a component and Spring can unambiguously choose it as the right one to instantiate a new object. Once there are more, you also need to annotate the one that is to be used by IoC container.

Consider the ApologizeService example:

@Component
@RequiredArgsConstructor
public class ApologizeService {

    private final Translator translator;
    private final String message;

    @Autowired
    public ApologizeService(Translator translator) {
        this(translator, "sorry");
    }

    public String produce() {
        return translator.translate(message);
    }
}

The above component is optionally configurable with the message field which cannot change after the component is created (hence the lack of a setter). It thus required us to provide two constructors – one with full configuration and the other with an implicit, default value of the message.

Unless one of the constructors is annotated with either @Autowired@Inject or @Resource, Spring will throw an error:

Failed to instantiate [...]: No default constructor found;

If we wanted to annotate the Lombok-generated constructor, we would have to pass the annotation with an onConstructor parameter of the @AllArgsConstructor:

@Component
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class ApologizeService {
    // ...
}

The onConstructor parameter accepts an array of annotations (or a single annotation like in this specific example) that are to be put on a generated constructor. The double underscore idiom has been introduced because of the backward compatibility issues. According to the documentation:

The reason of the weird syntax is to make this feature work in javac 7 compilers; the @__[/code] type is an annotation reference to the annotation type __[/code] (double underscore) which doesn’t actually exist; this makes javac 7 delay aborting the compilation process due to an error because it is possible an annotation processor will later create the __[/code] type.

5. Summary

In this tutorial, we showed that there is no need to favor field-based DI over constructor-based DI in terms of increased boilerplate code.

Thanks to Lombok, it’s possible to automate common code generation without a performance impact on runtime, abbreviating long, obscuring code to the use of a single-line annotation.

The code used during the tutorial is available over on GitHub.

Related posts:

Mệnh đề Switch-case trong java
Java Program to Implement HashTable API
XML-Based Injection in Spring
Java Program to Implement Repeated Squaring Algorithm
Write/Read cookies using HTTP and Read a file from the internet
Spring Boot - Servlet Filter
The Order of Tests in JUnit
Primitive Type Streams in Java 8
Basic Authentication with the RestTemplate
HttpClient Basic Authentication
Java Program to Check Whether a Directed Graph Contains a Eulerian Cycle
Java 14 Record Keyword
Java Program to Implement AttributeList API
Java Program to Perform the Shaker Sort
Concrete Class in Java
Daemon Threads in Java
Các chương trình minh họa sử dụng Cấu trúc điều khiển trong Java
Java Program to implement Priority Queue
Spring Cloud Bus
Java Program to Check Whether an Undirected Graph Contains a Eulerian Path
Hướng dẫn sử dụng biểu thức chính quy (Regular Expression) trong Java
Giới thiệu về Stream API trong Java 8
Java Program to Implement wheel Sieve to Generate Prime Numbers Between Given Range
Array to String Conversions
Java Program to Implement Direct Addressing Tables
Java Program to Find Shortest Path Between All Vertices Using Floyd-Warshall’s Algorithm
Spring Security – security none, filters none, access permitAll
Find the Registered Spring Security Filters
CyclicBarrier in Java
Java Program to Implement Wagner and Fisher Algorithm for online String Matching
Java Program to Implement Merge Sort Algorithm on Linked List
Getting Started with GraphQL and Spring Boot