I have a confession – I used to hate ORM upgrades. They usually break something obscure in a criteria query I wrote four years ago. I spent most of last Saturday dreading the bump to the new February Hibernate milestones for a legacy Spring Boot service. But we needed the new JSON mapping features bad enough to risk it.

The migration to Hibernate ORM 6.6.0.Alpha1 was surprisingly boring. I mean that as a compliment. I tested this on my M3 Pro Mac with 36GB RAM running PostgreSQL 16.2. The big draw for me was the native JSON handling improvements. In older versions, doing complex JSONB queries in Postgres required native queries or weird custom dialects. But now it just works natively.

Java programming code on screen - Software developer java programming html web code. abstract ...
Java programming code on screen – Software developer java programming html web code. abstract …
@Entity
public class UserProfile {
    @Id
    private Long id;

    @JdbcTypeCode(SqlTypes.JSON)
    private Map<String, String> preferences;
}

You can just write SELECT u FROM UserProfile u WHERE u.preferences['theme'] = 'dark' directly in HQL. And the SQL translation is spot on.

There is a catch though. If you try to map a deeply nested JSON array directly into a Java List<CustomObject> using this milestone, it chokes silently if the JSON has null elements. It won’t throw a mapping exception — it just returns an empty list. I wasted two hours figuring that out. You have to write a custom deserializer if your database has dirty JSON records.

The real reason I am writing this is the Hibernate Search 7.1 milestone. Vector search is everywhere now. I was skeptical about doing it through an ORM instead of just hitting the vector database directly with a dedicated client.

I set up a test with a local pgvector instance. Hooking up the new annotations took maybe five minutes.

@Entity
@Indexed
public class Document {
    @Id
    private Long id;

    @VectorField(dimension = 384)
    private float[] embeddings;
}

I ran a benchmark against 500,000 rows. I expected the ORM translation overhead to ruin the performance. But it didn’t. Querying the top 10 nearest neighbors took about 42ms through the Hibernate Search API. Doing the exact same query via a raw JDBC ORDER BY embeddings <-> ? took 39ms.

A 3ms penalty for type safety and avoiding raw SQL strings is a trade I will make every single time.

I barely touched the Reactive milestone. We have exactly one microservice using Hibernate Reactive with Mutiny. I bumped the version, the test suite passed, and I merged the PR. The Vert.x SQL client dependency tree is still a bit messy if you use Spring Boot 3.4, so watch your exclusions in Gradle. Probably if you don’t exclude the older Netty transitive dependencies, it will fail on startup with a very unhelpful classloader error.

I expected this upgrade to be a massive headache. But instead, I got to delete about 400 lines of custom native queries and replace them with standard HQL. And I am leaving the vector search in our staging environment for another week to watch memory usage under load. If the heap stays stable, it goes to production next Tuesday.