Spring Constructor Injection with Lombok

Examples of using Lombok annotations for Spring’s constructor-based dependency injection without adding boilerplate constructors.

Overview

The dependency Injection framework is one of Spring’s most powerful modules. Spring supports dependency injection through fields, setter methods and constructors, out of which constructor-based dependency injection is favoured more often. If you are new to Spring’s dependency injection, please read this article for details.

The project Lombok provides annotations which are very helpful if reducing boilerplate code blocks and keeping the source code focused on the business.

Boilerplate Constructors

Here is a simple example of Spring’s dependency injection using a constructor. The dependency of the DogsService has a ‘final’ modifier – that makes the dependency mandatory for the instantiation of the DogsService.

@Component
public class DogsService {
  private final DogsRepository repo;
  private final DogsTrainer trainer;

  @Autowired
  public DogsService(DogsRepository repo, DogsTrainer trainer) {
    this.repo = repo;
    this.trainer = trainer;
  }
}Code language: Java (java)

Spring Constructor Injection without Annotation

However, all the classes with only one constructor can skip the @Autowired annotation. As the class has only one constructor, Spring uses it to inject the dependencies and allows us to omit the boilerplate annotation.

We’ll rewrite the previous constructor-based dependencies injection example without using @Autowired annotation, and it will still work.

@Component
public class DogsService {
  private final DogsRepository repo;
  private final DogsTrainer trainer;

  public DogsService(DogsRepository repo, DogsTrainer trainer) {
    this.repo = repo;
    this.trainer = trainer;
  }
}Code language: Java (java)

Constructor Injection with Lombok

Lombok helps us generate different constructors for our class on the fly.

For example, @NoArgsConstructor annotation adds a zero argument or empty constructor, while @AllArgsConstructor annotation adds a constructor for all the class fields. Similarly, @RequiredArgsConstructor annotation adds a constructor to initialize only the ‘final‘ fields of the class.

@Component
@RequiredArgsConstructor
public class DogsService {
  private final DogsRepository repo;
  private final DogsTrainer trainer;
}Code language: Java (java)

For this class, Lombok will auto-generate two argument constructors on the fly. As this is the only constructor in our class, Spring uses it for constructor-based dependency injection.

Dependency Injection with Lombok When Multiple Constructors

The constructor-based implicit dependency injection works only when a class has one and only one constructor. In case of more than one constructor, we must instruct Spring to use a particular constructor with @Autowired@Inject or @Resource annotation.

@Component
@RequiredArgsConstructor
public class DogsService {
  private final DogsRepository repo;
  private final DogsTrainer trainer;

  public DogsService(DogsRepository repo) {
    this.repo = repo;
    this.trainer = null;
  }
}Code language: Java (java)

For example, dependency injection for the above class will fail with an error:

Caused by: org.springframework.beans.BeanInstantiationException: 
   Failed to instantiate [com...DogsService]: 
   No default constructor found; nested exception is 
   java.lang.NoSuchMethodException: com...DogsService.<init>()Code language: Bash (bash)

Thankfully, Lombok’s all constructor-generating annotations – @NoArgsConstructor, @AllArgsConstructor, and @RequiredArgsConstructor – have an ‘onConstructor‘ attribute that we can specify the annotation we want it to put on the generated constructors.

@Component
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class DogsService {
  private final DogsRepository repo;
  private final DogsTrainer trainer;

  public DogsService(DogsRepository repo) {
    this.repo = repo;
    this.trainer = null;
  }
}
Code language: Java (java)

The ‘onConstructor‘ attribute will add the given annotation to the auto-generated constructor. However, the syntax of providing the annotation is weird; as per the official documentation, it is done for backward compatibility.

Summary

In this article, we had a detailed look at Spring’s constructor-based dependency injection and how we can simplify it using Project Lombok’s annotations.

We understood that we could use @Autowired@Inject or @Resource annotation on a constructor to specify the constructor Spring should use for injecting dependencies. However, we can skip this annotation if a class has only one constructor. Project Lombok’s annotations – @NoArgsConstructor, @AllArgsConstructor, or @RequiredArgsConstructor – help us generate constructors on the fly and help us reduce boilerplate code blocks.