1. Overview
Lombok is a library developed for Java and serves as a tool to minimize the need to write boilerplate code. For example, with Lombok, we don’t need to write getters, setters, toString(), and certain other methods for our Java classes.
It’s also possible to integrate Java classes that use Lombok annotations with a Kotlin project.
In this short tutorial, we’ll look at how to enable Lombok in Kotlin and which of its features are available.
2. Configuring Lombok in Kotlin
The Kotlin Lombok plugin enables us to write Lombok annotations on our Java classes and use them with Kotlin. But unfortunately, we can’t apply Lombok annotations to Kotlin classes.
The plugin can be used with build tools such as Gradle and Maven. We can also use it with Kapt and the command line
2.1. Gradle
For use with Gradle, we apply the kotlin-lombok-plugin to Gradle in the build.gradle(.kts) file:
plugins {
kotlin("plugin.lombok") version "1.8.10"
id("io.freefair.lombok") version "5.3.0"
}
2.2. Maven
To use the Lombok compiler plugin with Maven, we add the plugin Lombok to the compilerPlugins block and the dependency kotlin-maven-lombok to the dependencies section of our pom.xml file:
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<version>1.8.10</version>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-lombok</artifactId>
<version>1.8.20-RC</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
<scope>provided</scope>
</dependency>
</dependencies>
</plugin>
2.3. Using kapt
By default, the kapt compiler plugin runs all annotation processors and disables annotation processing by javac. So to run Lombok along with Kapt, set up kapt to keep javac‘s annotation processors working
With Gradle, add this option to the build.gradle(.kts) file:
kapt {
keepJavacAnnotationProcessors = true
}
With Maven, add this setting to the pom.xml file:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<annotationProcessorPaths>
<annotationProcessorPath>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</annotationProcessorPath>
</annotationProcessorPaths>
</configuration>
</plugin>
2.4. Command-line
The Lombok compiler plugin JAR is available in the binary distribution of the Kotlin compiler. To attach this plugin to the compiler, we use the -Xplugin kotlinc option:
-Xplugin=$KOTLIN_HOME/lib/lombok-compiler-plugin.jar
3. Why Use Lombok With Kotlin
Kotlin inherently comes with capabilities similar to those Lombok provides.
For instance, we often need classes solely to hold data. Such classes require that we write boilerplate code such as getters, setters, equals(), toString(), and hashcode() methods. We can solve this issue with the @Data annotation for mutable classes and @Value for immutable classes.
Similarly, Kotlin’s Data classes derive similar boilerplate methods from properties in the primary constructor.
Let’s see an example Java class annotated with @Data:
@Data
public class Person {
private String name;
private int age;
}
This Java class is equivalent to the following Kotlin class:
data class Person(private val name: String, private val age: Int)
The Java class generates all the boilerplate code thanks to the @Data annotation, while the Kotlin data class comes with all these methods by default.
Principally, we use the Kotlin Lombok plugin to work with Kotlin code mixed with Java. This way, we don’t need to rewrite our Java classes into their Kotlin equivalent.
4. Lombok Annotations for Kotlin and Usage
The Kotlin Lombok plugin supports many of the Lombok annotations.
4.1. Supported Annotations
- @NoArgsConstructor – generate a class constructor with no arguments
- @Getter and @Setter – used at both class and field levels. At the class level, they generate getter and setter methods for all fields in the class, while these methods are generated for a specific field at the field level. The @Getter generates the code getter method for a field, while @Setter generates the setter for a field.
- @AllArgsConstructor – generates a parameterized constructor for a class, accepting a parameter for each field
- @ToString – provides a field-by-field implementation of the toString() method
- @EqualsAndHashCode – overrides the equals() and hashcode() methods with a default implementation
- @Data – combines the @Tostring(), @Getter, @Setter, @EqualsAndHashCode, and @RequiredArgsConstructor annotations
- @Value– acts similarly to @Data except that it creates immutable objects
- @With – when working with immutable objects, which by design don’t allow setters, allows a clone object to be created with a single field changed from the original
4.2. Code Example Using @Setter, @Getter, and @EqualsAndHashCode
Let’s look at an example of how we could make calls to the implicit code generated by Lombok in Kotlin.
Let’s start with a class Person:
@Getter
@Setter
@EqualsAndHashCode
public class Person {
private String name;
private int age;
private String gender;
private int id;
}
Here, the fields in this class are all private and normally should not be accessible from outside.
Now, let’s test this class:
val p = Person()
p.name = "Nappy"
p.age = 20
p.gender = "Male"
val p1 = Person()
p1.name = "Nappy"
p1.age = 20
p1.gender = "Male"
assertEquals("Nappy", p.name)
assertEquals(20, p.age)
assertEquals("Male", p.gender)
assertEquals(p, p1)
assertEquals(p.hashCode(), p1.hashCode())
The assert statements call the getter and setter methods for properties from the Person1 class, thanks to the Lombok @Setter and @Getter annotations. We can also make calls to the generated equals() and hashcode() methods.
4.2. Code Example Using @ToString and @AllArgsConstructor
Let’s consider the Java class Person1 annotated with @AllArgsConstructor and @ToString:
@AllArgsConstructor
@ToString
public class Person1 {
private String name;
private int age;
private String gender;
private int id;
}
val person = Person1("Nappy", 20, "Male",1)
assertEquals("Person(name=Nappy, age=20, gender=Male, id=1)", person.toString())
Now we see that the @AllArgsConstructor annotation allows us to create a new instance of Person1 with initial values for each property of the class in its constructor.
5. Conclusion
In this article, we looked at how to use the Lombok plugin and what it can offer a Kotlin project.
We saw the annotations supported and then looked at an example where a Lombok annotated class could be used from Kotlin code.
As usual, all code samples used in this article are available over on GitHub.