top | item 19046826

Lombok makes Java cool again

187 points| rdonovan | 7 years ago |bytes.grubhub.com | reply

234 comments

order
[+] ganonm|7 years ago|reply
Lombok is a useful crutch if you're writing lots of Java code on a day to day basis. However, given how easy it is to use Kotlin alongside Java I would question whether Lombok is the right solution to the problem.

Kotlin has data classes which auto generate sensible 'toString' and 'hashCode' methods which is a massive time saver.

Really, if you are considering introducing Kotlin to a Java project I'd recommend you just take the plunge. It's pretty much just a minor change to your pom file (if you're using Maven). Kotlin has Java interop as a primary feature and is flawless from my experience.

[+] kodablah|7 years ago|reply
> auto generate sensible [...] 'hashCode' methods

Unless you're using arrays. They went with "predictable" over "sensible" here.

> is flawless from my experience

As a heavy Kotlin user, I'd say it's far from flawless (not sure if you mean interop or the entirety of the language, but applies to both). I'm often creating and starring YouTrack issues. But yes, it's still a highly recommended alternative to Java.

[+] nine_k|7 years ago|reply
Kotlin is great. But go and try to persuade your company to bless another language for production.

It may be easy when your engineering org is 5 persons. It's much harder, genuinely harder, when it's 250 engineers, and an hour of downtime costs hundreds of thousands. Adoption of another language, even clearly superior and interoperable, becomes a large and costly undertaking.

So "just use Kotlin" is not always possible, and I'm thankful to Lombok's authors for their work.

[+] viach|7 years ago|reply
I see Kotlin as a great choice for these who don't want Java verbosity but can't really get used to read Scala.
[+] kovrik|7 years ago|reply
Yeah, Kotlin pretty much killed Lombok.
[+] pjmlp|7 years ago|reply
Kotlin has not flawless integration and some attention is required when writing libraries for Java consumption.

Additionally the JVM wasn't enough for JetBrains and code written for multi-platform has slightly different semantics (see Kotlin/Native and immutable data).

Kotlin is a good alternative on Android due to a frozen Java 8.

Against Java 12 not so much.

It is very hard to displace platform languages when others just feel like guests.

[+] monksy|7 years ago|reply
The same can be said about Scala and Groovy. (Groovy brings in those generators via an annotation)
[+] altmind|7 years ago|reply
I agree, it's as easy to tap into your build tool to build kotlin/groovy/scala alongside with java, as it is to tap into buildtool to process the annotations.
[+] apo|7 years ago|reply
Annotation-based programming might seem cool now, but wait a few years.

Magic always seems cool when you add it to a project - hey, look - I don't have to do <tedious thing> anymore.

Then time goes on, and you (or your successor) opens up the project to track down a bug. Only there's no logical flow - things just seem to happen as if by magic.

Lombok strikes me as magic in these ways.

I actually had to go to the project home page to figure out what problem it solves:

https://projectlombok.org

The examples refer to a specific kind of boilerplate, namely the kind that comes from treating classes a dumb bags of properties. Getters directly returning private fields. toString methods, etc.

An alternative approach to Lombok would be to think about how the project ended up with so many dumb data classes. How could the project be refactored to eliminate them, for example?

Doing so would avoid the need for magic and produce a code base in which effect followed cause.

[+] arcticbull|7 years ago|reply
I liked to refer to the genre as MOP -- Magic Oriented Programming. Every ecosystem I've seen go down that route ends up bailing out. A good example of this would be Apple's Cocoa Bindings [1] on macOS that were killed with fire when the iOS APIs were defined, and KVO [2] which is flat out rejected at every company I've ever worked.

On the other hand, when built into the language, this kind of explicit but automatic code generation can be awesome (as in Rust's #[derive()] traits [3]) but I think the difference there is the compiler/language vendor agree to support it indefinitely.

[1] https://developer.apple.com/library/archive/documentation/Co...

[2] https://developer.apple.com/library/archive/documentation/Co...

[3] https://doc.rust-lang.org/rust-by-example/trait/derive.html

[+] mrbrowning|7 years ago|reply
I grew to really hate annotation-based magic when I worked on a project that used Jackson for JSON serialization. Not only does it circumvent the type system entirely, it also makes errors incredibly hard to track down by virtue of the fact that there are next to no static constraints on how annotations are used. Something as simple as adding a serializable field to an interface or object often ended up requiring a ridiculous amount of trial and error to get right. I think annotations are valuable if used judiciously, but unfettered annotation-based metaprogramming only ever leads to pain in my experience.
[+] 75dvtwin|7 years ago|reply
> Annotation-based programming might seem cool now, but wait a few years.

I even have this experience on my own projects and with much shorter span than a year.

When I go back to a code base I worked just 3-4 month ago -- I have very hard time following Dagger injections. Braking one of the Dagger providers (I use dagger 2) creates 10s and 10s of compilation errors.

So I have been slowly removing dagger from my code bases. As I just cannot follow it, I do not know it well enough either.

I stopped using Lombok for same reason, although I found Lombok is much more intuitive.

I thought about going to Kotlin, but it was just too much of cognitive overload (in this particular instance both for backend and android UI).

Instead, I am finding the use of rxjava and friends a lot more intuitive and helpful for the type of things I need help with (interconnecting components on different threads, with different lifecycle and data structure semantics, with lots of asynchronous behavior options).

And the same rx-<> library is available to many other languages, therefore, the skill I am building up is sort of 'cross-language'.

[+] dmichulke|7 years ago|reply
> Then time goes on, and you (or your successor) opens up the project to track down a bug. Only there's no logical flow - things just seem to happen as if by magic.

This.

I use a different but similar analogy borrowing from DnD.

- Java and especially annotations need wisdom (WIS)

- E.g., Clojure needs intelligence (INT)

This holds even for syntax where homoiconicity requires just so much less "experience".

[+] j16sdiz|7 years ago|reply
Lombok only minimal boilerplate, not much magic. Most of them can be generated in IDE automatically, but those generated code hurt readibility.

It is difficult to avoid Getter/Setting in Java due to how popular framework works.

@ToString are useful for debugging. Why hand code pages of println if it can be generated?

[+] raz32dust|7 years ago|reply
+1, I would rather have the cruft than have magic annotations. These dumb data classes also tend to proliferate when you are using other annotation heavy magic libraries like hibernate/spring. If you are having a dumb data class that is not a class that is meant to be serialized on disk (protobuf/avro etc.), then you are likely doing something wrong. See if you can avoid it.
[+] ehnto|7 years ago|reply
Annotation based magic has always felt like a hack to me. Surely there is a way to solve these problems within the constraints of the language. It adds a layer of ambiguity to what code any class actually contains at run time and that is never ideal.
[+] pjmlp|7 years ago|reply
Remember the days of Aspects all over Java codebases?

I seemed a cool idea, however I thankfully no longer need to fix bugs in such projects.

[+] KoenDG|7 years ago|reply
So, like Spring?

ba dum tish

[+] vbsteven|7 years ago|reply
Spring boot with Lombok has been my go to framework for a few years now. Annotation-based programming seems to get a lot of negative attention here on HN, and it definitely is not perfect but there is just no other framework that (in my opinion) comes close in terms of productivity and workflow.

Currently I'm building my SaaS + Selfhosted software licensing product with this Spring Boot + Lombok + Postgresql combo and Annotations are helping me out for :

* @Bean, @Autowired, @Profile,... for configuring dependency injection with multiple profiles (saas vs selfhosted)

* @Entity, @Table, @Repository, @Enumerated, @Embedded for mapping my classes to Database tables

* @Api, @ApiOperation, @ApiParam,... for generating Swagger documentation for my endpoints

* @GetMapping, @PostMapping, @PreAuthorize for configuring and authorizing my endpoints

* Lombok @Data, @Value, @Builder for tedious boilerplate generation

* @NotNull, @NotBlank, @Email, @PhoneNumber, @Pattern(regex), @Length(max=12),... for validation of form input, api params and database models.

* @JsonProperty, @JsonSerialize, @JsonIgnore for configuring json deserializing for my DTO's

* @Value("${my.config.key}") for decoupling configuration from my code and injecting values at runtime

I probably forgot a few more use cases. All of these are pretty straightforward, are defined alongside the code they are modifying or interacting with and would lead me to a lot of lost time and a lot more code if I were to implement them myself, or configure them by hand "in real java code".

[+] raz32dust|7 years ago|reply
While it is great while you are trying to get your product to market quickly, I would highly recommend getting rid of all these annotations as soon as you can. Preferably before your team grows to 5+ people or complexity grows beyond around 100k lines of code. It's hard to explain this to people from non-Java background, but the time writing non-annotation code will save you in debugging and maintainability is well worth it beyond that point.
[+] diegof79|7 years ago|reply
I use the elements of programming from SICP[1] as a litmus test for this kind of frameworks.

The main issue with these annotation hacks is that they fail in the area of “means of combination” and “means of abstraction”.

For example if you have: @X @Y class Something{}

You cannot tell if X & Y can be combined (or how it’s combined), or you cannot easily create an abstraction Z with X and Y (you may be able to do that but it requires framework support and usually is painfully impractical)

It seems to be a small issue compared to the added value, but to me is not. As the code base grows the maintenance and debugging issues grow too... in the end probably is better to use Kotlin or Scala.

[1]: https://mitpress.mit.edu/sites/default/files/sicp/full-text/...

[+] ajkjk|7 years ago|reply
I agree, but it's helpful that the things Lombok abstracts away are very idiomatic and straightforward. I would never want to use it to take on anything more complicated.
[+] jimbokun|7 years ago|reply
Thanks for that!

Makes clear and explicit the queasy feeling I get from over reliance on Java annotations.

Lisp macros, for example, fare much better in the "means of combination" and "means of abstraction" tests, I think.

[+] mohaine|7 years ago|reply
My main issue with Java is all the annotation based programming. Some of these are nice and can make the easy case super easy but if you need go even slightly off the easy path you seem to quickly loose all the time gained on the easy path.

i.e.

@GET(url="http://host/users/$userid") public abstract User getUser(String userid)

isn't that much easier than the python requests version but much harder if you need to add a custom dynamic header to the call.

[+] zestyping|7 years ago|reply
Reading this just reminds me of all the terrible things about Java. The lack of reasonable default string representations, comparison and hashing methods, etc. are all glaring mistakes in the language design that have wasted huge amounts of time for millions of programmers. It's as though Java programmers are so deep in the grips of Stockholm Syndrome that ordinary, sensible behaviour seems amazing and "cool".

This is similar to the situation with design patterns. When design patterns came along, Java folks talked about them as though they were a wonderful new invention. But they only exist because Java is so clumsy that it needed crutches to do things that had been easy and natural in other languages for years; someone merely came along and gave the crutches names.

[+] platelminto|7 years ago|reply
I'm interested in the downsides of using Lombok, since the article seems to only focus on its positives and makes it seem like I should download it and start using it right now.

Is there anyone here with Lombok experience that wants to share any issues they've run into while using it? All I can think of right now is the fact that the source code isn't compatible with Java.

[+] shadowmatter|7 years ago|reply
I used it extensively while writing Java code at Airbnb. (It came included with Dropwizard, which we used for writing services.)

Some people are uncomfortable with the extensive bytecode manipulation that it does. While Lombok provides annotations, it is not your normal annotation processor. From http://notatube.blogspot.com/2010/11/project-lombok-trick-ex...:

> Project Lombok hooks itself into the compilation process as an annotation processor. But Lombok is not your normal annotation processor... The trick is that Lombok modifies the AST. It turns out that changes made to the AST in the Annotation Processing phase will be visible to the Analyse and Generate phase. Thus, changing the AST will change the generated class file.

That said, we never encountered any Lombok-related problems when running services in the cloud or locally. And the Lombok plugin for IntelliJ is good enough in that the auto-complete will "see" the Lombok-modified version of the file. For example, using the @Value annotation creates an immutable value type, which among other things a) makes every field private and final, and b) generates a getter method for each now-private field. With the Lombok plugin, IntelliJ auto-complete will a) not auto-complete the composed fields which are now private, and b) auto-complete the generated getter methods.

I highly recommend looking past the voodoo bytecode manipulation and using Lombok. The @Value annotation alone is worth the price of admission and made me a more productive programmer.

[+] gacba|7 years ago|reply
Yeah, I use it at a financial services client. A previous architect chose it because it was a pet project of his (he contributed to Delombok).

The premise is fine...I have no problem with it. But the default generation of @EqualsAndHashcode literally pulls in the WORLD to generate the output.

The real world scenario we had was this. Lots of POJOs were created, many were simply but a non-trivial number were NOT. Those POJOs could have dozens and dozens of fields. And if you have a key abstraction with say, 86 fields, things get interesting.

Suppose you don't use @EqualsAndHashCode on one of these POJOS with lots of fields, ALL 86 fields are included in the default equals and hashCode methods. They didn't realize this, or didn't care, and as a result, had some serious performance issues because trying to run hashCode on insert to a map when you're hashing 86 fields together might actually take some time inserting 100,000 records... ugh

So in short, it's OK and useful, but you have to understand the side effects of everything to know if it's the right thing for you.

SIDE NOTE: A POJO with 86 fields can be common in financial services when you are representing various kinds of financial trades where gazillions of things are tracked on them...interest rates of note, ratings, security characteristics, etc. That in and of itself isn't necessarily poor design, although these choices predated me at this company.

[+] cakeface|7 years ago|reply
I dislike Lombok. One reason I dislike it is that it makes IDE navigation, even with a required Lombok plugin, more difficult. A common task in a Java IDE is finding usages. It's harder with Lombok. Generally it's just more friction than plain Java code.

I also don't like that the generated code is not checked in or visible. It makes code review harder. In theory you can have magic change to all Lombok classes just by upgrading the library.

Also it doesn't pass the cost/benefit test for me. Adding Lombok adds complexity to your code, build system, and IDE. What do you get? Slightly shorter classes? Less characters? Most of this code can be generated by the IDE.

I'll give Lombok one win. It will keep equals and hashcode up to date if you add properties. That's a pretty common error.

As others have said, Kotlin is the best alternative. But even without Kotlin I skip Lombok happily.

[+] cs02rm0|7 years ago|reply
The downside is that you'll need to install it into your IDE. And again when you upgrade it. I guess the version needs to loosely match the one your projects use too. That might not sound like a lot but some colleagues hate that overhead.

I love it though, think I've been using it for at least 8 years now in just about every Java project.

[+] twblalock|7 years ago|reply
The @Builder annotation has some odd behavior if you want to add default values (it just hardcodes them and you cannot override them!) or extra builder methods.

Actually, anything involving default values seems to be very brittle and difficult to work with -- especially when deserializing objects from JSON.

The @Wither annotation results in methods that do not always make a copy, and sometimes use == instead of .equals when comparing class members. If you call one of the Wither methods and assume you have a copy of the original object, and then you modify that "copy", you might have just created a very subtle bug.

If you are using IntelliJ you can use the Refactor > Delombok menu option to show you the code that Lombok generates. I've been told that does not actually invoke the same code that the annotation processor invokes at compile time, so the results of Delombok might be misleading.

[+] janslow|7 years ago|reply
One of the issues is that it's tied quite heavily to the Java compiler, so you may need to wait until Lombok supports a new Java version before you can use it.

Also as it is compiler magic, it can be a bit confusing to developers who haven't used it before.

[+] dangets|7 years ago|reply
I've heard it makes Kotlin integration a pain also if you are ever planning on that. If your Kotlin code depends on Java lombok classes, the compiler fails. Most people probably don't have this concern, but IMHO a mixed Kotlin-Java project is better than any of the current 'data class' libraries available for Java (Lombok, Immutables, Joda-Beans, AutoValue) ... ymmv, and I'm eager to see what comes of the "data classes in java proposal".

https://cr.openjdk.java.net/~briangoetz/amber/datum.html

[+] chvid|7 years ago|reply
You get a more complex (and slower) build. Poorer editor support. It may be hard to upgrade Java version (ie. going from 8 to 11). More string for developers to hang in. I wouldn't use it.
[+] zdwolfe|7 years ago|reply
The only downside I've come across was test coverage tools like jacoco can have problems with the auto-generated code (complaining about your tests not covering enough branches of an auto-generated hashCode() implementation, for example). However it seems new-ish versions of jacoco seem to have built support for it.
[+] ilovecaching|7 years ago|reply
It’s ok to let languages die; we’re just barely scraping out of the infancy of programming. Languages like Java and C++ which have carried us a long way need to evolve into new and better languages that incorporate lessons learned and the next wave of research.

We also know from Google’s paper on software practices that software naturally gets rewritten over time, at a cadence that makes it acceptable to switch languages. So there is really no reason not to have a plan for your business to migrate languages periodically.

Unfortunately the industry seems to be stuck in a rut, and we’re forced to retrofit ancient compilers like horse drawn buggies with plate armor and machine guns on them.

[+] chooseaname|7 years ago|reply
Java the language is cool. What the enterprise has done with it is not cool. Writing apps with layer upon layer upon layer upon layer of abstraction is ... self defeating. Then they'll holler, we need to rewrite it! All in the name of finding that one true architecture that can handle any business CR. Blech.
[+] afpx|7 years ago|reply
Please don't.

Why? It adds more time to the build, it requires plugins to work effectively, and it confuses the hell out of people when they expect to see Java. If you really want a better syntax, use Scala or Kotlin (I'm a huge Scala convert).

[+] saagarjha|7 years ago|reply
> Although Java is one of the most popular JVM languages

Is it not the most popular JVM language?

[+] hota_mazi|7 years ago|reply
At this point, it's less disruption to a Java project to start writing it in Kotlin than adding Lombok to it.
[+] dionian|7 years ago|reply
Lombok solves one of the major problems with Java, but doesnt solve a million others. Scala, Kotlin, or Clojure are way better alternatives...
[+] eweise|7 years ago|reply
We initially used lombok to decrease the pain of writing in Java but eventually moved to Kotlin and are sooo much happier.
[+] BtdTom|7 years ago|reply
Kotlin is great and very easy to use if you already know Java.
[+] rubyfan|7 years ago|reply
Annotations have always come across as a crutch. It’s noisy at best and unsightly in large concentrations.
[+] the-alchemist|7 years ago|reply
i also wanna give a shoutout to https://immutables.github.io/ over Lombok. No AST magic, and even optimized Jackson/GSON code.
[+] JanecekPetr|7 years ago|reply
This, a million times.

In my professional bubble Lombok is completely gone. I'll go as far and say that modern Java does not use Lombok. Smaller, focused libraries like Immutables or AutoValue, solve the problem of boilerplate for data classes.

Lombok tries to do too much across many concerns, in a fairly opaque way, and makes the code and tooling around it more magic than it needs to be.

Skip Lombok. Modern Java is better off without it...

[+] koolba|7 years ago|reply
What's the point of this part of the generated Java code? (I split it out onto multiple lines for legibility)

    favoriteFoods = new java.util.LinkedHashSet<String>(
      this.favoriteFoods.size() < 1073741824
        ? 1 + this.favoriteFoods.size() + (this.favoriteFoods.size() - 3) / 3
        : Integer.MAX_VALUE
    );
    favoriteFoods.addAll(this.favoriteFoods);
Why not just?

    this.favoriteFoods = new java.util.LinkedHashSet<>(this.favoriteFoods);
[+] salvadormon|7 years ago|reply
I helped in the development of a microservice as a third party developer for a big lodgings reservation company.

The infrastructure team of the main company forced us to include Lombok and use it and the code was a mess. Too much automagically generated code that was hard to debug.

My company managed to deliver the microservice with enough quality, but I really hated the experience with Lombok, vanilla Java with the libraries needed for the task is more than enough (more control over your code).

[+] spricket|7 years ago|reply
Lombok is awesome. There's still some painful stuff in Java but Lombok gets rid of most of it. I agree with other comments about using Kotlin instead, but I've had a ton of resistance to switching languages since all our devs know java.

Since Lombok is "just a library" I've managed to sneak it in almost every project I've worked on. Deftly used, I swear it cuts the LoC in a project by 30%

[+] grahamm|7 years ago|reply
I use Lombok all the time. Yes it has some awful bits but generally it's positives outweigh it's negatives.