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:

Java Program to Implement Slicker Algorithm that avoids Triangulation to Find Area of a Polygon
Sử dụng Fork/Join Framework với ForkJoinPool trong Java
Vòng lặp for, while, do-while trong Java
Java Program to Test Using DFS Whether a Directed Graph is Weakly Connected or Not
Java Program to Compare Binary and Sequential Search
Map Interface trong java
Sử dụng JDBC API thực thi câu lệnh truy vấn dữ liệu
Reading an HTTP Response Body as a String in Java
Spring’s RequestBody and ResponseBody Annotations
Spring REST API + OAuth2 + Angular
Apache Commons Collections OrderedMap
Interface trong Java 8 – Default method và Static method
Java Program to Implement Bellman-Ford Algorithm
Spring Security Custom AuthenticationFailureHandler
Spring Boot - Servlet Filter
Java Program to Implement CountMinSketch
Spring Boot - Hystrix
Notify User of Login From New Device or Location
Introduction to Spring Security Expressions
Tạo ứng dụng Java RESTful Client với thư viện OkHttp
Java Program to Find the Vertex Connectivity of a Graph
LinkedList trong java
The SpringJUnitConfig and SpringJUnitWebConfig Annotations in Spring 5
Refactoring Design Pattern với tính năng mới trong Java 8
Testing an OAuth Secured API with Spring MVC
Java Program to Implement Hash Tables Chaining with Doubly Linked Lists
Explain about URL and HTTPS protocol
Java Program to Find All Pairs Shortest Path
Java Program to Construct an Expression Tree for an Prefix Expression
Bootstrap a Web Application with Spring 5
Create a Custom Auto-Configuration with Spring Boot
Sort a HashMap in Java