Project Valhalla seems to be on the verge of being incorporated into the JVM… as a preview feature in JDK 28 that is.
This blog might be a bit premature, since it isn’t likely value types will be final in JDK 29.
Premature, yes, but the JEP is already worth a careful read.
I stumbled upon some interesting behavioral changes regarding equality.
Traditionally, the purpose of the == operator was to test whether two referenced objects have the same identity.
…
After the introduction of value objects, the purpose of the == operator is to test whether two referenced objects are indistinguishable.
— JEP 401
Continue reading →
After working on Kotlin projects for over seven years, I recently started on a Java project again.
One of the things I missed most was the fact that Kotlin explicitly supports nullability as part of its type system. Within the first day I ran into a NullPointerException.
Luckily, we can now add compile-time null checks to Java as well, making Java null safe(r)!
Continue reading →
When migrating database schemas, you rarely get clean, predictable data. Legacy databases often have cryptic column names, partially backfilled fields, nullable values, or columns that are completely empty.
That’s why you write custom Java JDBC mappers in the first place: to explicitly control how legacy database columns map to your target Java objects, rather than relying on automatic mapping that may not handle these inconsistencies correctly.
But there’s a catch: standard unit tests can pass even when you completely forget to map a field. Because null == null, a missing mapping line looks identical to a column that is legitimately empty in your database.
Continue reading →
While managing concurrency solves rate-limiting issues, another silent budget-killer remains: unresponsive, frozen code.
Continue reading →
While working on a Spring Boot 4 service using Java 25, I wanted to protect my external API calls as these can go down every now and then.
For this I used Resilience4j @CircuitBreaker and @Retry annotations, and put a @Cacheable on top.
Three annotations stacked on a single method, what could possibly go wrong?
It turns out that the order in which they are applied by default is probably not the one you want.
This makes your circuit breaker count every retry attempt as a separate failure.
And once the circuit opens it even blocks data that is sitting right there in your cache.
Here is what happens by default, and how I changed it.
Continue reading →
In our projects we have been using ArchUnit for years to write unit tests that fail when the code no longer follows the architecture we chose.
Over the last year, we’ve written more and more of these tests.
What changed? Our audience grew.
These tests no longer just help fellow developers stick to the architecture; they help our coding agents too.
Coding agents are getting quite good at making larger changes to existing codebases.
Give an agent a task, some context and a test suite, and it often finds its way surprisingly well.
But one type of context is much harder to provide: the architecture we intended.
That is exactly the gap ArchUnit fills.
In this blog post I explain why ArchUnit becomes more valuable when working with coding agents, and I show some rules that actually help to guide them.
The list is far from complete, but I hope it inspires you to capture your own architecture in rules, whether you write them yourself or let your agent do it.
Continue reading →
In my journey away from the mouse and trackpad, I found Neovim recommended often.
Having developed in Java for over 13 years, I’ve relied heavily on IDEs like IntelliJ or NetBeans for most of that time.
I decided to step outside those walls to see what lay beyond.
Continue reading →
Since Java 9 the methods requireNonNullElse and requireNonNullElseGet are part of the java.util.Objects class. The method requireNonNullElse accepts two arguments. The first argument is an object that will be returned if that object is not null. The second argument is an object to be returned when the first argument is null. With this method you can replace the following ternary operator if (a != null) ? a : b (or if (a == null) ? b : a) with Objects.requireNonNullElse(a, b).
The method requireNonNullElseGet allows to define a Supplier function as second argument. The Supplier is only invoked when the first argument is null, so it is lazy and will only be invoked when the first argument is null.
Continue reading →
Kotlin is null-safe, a quote I hear often from Kotlin developers.
And yet, I still managed to get a NullPointerException while converting a java.util.Optional to a nullable Kotlin value…
Continue reading →
Java and Python are both excellent tools, and even though programmers usually like nothing better
than debating which language, framework, or editor is best, that is not the goal of this post. Each
language has strengths and weaknesses, but what I consider interesting is that Java and Python
complement each other so well. However, systems using multiple languages face increased
complexity in deployment, maintenance, testing, integration, and interoperability.
This post aims to answer two main questions through a set of practical hands-on
experiments.
Continue reading →
SDKMAN! is as powerful tool to install and manage software development kits (SDKs) and tools, like Java, Groovy, Gradle, Maven, Spring Boot and Quarkus. If you want to see if a new version of a SDK or tool is available, you can use the sdk upgrade command. This command will list all outdated SDKs and tools. The installed version and the latest version are shown for each SDK and tool. To see if a single SDK or tool is outdated, you can use the name of the SDK or tool as argument to the sdk upgrade command.
Continue reading →
When you enable the /observe endpoints you can configure them to be served on a different port than the application. By default the endpoints are available on the same port as the application. But you can define an extra named socket with another port number in the configuration of the WebServer instance. And in the configuration of the ObserveFeature instance you can define the socket name that should be used for the observe endpoints.
Continue reading →