I recently read and shared You’re Wasting Time in Java Without These 10 Libraries. I commented on it a bit in my newsletter, but given the amount and intensity of reactions, I think a full-blown post is in order. The referenced libraries are:
- Project Lombok
- MapStruct
- JUnit 5 & Mockito
- SLF4J with Logback
- Apache Commons Lang & Google Guava
- Jackson
- Hibernate Validator
- Spring Framework
- Apache HttpClient / OkHttp
- Liquibase or Flyway
Lombok
Project Lombok is a java library that automatically plugs into your editor and build tools, spicing up your java. Never write another getter or equals method again, with one annotation your class has a fully featured builder, Automate your logging variables, and much more.
I remember discovering Lombok: I was awestruck. It fixed many of the Java language's needs for boilerplate code at the time. I wrote an enthusiastic post about it back then (2009). I even described the idea for a @Delegate annotation. I emailed the committer the blog post, and his reaction was mostly positive, especially about @Delegate:
Would you mind if we learn from and perhaps even copy some parts of your delegate implementation? The biggest hurdle for @Delegate and friends is eclipse, which doesn't use a round-based system to mesh parsing and resolution, which @Delegate needs*, but having the work mostly done for javac is still useful.
I'm happy to mention it was added in the codebase in 2010. It still is in the experimental package, though. I mention all of this to emphasize that I really liked the project at the time. Lombok was relevant in the Java context at that time to save writing dozens of lines of code. Nowadays, the cost-benefit ratio has tipped.
For example, instead of writing Java with Lombok, you can switch to Kotlin. I actually wrote a comparison matrix in 2016. Unless you're stuck with an old Java version, feel free to reuse the matrix and substitute Kotlin's features for Java's, e.g., records for data classes.
Verdict: Don't waste your time using Lombok.
MapStruct
Developers had to address a simple design problem: how do you pass objects from the persistence layer to the view layer? Proper design mandated different objects between these two layers. We created the Data Transfer Object.
MapStruct is a code generator that greatly simplifies the implementation of mappings between Java bean types based on a convention over configuration approach.
-- MapStruct
The issue here isn't the tool. MapStruct isn't the first one to automate object-to-object conversion.
The problem is that the view model is supposed to be very different from the persistence model. In theory, a view probably needs several tables. In all projects I've been involved in, they nearly mirror them to perfection.
The showcase example from the site is telling:
public class Car {
private String make;
private int numberOfSeats;
private CarType type;
//constructor, getters, setters, etc.
}
public class CarDto {
private String make;
private int seatCount;
private String type; //1
//constructor, getters, setters, etc.
}
- Yes, that's the only difference!
At this point, anything more complex than overriding toString() is over-engineering. Even more, if your app is an API, chances are you'll serialize objects to JSON, and that it won't be useful.
Verdict: Don't waste your time using MapStruct.
SLF4J with Logback
In the Java early days, there wasn't much interest in logging, if at all. When organizations started to use the JVM en masse, it became a problem. The first true logging framework was Log4J, hosted by the Apache Foundation. Then came SLF4J and Logback, for... reasons. You can read my thoughts on the ecosystem state at the time if you're interested in archeology.
At the time, SFL4J and Logback were in full development, while Log4J had come to a halt. A new team re-started the Log4J project, unimaginatively christened Log4J2. It caught up with SLF4J, then surpassed it. Then it was SLF4J's turn to catch up.
I can't say which one has the lead right now. Here are my two cents: SLF4J is the default API for Spring Boot. However, Log4J2 has the full backing of the Apache Foundation.
Verdict: I'd use SLF4J2 in Spring Boot projects, and Log4J2 in other cases.
Apache Commons Lang and Google Guava
Apache Commons Lang and Google Guava play the same role in the ecosystem, even though the former predates the latter: fill in the gaps in the Java standard APIs. For example, one of the biggest current PITAs in modern Java is checked exceptions inside lambdas. Both libraries provide wrapping methods to handle this specific use case. In general, modern Java versions and Kotlin drastically diminish the need for these additional dependencies.
Note that you should be careful before you add a dependency.
In the past, I used regular comments, until a colleague pointed out Guava's @VisibleForTesting to me. I became a big fan instantly. And yet, I wouldn't bring in the dependency for
@VisibleForTestingonly. If that's the only annotation I have for Guava, then I'd rather create my own.If I need other classes from Guava, however, I'd reassess my decision. For example, Multimap, a map with possibly multiple values stored under a key, requires a lot more time to develop. Thus, if I need
Multimap, I'd probably add the dependency.
Also, I dislike how Guava is heavyweight.
Verdict: It's a context-dependent decision.
Liquibase and Flyway
I remember during my first mission, developers designed the applications' database schema. However, databases were few and expensive, and database administrators watched over them like dragons over treasures. For this reason, we had to get the schemas vetted. I learned many facts about databases during these vetting sessions.
The need for software grew. Companies hired more developers, but didn't hire that many DBAs. The latter couldn't vet as many schemas as before, if at all. Hibernate appeared and allowed developers to create schemas from the model. Even more, Spring Boot leveraged this feature at application start. It improved development productivity by a large margin, but didn't help much regarding production environments, in particular with schema changes.
Imagine a table created from an Hibernate model, for example, a Customer class. On the first run, Hibernate creates the table according to your configuration. Later, the business requires adding a middleName to the Customer class. The issue is that Hibernate can't compute the diff. The only exit is to drop the old model's schema and create the new one. It's not possible when the table already contains data.
To fill this gap, the community created two similar technologies: Liquibase and Flyway. Both work by making the developers create the diff scripts that the tool applies. Whether the format is XML (Liquibase) or SQL (Flyway) is irrelevant to the subject at hand. Suffice to say that for mature software development and deployment, either of these tools is mandatory.
Verdict: Required.
Hibernate Validator
The Hibernate Validator originates from the idea of validating entities before sending them to the database. Nowadays, the project is unrelated to a layer. I think I used the project once, to generate the schema, complete with field size and non-null constraints.
I have an opinion regarding the Validator, but not a very strong one. It made some sense for entities. For regular objects, you can get the same benefits with a regular Builder pattern. I would definitely like to see the Validator in large-scale projects to assess how useful or wasteful it can be.
Verdict: Not using it is definitely not a waste of time.
Apache HttpClient / OkHttp
The JDK 11 finally saw the addition of an HTTP client API. I never used it, so I can't say how good or bad it is for normal usage. If you are using Spring, I urge you to use either RestClient for synchronous calls or WebClient for asynchronous calls.
I don't remember using the Apache HttpClient. However, I used the OkHttp library once in the context of a batch project, which polled data daily. I think it's quite good. Icing on the cake, it's Kotlin-based.
Verdict: It's another context-dependent decision.
Others
Jackson is the leader in JSON serialization/deserialization. The Spring framework uses it heavily. Use Jackson unless you're in a resource-limited environment and don't require many of its features.
JUnit is the lead testing framework in Java, if not on the JVM. Spock, which was based on Groovy, was a contender a long time ago, but I never saw it used in any of the projects I have been part of. I think it's safe to say that it's not used on greenfield projects.
I was an ardent TestNG fan at a time when it was ahead feature-wise. However, in my latest assessment already four years ago, the gap was much smaller.
Spring? Do you really want me to write how awesome Spring is?
Conclusion
Great developers not only know a wide range of tools to choose from, but they can also choose those that are the most relevant to the context at hand. Listicles are good to widen your horizon, but most fail at providing you the context for using the tool.
Originally published at A Java Geek on November 16th, 2025
Top comments (0)