Expand Authors Top

If you have a few years of experience in the Java ecosystem and you’d like to share that with the community, have a look at our Contribution Guidelines.

Expanded Audience – Frontegg – Security (partner)
announcement - icon User management is very complex, when implemented properly. No surprise here.

Not having to roll all of that out manually, but instead integrating a mature, fully-fledged solution - yeah, that makes a lot of sense.
That's basically what Frontegg is - User Management for your application. It's focused on making your app scalable, secure and enjoyable for your users.
From signup to authentication, it supports simple scenarios all the way to complex and custom application logic.

Have a look:

>> Elegant User Management, Tailor-made for B2B SaaS

November Discount Launch 2022 – Top
We’re finally running a Black Friday launch. All Courses are 30% off until end-of-day today:

>> GET ACCESS NOW

NPI – Lightrun – Spring (partner)

We rely on other people’s code in our own work. Every day. It might be the language you’re writing in, the framework you’re building on, or some esoteric piece of software that does one thing so well you never found the need to implement it yourself.

The problem is, of course, when things fall apart in production - debugging the implementation of a 3rd party library you have no intimate knowledge of is, to say the least, tricky. It’s difficult to understand what talks to what and, specifically, which part of the underlying library is at fault.

Lightrun is a new kind of debugger.

It's one geared specifically towards real-life production environments. Using Lightrun, you can drill down into running applications, including 3rd party dependencies, with real-time logs, snapshots, and metrics. No hotfixes, redeployments, or restarts required.

Learn more in this quick, 5-minute Lightrun tutorial:

>> The Essential List of Spring Boot Annotations and Their Use Cases

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 @__ 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.

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.

November Discount Launch 2022 – Bottom
We’re finally running a Black Friday launch. All Courses are 30% off until end-of-day today:

>> GET ACCESS NOW

Generic footer banner
Comments are closed on this article!