
Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:
Once the early-adopter seats are all used, the price will go up and stay at $33/year.
Last updated: January 8, 2024
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.
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:
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.
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;
}
}
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
@__
type is an annotation reference to the annotation type__
(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__
type.
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.
Follow the Spring Category