If you're a Java developer reading this in August 2026, the landscape shifted under your feet in the last 90 days — and most of the internet hasn't caught up.
Spring AI hit 2.0 GA. Embabel reached 1.0. MCP went stateless. LangChain4j shipped BDI agents. The Spring AI AgentCore SDK went GA. And Koog (JetBrains) stabilized its core. All between May and July 2026. All for the JVM.
Catch up on — ai4jvm.com
This isn't a listicle of announcements. This is an architecture essay — the synthesis of a 68-minute studio conversation I had with James Ward. Java Champion. AWS Principal Developer Advocate. 12-Factor App contributor. Building software since 1997. We recorded 3 hours. Published 68 minutes. What made the cut was the stuff that changes how you think about building production systems — not demos.
The Foundational Claim: Python Trains AI. Java Runs AI.
Let me ground this with numbers.
- 60% of external AWS SDK API calls come through the Java SDK. 8% come from Python. (Source: James Ward, "Going Big with Java for Agentic Workloads," 2026)
- 90% of Fortune 500 companies run Java in production. (Oracle, 2025)
- 62% of enterprises now use Java to power AI applications. (Azul survey, January 2026)
- A Spring AI survey indicates 65% of Spring users prefer building agents in Spring AI/Embabel over Python/TypeScript alternatives (17%) or other JVM frameworks (18%).
The distinction matters because people conflate building with AI (integrating models into applications — the Java play) with building AI (training models — the Python play).
When an AI agent needs to call your payment gateway at 3am with proper retry logic, circuit breakers, type-safe validation, and an audit trail — that's a distributed systems problem. It always was. The model is a component in that system, not the system itself.
The agents of 2026 are calling the same enterprise APIs, hitting the same backends, running on the same infrastructure that Java has owned for two decades. The language that runs those backends is the language best positioned to serve them to autonomous consumers.
The Framework Decision: A Concrete Comparison (Not a Vibe Check)
The question I get most — at meetups, in YouTube comments, at the MCP Dev Summit booth (100+ conversations across Bangalore and Mumbai) — is: "Spring AI or LangChain4j?"
James's answer was blunt: pick one, go deep. The architectural concepts — tool calling, RAG, structured outputs, memory, observability — are transferable.
Here's the concrete state of play as of August 2026:
| Spring AI 2.0 | LangChain4j 1.18 | Embabel 1.0 | Koog 1.0 | |
|---|---|---|---|---|
| GitHub Stars | 7.4K | 10K | 2.9K | 3.5K |
| GA Date | Jun 12, 2026 | Jul 2026 | Jul 20, 2026 | Jul 2026 |
| Foundation | Spring Boot 4 | Standalone / Quarkus | Built ON Spring AI | Kotlin multiplatform |
| Agent Pattern | Advisor chain (composable interceptors) | BDI (Belief-Desire-Intention) | GOAP (Goal-Oriented Action Planning) | Type-safe DSL |
| MCP Support | Annotation-driven (@McpTool) | Declarative via @tool | Inherits from Spring AI | A2A + MCP |
| Key Differentiator | Enterprise convention-over-config | Broadest provider support (20+ LLMs, 20+ vector stores) | Runtime replanning when actions fail | Multiplatform (JVM, JS, iOS, Android) |
| Best For | Spring Boot teams (66% of enterprise Java) | Non-Spring shops, polyglot provider needs | Teams wanting declarative goal-driven agents | Kotlin-first teams |
The framework matters less than understanding what's underneath. If you understand how tool calling works at the protocol level (MCP), how memory strategies differ (semantic vs episodic), and how retry responsibility splits between infra and reasoning — switching between these is a weekend of refactoring, not a rewrite.
The anti-pattern I see repeatedly: Teams spending 4 weeks evaluating frameworks, building proof-of-concepts in each, writing comparison docs for leadership — and never shipping anything. The framework you ship with is better than the three you evaluated.
MCP 2026–07–28: The Protocol Layer Just Broke and Rebuilt Itself
On July 28, 2026, the Model Context Protocol shipped its biggest revision since launch. This isn't a point release. It's a new era.
What changed (the technical diff):
The old protocol was stateful — a two-round-trip initialize handshake, a Mcp-Session-Id header that required sticky sessions, server-side session stores, and affinity routing at the load balancer.
The new protocol is stateless: every request is self-contained. Protocol version and client capabilities ride in _meta on every request. No handshake. No session ID.
// Before (2025-11-25): Two round trips minimum
POST /mcp → initialize → get Mcp-Session-Id → sticky-route forever
// After (2026-07-28): One round trip. Everything in the envelope.
POST /mcp
Mcp-Method: tools/call
Mcp-Name: get_user
{
"jsonrpc":"2.0",
"method":"tools/call",
"params":{
"name":"get_user",
"arguments":{"id":"123"},
"_meta":{
"io.modelcontextprotocol/protocolVersion":"2026-07-28",
"io.modelcontextprotocol/clientInfo":{"name":"my-client","version":"1.0.0"}
}
}
}
Why this matters for Java developers:
Your MCP server (the Spring Boot app with @McpTool annotations) can now sit behind a plain round-robin load balancer. No sticky sessions. No shared session store. No distributed cache for session state. The serverless deployment model (Lambda, AgentCore Runtime, Cloud Run) becomes trivially simple because there's nothing to share between invocations.
The MCP Java SDK 2.0 tracks this spec. SSE transport is deprecated (12-month clock). Streamable HTTP is the path forward. server/discover is now mandatory — it replaces the initialization handshake as the capability advertisement mechanism. Tool lists must be deterministic and carry ttlMs and cacheScope for client-side caching.
The migration reality: You have 12 months. Both eras coexist. But if you're building a NEW MCP server today, build to 2026–07–28. Don't accumulate session-dependent tech debt you'll need to unwind.
Embabel 1.0: Why Rod Johnson Built a Framework on Top of His Own Framework
The InfoQ coverage frames it precisely: "An analogy: Spring AI exists at the level of the Servlet API, while Embabel is more like Spring MVC."
Rod Johnson — who created Spring in 2003 — is making the same layering bet he made 23 years ago.
What makes Embabel architecturally different:
Embabel uses Goal-Oriented Action Planning (GOAP), a technique borrowed from video game AI. Instead of wiring a static graph of nodes and edges (the LangGraph approach), you define:
- Typed goals — what you want to achieve
- Typed actions — each with preconditions and effects
- A planner — that searches for a sequence of actions reaching the goal at runtime
If the world changes mid-task (a tool fails, new data arrives), the planner reassesses and finds a new path. You don't need to have anticipated every branch in advance.
This matters for production because agents fail mid-execution constantly. An API returns a 503. The user changes their mind. A guardrail blocks an intermediate step. With a static graph, you either crash or you need explicit error edges for every possible failure. With GOAP, the planner routes around the failure — the same way a GPS recalculates when you miss a turn.
The distinction from LangGraph4j: LangGraph requires you to define the graph upfront — which nodes exist, which edges connect them, under what conditions. Embabel's planner discovers viable paths through typed actions at runtime. Both approaches have merit. LangGraph gives you predictability and auditability. Embabel gives you adaptability and less upfront wiring. Embabel even supports mixing both: GOAP planning alongside explicit state machines in the same agent.
Memory Is the Silent Killer of Agent Reliability
The most technically interesting segment of our conversation — and the one that's generated the most YouTube comments — was about agent memory architecture.
The failure mode nobody warns you about: Your agent keeps the last 20 messages in a sliding window. On message 21, the original user intent rolls off. The agent continues executing — but toward a goal it's forgotten. No crash. No error. Just quiet drift. Your trace shows every tool call succeeded. The output is confidently wrong.
The 4-strategy architecture:
| Strategy | What It Stores | When It's Used | Example |
|---|---|---|---|
| Semantic | Factual information about the user | Injected when relevant to current query | "User works in financial services" |
| User Preference | Explicit settings and choices | Always injected for personalization | "Prefers metric units" |
| Summary | Condensed conversation history | Injected at session start for continuity | "Last session: analyzed Q3 expenses, found anomaly in travel category" |
| Episodic | Past interactions and lessons learned | Injected when similar situations arise | "User had trouble with CSV parsing last week — offer the helper tool proactively" |
The production pattern: Short-term memory (sliding window) handles the current conversation. Long-term memory (the 4 strategies above) handles everything that should survive across sessions. The consolidation happens asynchronously — the system extracts relevant facts without explicit developer intervention.
The anti-pattern: Using only short-term memory and increasing the window size to compensate. This burns tokens (every message is re-sent to the model) and eventually hits context limits. It's the equivalent of solving a database scaling problem by buying more RAM instead of indexing properly.
The Principle I Now Repeat in Every Talk
"Don't let the non-deterministic system make the final move."
LLMs reason. Deterministic tools execute. The boundary between them must be type-safe, validated, and auditable.
In practice, this means your @McpTool methods (or @Tool in LangChain4j) have:
- Strict input types (not
Map<String, Object>) - Validation annotations (
@NotNull,@Min,@Pattern) - Structured error responses the agent can reason about
- No direct writes without validation passing first
@McpTool(description = "Transfer funds between accounts. Validates balance before executing.")
public TransferResult transfer(
@NotNull @Pattern(regexp = "ACC-\\d{10}") String fromAccount,
@NotNull @Pattern(regexp = "ACC-\\d{10}") String toAccount,
@Min(1) @Max(100000) BigDecimal amount,
@NotBlank String currency
) {
// The agent reasoned about WHAT to transfer.
// This method validates HOW — deterministically.
// If validation fails, the structured error tells the agent why.
}
This is just dependency injection and interface contracts — the things Java developers have been doing for 20 years. The reasoning is new. The execution boundary isn't.
What This Means for Your Career in 2026
The Java AI stack crystallized in 90 days. Before May 2026, it was emerging. Now it's production-ready. The window where "I'm still evaluating" was a reasonable position has closed.
The decision tree:
- Already on Spring Boot? → Spring AI 2.0. No contest. Annotation-driven, advisor-chain composable, MCP built in.
- Want high-level goal-driven agents? → Embabel 1.0 (on top of Spring AI). GOAP replanning, typed domain objects.
- Not on Spring? → LangChain4j 1.18. BDI pattern, broadest provider support, crash-resilient HITL.
- Kotlin-first? → Koog 1.0. Multiplatform, type-safe DSL, A2A support.
- Need managed deployment? → Spring AI AgentCore SDK. One annotation → managed runtime, memory, observability, scaling.
But the framework is 20% of the decision. The 80% is: Do you understand how MCP tool discovery works? Do you understand the 4 memory strategies? Do you understand where retry responsibility lives (infra vs reasoning)?
If yes — you can build production agents in any of these frameworks by next week.
If no — learning a second framework teaches you nothing new.
The full conversation goes deeper into each of these areas. Timestamps in the video description — jump to what matters most to you.
🎬 Watch: 68 Minutes That Could Change How You Think About Java and AI
📺 Subscribe: Code With Ease — By Varsha
📝 More writing: medium.com/@varshadas | dev.to/varshadas
🔗 Connect: linkedin.com/in/varsha-das-se
Top comments (0)