Java Records: The Complete Guide to Immutable Data Classes

Before Java 16, writing a simple data-carrier class required a constructor, private fields, getters, equals(), hashCode(), and toString() — anywhere from 30 to 60 lines of boilerplate for a handful of fields. Java Records eliminate all of that. A record is a restricted class that is transparently immutable: you declare the fields once, and the compiler generates everything else.

This guide covers every aspect of Java Records you will encounter in a production Spring Boot or Hibernate codebase: declaration syntax, compact constructors, custom accessors, serialisation with Jackson, usage with Hibernate, and the important limitations you need to understand before choosing a record over a plain class.

Continue reading Java Records: The Complete Guide to Immutable Data Classes

Java Generics: The Complete Developer’s Reference

Generics are the feature that transformed Java from a language of unchecked casts into one of verified type contracts. Introduced in Java 5, they let you write a class or method once and have the compiler enforce type correctness at every call site — without paying a runtime cost. When you write List<Product> instead of List, the compiler catches a misplaced String at compile time rather than surfacing a ClassCastException at 2 a.m. in production. This guide is a complete, runnable reference: generic classes, generic methods, bounded type parameters, wildcards, the PECS rule, and type erasure — with the patterns you will actually reach for in enterprise Java.

Continue reading Java Generics: The Complete Developer’s Reference

LLM Gateway for Java Microservices — Complete Runnable Code & Demo

This is the companion code post to ← The LLM Gateway Pattern for Java Microservices. That article explains the design decisions behind each layer. This post gives you the complete project — every file, ready to clone and run.

Prerequisites

  • Java 21+ and Maven 3.9+
  • Docker and Docker Compose (for Redis)
  • An OpenAI API key — required. Anthropic and Ollama keys are optional; the gateway falls back automatically if they are absent.

Project Structure

llm-gateway/
├── docker-compose.yml
├── pom.xml
└── src/main/
    ├── java/com/example/gateway/
    │   ├── LlmGatewayApplication.java
    │   ├── cache/
    │   │   ├── CacheEntry.java
    │   │   └── SemanticCache.java
    │   ├── controller/
    │   │   └── LlmGatewayController.java
    │   ├── cost/
    │   │   └── CostTracker.java
    │   ├── model/
    │   │   ├── LlmGatewayRequest.java
    │   │   └── LlmGatewayResponse.java
    │   ├── orchestrator/
    │   │   ├── LlmGatewayOrchestrator.java
    │   │   └── RateLimitExceededException.java
    │   ├── ratelimit/
    │   │   ├── TenantTier.java
    │   │   ├── TenantTierRepository.java
    │   │   └── TokenBudgetRateLimiter.java
    │   └── registry/
    │       ├── AllProvidersUnavailableException.java
    │       ├── LlmProviderRegistry.java
    │       └── ResilientProviderCaller.java
    └── resources/
        └── application.yml
Continue reading LLM Gateway for Java Microservices — Complete Runnable Code & Demo

Spring AI RAG in Java — Complete Runnable Code & End-to-End Demo

This is the companion code post to ← Production-Grade RAG with Spring AI 1.1.0. That article explains how every layer works. This post gives you the complete project — every file, ready to clone and run.

Prerequisites

  • Java 21+ and Maven 3.9+
  • Docker and Docker Compose (for PostgreSQL + pgvector)
  • An OpenAI API key (export OPENAI_API_KEY=sk-...)

Project Structure

spring-ai-rag/
├── docker-compose.yml
├── init.sql
├── pom.xml
└── src/main/
    ├── java/com/example/rag/
    │   ├── RagApplication.java
    │   ├── config/
    │   │   └── RagConfig.java
    │   ├── controller/
    │   │   └── RagController.java
    │   ├── ingestion/
    │   │   ├── DocumentIngestionService.java
    │   │   ├── IngestionException.java
    │   │   └── IngestionTracker.java
    │   ├── model/
    │   │   ├── FaithfulnessResult.java
    │   │   ├── IngestionResult.java
    │   │   ├── QueryRequest.java
    │   │   ├── RagQueryOptions.java
    │   │   ├── RagResponse.java
    │   │   ├── ScoredDocument.java
    │   │   └── SourceAttribution.java
    │   └── query/
    │       ├── CrossEncoderReranker.java
    │       ├── HallucinationGuard.java
    │       └── RagQueryService.java
    └── resources/
        └── application.yml
Continue reading Spring AI RAG in Java — Complete Runnable Code & End-to-End Demo

The LLM Gateway Pattern for Java Microservices: Multi-Provider Failover, Cost Control, and Rate Limiting

Every Java team building AI features eventually faces the same set of problems: a single LLM provider goes down during a critical demo, a runaway loop burns $500 of API credit overnight, or two product teams independently hard-code OpenAI keys into separate microservices and you lose all cost visibility. The LLM Gateway pattern solves all of these — and it’s the most underbuilt component in the Java AI ecosystem today. This post walks through designing and implementing a production-grade LLM Gateway in Spring Boot: multi-provider routing with automatic failover, circuit breaking, rate limiting, cost tracking, semantic caching, and tenant isolation.

Continue reading The LLM Gateway Pattern for Java Microservices: Multi-Provider Failover, Cost Control, and Rate Limiting

Production-Grade RAG with Spring AI 1.0 in Java: Chunking, Reranking, and Hallucination Guards

Most RAG tutorials stop at “load a PDF, embed it, ask a question.” That works in a demo. In production — handling 10 000 documents, diverse query types, and user expectations of factual accuracy — it falls apart within weeks. This guide walks through every layer of a production-grade Retrieval-Augmented Generation (RAG) system built entirely in Java using Spring AI 1.1.0: from chunking strategy selection and vector store tuning to reranking, hallucination guards, cost tracking, and observability.

Continue reading Production-Grade RAG with Spring AI 1.0 in Java: Chunking, Reranking, and Hallucination Guards

28× Faster? Virtual Threads vs Platform Threads in Java: Real Benchmarks, Code, and When to Use Which

Virtual threads shipped as a final feature in Java 21 and matured further in Java 25 (JEP 491 eliminates carrier-thread pinning inside synchronized blocks). The marketing says “millions of threads, almost free” — but what does that actually look like under a stopwatch? In this post we run reproducible benchmarks against platform threads, show where virtual threads win big (and where they don’t), and give you a clear decision table for your own code.

Continue reading 28× Faster? Virtual Threads vs Platform Threads in Java: Real Benchmarks, Code, and When to Use Which