How to use Lombok In Spring Boot

How to use Lombok In Spring Boot

Project Lombok, is one of the coolest java libraries capable of minimizing your code. This is a plugin that we could configure with your editor and build tools. Then you would not have to worry about writing getters, setters, and much more boilerplate stuff you have to write in java classes. Here I’ll discuss how we can integrate Lombok with a Spring Boot application and ways to get used of it.

Technologies Going to Use,

  • Java 1.8
  • Spring Boot: 2.3.4.RELEASE
  • Lombok
  • Gradle
  • Intellij Idea for IDE

Main topics I’m going to discuss here are,

How Lombok Works?

Lombok is an annotation processor, which works on compile-time to add codes into your classes. Annotation processing was added since Java 5, Basically, if we use any type of annotation processor, the compiler coming to that level when compiling the class and give the control to that specific processor to process and do what they need to be done to that class.

Let’s think we added @Getter and @Setter annotation from Lombok to any class. While compilation is happening, the compiler gives the Lombok annotation processor a chance to add whatever the things that need to be added inside the class. So Lombok will add the following into the class.

How Lombok Annotation Processor change the code on compile time.

How Lombok Annotation Processor change the code on compile time.

Adding Required Dependencies

I’ll use Spring Initializr to generate a spring boot project with all the dependencies I need for this tutorial. If you are really new to Spring Boot, Please follow our article on How to Create a Spring Boot Project.

Creating spring boot project with lombok dependency using spring initializr

Creating spring boot project with lombok dependency using spring initializr

Here I’m only using Spring web and Lombok dependency for this tutorial.

If you need to add these libs manually, for Gradle project add the following into your build.gradle dependencies section,

implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
  • compileOnly – This Lombok dependency is only used while compiling the code, So we can use compileOnly for Lombok dependency,
  • annotationProcessor – Very similar to **compileOnly** but also guarantees that transitive dependency are not visible for consumer.

If you are using maven based project, use the following dependencies with your project,

<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <optional>true</optional>
</dependency>

Base project structure will be like,

Base project structure with intelljIdea

Base project structure with intelljIdea

Practical Ways to Use Lombok

From here I’ll explain how we can use lombok with common java projects with real examples and codes. Additionally I’ll embed how lombok will change the code on compilation time when necessary.

Using @Getter and @Setter In Lombok

We use getters and setters to achieve the encapsulations in java. So basically we declare variables/attributes as private and provide public methods to access and update those private variables.

The traditional way for defining getters and setters

package com.javatodev.api.rest.request;

public class UserCreateRequest {
    private String username;
    private String password;
    
    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

Lombok way, we can write the same class using Lombok with fewer codes as below,

package com.javatodev.api.rest.request;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class UserCreateRequest {
    private String username;
    private String password;
}

@Data for Additional Methods

@Data annotation has more power than using Getter and Setter alone since Data annotation comes with the following additional auto-generated methods,

  • RequiredArgsConstructor – Generates a constructor with required arguments.
  • ToString – Useful to String method.
  • EqualsAndHashCode – Hashcode and equals implementation that check all non-transient fields.

Example usage of @Data for a class.

package com.javatodev.api.rest.request;

import lombok.Data;

@Data
public class BooksResponse {
    private String bookIsbn;
    private String authorName;
    private Double netPrice;
}

Lombok issue with first char lowerCase and next upperCase

There is a known issue with Lombok, where that Lombok generates wrong getter and setter for variable/attributes which named as first char lowerCase and next char upperCase.

Eg:-

package com.javatodev.api.rest.request;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class ParticipantRequest {
    private String pCode;
}

If we generate getter setter manually it will generate as following, and this is the correct way of having a getter and setter,

public String getpCode() {
        return pCode;
    }

    public void setpCode(String pCode) {
        this.pCode = pCode;
    }

But with Lombok, It generates as following,

public String getPCode() {
        return this.pCode;
    }

    public void setPCode(final String pCode) {
        this.pCode = pCode;
    }

As you can see p is capital in both getter and setter, hence the Lombok generated getter and setter is wrong.

The way Lombok generates a wrong getter and setter could be problematic when you define an API using spring. Since we couldn’t deserialize incoming HttpRequest with include pCode value to Java Object which has pCode. This happens because of the wrong way Lombok generates these Getters and Setters.

This is just a simple issue which we can face while using Lombok for spring boot. Keep that in mind while you define variables/attributes inside a project.

Lombok @Builder For Easy Builder Pattern In Java

Builder pattern allows us to build a complex object with whatever the available values when we need it. So in a common way we need to introduce Builder methods along with encapsulation to a class. But with Lombok, we can easily enable the builder method to any type of class we need.

package com.javatodev.api.rest.request;

import lombok.Builder;
import lombok.ToString;

@Builder
public class BuilderTestRequest {
    private String name;
    private Integer number;
    private Double totalSalary;
}

While we used @Builder, It adds all the classes and methods we should implement in order to introduce a builder. So the generated class for above BuilderTestRequest is like below,

package com.javatodev.api.rest.request;

public class BuilderTestRequest {
    private String name;
    private Integer number;
    private Double totalSalary;

    BuilderTestRequest(final String name, final Integer number, final Double totalSalary) {
        this.name = name;
        this.number = number;
        this.totalSalary = totalSalary;
    }

    public static BuilderTestRequest.BuilderTestRequestBuilder builder() {
        return new BuilderTestRequest.BuilderTestRequestBuilder();
    }

    public static class BuilderTestRequestBuilder {
        private String name;
        private Integer number;
        private Double totalSalary;

        BuilderTestRequestBuilder() {
        }

        public BuilderTestRequest.BuilderTestRequestBuilder name(final String name) {
            this.name = name;
            return this;
        }

        public BuilderTestRequest.BuilderTestRequestBuilder number(final Integer number) {
            this.number = number;
            return this;
        }

        public BuilderTestRequest.BuilderTestRequestBuilder totalSalary(final Double totalSalary) {
            this.totalSalary = totalSalary;
            return this;
        }

        public BuilderTestRequest build() {
            return new BuilderTestRequest(this.name, this.number, this.totalSalary);
        }

        public String toString() {
            return "BuilderTestRequest.BuilderTestRequestBuilder(name=" + this.name + ", number=" + this.number + ", totalSalary=" + this.totalSalary + ")";
        }
    }
}

We can use builder enabled class as below, The specialty here is that we can have a BuilderTestRequest with whatever the available values.

package com.javatodev.api;

import com.javatodev.api.rest.request.BuilderTestRequest;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class BuilderUsage {

    public static void main(String[] args) {
        BuilderTestRequest symond_doe = BuilderTestRequest.builder().name("Symond Doe").build();
        BuilderTestRequest raymond_doe = BuilderTestRequest.builder().name("Raymond Doe").totalSalary(2000.00).build();
        BuilderTestRequest john_doe = BuilderTestRequest.builder().name("John Doe").totalSalary(200000.00).number(5996).build();
        log.info("Build {} ", symond_doe.toString());
        log.info("Built {} ", raymond_doe.toString());
        log.info("Built {} ", john_doe.toString());
    }

}

Output

Build BuilderTestRequest(name=Symond Doe, number=null, totalSalary=null) 
Built BuilderTestRequest(name=Raymond Doe, number=null, totalSalary=2000.0) 
Built BuilderTestRequest(name=John Doe, number=5996, totalSalary=200000.0) 

Here I’ve used Lombok.Slf4j to logging, It is discussed in the below part in this article.

How to Use Lombok with Spring Boot

The discussed areas in above like @Getter @Setter and @Data are common for any Java based application development. From here I’ll explain how we can use Lombok plugin to add value addition while writing a clean code in Spring Boot project.

Constructor Based Dependency Injection Using Lombok @RequiredArgsConstructor

Dependency injection, basically the way of providing dependent class objects into the class where it needs in order to perform its operation. So there are few ways of doing the dependency injection.

Constructor based dependency injection is one of them. Here I’ll explain how we can write constructor based dependency injection using Lombok.

Let’s define sample service and a rest controller inside our application calling UserService.java and BaseAPIController.java

package com.javatodev.api.service;

import org.springframework.stereotype.Service;

@Service
public class UserService {
    public String readUser () {
        return "John Doe";
    }
}
package com.javatodev.api.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping(value = "/api")
public class BaseAPIController {
}

Ok, now we need to inject our UserService.java into the BaseAPIController.java in order to call the method readUser() in UserService.

The UserService dependency can inject using @RequiredArgsConstructor in Lombok as follows.

package com.javatodev.api.controller;

import com.javatodev.api.service.UserService;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import lombok.RequiredArgsConstructor;

@RestController
@RequestMapping(value = "/api")
@RequiredArgsConstructor
public class BaseAPIController {

    private final UserService userService;

    @GetMapping
    public ResponseEntity readUserFromDB () {
        return ResponseEntity.ok(userService.readUser());
    }

}

So after using @RequiredArgsConstructor Lombok will create the following constructor which make constructor based dependency injection inside the BaseAPIController

public BaseAPIController(final UserService userService) {
        this.userService = userService;
    }

@Slf4j in Lombok For Logging

Slf4J, serves as a simple facade or abstraction for various logging frameworks, such as java.util.logging, logback, and log4j. We can use Slf4j as a logging partner easily when using it lombok.extern.slf4j.

Usage with java class,

package com.javatodev.api.Util;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class LoggerTestUtil {

    public static void writeLogs () {
        log.info("INFO log using Lombok Slf4j ");
        log.error("ERROR log using Lombok Slf4j ");
        log.warn("WARN log using Lombok Slf4j ");
    }
}

The following line will be added from Lombok while the compilation is happening,

Lombok Generated Class

package com.javatodev.api.Util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class LoggerTestUtil implements RandomWork {
    private static final Logger log = LoggerFactory.getLogger(LoggerTestUtil.class);

    public LoggerTestUtil() {
    }

    public static void writeLogs() {
        log.info("INFO log using Lombok Slf4j ");
        log.error("ERROR log using Lombok Slf4j ");
        log.warn("WARN log using Lombok Slf4j ");
    }
}

Sample usage inside a RestController

package com.javatodev.api.controller;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@RestController
@RequestMapping(value = "/api")
public class BaseAPIController {

    @GetMapping("/{id}")
    public ResponseEntity<Void> readUserFromDB (@PathVariable Long id) {
        log.info("Executing Reading user from DB : {} ", id);
        return ResponseEntity.ok().build();
    }

}

Using @Slf4j Inside an Interface

Lombok @Slf4J is valid for classes and enumerations by design, But we can use @Slf4j inside a java interface if we needed.

Here I’m using default methods which introduced with java 8 which allows us to have methods inside an interface,

package com.javatodev.api.Util;

import lombok.extern.slf4j.Slf4j;

public interface RandomWork {

    @Slf4j
    final class LoggerForRandomWork {}

    default void doTheRandomLog () {
        LoggerForRandomWork.log.info("Doing the random Log using Lombok Slf4J");
    }

}

Additional Tools For Lombok with Java

You can use Json to Java Converter from instantwebtools.net to easily generate java POJO classes with Lombok annotations for your next project. Using this converter you can generate

Conclusion

All done, I hope now you have a good idea about how to use Lombok In Spring Boot and any Java based application development. Comment your ideas or issues you are facing while using Lombok in your project.

You can find source codes for this tutorial from our Github.