December 23, 2017

Why Kotlin Over Lombok?

7 minute read


This is a continuation of the ideas from “Is Kotlin the New Java?”.

What is Lombok?

For those of you who are not familiar, Project Lombok is a build tool for the Java programming language, which adds nifty capabilities that many Java developers feel they sorely lack. Some of the more vanilla features include:

There’s also a few more exotic features (which I personally have not seen developers) use in the wild, but which no doubt someone is using, including suppressing checked exceptions, lazy fields, magic “val” keyword, delegation, “with"ers, util and helper classes.

Lombok ameliorates common concerns with the Java programming language, from “within” the programming language (ie by not formally changing languages as in Scala or Kotlin). Thereby, developers can gain access to the features they crave, without having to foresake the Java programming language they know and “love” (for some definition of “love”).

// When Lombok compiles, this...
@Value
class MyPojo {
    String string;
    Integer integer;
    Object object;
}
// turns into something
// like this...
final class MyPojo {
    final String string;
    final Integer integer;
    final Object object;

    MyPojo(String string, Integer integer, Object object) { }
    public String getString() { }
    public Integer getInteger() { }
    public Object getObject() { }
    public int hashCode() { }
    public String toString() { }
    public boolean equals(Object o) { }
}

This excellent post explains that Lombok does this by abusing Java annotations and annotation processors. When the Java compiler runs, it offers (what it believes to be) a read-only copy of the abstract syntax tree (AST) of the Java program to Lombok. Lombok uses its knowledge of which classes are used in the implementation of some Java compilers to plumb the API’s of the compiler, learn its abstract syntax tree implementation, and then manipulate the tree to effectively re-write the in-memory representation of the Java program before compilation completes. It’s a clever trick which results in “extensions” to the Java programming language without ever writing syntactically invalid Java programs. And as long as you compile your Java programs using the Java compiler, this works fine. (More on this later.)

However, Lombok is mildly controversial in the Java/JVM community, for the same reason. Fundamentally, reaching inside internal compiler calls and making non-standard modifications to the AST are no-no’s. The technical debt here manifests itself in subtle ways; when competing annotation processors run, or when alternate programming languages want to call Lombok, they often hit issues. Those other systems cannot see the Lombok-generated code, and getting them to play nicely can be challenging.

Probably more Java developers than not would rather take what Lombok has to offer than deal with its absence; although alternate tools exist for POJO generation, such as Immutables.io, they are a little more verbose and a little more narrowly scoped than Lombok, and came along much later.

What is Kotlin?

You may already recognize Kotlin from my previous post, “Is Kotlin the New Java?” In short, Kotlin is a hot new programming language from the folks behind the IntelliJ IDEA editor.

Kotlin has virtually all of the same features that Lombok enumerated below, but in a first-class way, because the features are built into a language designed to support them: Data classes, default function values, lazy properties, extension methods, null checks, resource cleanup, and much more, just on a getting started page!

// This...
data class MyPojo(val string: String, val integer: Int, val object: Any)
// Also translates to this...
final class MyPojo {
    final String string;
    final Integer integer;
    final Object object;

    MyPojo(String string, Integer integer, Object object) { }
    public String getString() { }
    public Integer getInteger() { }
    public Object getObject() { }
    public int hashCode() { }
    public String toString() { }
    public boolean equals(Object o) { }
}

Kotlin doesn’t stop there, though. It has many more powerful features which are impossible to hack onto Java through Lombok:

One of my favorite and underrated features of Kotlin, which seemingly all modern languages have now, is string interpolation:

val firstName = "firstName"
val lastName = "lastName"
val query = """
SELECT $firstName, $lastName
FROM customers
WHERE $lastName LIKE '%smith%';
"""

Another one of my favorite features of Kotlin is its type-safe builders feature (which I am given to understand is derived from Groovy). For example, the KotlinTest library adds support for behavior-driven development from within Kotlin programs!

class MyTests : StringSpec() {
  init {
    "length should return size of string" {
      "hello".length shouldBe 5
    }
  }
}

Compare this with some of the most popular ways of achieving behavior-driven development in Java, and you get a list of tools which are either difficult to read/understand/write, require magic text files in other languages, or aren’t even written in Java! (Okay, sure, Groovy is better than magic text files, but it concedes the point that Java is at a huge disadvantage.)

Why Kotlin?

As summarized on this thread, the raison d’ĂȘtre of Kotlin is to be a next-generation JVM programming language with fully native bi-directional interop with existing Java programs, with fast compile times and superb IDE experience. Although Scala, Groovy, and Clojure already each exist, none of them are ideal fits for interoperating with existing legacy code bases with large footprints, sensitive responsiveness times, and requirements for fast and easy tooling and compilation.

As seen in this widget below, (originally pointed out by a colleague), Kotlin interest surged in the late spring when Google announced official support for Kotlin on Android, and has been steadily climbing ever since.

What are the differences between Lombok and Kotlin?

Here’s where I believe most Java developers’ ears pick up. To date, Lombok has excelled at the POJO use case, and some developers also enjoy its ability to aid with other types of common application-level boilerplate. Kotlin provides all of this as table-stakes, and also adds features from many other popular Java tools and competing programming languages. As the cost-of-entry, Kotlin requires learning a new formal programming language, but one which has a very low learning curve and strong compatibility with Java code. The result is a more enjoyable and consistent programming experience across the board, as long as you are willing to venture out and try a new programming language.

To aid with decision-making, I’ll provide a table of abbreviated features and of expanded features, to help see where Lombok provides parity and where it does not.

FeatureTotal PointsLombokKotlin
POJOs555
Null Safety313
Util/Helper/Delegates323
val/var222
Interop1099
Total231922

On its own turf, Lombok and Kotlin are very close. I gave some more points to Kotlin for null safety; although Lombok has @NotNull, it’s not the same as having ubiquitous null safety guarantees throughout the code base. Similarly, although Lombok has clever delegation/util hooks, they don’t compete with how native and fluent Kotlin’s own extensions are. For interop, I deducted a point from each because of niggling concerns I have. Lombok, as referenced above, sometimes doesn’t play nice with other tools; Kotlin has nearly flawless Java interop, but sometimes it’s not perfect.

And if we add points for the other features which Kotlin brings and Lombok simply does not, then the imbalance becomes much more pronounced. For fairness, I did not do that here; however, that is essentially the operative concern for Java developers. If you are conservative and think that Lombok is the most extreme set of features you’d like to ever see be added to the Java programming language, then maybe sticking with Lombok is a good choice for your projects. However, if you’ve been pining for a modern, statically typed and compiled programming language; a language which provides in a single coherent and fun compiler/runtime all the features you want from a dozen different libraries and tools; and a language which was written by working developers, for developers, then Kotlin is surely your bet!

© Jeff Rabinowitz, 2023