Spring AI Series: Structured Outputs

Spring AI Series: 5-Structured Outputs

Let me show you the exact moment a Spring AI demo turns into a Spring AI application. In the last two articles, BrightCart’s summarizer happily returned prose, and prose was the right answer — a human support agent reads it. But the moment I tried to make the system do something with a model’s answer, I hit a wall. I wanted to classify tickets so they could be routed automatically: delivery problems to the logistics team, billing issues to finance, and so on. So I asked the model to classify a ticket, and it cheerfully replied: ...

July 3, 2026 · 13 min
Compact Object Headers by Default

JEP 534: Compact Object Headers by Default

A few years ago, a colleague of mine was convinced that a memory leak had crept into one of our microservices. The heap was consistently at 70% after startup — before a single request had been processed. We profiled it, combed through the GC logs, and eventually concluded that no, nothing was leaking. It was just object overhead. Lots of small objects, each carrying its overhead around like a briefcase it didn’t need. ...

June 29, 2026 · 11 min
Spring AI Series: Prompt Engineering

Spring AI in Depth - 4 - Prompt Engineering

In the last article, BrightCart got its first real feature: an endpoint that summarizes support tickets. The system prompt that powered it was a triple-quoted string sitting in a @Bean method. It worked, it was readable, and for one prompt it was completely fine. But I’ve been writing Spring AI applications long enough to know what happens next. One prompt becomes three. Three become a dozen. Someone wants the summary to mention the customer’s loyalty tier. Someone else wants a different prompt for priority tickets. Before long you’ve got string concatenation scattered across five service classes, nobody remembers which prompt is the good one, and changing the wording means a recompile and a redeploy. ...

June 26, 2026 · 14 min
Structured Concurrency in JDK 27

JEP 533 - Structured Concurrency Gets Sharper in JDK 27

If you’ve been following the evolution of Project Loom, you’ll know that Structured Concurrency has been on quite a journey. It started as an incubator module in JDK 19, became a preview API in JDK 21, and has now re-previewed five more times since — JDK 22, 23, 24, 25, and 26. JEP 533 is the seventh preview, targeting JDK 27, and this time the changes are meaningful enough that it’s worth taking a proper look. ...

June 23, 2026 · 9 min
Spring AI Series: Spring AI ChatClient

Spring AI Series: 3-ChatClient

Somewhere in articles 1 and 2, I kept writing this line and asking you to take it on faith: java chatClient.prompt().user(question).call().content(); It works. It reads nicely. And if you’re anything like me, the fact that it works without you understanding why has been quietly bothering you since article 1. Today we fix that. This article takes ChatClient apart — every method in that chain, every configuration option that matters, and the parts of the API we haven’t even touched yet. By the end, the fluent API won’t be a magic incantation anymore. It’ll just be… an API. A well-designed one, but still. ...

June 19, 2026 · 17 min
Primitive Types in Patterns

Java 27 - part 4: JEP 532 - Primitive Types in Patterns

Same Feature, Fifth Time Around If you read my JEP 530 post at the tail end of the Java 26 series, this one is going to feel familiar. Very familiar. JEP 532 is the fifth preview of “Primitive Types in Patterns, instanceof, and switch”, now targeting JDK 27. And here’s the honest headline: nothing has changed. No new syntax, no removed methods, no behavioural tweaks. The JDK team looked at JEP 530, decided it was in good shape, and re-proposed it as-is to bake for another release cycle. ...

June 15, 2026 · 5 min
Spring AI Series: Introduction to Spring AI

Spring AI Series: 2-Setup Spring AI

Intro In the previous article, we ran a Spring AI application in about twenty lines of Java. It worked. A ChatClient appeared out of nowhere, we called .prompt().user(...).call().content(), and Claude answered. That’s the magic of Spring Boot autoconfiguration — and also the danger of it. When things work without explanation, you’re fine right up until you need to debug something, customise something, or explain to a colleague what exactly is happening. Then you’re stuck. I’ve been there more times than I care to admit — staring at a NoSuchBeanDefinitionException at 4pm on a Friday, completely unable to explain why a bean that “should just be there” isn’t. (It was a missing property. It’s always a missing property.) ...

June 12, 2026 · 14 min
Spring AI Series: Introduction to Spring AI

Spring AI Series: 1-Introduction to Spring AI

I still remember the moment it clicked — and the much longer stretch before it did. I’d been building Spring Boot applications for years. I knew the ecosystem. I knew how to wire beans, configure starters, and navigate the autoconfiguration magic without panicking. Then I started exploring Spring AI, and suddenly I was lost again. Embeddings. Vector stores. RAG pipelines. Advisors. ChatClient vs ChatModel. A wall of new terminology that felt completely disconnected from everything I already knew. ...

June 6, 2026 · 7 min
Lazy Constants

Java 27 - part 3: JEP 531 - Lazy Constants, Round Three

Third Time’s the Charm: Lazy Constants Get a Trim and a New Trick Back in the Java 26 series, I walked you through JEP 526 and the (then) second preview of the Lazy Constants API. If you missed it, the short version is this: Java finally got a clean way to do deferred immutability — fields that initialize on demand but, once set, are treated by the JVM as if they’d been hard-coded constants. No more double-checked locking. No more holder idioms. Just LazyConstant.of(...) and a .get(). ...

May 27, 2026 · 4 min
Structured Concurrency

Java 27 - part 1: JEP 523 - G1 Becomes the Default Everywhere

G1 Garbge Collector, Always. If you’ve ever wondered which garbage collector the JVM actually picked for you when you didn’t tell it which one to use, the answer was always a little annoying: “well, it depends.” That “it depends” is exactly what JEP 523, targeting JDK 27, gets rid of. From now on, when you don’t specify a collector on the command line, the JVM always picks G1. No exceptions, no hardware-dependent surprises. Let me walk you through what’s changing and — more importantly — whether you should care. ...

May 22, 2026 · 5 min