<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="https://feeds.feedblitz.com/feedblitz_rss.xslt"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:webfeeds="http://webfeeds.org/rss/1.0"  xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">
<channel>
	<title>Baeldung</title>
	<atom:link href="https://www.baeldung.com/feed" rel="self" type="application/rss+xml" />
	<link>https://www.baeldung.com</link>
	<description>Java, Spring and Web Development tutorials</description>
	<lastBuildDate>Thu, 10 Sep 2026 19:10:48 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
<meta xmlns="http://www.w3.org/1999/xhtml" name="robots" content="noindex" />
<item>
<feedburner:origLink>https://www.baeldung.com/java-jackson-3-updates</feedburner:origLink>
		<title>What&#8217;s New in Jackson 3?</title>
		<link>https://feeds.feedblitz.com/~/968938295/0/baeldung~Whats-New-in-Jackson</link>
					<comments>https://feeds.feedblitz.com/~/968938295/0/baeldung~Whats-New-in-Jackson#respond</comments>
		
		<dc:creator><![CDATA[Mateusz Szablak]]></dc:creator>
		<pubDate>Thu, 10 Sep 2026 19:10:48 +0000</pubDate>
				<category><![CDATA[Jackson]]></category>
		<category><![CDATA[Jackson Basics]]></category>
		<guid isPermaLink="false">https://www.baeldung.com/java-jackson-3-updates</guid>
					<description><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/2024/11/Data-Featured-Image-07-1024x536.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="An image of an engineer at the center pointing at a background of graphs and charters. They have a house plant at their right and on the left are the words &quot;Data on Baeldung&quot;" style="max-width:100% !important;height:auto !important;float: left; margin-right: 5px;" fetchpriority="high" /><p>Learn what's new in Jackson 3, how it differs from Jackson 2, and what you need to do in order to migrate from Jackson 2.x to the new version.</p>
<p>The post <a rel="NOFOLLOW" href="https://feeds.feedblitz.com/~/968938295/0/baeldung~Whats-New-in-Jackson">What’s New in Jackson 3?</a> first appeared on <a rel="NOFOLLOW" href="https://www.baeldung.com">Baeldung</a>.</p><div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/968938295/baeldung"><img height="20" src="https://assets.feedblitz.com/i/fblike20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Pin it!" href="https://feeds.feedblitz.com/_/29/968938295/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2024%2f11%2fData-Featured-Image-07-1024x536.jpg"><img height="20" src="https://assets.feedblitz.com/i/pinterest20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Post to X.com" href="https://feeds.feedblitz.com/_/24/968938295/baeldung"><img height="20" src="https://assets.feedblitz.com/i/x.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by email" href="https://feeds.feedblitz.com/_/19/968938295/baeldung"><img height="20" src="https://assets.feedblitz.com/i/email20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by RSS" href="https://feeds.feedblitz.com/_/20/968938295/baeldung"><img height="20" src="https://assets.feedblitz.com/i/rss20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a rel="NOFOLLOW" title="View Comments" href="https://www.baeldung.com/java-jackson-3-updates#respond"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/comments20.png"></a>&#160;<a title="Follow Comments via RSS" href="https://www.baeldung.com/java-jackson-3-updates/feed"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/commentsrss20.png"></a>&#160;</div>]]>
</description>
										<content:encoded><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/2024/11/Data-Featured-Image-07-1024x536.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="An image of an engineer at the center pointing at a background of graphs and charters. They have a house plant at their right and on the left are the words &quot;Data on Baeldung&quot;" style="float: left; margin-right: 5px;" decoding="async" srcset="https://www.baeldung.com/wp-content/uploads/2024/11/Data-Featured-Image-07-1024x536.jpg 1024w, https://www.baeldung.com/wp-content/uploads/2024/11/Data-Featured-Image-07-300x157.jpg 300w, https://www.baeldung.com/wp-content/uploads/2024/11/Data-Featured-Image-07-768x402.jpg 768w, https://www.baeldung.com/wp-content/uploads/2024/11/Data-Featured-Image-07-100x52.jpg 100w, https://www.baeldung.com/wp-content/uploads/2024/11/Data-Featured-Image-07-600x314.jpg 600w, https://www.baeldung.com/wp-content/uploads/2024/11/Data-Featured-Image-07.jpg 1200w" sizes="(max-width: 580px) 100vw, 580px" /><h2 id="bd-overview" data-id="overview">1. Overview</h2>
<div class="bd-anchor" id="overview"></div>
<p>Jackson has been the most popular JSON processing library in the Java ecosystem for over a decade. After years of incremental updates in the 2.x line, the release of <strong>Jackson 3.0 introduces a major architectural overhaul</strong> designed to address long-standing technical debt and modernize its API.</p>
<p>In this tutorial, we&#8217;ll explore key changes in Jackson 3, how they impact our existing codebases, and the steps required to migrate from the 2.x line.</p>
<h2 id="bd-technical-prerequisites-and-migration-path" data-id="technical-prerequisites-and-migration-path">2. Technical Prerequisites and Migration Path</h2>
<div class="bd-anchor" id="technical-prerequisites-and-migration-path"></div>
<p>Let&#8217;s review the foundational changes in Jackson 3, including minimum requirements and the necessary steps to prepare our project for migration.</p>
<h3 id="bd-1-java-17-baseline" data-id="1-java-17-baseline">2.1. Java 17 Baseline</h3>
<div class="bd-anchor" id="1-java-17-baseline"></div>
<p><strong>Jackson 3.0 raises its minimum supported JDK version from Java 8 to Java 17</strong>. This allows Jackson to natively use modern Java language features, such as Java Records or pattern matching.</p>
<p>Before migrating to Jackson 3.0, we should ensure that our project meets this requirement. If not, we must consider upgrading the Java version in our project or remaining on the Jackson 2.x line.</p>
<h3 id="bd-2-artifacts-and-groupid" data-id="2-artifacts-and-groupid">2.2. Artifacts and <em>GroupId</em></h3>
<div class="bd-anchor" id="2-artifacts-and-groupid"></div>
<p>The new major <strong>Jackson version introduces a completely new <em>groupId</em></strong> for its artifacts &#8211; <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://mvnrepository.com/artifact/tools.jackson.core/jackson-core"><em>tools.jackson.core</em></a>, replacing <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://mvnrepository.com/artifact/com.fasterxml.jackson.core"><em>com.fasterxml.jackson.core</em></a>. This change <strong>allows Jackson 2.x and 3.x to coexist on the classpath</strong> in parallel during gradual migrations.</p>
<p>To install the new version of the library, we add it to our <em>pom.xml</em>:</p>
<pre><code class="language-xml">&lt;dependency&gt; 
    &lt;groupId&gt;tools.jackson.core&lt;/groupId&gt;
    &lt;artifactId&gt;jackson-databind&lt;/artifactId&gt;
    &lt;version&gt;3.2.1&lt;/version&gt;
&lt;/dependency&gt;</code></pre>
<p>Alternatively, if we want to add a dedicated mapper for another format, such as XML, we need to include its specific module:</p>
<pre><code class="language-">&lt;dependency&gt;
    &lt;groupId&gt;tools.jackson.dataformat&lt;/groupId&gt;
    &lt;artifactId&gt;jackson-dataformat-xml&lt;/artifactId&gt;
    &lt;version&gt;3.2.1&lt;/version&gt;
&lt;/dependency&gt;</code></pre>
<p>For these format-specific modules, the group is <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://mvnrepository.com/search?q=tools.jackson.dataformat"><em>tools.jackson.dataformat</em></a>. It&#8217;s also worth noting that the <strong><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations"><em>jackson-annotations</em></a> dependency still remains under the old <em>com.fasterxml.jack</em><em>son.core</em> group</strong>. This exception ensures that our core domain models with Jackson annotations do not require modifications when upgrading.</p>
<h3 id="bd-3-package-name-changes" data-id="3-package-name-changes">2.3. Package Name Changes</h3>
<div class="bd-anchor" id="3-package-name-changes"></div>
<p>Because of the artifacts <em>groupId</em> change, the base<strong> Java package has also shifted from <em>com.fasterxml.jackson</em> to <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://javadoc.io/doc/tools.jackson.core/jackson-databind/latest/tools.jackson.databind/module-summary.html"><em>tools.jackson</em></a></strong>. When <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/FasterXML/jackson/blob/main/jackson3/MIGRATING_TO_JACKSON_3.md">migrating projects</a>, we need to update our import statements:</p>
<pre><code class="language-java">// Remove Old Jackson 2.x imports
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.JsonNode;
// Use New Jackson 3.x imports
import tools.jackson.databind.ObjectMapper;
import tools.jackson.databind.json.JsonMapper;
import tools.jackson.databind.JsonNode;</code></pre>
<h3 id="bd-4-android-compatibility" data-id="4-android-compatibility">2.4. Android Compatibility</h3>
<div class="bd-anchor" id="4-android-compatibility"></div>
<p>Because Jackson 3 relies entirely on Java 17, Android projects must be properly configured to support these language features.</p>
<p><strong>Android developers should to target API level 34 (Android 14)</strong> or enable core library desugaring in their build configuration to use Jackson 3.</p>
<h3 id="bd-5-removal-of-deprecated-methods" data-id="5-removal-of-deprecated-methods">2.5. Removal of Deprecated Methods</h3>
<div class="bd-anchor" id="5-removal-of-deprecated-methods"></div>
<p>As part of the major version bump, Jackson 3 removes all classes, methods, and configurations that had the <em>@Deprecated</em> annotation in the 2.x line. If our current codebase uses any legacy methods, we must replace them with 3.x alternatives before the migration.</p>
<p>Now, let&#8217;s move on to specific functional changes in Jackson 3.</p>
<h2 id="bd-immutable-objectmapper-and-the-builder-pattern" data-id="immutable-objectmapper-and-the-builder-pattern">3. Immutable <i>ObjectMapper</i> and the Builder Pattern</h2>
<div class="bd-anchor" id="immutable-objectmapper-and-the-builder-pattern"></div>
<p>In previous versions,<strong> <em>ObjectMapper</em> instances were mutable</strong>. By <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/jackson-object-mapper-tutorial#1-configuring-serialization-or-deserialization-feature">modifying configurations or registered modules</a> on an active mapper after initialization, we risked running into thread-safety issues, such as race conditions when concurrent threads tried to read and alter the mapper&#8217;s state simultaneously.</p>
<p><strong>Jackson 3 solves this by enforcing strict immutability for its mappers.</strong> <strong>It removes direct</strong><strong> configuration methods on <em><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://javadoc.io/doc/tools.jackson.core/jackson-databind/latest/tools.jackson.databind/tools/jackson/databind/ObjectMapper.html">ObjectMapper</a></em>.</strong> Instead, we <strong>use the builder pattern</strong> and format-specific builders to configure our mappers before instantiation.</p>
<h3 id="bd-1-building-ajsonmapper" data-id="1-building-ajsonmapper">3.1. Building a <em>JsonMapper</em></h3>
<div class="bd-anchor" id="1-building-ajsonmapper"></div>
<p>Let&#8217;s see how to construct and configure a <em><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://javadoc.io/doc/tools.jackson.core/jackson-databind/latest/tools.jackson.databind/tools/jackson/databind/json/JsonMapper.html">JsonMapper</a></em> using the available API:</p>
<pre><code class="language-java">JsonMapper mapper = JsonMapper.builder()
  .enable(SerializationFeature.INDENT_OUTPUT)
  .disable(JsonWriteFeature.ESCAPE_NON_ASCII)
  .configure(DateTimeFeature.WRITE_DATES_AS_TIMESTAMPS, false)
  .build();</code></pre>
<p>Here, we initialize a builder for the JSON format. We enable pretty-printing, disable the escaping of non-ASCII characters, and tell Jackson not to serialize dates as numeric timestamps.</p>
<p><strong>Jackson uses Java enums as sets of feature toggles to control parsing, serialization, and mapping behavior.</strong> We can find general configuration options in the <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://javadoc.io/doc/tools.jackson.core/jackson-databind/latest/tools.jackson.databind/tools/jackson/databind/SerializationFeature.html"><em>SerializationFeature</em></a>, <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://javadoc.io/doc/tools.jackson.core/jackson-databind/latest/tools.jackson.databind/tools/jackson/databind/DeserializationFeature.html#FAIL_ON_UNKNOWN_PROPERTIES"><em>DeserializationFeature</em></a>, and <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://javadoc.io/doc/tools.jackson.core/jackson-databind/latest/tools.jackson.databind/tools/jackson/databind/MapperFeature.html"><em>MapperFeature</em></a> enums. For format- or type-specific requirements, Jackson provides dedicated enums such as <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://javadoc.io/doc/tools.jackson.core/jackson-core/latest/tools.jackson.core/tools/jackson/core/json/JsonWriteFeature.html"><em>JsonWriteFeature</em></a> (for JSON generation) and <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://javadoc.io/doc/tools.jackson.core/jackson-databind/latest/tools.jackson.databind/tools/jackson/databind/cfg/DateTimeFeature.html"><em>DateTimeFeature</em></a> (for date handling).</p>
<h3 id="bd-2-copying-mappers" data-id="2-copying-mappers">3.2. Copying Mappers</h3>
<div class="bd-anchor" id="2-copying-mappers"></div>
<p>If we need a slightly modified version of an existing mapper, we can use the <em>rebuild()</em> method:</p>
<pre><code class="language-java">JsonMapper prettyMapper = mapper.rebuild()
  .enable(SerializationFeature.INDENT_OUTPUT)
  .build();</code></pre>
<p>Note that <strong><em>prettyMapper</em> and <em>mapper </em>from the previous snippet are completely different objects.</strong> The <em>rebuild()</em> method copies the internal configuration of the original mapper into a new builder, allowing us to spawn a new instance with slight modifications. Because the mappers are immutable, this operation is entirely thread-safe and won&#8217;t affect the original mapper.</p>
<h3 id="bd-3-support-for-alternative-data-formats" data-id="3-support-for-alternative-data-formats">3.3. Support for Alternative Data Formats</h3>
<div class="bd-anchor" id="3-support-for-alternative-data-formats"></div>
<p>If our project requires a different data format, we simply switch to the corresponding format-specific builder. For example, we can configure an <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.javadoc.io/doc/tools.jackson.dataformat/jackson-dataformat-xml/latest/tools.jackson.dataformat.xml/tools/jackson/dataformat/xml/XmlMapper.html"><em>XmlMapper</em></a> for XML or a <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.javadoc.io/doc/tools.jackson.dataformat/jackson-dataformat-yaml/latest/tools.jackson.dataformat.yaml/tools/jackson/dataformat/yaml/YAMLMapper.html"><em>YAMLMapper</em></a> for YAML using their respective builders:</p>
<pre><code class="language-java">XmlMapper xmlMapper = XmlMapper.builder()
  .enable(SerializationFeature.INDENT_OUTPUT)
  .build();
YAMLMapper yamlMapper = YAMLMapper.builder()
  .disable(YAMLGenerator.Feature.WRITE_DOC_START_MARKER)
  .build();</code></pre>
<h2 id="bd-unchecked-exceptions" data-id="unchecked-exceptions">4. Unchecked Exceptions</h2>
<div class="bd-anchor" id="unchecked-exceptions"></div>
<p>One of the <strong>biggest readability issues in Jackson 2.x was dealing with the checked <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://javadoc.io/doc/com.fasterxml.jackson.core/jackson-core/latest/com/fasterxml/jackson/core/JsonProcessingException.html"><em>JsonProcessingException</em></a> and <em>IOException</em></strong> during serialization and deserialization. Supporting them inside Java Streams or lambda expressions often led to verbose <em>try-catch</em> blocks or custom wrapper utilities.</p>
<p><strong>In Jackson 3, <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://javadoc.io/doc/tools.jackson.core/jackson-core/latest/tools.jackson.core/tools/jackson/core/JacksonException.html"><em>JacksonException</em></a> replaces <em>JsonProcessingException</em> as the root exception</strong>, and it now extends <em>RuntimeException</em>:</p>
<pre><code class="language-java">List&lt;User&gt; users = jsonPayloads.stream()
  .map(json -&gt; mapper.readValue(json, User.class)) // No try-catch needed!
  .toList();</code></pre>
<p>This change significantly cleans up our stream operations. Because the exception is unchecked, the compiler no longer forces us to handle it immediately. We can omit the clutter of <em>try-catch</em> blocks within our lambdas, resulting in much cleaner code.</p>
<h2 id="bd-built-in-java-8-features" data-id="built-in-java-8-features">5. Built-in Java 8+ Features</h2>
<div class="bd-anchor" id="built-in-java-8-features"></div>
<p>Historically, to <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/jackson-serialize-dates#java-8">properly handle Java 8 features like <em>java.time</em></a> classes, <em>java.util.Optional</em>, or constructor parameter name detection, we had to explicitly include and register three separate modules: <em>jackson-datatype-jsr310</em>, <em>jackson-datatype-jdk8</em>, and <em>jackson-module-parameter-names</em>.</p>
<p>Since Jackson 3 targets Java 17, <strong>these three modules are now integrated into <em>jackson-databind</em></strong>. We can serialize and deserialize <em>LocalDateTime</em> and <em>Optional</em> properties immediately upon creating a new mapper:</p>
<pre><code class="language-java">public record Event(String title, Optional&lt;String&gt; description, LocalDateTime eventDate) {}
// ...
Event event = new Event("Tech Talk", Optional.of("Jackson 3 overview"), LocalDateTime.now());
JsonMapper mapper = JsonMapper.builder().build();    
String json = mapper.writeValueAsString(event);
Event deserialized = mapper.readValue(json, Event.class);</code></pre>
<p>This native support significantly simplifies the codebase when working with Java 8+ types, as it requires no additional configuration.</p>
<h2 id="bd-configuration-defaults-and-behavioral-changes" data-id="configuration-defaults-and-behavioral-changes">6. Configuration Defaults and Behavioral Changes</h2>
<div class="bd-anchor" id="configuration-defaults-and-behavioral-changes"></div>
<p><strong>Jackson 3 changes several default settings</strong> to reflect modern development practices and community feedback. A full list of changes can be found in the <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/FasterXML/jackson/wiki/Jackson-Release-3.0">official documentation</a>. We describe the most impactful ones.</p>
<h3 id="bd-1-failonunknownproperties-defaults-to-false" data-id="1-failonunknownproperties-defaults-to-false">6.1. <em>FAIL_ON_UNKNOWN_PROPERTIES</em> Defaults to <em>false</em></h3>
<div class="bd-anchor" id="1-failonunknownproperties-defaults-to-false"></div>
<p>In Jackson 2.x, encountering unknown JSON fields during deserialization threw an <em>UnrecognizedPropertyException</em> by default unless we explicitly disabled it on the mapper.</p>
<p>In Jackson 3.0, <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://javadoc.io/doc/tools.jackson.core/jackson-databind/latest/tools.jackson.databind/tools/jackson/databind/DeserializationFeature.html#FAIL_ON_UNKNOWN_PROPERTIES"><em>DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES</em></a> defaults to <em>false</em>. <strong>Jackson safely ignores unrecognized fields in incoming JSON payloads</strong> unless we explicitly set this flag to true. Let&#8217;s verify this:</p>
<pre><code class="language-java">record User(String name) {}
// ...
JsonMapper mapper = JsonMapper.builder().build();
// The JSON contains "unknownField" which is not present in the User class
String json = "{\"name\":\"Alice\", \"unknownField\":\"ignored_value\"}";
    
// This executes without throwing an exception
User user = mapper.readValue(json, User.class);</code></pre>
<p>In some cases such as strict API validations, it may be necessary to throw an exception when encountering an unknown field. To achieve this, we reenable the feature on the builder:</p>
<pre><code class="language-java">JsonMapper strictMapper = JsonMapper.builder()
    .enable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
    .build();
User strictUser = strictMapper.readValue(json, User.class);</code></pre>
<p>This now throws an <em>UnrecognizedPropertyException</em>.</p>
<h3 id="bd-2-fast-floating-point-operations" data-id="2-fast-floating-point-operations">6.2. Fast Floating-Point Operations</h3>
<div class="bd-anchor" id="2-fast-floating-point-operations"></div>
<p><strong>Jackson 3 enables fast floating-point parsing and writing algorithms by default, significantly increasing performance</strong> when processing heavy numerical payloads.</p>
<p>In the late Jackson 2.x releases, we had to manually activate this behavior by configuring the factory features <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://javadoc.io/static/com.fasterxml.jackson.core/jackson-core/2.22.1/com/fasterxml/jackson/core/StreamReadFeature.html#USE_FAST_DOUBLE_PARSER"><em>StreamReadFeature.USE_FAST_DOUBLE_PARSER</em></a>:</p>
<pre><code class="language-java">JsonFactory.builder()
    .enable(StreamReadFeature.USE_FAST_DOUBLE_PARSER)
    .build()</code></pre>
<p>In Jackson 3, we benefit from this performance boost right out of the box.</p>
<h3 id="bd-3-simplified-date-and-time-formatting" data-id="3-simplified-date-and-time-formatting">6.3. Simplified Date and Time Formatting</h3>
<div class="bd-anchor" id="3-simplified-date-and-time-formatting"></div>
<p><strong>Jackson 3 introduces <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://javadoc.io/doc/tools.jackson.core/jackson-databind/latest/tools.jackson.databind/tools/jackson/databind/cfg/DateTimeFeature.html"><em>DateTimeFeature</em></a>, consolidating date and time configuration</strong> options across standard JDK dates, Java 8 <em>java.time</em>, and <em>Joda-Time</em> into a single, unified feature set:</p>
<pre><code class="language-java">JsonMapper mapper = JsonMapper.builder()
    .enable(DateTimeFeature.WRITE_DATES_AS_TIMESTAMPS)
    .build();</code></pre>
<p>We can now format dates globally across all date types.</p>
<h3 id="bd-4-standard-bean-naming" data-id="4-standard-bean-naming">6.4. Standard Bean Naming</h3>
<div class="bd-anchor" id="4-standard-bean-naming"></div>
<p><strong>Jackson 3 bakes standard bean naming into its core engine as the permanent default behavior.</strong> Because this behavior is no longer optional, Jackson 3 removed the <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.javadoc.io/doc/com.fasterxml.jackson.core/jackson-databind/latest/com/fasterxml/jackson/databind/MapperFeature.html#USE_STD_BEAN_NAMING"><em>MapperFeature.USE_STD_BEAN_NAMING</em></a> configuration flag entirely.</p>
<p>Now, we get more consistent property naming out of the box, as we can derive property names from standard getters and setters. Consider a Java class with a getter <em>getTheURL()</em>:</p>
<pre><code class="language-java">class Link {
    private String address;
    public Link(String address) {
        this.address = address;
    }
    public String getTheURL() {
        return address;
    }
}
// ...
String json = mapper.writeValueAsString(new Link("https://baeldung.com"));</code></pre>
<p>Note that Jackson derives JSON property names from getters instead of private fields. In this example, the getter <em>getTheURL()</em> determines the output key <em>theURL</em>:</p>
<pre><code class="language-json">{"theURL":"https://baeldung.com"}</code></pre>
<p>The backing private field <em>address</em> isn&#8217;t considered.</p>
<h2 id="bd-enhancements-to-the-jsonnode-tree-model" data-id="enhancements-to-the-jsonnode-tree-model">7. Enhancements to the <i>JsonNode</i> Tree Model</h2>
<div class="bd-anchor" id="enhancements-to-the-jsonnode-tree-model"></div>
<p>The <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://javadoc.io/doc/tools.jackson.core/jackson-databind/latest/tools.jackson.databind/tools/jackson/databind/JsonNode.html"><em>JsonNode</em></a> tree model remains crucial for working with unstructured data. <strong>In Jackson 3, the API underwent several structural updates</strong> to make traversing JSON trees safer and more intuitive.</p>
<p>First, <strong>the node trees now expose dedicated subtypes</strong>, such as <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://javadoc.io/doc/tools.jackson.core/jackson-core/latest/tools.jackson.core/tools/jackson/core/tree/ObjectTreeNode.html"><em>ObjectTreeNode</em></a> and <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://javadoc.io/doc/tools.jackson.core/jackson-core/latest/tools.jackson.core/tools/jackson/core/tree/ArrayTreeNode.html"><em>ArrayTreeNode</em></a>. This shift provides better type-safety and clearer intentions when manipulating complex JSON structures, compared to checking node types on a generic JsonNode interface.</p>
<p>The <strong>API also introduces safer method names</strong> to align with Java conventions. For example, <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://javadoc.io/static/tools.jackson.core/jackson-core/3.2.1/tools.jackson.core/tools/jackson/core/JsonParser.html#getText()"><em>JsonParser.getText()</em></a> has been renamed to <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://javadoc.io/static/tools.jackson.core/jackson-core/3.2.1/tools.jackson.core/tools/jackson/core/JsonParser.html#getString()"><em>getString()</em></a> to avoid ambiguity and standardize the naming scheme.</p>
<p>Finally, <strong>Jackson 3 introduces optional value accessors,</strong> such as <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://javadoc.io/doc/tools.jackson.core/jackson-databind/latest/tools.jackson.databind/tools/jackson/databind/JsonNode.html#intValueOpt()"><em>intValueOpt()</em></a>, <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://javadoc.io/static/tools.jackson.core/jackson-databind/3.2.1/tools.jackson.databind/tools/jackson/databind/JsonNode.html#asInt()"><em>asInt()</em></a>, and <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://javadoc.io/static/tools.jackson.core/jackson-databind/3.2.1/tools.jackson.databind/tools/jackson/databind/JsonNode.html#required(int)"><em>required()</em></a>. They eliminate the need for manual <em>null </em>checking and provide a much cleaner approach to extracting data.</p>
<p>Here&#8217;s an example showing all the three updates:</p>
<pre><code class="language-java">String json = "{\"product\":\"Laptop\",\"price\":1200}";
JsonNode root = mapper.readTree(json);
String product = root.get("product").asString();
OptionalInt price = root.get("price").intValueOpt();</code></pre>
<p>In this snippet, we parse a raw JSON string into a tree model. We then safely navigate the structure using the <em>get()</em> method and extract typed values using the new <em>asString()</em> and <em>intValueOpt()</em> accessors. <strong>This approach bypasses the clunky type-checking and manual casting that were often required in previous versions.</strong></p>
<h2 id="bd-conclusion" data-id="conclusion">8. Conclusion</h2>
<div class="bd-anchor" id="conclusion"></div>
<p>In this article, we explored the major architectural and functional changes introduced in Jackson 3.0. <strong>By raising the baseline to Java 17, the library drops years of technical debt and natively embraces modern Java features</strong> like Records, <em>java.util.Optional</em>, and the <em>java.time</em> API without the need for external modules.</p>
<p>The shift toward <strong>strict immutability via the builder pattern successfully resolves historic thread-safety issues, while the transition to unchecked exceptions greatly improves developer readability</strong>, especially when working with modern Java Streams. <strong>Additionally, smarter configuration defaults and Tree Model enhancements</strong> make everyday JSON processing cleaner and more intuitive.</p>
<p><strong>While migrating from the 2.x line requires some work, the long-term benefits of a faster, safer, and more robust API make the upgrade well worth the effort. </strong></p>
<p>As always, the complete source code for all the examples is available <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/eugenp/tutorials/tree/master/jackson-modules/jackson-core-3">over on GitHub</a>.</p><p>The post <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-jackson-3-updates">What’s New in Jackson 3?</a> first appeared on <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com">Baeldung</a>.</p><Img align="left" border="0" height="1" width="1" alt="" style="border:0;float:left;margin:0;padding:0;width:1px!important;height:1px!important;" hspace="0" src="https://feeds.feedblitz.com/~/i/968938295/0/baeldung">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/968938295/baeldung"><img height="20" src="https://assets.feedblitz.com/i/fblike20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Pin it!" href="https://feeds.feedblitz.com/_/29/968938295/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2024%2f11%2fData-Featured-Image-07-1024x536.jpg"><img height="20" src="https://assets.feedblitz.com/i/pinterest20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Post to X.com" href="https://feeds.feedblitz.com/_/24/968938295/baeldung"><img height="20" src="https://assets.feedblitz.com/i/x.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by email" href="https://feeds.feedblitz.com/_/19/968938295/baeldung"><img height="20" src="https://assets.feedblitz.com/i/email20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by RSS" href="https://feeds.feedblitz.com/_/20/968938295/baeldung"><img height="20" src="https://assets.feedblitz.com/i/rss20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a rel="NOFOLLOW" title="View Comments" href="https://www.baeldung.com/java-jackson-3-updates#respond"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/comments20.png"></a>&#160;<a title="Follow Comments via RSS" href="https://www.baeldung.com/java-jackson-3-updates/feed"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/commentsrss20.png"></a>&#160;</div>]]>
</content:encoded>
					
					<wfw:commentRss>https://feeds.feedblitz.com/~/968938295/0/baeldung~Whats-New-in-Jackson/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<webfeeds:featuredImage>https://www.baeldung.com/wp-content/uploads/2024/11/Data-Featured-Image-07-150x150.jpg</webfeeds:featuredImage></item>
<item>
<feedburner:origLink>https://www.baeldung.com/java-httpclient-http-3-quic</feedburner:origLink>
		<title>HTTP/3 Support in HTTP Client API in Java 26</title>
		<link>https://feeds.feedblitz.com/~/968937662/0/baeldung~HTTP-Support-in-HTTP-Client-API-in-Java</link>
					<comments>https://feeds.feedblitz.com/~/968937662/0/baeldung~HTTP-Support-in-HTTP-Client-API-in-Java#respond</comments>
		
		<dc:creator><![CDATA[Rajat Garg]]></dc:creator>
		<pubDate>Thu, 10 Sep 2026 18:50:56 +0000</pubDate>
				<category><![CDATA[Networking]]></category>
		<category><![CDATA[Java HttpClient]]></category>
		<guid isPermaLink="false">https://www.baeldung.com/java-httpclient-http-3-quic</guid>
					<description><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-13-1024x536.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="max-width:100% !important;height:auto !important;float: left; margin-right: 5px;" /><p>Learn how HttpClient API supports HTTP/3 now, and how to set  your apps to use HTTP/3.</p>
<p>The post <a rel="NOFOLLOW" href="https://feeds.feedblitz.com/~/968937662/0/baeldung~HTTP-Support-in-HTTP-Client-API-in-Java">HTTP/3 Support in HTTP Client API in Java 26</a> first appeared on <a rel="NOFOLLOW" href="https://www.baeldung.com">Baeldung</a>.</p><div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/968937662/baeldung"><img height="20" src="https://assets.feedblitz.com/i/fblike20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Pin it!" href="https://feeds.feedblitz.com/_/29/968937662/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2024%2f07%2fJava-Featured-13-1024x536.jpg"><img height="20" src="https://assets.feedblitz.com/i/pinterest20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Post to X.com" href="https://feeds.feedblitz.com/_/24/968937662/baeldung"><img height="20" src="https://assets.feedblitz.com/i/x.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by email" href="https://feeds.feedblitz.com/_/19/968937662/baeldung"><img height="20" src="https://assets.feedblitz.com/i/email20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by RSS" href="https://feeds.feedblitz.com/_/20/968937662/baeldung"><img height="20" src="https://assets.feedblitz.com/i/rss20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a rel="NOFOLLOW" title="View Comments" href="https://www.baeldung.com/java-httpclient-http-3-quic#respond"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/comments20.png"></a>&#160;<a title="Follow Comments via RSS" href="https://www.baeldung.com/java-httpclient-http-3-quic/feed"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/commentsrss20.png"></a>&#160;</div>]]>
</description>
										<content:encoded><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-13-1024x536.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="float: left; margin-right: 5px;" decoding="async" loading="lazy" srcset="https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-13-1024x536.jpg 1024w, https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-13-300x157.jpg 300w, https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-13-768x402.jpg 768w, https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-13-100x52.jpg 100w, https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-13.jpg 1200w" sizes="auto, (max-width: 580px) 100vw, 580px" /><h2 id="bd-overview" data-id="overview">1. Overview</h2>
<div class="bd-anchor" id="overview"></div>
<p>Modern applications demand faster, more reliable, and more secure network communication, and HTTP/3 addresses these requirements.</p>
<p>Java introduced the modern HttpClient API in Java 11 to replace the legacy <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-http-url-connection">HttpURLConnection</a> API and provide built-in support for <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://en.wikipedia.org/wiki/HTTP/2">HTTP/2</a>, asynchronous communication, and <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/rest-vs-websockets#descriptions">WebSocket</a> integration. <strong>With Java 26, the HttpClient API continues its evolution by adding support for HTTP/3.</strong></p>
<p>In this tutorial, we&#8217;ll explore how Java 26 extends the HttpClient API with HTTP/3 support and use it to build a Java application.</p>
<h2 id="bd-what-is-http3" data-id="what-is-http3">2. What Is HTTP/3?</h2>
<div class="bd-anchor" id="what-is-http3"></div>
<p>As the name suggests, <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://httpwg.org/specs/rfc9114.html">HTTP version 3, or simply HTTP/3</a>, is the newer version of the Hypertext Transfer Protocol.</p>
<p><strong>HTTP/3 delivers significant improvements in performance, reliability, and security by replacing <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/cs/udp-vs-tcp">TCP</a> with Quick UDP Internet Connections (QUIC) as its transport layer.</strong> QUIC combines the transport and TLS 1.3 handshake into a single round trip, which cuts connection setup time compared to TCP. It&#8217;s particularly effective on high-latency and mobile networks.</p>
<p>QUIC streams are independent, so a lost packet affects only that stream, whereas other streams continue without interruption. Most modern <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://caniuse.com/http3">browsers now support HTTP/3</a> and use it automatically when a server advertises it.</p>
<h2 id="bd-using-http3-in-java-26" data-id="using-http3-in-java-26">3. Using HTTP/3 in Java 26</h2>
<div class="bd-anchor" id="using-http3-in-java-26"></div>
<p>We can continue using the same high-level HTTP Client API while the runtime handles protocol negotiation internally.</p>
<h3 id="bd-1-declaring-http3" data-id="1-declaring-http3">3.1. Declaring HTTP/3</h3>
<div class="bd-anchor" id="1-declaring-http3"></div>
<p>Before we send an HTTP request, we first create an instance of an <em>HttpClient</em>. <strong><em>HttpClient </em>instances can be configured and created via their builder</strong><strong>:</strong></p>
<pre><code class="language-java">public Http3Demo() {
    this.client = HttpClient.newBuilder()
      .version(HttpClient.Version.HTTP_3)
      .build();
}</code></pre>
<p>When we call <em>.version(HttpClient.Version.HTTP_3)</em>, we instruct the client to prefer HTTP/3 for outgoing requests.<strong> By default, Java 26 uses HTTP/2, so existing applications require no change if we don&#8217;t need HTTP/3.</strong></p>
<h3 id="bd-2-protocol-discovery" data-id="2-protocol-discovery">3.2. Protocol Discovery</h3>
<div class="bd-anchor" id="2-protocol-discovery"></div>
<p><strong>If we set the client to use HTTP/3, the client needs to discover whether the server supports it.</strong> As HTTP/3 runs over QUIC, a UDP-based transport, whereas HTTP/1.1 and HTTP/2 run over TCP, the client can&#8217;t upgrade an existing connection to HTTP/3 the way it switches between the older versions.</p>
<p>We choose how the client discovers HTTP/3 per request by setting <em>HttpOption.H3_DISCOVERY</em>. Three modes are supported:</p>
<ul>
<li><em><strong>ANY (default)</strong></em>: The client uses its own algorithm to establish a connection. It may attempt HTTP/3 over QUIC and HTTP over TLS/TCP, using whichever succeeds first.</li>
<li><em><strong>HTTP_3_URI_ONLY</strong></em>: The client attempts HTTP/3 directly at the host and port from the request URI without using Alternative Services. This succeeds only if the server is already listening for HTTP/3 on that port.</li>
<li><em><strong>ALT_SVC</strong></em>: The client relies only on HTTP Alternative Services to discover HTTP/3. Servers advertise HTTP/3 through HTTP Alternative Services, defined in RFC 7838. A server can answer the first request over HTTP/1.1 or HTTP/2 and<strong> include an Alt-Svc header frame that names an h3 endpoint.</strong> The header tells the client that the same resource is available at a given host and port over HTTP/3. Then, <strong>the client can send later requests over HTTP/3.</strong> Alternatively, the server can also advertise HTTP/3 via an HTTP/2 ALTSVC frame.</li>
</ul>
<p>If we don&#8217;t set <em>H3_DISCOVERY</em>, the client uses <em>ANY</em> by default. This option only works when HTTP/3 is the preferred version (set on the client or the request).</p>
<h3 id="bd-3-sending-requests" data-id="3-sending-requests">3.3. Sending Requests</h3>
<div class="bd-anchor" id="3-sending-requests"></div>
<p>Let&#8217;s see this in action. Our <em>fetch() </em>method builds and sends an <em>HttpRequest</em>:</p>
<pre><code class="language-java">public HttpResponse&lt;String&gt; fetch(String url) throws IOException, InterruptedException {
    HttpRequest request = HttpRequest.newBuilder(URI.create(url))
      .GET()
      .setOption(HttpOption.H3_DISCOVERY, HttpOption.Http3DiscoveryMode.HTTP_3_URI_ONLY)
      .build();
    return this.client.send(request, BodyHandlers.ofString());
}</code></pre>
<p>Here, we set the discovery mode using <em>setOption(). </em><strong>We</strong> <strong>use <em>HTTP_3_URI_ONLY </em>to attempt HTTP/3 directly at the server&#8217;s host and port, without waiting for the server to advertise it via <em>Alt-Svc. </em></strong></p>
<p>Note that <em>HttpOption.H3_DISCOVERY</em> takes effect in our example because we set HTTP/3 as the client&#8217;s preferred version. <strong>If neither the client nor the request preferred HTTP/3, the client would ignore <em>H3_DISCOVERY.</em></strong></p>
<p><em>BodyHandlers.ofString()</em> instructs the client to read the response body as a string. The client decodes the response using the charset specified in the <em>Content-Type</em> header, falling back to UTF-8 if no valid charset is provided.</p>
<p>We continue to handle the same checked exceptions we handled with <em>HttpClient: IOException</em> for network or protocol failures, and <em><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-interrupted-exception">InterruptedException</a> (</em>because the <em>send() </em>method blocks the calling thread).</p>
<h2 id="bd-protocol-selection-and-error-handling" data-id="protocol-selection-and-error-handling">4. Protocol Selection and Error Handling</h2>
<div class="bd-anchor" id="protocol-selection-and-error-handling"></div>
<p>Setting HTTP/3 preference doesn&#8217;t guarantee the client will use it. Let&#8217;s discuss how the client picks a protocol version and how it informs us it can&#8217;t use HTTP/3.</p>
<h3 id="bd-1-how-the-client-chooses-the-protocol-version" data-id="1-how-the-client-chooses-the-protocol-version">4.1. How the Client Chooses the Protocol Version</h3>
<div class="bd-anchor" id="1-how-the-client-chooses-the-protocol-version"></div>
<p>As with HTTP/2, several factors decide the actual protocol version for each request.</p>
<p>HTTP/3 stays off by default. We turn it on by setting the preferred version to HTTP/3 when building the client or an individual request. Once HTTP/3 is enabled, the discovery mode guides how the client establishes the exchange. If we don&#8217;t set the mode, the client uses the default mode.</p>
<p>However, there are exceptions that can override our preference:</p>
<ul>
<li><strong>The client never sends a request over HTTP/3 unless the URI uses the <em>https</em> scheme. </strong></li>
<li><strong>It also skips HTTP/3 when a proxy is used. </strong></li>
</ul>
<h3 id="bd-2-handling-unsupportedprotocolversionexception" data-id="2-handling-unsupportedprotocolversionexception">4.2. Handling <em>UnsupportedProtocolVersionException</em></h3>
<div class="bd-anchor" id="2-handling-unsupportedprotocolversionexception"></div>
<p>Sometimes, a client doesn&#8217;t support HTTP/3<em>. </em>Such a client may throw an <em>UnsupportedProtocolVersionException:</em></p>
<ul>
<li>when building the client with HTTP/3 as its preferred version</li>
<li>when sending a request that enables HTTP/3 but has the discovery mode set to <em>HTTP_3_URI_ONLY</em></li>
</ul>
<p>Since our example uses <em>HTTP_3_URI_ONLY</em>, production code should account for this exception around the <em>send() </em>call, alongside the<em> IOException </em>and<em> InterruptedException </em>we already handle.</p>
<h2 id="bd-verifying-http3-support-with-unit-tests" data-id="verifying-http3-support-with-unit-tests">5. Verifying HTTP/3 Support With Unit Tests</h2>
<div class="bd-anchor" id="verifying-http3-support-with-unit-tests"></div>
<p>Let&#8217;s verify that our HTTP/3 client handles both supported and unsupported scenarios.</p>
<h3 id="bd-1-verifying-a-valid-http3-endpoint" data-id="1-verifying-a-valid-http3-endpoint">5.1. Verifying a Valid HTTP/3 Endpoint</h3>
<div class="bd-anchor" id="1-verifying-a-valid-http3-endpoint"></div>
<p>Let&#8217;s send a request to <em>https://cloudflare-quic.com/</em>, a public endpoint that Cloudflare provides for HTTP/3 experiments:</p>
<pre><code class="language-java">@Test
void givenValidHttpsUrl_whenFetch_thenReturnsResponseBody() {
    HttpResponse&lt;String&gt; response;
    try {
        response = new Http3Demo().fetch(HTTP3_URL);
    } catch (IOException | InterruptedException e) {
        Assumptions.abort("Skipping: cloudflare-quic.com unreachable in this environment - " + e.getMessage());
        return;
    }
    assertEquals(200, response.statusCode());
    assertEquals(HttpClient.Version.HTTP_3, response.version());
}</code></pre>
<p>We call the endpoint with <em>Http3Demo.fetch() </em>and expect a successful <em>200 OK</em> response. Then, we use <em>response.version() </em>to verify whether the client successfully negotiated HTTP/3.</p>
<h3 id="bd-2-rejecting-a-plain-http-endpoint" data-id="2-rejecting-a-plain-http-endpoint">5.2. Rejecting a Plain HTTP Endpoint</h3>
<div class="bd-anchor" id="2-rejecting-a-plain-http-endpoint"></div>
<p>In this test, we start a local server using plain HTTP and attempt to fetch it through our HTTP/3 client. We expect the request to throw an<em> UnsupportedProtocolVersionException:</em></p>
<pre><code class="language-java">@Test
void givenPlainHttpUrl_whenFetch_thenThrowsUnsupportedProtocolVersionException() {
    assertThrows(UnsupportedProtocolVersionException.class,() -&gt; new Http3Demo().fetch(
      plainBaseUrl + "/hello"));
}</code></pre>
<p>This happens because HTTP/3 requires a secure HTTPS connection and uses QUIC as its transport protocol, while our local server only supports HTTP.</p>
<h2 id="bd-conclusion" data-id="conclusion">6. Conclusion</h2>
<div class="bd-anchor" id="conclusion"></div>
<p>In this article, we learned about HTTP/3 support in Java 26&#8217;s <em>HttpClient</em>, which we enable by setting the version to HTTP/3 on the builder.</p>
<p>The rest of the <em>HttpClient </em>API stays the same. <strong>HTTP/2 remains the default, so our existing code continues to work without modifications. When the server doesn&#8217;t support HTTP/3, the client can use HTTP/2 or HTTP/1.1 instead in some cases.</strong></p>
<p>The API also supports multiple discovery modes for more control over protocol selection.</p>
<p>As always, the code used in this article is available <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/eugenp/tutorials/tree/master/core-java-modules/core-java-httpclient-2">over on GitHub</a>.</p><p>The post <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-httpclient-http-3-quic">HTTP/3 Support in HTTP Client API in Java 26</a> first appeared on <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com">Baeldung</a>.</p><Img align="left" border="0" height="1" width="1" alt="" style="border:0;float:left;margin:0;padding:0;width:1px!important;height:1px!important;" hspace="0" src="https://feeds.feedblitz.com/~/i/968937662/0/baeldung">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/968937662/baeldung"><img height="20" src="https://assets.feedblitz.com/i/fblike20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Pin it!" href="https://feeds.feedblitz.com/_/29/968937662/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2024%2f07%2fJava-Featured-13-1024x536.jpg"><img height="20" src="https://assets.feedblitz.com/i/pinterest20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Post to X.com" href="https://feeds.feedblitz.com/_/24/968937662/baeldung"><img height="20" src="https://assets.feedblitz.com/i/x.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by email" href="https://feeds.feedblitz.com/_/19/968937662/baeldung"><img height="20" src="https://assets.feedblitz.com/i/email20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by RSS" href="https://feeds.feedblitz.com/_/20/968937662/baeldung"><img height="20" src="https://assets.feedblitz.com/i/rss20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a rel="NOFOLLOW" title="View Comments" href="https://www.baeldung.com/java-httpclient-http-3-quic#respond"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/comments20.png"></a>&#160;<a title="Follow Comments via RSS" href="https://www.baeldung.com/java-httpclient-http-3-quic/feed"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/commentsrss20.png"></a>&#160;</div>]]>
</content:encoded>
					
					<wfw:commentRss>https://feeds.feedblitz.com/~/968937662/0/baeldung~HTTP-Support-in-HTTP-Client-API-in-Java/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<webfeeds:featuredImage>https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-13-150x150.jpg</webfeeds:featuredImage></item>
<item>
<feedburner:origLink>https://www.baeldung.com/spring-ai-mcp-logging</feedburner:origLink>
		<title>MCP Logging in Spring AI</title>
		<link>https://feeds.feedblitz.com/~/968567129/0/baeldung~MCP-Logging-in-Spring-AI</link>
					<comments>https://feeds.feedblitz.com/~/968567129/0/baeldung~MCP-Logging-in-Spring-AI#comments</comments>
		
		<dc:creator><![CDATA[Burak Gökmen]]></dc:creator>
		<pubDate>Sun, 06 Sep 2026 23:19:21 +0000</pubDate>
				<category><![CDATA[Spring AI]]></category>
		<category><![CDATA[MCP]]></category>
		<category><![CDATA[popular]]></category>
		<guid isPermaLink="false">https://www.baeldung.com/?p=204813</guid>
					<description><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-11-1024x536.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="max-width:100% !important;height:auto !important;float: left; margin-right: 5px;" loading="lazy" /><p>Learn about MCP logging in Spring AI,  both in an MCP server and a client.</p>
<p>The post <a rel="NOFOLLOW" href="https://feeds.feedblitz.com/~/968567129/0/baeldung~MCP-Logging-in-Spring-AI">MCP Logging in Spring AI</a> first appeared on <a rel="NOFOLLOW" href="https://www.baeldung.com">Baeldung</a>.</p><div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/968567129/baeldung"><img height="20" src="https://assets.feedblitz.com/i/fblike20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Pin it!" href="https://feeds.feedblitz.com/_/29/968567129/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2024%2f07%2fJava-Featured-11-1024x536.jpg"><img height="20" src="https://assets.feedblitz.com/i/pinterest20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Post to X.com" href="https://feeds.feedblitz.com/_/24/968567129/baeldung"><img height="20" src="https://assets.feedblitz.com/i/x.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by email" href="https://feeds.feedblitz.com/_/19/968567129/baeldung"><img height="20" src="https://assets.feedblitz.com/i/email20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by RSS" href="https://feeds.feedblitz.com/_/20/968567129/baeldung"><img height="20" src="https://assets.feedblitz.com/i/rss20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a rel="NOFOLLOW" title="View Comments" href="https://www.baeldung.com/spring-ai-mcp-logging#comments"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/comments20.png"></a>&#160;<a title="Follow Comments via RSS" href="https://www.baeldung.com/spring-ai-mcp-logging/feed"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/commentsrss20.png"></a>&nbsp;
<div style="clear:left;"><a rel="NOFOLLOW" href="https://www.baeldung.com/spring-ai-mcp-logging#comments"><h3>Comments</h3></a><ul><li><a rel="NOFOLLOW" href="https://www.baeldung.com/spring-ai-mcp-logging#comment-15703">In reply to Hayrullah.   Hey, Hayrullah.   Thanks for the ...</a> <i>by Ulisses Lima</i><li><a rel="NOFOLLOW" href="https://www.baeldung.com/spring-ai-mcp-logging#comment-15702">Thank you for sharing 🙂</a> <i>by Hayrullah</i></ul></div>&#160;</div>]]>
</description>
										<content:encoded><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-11-1024x536.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="float: left; margin-right: 5px;" decoding="async" loading="lazy" srcset="https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-11-1024x536.jpg 1024w, https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-11-300x157.jpg 300w, https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-11-768x402.jpg 768w, https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-11-100x52.jpg 100w, https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-11.jpg 1200w" sizes="auto, (max-width: 580px) 100vw, 580px" /><h2 id="bd-overview" data-id="overview">1. Overview</h2>
<div class="bd-anchor" id="overview"></div>
<p><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-sdk-model-context-protocol">MCP</a> (Model Context Protocol) is an open-source, <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/cs/rest-vs-rpc#2-rpc">JSON-RPC</a>-based (JavaScript Object Notation-Remote Procedure Call) protocol. It provides a standardized way for AI (Artificial Intelligence) applications to connect to external tools, services, and data sources. Therefore, it eliminates the need for custom integrations.</p>
<p>Logging in MCP gives servers a standardized way to send structured, severity-tagged log messages to clients. This might be especially useful while debugging an MCP server.</p>
<p>In this tutorial, we’ll discuss MCP logging in Spring AI. Firstly, we’ll give brief information about MCP logging. Then, we’ll discuss logging both in an MCP server and client.</p>
<h2 id="bd-basic-information-about-mcp-logging" data-id="basic-information-about-mcp-logging">2. Basic Information About MCP Logging</h2>
<div class="bd-anchor" id="basic-information-about-mcp-logging"></div>
<p>An MCP server pushes log messages to an MCP client as <em>notifications/message</em> JSON-RPC notifications<strong>. This one-way notification message from the server to the client contains a severity level, an optional logger name, and the log message</strong>.</p>
<p>The MCP client can send the <em>logging/setLevel</em> JSON-RPC request to the server to configure log-message verbosity. Consequently, <strong>the server only sends log messages that meet or exceed the requested severity level</strong>. The client can dynamically adjust log verbosity by issuing another <em>logging/setLevel</em>.</p>
<p>An important caveat is that <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://modelcontextprotocol.io/specification/2026-07-28/server/utilities/logging">the July 2026 spec revision (2026-07-28)</a> formally deprecated the logging feature along with other features, in favor of newer mechanisms. However, existing implementations will continue to work for at least a year. It’s recommended that newer implementations migrate to using stderr (standard error) for the stdio (standard input/output) transport and <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/spring-boot-opentelemetry-setup">OpenTelemetry</a> for structured observability.</p>
<h2 id="bd-maven-dependencies" data-id="maven-dependencies">3. Maven Dependencies</h2>
<div class="bd-anchor" id="maven-dependencies"></div>
<p>Let’s start by adding the necessary Maven dependencies to our <em>pom.xml</em>:</p>
<pre><code class="language-java">&lt;dependency&gt;
    &lt;groupId&gt;org.springframework.ai&lt;/groupId&gt;
    &lt;artifactId&gt;spring-ai-starter-mcp-client&lt;/artifactId&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
    &lt;groupId&gt;org.springframework.ai&lt;/groupId&gt;
    &lt;artifactId&gt;spring-ai-starter-mcp-server&lt;/artifactId&gt;
&lt;/dependency&gt;</code></pre>
<p>The <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://mvnrepository.com/artifact/org.springframework.ai/spring-ai-starter-mcp-client">MCP client starter</a> dependency enables a Spring AI application to connect to MCP servers and use their tools. On the other hand, we use the <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://mvnrepository.com/artifact/org.springframework.ai/spring-ai-starter-mcp-server">MCP server starter</a> dependency to turn a Spring Boot application into an MCP server. The dependency lets the application expose tools and resources to other LLM (Large Language Model) applications.</p>
<p>We use the <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://mvnrepository.com/artifact/org.springframework.ai/spring-ai-bom">Spring AI BOM</a> (Bill of Materials) to avoid the risk of version conflicts between Spring AI dependencies:</p>
<pre><code class="language-java">&lt;dependencyManagement&gt;
    &lt;dependencies&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;org.springframework.ai&lt;/groupId&gt;
            &lt;artifactId&gt;spring-ai-bom&lt;/artifactId&gt;
            &lt;version&gt;${spring-ai.version}&lt;/version&gt;
            &lt;type&gt;pom&lt;/type&gt;
            &lt;scope&gt;import&lt;/scope&gt;
        &lt;/dependency&gt;
    &lt;/dependencies&gt;
&lt;/dependencyManagement&gt;
</code></pre>
<p><strong>Therefore, we don’t have to specify the versions of MCP starters explicitly</strong>.</p>
<h2 id="bd-logging-on-the-server-side" data-id="logging-on-the-server-side">4. Logging on the Server Side</h2>
<div class="bd-anchor" id="logging-on-the-server-side"></div>
<p>Let’s start by discussing logging in the MCP server. <strong>The server we’ll discuss exposes a tool that an MCP client can run whenever a user requests a password strength evaluation</strong>.</p>
<h3 id="bd-1-tool-implementation" data-id="1-tool-implementation">4.1. Tool Implementation</h3>
<div class="bd-anchor" id="1-tool-implementation"></div>
<p>The <em>PasswordStrengthService</em> class holds the actual tool implementation, the <em>checkStrength()</em> method exposed by the <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/spring-ai-mcp-annotations#exposing-functionality-with-mcptool"><em>@McpTool</em></a> server annotation. It’s a Spring bean since it’s annotated with <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/spring-component-repository-service#service"><em>@Service</em></a>:</p>
<pre><code class="language-java">@Service
public class PasswordStrengthService {
    ...
    @McpTool(name = "check_password_strength", 
      description = "Evaluates password strength and returns a score with recommendations.")
    public PasswordStrengthResult checkStrength(
        @McpToolParam(description = "The password to evaluate", required = true) String password,
	  McpSyncRequestContext ctx) {
        ...
    }
}</code></pre>
<p>The <em>checkStrength()</em> method, i.e., the tool, takes two parameters. The first one is the password to be evaluated. The tool checks whether the password is at least 12 characters long, contains at least one uppercase letter, and contains at least one digit. It also checks whether the password matches common passwords such as <em>&#8220;123456&#8221;</em> or <em>&#8220;qwerty&#8221;</em>.</p>
<p>The second parameter is of type <em>McpSyncRequestContext</em>, which we’ll use for logging. The Spring AI MCP annotations framework injects it automatically. <strong>An MCP server uses an object of this special type to log messages</strong>. It doesn’t write the log messages directly to the stdout (standard output) stream. Instead, it packages them into standard MCP protocol notification payloads and sends them over the transport layer, like stdio or SSE (Server-Sent Events), to the client. We use the stdio transport in our example.</p>
<p><strong>The <em>McpSyncRequestContext</em> interface provides several logging methods such as <em>debug()</em>, <em>info()</em>, <em>warn()</em>, and <em>error()</em></strong>. For example, if the password matches a common password, we log it using the <em>ctx.error(&#8220;Password found in common-password list&#8221;)</em> call in our example:</p>
<pre><code class="language-java">if (COMMON_PASSWORDS.contains(password.toLowerCase())) {
    ctx.error("Password found in common-password list");
    issues.add("commonly used");
}
</code></pre>
<p>Therefore, <strong>on the server side, we can choose the logging level per call</strong>.</p>
<h3 id="bd-2-mcp-server" data-id="2-mcp-server">4.2. MCP Server</h3>
<div class="bd-anchor" id="2-mcp-server"></div>
<p><strong>The <em>McpLoggingServerApplication</em> class provides the Spring Boot entry point for the MCP server process</strong>:</p>
<pre><code class="language-java">@SpringBootApplication
public class McpLoggingServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(McpLoggingServerApplication.class, args);
    }
}
</code></pre>
<p>When the server process starts, Spring AI’s MCP server auto-configuration scans for methods annotated with<em> @McpTool</em>. Then, it registers and exposes the detected tools over the stdio transport. A connected client can therefore discover and call them.</p>
<p><strong>We need to enable the stdio transport in the server’s configuration file</strong>, <em>application-server.properties</em>:</p>
<pre><code class="language-java">spring.ai.mcp.server.stdio=true</code></pre>
<p>Besides, we must prevent the server application from printing logs to stdout. <strong>The stdout stream is dedicated to exchanging the MCP protocol’s JSON-RPC messages</strong>:</p>
<pre><code class="language-java">spring.main.web-application-type=none
spring.main.banner-mode=off
logging.pattern.console=
</code></pre>
<p>Setting <em>spring.main.web-application-type</em> to <em>none</em> prevents Spring Boot from starting a web server. This means that no web-related startup logs are emitted. Setting <em>spring.main.banner-mode</em> to <em>off</em> suppresses the Spring Boot banner that is normally printed to stdout on startup. Finally, <em>logging.pattern.console=</em> strips the pattern formatting in logs.</p>
<h2 id="bd-handling-logs-on-the-client-side" data-id="handling-logs-on-the-client-side">5. Handling Logs on the Client Side</h2>
<div class="bd-anchor" id="handling-logs-on-the-client-side"></div>
<p>Let’s now discuss logging in the MCP client.</p>
<h3 id="bd-1-mcp-client" data-id="1-mcp-client">5.1. MCP Client</h3>
<div class="bd-anchor" id="1-mcp-client"></div>
<p><strong>Similar to <em>McpLoggingServerApplication</em>, the <em>McpLoggingClientApplication</em> class provides the Spring Boot entry point for the MCP client process</strong>:</p>
<pre><code class="language-java">@SpringBootApplication
public class McpLoggingClientApplication {
    public static void main(String[] args) {
        SpringApplication.run(McpLoggingClientApplication.class, args);
    }
}
</code></pre>
<p>On startup, the client boot starter reads the <em>spring.ai.mcp.client.stdio.connections.*</em> properties in the <em>application-client.properties</em> file and launches the server as a child process. For example, the configuration property <em>spring.ai.mcp.client.stdio.connections.password-strength-logging-server.args</em> specifies which arguments the client passes to the server when spawning it. <strong>The <em>stdio</em> segment in these configuration properties selects the stdio transport for the named connection, <em>password-strength-logging-server</em></strong>.</p>
<p>The <em>spring.ai.mcp.client.type=SYNC</em> configuration property selects the synchronous client implementation, i.e., <em>McpSyncClient</em>. Therefore, client calls block until the server responds.</p>
<h3 id="bd-2-logging-handler" data-id="2-logging-handler">5.2. Logging Handler</h3>
<div class="bd-anchor" id="2-logging-handler"></div>
<p><strong>To capture the notification logs sent by the server on the client side, we have to use the <em>@McpLogging</em> client annotation</strong>:</p>
<pre><code class="language-java">@Component public class PasswordStrengthMcpClientHandlers {
    ...
    @McpLogging(clients = "password-strength-logging-server")
    public void handleLoggingMessage(McpSchema.LoggingMessageNotification notification) {
        LOGGER.info("Received server logging notification [{}]: {}"
          , notification.level(), notification.data());
        receivedLogs.add(notification);
    }
    ...
} </code></pre>
<p><em>@McpLogging</em> is a Spring AI MCP annotation that registers a method as a notification handler for a specific MCP client connection. The handler’s name is <em>handleLoggingMessage()</em> in our example. The connection’s name is <em>password-strength-logging-server</em>, which matches the ID configured for the stdio connection in the server’s configuration file, <em>application-server.properties</em>:</p>
<pre><code class="language-java">spring.ai.mcp.server.name= password-strength-logging-server</code></pre>
<p><strong>The handler’s parameter, <em>notification</em>, is the deserialized payload of an MCP logging notification</strong>. Its <em>level()</em> method prints the log severity (e.g., <em>DEBUG</em>, <em>ERROR</em>). Its <em>data()</em> method, on the other hand, contains the actual log sent by the server.</p>
<p>We’ve already seen that the server can choose the logging level per call since the <em>McpSyncRequestContext</em> interface provides several logging methods such as <em>warn()</em> and <em>error()</em>. However, the client can set the server’s logging level. Therefore, <strong>the server can filter out notification messages at a specific level and below</strong>:</p>
<pre><code class="language-java">mcpSyncClient.setLoggingLevel(McpSchema.LoggingLevel.WARNING);</code></pre>
<p>Here, this client-side call instructs the server to filter out anything below <em>WARNING</em>. For example, the server doesn’t send notifications with <em>DEBUG</em> or <em>INFO</em> levels.</p>
<h2 id="bd-an-example" data-id="an-example">6. An Example</h2>
<div class="bd-anchor" id="an-example"></div>
<p>When we send <em>&#8220;</em><em>weak</em><em>&#8220;</em> as the password to be evaluated by the MCP server, the logging handler prints the following list of log messages:</p>
<pre><code class="language-bash">Received server logging notification [WARNING]: Password shorter than recommended 12 characters
Received server logging notification [WARNING]: Password missing uppercase letters
Received server logging notification [WARNING]: Password missing digits
Received server logging notification [INFO]: Final score: 25
</code></pre>
<p>This is expected since the password <em>&#8220;</em><em>weak</em><em>&#8220;</em> is shorter than 12 characters and doesn’t contain uppercase letters and digits. It only satisfies the common password criterion. Therefore, it gets a final score of <em>25</em> out of <em>100</em>.</p>
<p>Our example consists of only an MCP server and client. But if the client were an LLM-orchestrated agent, a list of transactions similar to the following list would have occurred:</p>
<ul>
<li>User -&gt; Client: The user asks the following question: <em>&#8220;How strong is the password weak?&#8221;</em></li>
<li>Client -&gt; LLM: The client sends the user’s message to the LLM together with the tool information received from the MCP server at session start</li>
<li>LLM -&gt; Client: The LLM doesn’t call the server itself. Instead, it returns a response that indicates that it wants to call the tool <em>checkStrength</em> with <em>password=weak</em></li>
<li>Client -&gt; Server: The client issues the actual JSON-RPC request over the stdio transport</li>
<li>Server -&gt; Client: The server returns the response we saw earlier as a JSON-RPC response</li>
<li>Client -&gt; LLM: The client forwards the tool result back to the conversation and asks the LLM to continue</li>
<li>LLM –&gt; User: The LLM generates a natural-language answer synthesizing the structured result from the tool, something like: <em>&#8220;That password is very weak. It&#8217;s only 4 characters long — you&#8217;ll need at least 12 — and it doesn&#8217;t include any uppercase letters or digits. I can make suggestions if you like.</em><em>&#8220;</em></li>
</ul>
<h2 id="bd-conclusion" data-id="conclusion">7. Conclusion</h2>
<div class="bd-anchor" id="conclusion"></div>
<p>In this article, we discussed MCP logging in Spring AI. Firstly, we learned about how logging works within the MCP ecosystem. Then, we examined the details of MCP logging on an MCP server evaluating a password’s strength. We saw that we can use the logging methods in the <em>McpSyncRequestContext</em> interface to print log messages at different severity levels.</p>
<p>Then, we discussed logging on the MCP client. We learned that we can use a handler annotated with <em>@McpLogging</em> for handling logs. Finally, we saw an example using the server and client and discussed the interaction between an LLM, the client, and the server when a user asks for an evaluation of a password’s strength.</p>
<p>As usual, the complete source code for the examples is available <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/eugenp/tutorials/tree/master/spring-ai-modules/spring-ai-mcp-logging">over on GitHub</a>.</p><p>The post <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/spring-ai-mcp-logging">MCP Logging in Spring AI</a> first appeared on <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com">Baeldung</a>.</p><Img align="left" border="0" height="1" width="1" alt="" style="border:0;float:left;margin:0;padding:0;width:1px!important;height:1px!important;" hspace="0" src="https://feeds.feedblitz.com/~/i/968567129/0/baeldung">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/968567129/baeldung"><img height="20" src="https://assets.feedblitz.com/i/fblike20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Pin it!" href="https://feeds.feedblitz.com/_/29/968567129/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2024%2f07%2fJava-Featured-11-1024x536.jpg"><img height="20" src="https://assets.feedblitz.com/i/pinterest20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Post to X.com" href="https://feeds.feedblitz.com/_/24/968567129/baeldung"><img height="20" src="https://assets.feedblitz.com/i/x.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by email" href="https://feeds.feedblitz.com/_/19/968567129/baeldung"><img height="20" src="https://assets.feedblitz.com/i/email20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by RSS" href="https://feeds.feedblitz.com/_/20/968567129/baeldung"><img height="20" src="https://assets.feedblitz.com/i/rss20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a rel="NOFOLLOW" title="View Comments" href="https://www.baeldung.com/spring-ai-mcp-logging#comments"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/comments20.png"></a>&#160;<a title="Follow Comments via RSS" href="https://www.baeldung.com/spring-ai-mcp-logging/feed"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/commentsrss20.png"></a>&nbsp;
<div style="clear:left;"><a rel="NOFOLLOW" href="https://www.baeldung.com/spring-ai-mcp-logging#comments"><h3>Comments</h3></a><ul><li><a rel="NOFOLLOW" href="https://www.baeldung.com/spring-ai-mcp-logging#comment-15703">In reply to Hayrullah.   Hey, Hayrullah.   Thanks for the ...</a> <i>by Ulisses Lima</i><li><a rel="NOFOLLOW" href="https://www.baeldung.com/spring-ai-mcp-logging#comment-15702">Thank you for sharing 🙂</a> <i>by Hayrullah</i></ul></div>&#160;</div>]]>
</content:encoded>
					
					<wfw:commentRss>https://feeds.feedblitz.com/~/968567129/0/baeldung~MCP-Logging-in-Spring-AI/feed</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
		<webfeeds:featuredImage>https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-11-150x150.jpg</webfeeds:featuredImage></item>
<item>
<feedburner:origLink>https://www.baeldung.com/java-weekly-662</feedburner:origLink>
		<title>Java Weekly, Issue 662</title>
		<link>https://feeds.feedblitz.com/~/968560595/0/baeldung~Java-Weekly-Issue</link>
					<comments>https://feeds.feedblitz.com/~/968560595/0/baeldung~Java-Weekly-Issue#respond</comments>
		
		<dc:creator><![CDATA[baeldung]]></dc:creator>
		<pubDate>Sun, 06 Sep 2026 09:25:19 +0000</pubDate>
				<category><![CDATA[Weekly Review]]></category>
		<category><![CDATA[no-ads]]></category>
		<category><![CDATA[no-after-post]]></category>
		<category><![CDATA[no-before-post]]></category>
		<category><![CDATA[no-optins]]></category>
		<guid isPermaLink="false">https://www.baeldung.com/?p=204825</guid>
					<description><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/2016/10/social-Weekly-Reviews-4.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="max-width:100% !important;height:auto !important;float: left; margin-right: 5px;" loading="lazy" /><p>The three Loom pillars and, more importantly, the tooling. Plus IntelliJ IDEA Conf 2026 getting close.</p>
<p>The post <a rel="NOFOLLOW" href="https://feeds.feedblitz.com/~/968560595/0/baeldung~Java-Weekly-Issue">Java Weekly, Issue 662</a> first appeared on <a rel="NOFOLLOW" href="https://www.baeldung.com">Baeldung</a>.</p><div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/968560595/baeldung"><img height="20" src="https://assets.feedblitz.com/i/fblike20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Pin it!" href="https://feeds.feedblitz.com/_/29/968560595/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2016%2f10%2fsocial-Weekly-Reviews-4.jpg"><img height="20" src="https://assets.feedblitz.com/i/pinterest20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Post to X.com" href="https://feeds.feedblitz.com/_/24/968560595/baeldung"><img height="20" src="https://assets.feedblitz.com/i/x.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by email" href="https://feeds.feedblitz.com/_/19/968560595/baeldung"><img height="20" src="https://assets.feedblitz.com/i/email20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by RSS" href="https://feeds.feedblitz.com/_/20/968560595/baeldung"><img height="20" src="https://assets.feedblitz.com/i/rss20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a rel="NOFOLLOW" title="View Comments" href="https://www.baeldung.com/java-weekly-662#respond"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/comments20.png"></a>&#160;<a title="Follow Comments via RSS" href="https://www.baeldung.com/java-weekly-662/feed"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/commentsrss20.png"></a>&#160;</div>]]>
</description>
										<content:encoded><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/2016/10/social-Weekly-Reviews-4.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="float: left; margin-right: 5px;" decoding="async" loading="lazy" srcset="https://www.baeldung.com/wp-content/uploads/2016/10/social-Weekly-Reviews-4.jpg 952w, https://www.baeldung.com/wp-content/uploads/2016/10/social-Weekly-Reviews-4-300x157.jpg 300w, https://www.baeldung.com/wp-content/uploads/2016/10/social-Weekly-Reviews-4-768x402.jpg 768w" sizes="auto, (max-width: 580px) 100vw, 580px" /><h2 style="text-align: left;" id="bd-spring-and-java" data-id="spring-and-java">1.<strong> Spring and Java</strong></h2>
<div class="bd-anchor" id="spring-and-java"></div>
<p><strong><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://blog.jetbrains.com/idea/2026/08/project-loom-in-intellij-idea-virtual-threads-scoped-values-and-structured-concurrency/">&gt;&gt; Project Loom in IntelliJ IDEA: Virtual Threads, Scoped Values, and Structured Concurrency</a></strong> [<span style="color: #993300;">jetbrains.com</span>]</p>
<p>A hands-on tour of the three Loom pillars: virtual threads, scoped values, and structured concurrency. This show you exactly what each feature buys and the tooling coming along with it. Solid stuff.</p>
<h4><strong>Also worth reading:</strong></h4>
<ul>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.infoq.com/articles/pqc-in-spring-boot/" target="_blank" rel="noopener"><strong>Post-Quantum Cryptography in Spring Boot: Four Patterns You Can Ship This Sprint</strong></a> [<span style="color: #800000;">infoq.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://blog.jetbrains.com/idea/2026/09/the-grails-plugin-has-a-new-home-apache-grails/" target="_blank" rel="noopener"><strong>The Grails Plugin Has a New Home: Apache Grails</strong></a> [<span style="color: #800000;">jetbrains.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.javaspecialists.eu/archive/Issue337-Module-Imports.html" target="_blank" rel="noopener"><strong>Module Imports</strong></a> [<span style="color: #800000;">javaspecialists.eu</span>]</li>
</ul>
<h4><strong>Webinars and presentations:</strong></h4>
<ul>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://inside.java/2026/08/27/podcast-068/" target="_blank" rel="noopener"><strong>Episode 68 “Operator Overloading with Type Classes” [AtA]</strong></a> [<span style="color: #800000;">inside.java</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://spring.io/blog/2026/08/27/a-bootiful-podcast-joe-grandja" target="_blank" rel="noopener"><strong>A Bootiful Podcast: Joe Grandja on Spring Authorization Server, OAuth, and so much more</strong></a> [<span style="color: #800000;">spring.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://spring.io/blog/2026/08/31/spring-office-hours-podcast-S5E21" target="_blank" rel="noopener"><strong>Spring Office Hours Podcast: S5E21 &#8211; Pro Spring Boot 4 with Felipe Gutierrez</strong></a> [<span style="color: #800000;">spring.io</span>]</li>
</ul>
<h4><strong>Time to upgrade:</strong></h4>
<ul>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://blog.jetbrains.com/idea/2026/09/intellij-idea-2026-2-2/" target="_blank" rel="noopener"><strong>IntelliJ IDEA 2026.2.2 Is Out!</strong></a> [<span style="color: #800000;">jetbrains.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://blog.jetbrains.com/kotlin/2026/08/compose-multiplatform-1-12-0/" target="_blank" rel="noopener"><strong>Compose Multiplatform 1.12.0 Released</strong></a> [<span style="color: #800000;">jetbrains.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://quarkus.io/blog/quarkus-flow-1-0-0-released/" target="_blank" rel="noopener"><strong>Quarkus Flow 1.0.0 released</strong></a> [<span style="color: #800000;">quarkus.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://quarkus.io/blog/quarkus-3-39-released/" target="_blank" rel="noopener"><strong>Quarkus 3.39 &#8211; Post-quantum cryptography support in TLS registry</strong></a> [<span style="color: #800000;">quarkus.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.wildfly.org/news/2026/08/27/WildFly-41-0-1-is-released/" target="_blank" rel="noopener"><strong>WildFly 41.0.1 is released!</strong></a> [<span style="color: #800000;">wildfly.org</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/jhipster/generator-jhipster/releases/tag/v9.3.0" target="_blank" rel="noopener"><strong>JHipster v9.3.0</strong></a> [<span style="color: #800000;">github.com/jhipster</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/eclipse-vertx/vert.x/releases/tag/4.5.33" target="_blank" rel="noopener"><strong>Vert.x 4.5.33</strong></a> and <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/eclipse-vertx/vert.x/releases/tag/5.1.7" target="_blank" rel="noopener"><strong>5.1.7</strong></a> [<span style="color: #800000;">github.com/eclipse-vertx</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/elastic/elasticsearch/releases/tag/v9.4.6" target="_blank" rel="noopener"><strong>Elasticsearch 9.4.6</strong></a> and <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/elastic/elasticsearch/releases/tag/v8.19.21" target="_blank" rel="noopener"><strong>8.19.21</strong></a> [<span style="color: #800000;">github.com/elastic</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/Netflix/zuul/releases/tag/v4.1.5" target="_blank" rel="noopener"><strong>Zuul v4.1.5</strong></a> [<span style="color: #800000;">github.com/Netflix</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/micronaut-projects/micronaut-core/releases/tag/v5.1.13" target="_blank" rel="noopener"><strong>Micronaut Core 5.1.13</strong></a> [<span style="color: #800000;">github.com/micronaut-projects</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/helidon-io/helidon/releases/tag/4.5.4" target="_blank" rel="noopener"><strong>Helidon 4.5.4</strong></a> [<span style="color: #800000;">github.com/helidon-io</span>]</li>
</ul>
<h2 style="text-align: left;" id="bd-technical-amp-musings" data-id="technical-amp-musings">2.<strong> Technical &amp; Musings</strong></h2>
<div class="bd-anchor" id="technical-amp-musings"></div>
<p><strong><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://martinfowler.com/rachels-ramblings/code-review.html">&gt;&gt; Maybe We Shouldn’t Be Reviewing All This Code</a></strong> [<span style="color: #993300;">martinfowler.com</span>]</p>
<p>PR sizes really are ballooning, but the fix isn’t automating review away, it’s noticing that we’d been leaning on review to carry things that belongs much earlier in the flow. An interesting weekend read.</p>
<h4><strong>Also worth reading:</strong></h4>
<ul>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://blog.frankel.ch/ai-assisted-genealogy/" target="_blank" rel="noopener"><strong>AI-assisted genealogy</strong></a> [<span style="color: #800000;">frankel.ch</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.allthingsdistributed.com/2026/08/duckdb-and-the-changing-physics-of-analytics.html" target="_blank" rel="noopener"><strong>DuckDB and the changing physics of analytics</strong></a> [<span style="color: #800000;">allthingsdistributed.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://martinfowler.com/articles/making-data-ready-for-agentic-ai.html" target="_blank" rel="noopener"><strong>Making Your Data Ready for Agentic AI</strong></a> [<span style="color: #800000;">martinfowler.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://martinfowler.com/articles/exploring-gen-ai/an-accidental-blackboard.html" target="_blank" rel="noopener"><strong>An Accidental Blackboard</strong></a> [<span style="color: #800000;">martinfowler.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://netflixtechblog.com/maps-netflixs-multimodal-asset-personalization-at-scale-32f96320785e" target="_blank" rel="noopener"><strong>MAPS: Netflix’s Multimodal Asset Personalization at Scale</strong></a> [<span style="color: #800000;">netflixtechblog.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://netflixtechblog.medium.com/running-apache-spark-experiments-in-my-sleep-and-on-a-plane-588816b6b5f8" target="_blank" rel="noopener"><strong>Running Apache Spark experiments in my sleep (and on a plane)</strong></a> [<span style="color: #800000;">netflixtechblog.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://blog.codinghorror.com/you-cant-vibe-code-love/" target="_blank" rel="noopener"><strong>You Can’t “Vibe Code” Love</strong></a> [<span style="color: #800000;">codinghorror.com</span>]</li>
</ul>
<h2 style="text-align: left;" id="bd-pick-of-the-week" data-id="pick-of-the-week">3.<strong> Pick of the Week</strong></h2>
<div class="bd-anchor" id="pick-of-the-week"></div>
<p>And from last week, the <strong>free, fully virtual conference</strong> for our ecosystem:</p>
<p><strong><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/jetbrains-conf-jw-agof" rel="sponsored ">&gt;&gt; IntelliJ IDEA Conf 2026</a></strong> [<span style="color: #993300;">jetbrains.com</span>]</p><p>The post <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-weekly-662">Java Weekly, Issue 662</a> first appeared on <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com">Baeldung</a>.</p><Img align="left" border="0" height="1" width="1" alt="" style="border:0;float:left;margin:0;padding:0;width:1px!important;height:1px!important;" hspace="0" src="https://feeds.feedblitz.com/~/i/968560595/0/baeldung">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/968560595/baeldung"><img height="20" src="https://assets.feedblitz.com/i/fblike20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Pin it!" href="https://feeds.feedblitz.com/_/29/968560595/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2016%2f10%2fsocial-Weekly-Reviews-4.jpg"><img height="20" src="https://assets.feedblitz.com/i/pinterest20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Post to X.com" href="https://feeds.feedblitz.com/_/24/968560595/baeldung"><img height="20" src="https://assets.feedblitz.com/i/x.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by email" href="https://feeds.feedblitz.com/_/19/968560595/baeldung"><img height="20" src="https://assets.feedblitz.com/i/email20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by RSS" href="https://feeds.feedblitz.com/_/20/968560595/baeldung"><img height="20" src="https://assets.feedblitz.com/i/rss20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a rel="NOFOLLOW" title="View Comments" href="https://www.baeldung.com/java-weekly-662#respond"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/comments20.png"></a>&#160;<a title="Follow Comments via RSS" href="https://www.baeldung.com/java-weekly-662/feed"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/commentsrss20.png"></a>&#160;</div>]]>
</content:encoded>
					
					<wfw:commentRss>https://feeds.feedblitz.com/~/968560595/0/baeldung~Java-Weekly-Issue/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<webfeeds:featuredImage>https://www.baeldung.com/wp-content/uploads/2016/10/social-Weekly-Reviews-4-150x150.jpg</webfeeds:featuredImage></item>
<item>
<feedburner:origLink>https://www.baeldung.com/java-embabel-streaming-objects</feedburner:origLink>
		<title>LLM Streaming in the Embabel Agentic AI Framework</title>
		<link>https://feeds.feedblitz.com/~/968282549/0/baeldung~LLM-Streaming-in-the-Embabel-Agentic-AI-Framework</link>
					<comments>https://feeds.feedblitz.com/~/968282549/0/baeldung~LLM-Streaming-in-the-Embabel-Agentic-AI-Framework#respond</comments>
		
		<dc:creator><![CDATA[Igor Dayen]]></dc:creator>
		<pubDate>Wed, 26 Aug 2026 22:02:05 +0000</pubDate>
				<category><![CDATA[Spring AI]]></category>
		<category><![CDATA[Embabel]]></category>
		<guid isPermaLink="false">https://www.baeldung.com/java-embabel-streaming-objects</guid>
					<description><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-14-1024x536.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="Two co-workers; the one on the left is holding up a magnifying glass to an artistic representation of files and folders. The one on the right is looking at a projection of some Java code. In between them there is an office plant. To the left of the image are the words &quot;Java on Baeldung&quot;" style="max-width:100% !important;height:auto !important;float: left; margin-right: 5px;" loading="lazy" /><p>Learn to how to use Embabel AI to automatically parse objects as the data arrive in a stream from the large language model you use in your application.</p>
<p>The post <a rel="NOFOLLOW" href="https://feeds.feedblitz.com/~/968282549/0/baeldung~LLM-Streaming-in-the-Embabel-Agentic-AI-Framework">LLM Streaming in the Embabel Agentic AI Framework</a> first appeared on <a rel="NOFOLLOW" href="https://www.baeldung.com">Baeldung</a>.</p><div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/968282549/baeldung"><img height="20" src="https://assets.feedblitz.com/i/fblike20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Pin it!" href="https://feeds.feedblitz.com/_/29/968282549/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2024%2f07%2fJava-Featured-14-1024x536.jpg"><img height="20" src="https://assets.feedblitz.com/i/pinterest20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Post to X.com" href="https://feeds.feedblitz.com/_/24/968282549/baeldung"><img height="20" src="https://assets.feedblitz.com/i/x.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by email" href="https://feeds.feedblitz.com/_/19/968282549/baeldung"><img height="20" src="https://assets.feedblitz.com/i/email20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by RSS" href="https://feeds.feedblitz.com/_/20/968282549/baeldung"><img height="20" src="https://assets.feedblitz.com/i/rss20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a rel="NOFOLLOW" title="View Comments" href="https://www.baeldung.com/java-embabel-streaming-objects#respond"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/comments20.png"></a>&#160;<a title="Follow Comments via RSS" href="https://www.baeldung.com/java-embabel-streaming-objects/feed"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/commentsrss20.png"></a>&#160;</div>]]>
</description>
										<content:encoded><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-14-1024x536.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="Two co-workers; the one on the left is holding up a magnifying glass to an artistic representation of files and folders. The one on the right is looking at a projection of some Java code. In between them there is an office plant. To the left of the image are the words &quot;Java on Baeldung&quot;" style="float: left; margin-right: 5px;" decoding="async" loading="lazy" srcset="https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-14-1024x536.jpg 1024w, https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-14-300x157.jpg 300w, https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-14-768x402.jpg 768w, https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-14-100x52.jpg 100w, https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-14.jpg 1200w" sizes="auto, (max-width: 580px) 100vw, 580px" /><h2 id="bd-overview" data-id="overview">1. Overview</h2>
<div class="bd-anchor" id="overview"></div>
<p>LLM streaming delivers output token by token as it&#8217;s generated. This reduces latency, as users see the first results in the UI within milliseconds instead of waiting seconds for a complete answer.</p>
<p>For agents with structured output and reasoning-aware agents, <strong>streaming should enable incremental processing:</strong></p>
<ul>
<li><strong>parsing responses into Java objects as they arrive, </strong>and</li>
<li><strong>processing thinking blocks as they arrive as well</strong></li>
</ul>
<p>However, current major frameworks don&#8217;t support these functionalities.</p>
<p>In this tutorial, we&#8217;ll:</p>
<ul>
<li>briefly review the limitations of these frameworks</li>
<li>and show how to use the <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/embabel/embabel-agent">Embabel Agentic AI Framework</a> to process objects and thinking blocks incrementally, as they arrive in a stream</li>
</ul>
<p>We&#8217;ll cover four cases:</p>
<ul>
<li>one object without reasoning</li>
<li>multiple objects without reasoning</li>
<li>multiple objects with reasoning but without tool calls</li>
<li>multiple objects with both reasoning and tool calls</li>
</ul>
<h2 id="bd-structured-streaming-framework-limitations" data-id="structured-streaming-framework-limitations">2. Structured Streaming: Framework Limitations</h2>
<div class="bd-anchor" id="structured-streaming-framework-limitations"></div>
<p>The major Java frameworks for LLM integration, Spring AI and LangChain4j, support streaming at a limited level. We can get a live stream of text as the model generates it, but neither framework turns that stream into a collection of typed objects out of the box.</p>
<p>The Spring AI&#8217;s <em>entity()</em> method, which converts model output into a Java object, works with the blocking <em>call()</em> method but not with <em>stream()</em>. The <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://docs.spring.io/spring-ai/reference/api/chatclient.html">ChatClient API reference</a> spells this out directly: <strong>&#8220;In the future, we will offer a convenience method that will let you return a Java entity with the reactive stream() method. In the meantime, you should use the Structured Output Converter.&#8221; </strong></p>
<p>LangChain4j has the same limitation. Its <em>AiServices</em> allows returning custom POJOs, lists, and enums only for non-streaming calls. For streaming, the return type must be a <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://docs.langchain4j.dev/tutorials/ai-services#streaming"><em>TokenStream</em></a>, which <strong>gives us raw text as it arrives,</strong> plus rich callback hooks, but <strong>doesn&#8217;t provide typed objects as stream output.</strong></p>
<p><strong>In practice, anyone who wants a stream of structured objects with reasoning has to build that functionality themselves, as in this <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/spring-ai-chatclient-stream-response">Baeldung&#8217;s article</a>.</strong> This means choosing an NL-delimited format like JSONL, buffering tokens until a full line is available, parsing each line as JSON, and filtering out any thinking blocks along the way. Implementing this takes time away from the actual project.</p>
<p>This is where <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/embabel/embabel-agent">Embabel</a> Agentic AI comes in handy. It natively provides the desired functionality, which we further explore.</p>
<h2 id="bd-setup" data-id="setup">3. Setup</h2>
<div class="bd-anchor" id="setup"></div>
<p>First, let’s define the necessary Embabel dependencies:</p>
<pre><code class="language-xml">&lt;dependency&gt;
    &lt;groupId&gt;com.embabel.agent&lt;/groupId&gt;
    &lt;artifactId&gt;embabel-agent-starter-anthropic&lt;/artifactId&gt;
    &lt;version&gt;${embabel-agent.version}&lt;/version&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
    &lt;groupId&gt;com.embabel.agent&lt;/groupId&gt;
    &lt;artifactId&gt;embabel-agent-test-internal&lt;/artifactId&gt;
    &lt;version&gt;${embabel-agent.version}&lt;/version&gt;
    &lt;scope&gt;test&lt;/scope&gt;
&lt;/dependency&gt;</code></pre>
<p>The <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://central.sonatype.com/artifact/com.embabel.agent/embabel-agent-starter-anthropic">embabel-agent-starter-anthropic</a> dependency provides the core classes we need to use Anthropic models with Embabel. In the examples in this tutorial, we use the Anthropic model <em>claude-sonnet-4-5.</em></p>
<p>Additionally, we include <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://central.sonatype.com/artifact/com.embabel.agent/embabel-agent-test-internal">embabel-agent-test-internal</a> to use the <em>AgentTestApplication</em> test support class with <em>@SpringBootTest</em>.</p>
<h3 id="bd-1-provider-support-in-embabel" data-id="1-provider-support-in-embabel">3.1. Provider Support in Embabel</h3>
<div class="bd-anchor" id="1-provider-support-in-embabel"></div>
<p>Note that model providers differ in how they combine streaming with thinking and tools. Anthropic&#8217;s native thinking produces explicit reasoning blocks, but other providers may not surface reasoning in the same way.</p>
<p><strong>Embabel supports over a dozen LLM providers, with <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-embabel-ai-agent-tool-call-reasoning">examples using OpenAI</a> published on Baeldung in the past.</strong></p>
<h3 id="bd-2-parkingrecommendation" data-id="2-parkingrecommendation">3.2. <em>ParkingRecommendation</em></h3>
<div class="bd-anchor" id="2-parkingrecommendation"></div>
<p>We&#8217;ll stream <em>ParkingRecommendation</em> objects in all tests throughout the article:</p>
<a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/wp-content/uploads/2026/08/img_6a8c6eb8d416e.svg"><img loading="lazy" decoding="async" class="alignnone wp-image-261115 size-full" src="https://www.baeldung.com/wp-content/uploads/2026/08/img_6a8c6eb8d416e.svg" alt="The ParkingRecommendation record" width="660" height="280" /></a>
<p>The record includes four scalar properties: parking scenario (<em>scenario</em>), chosen option cost (<em>estimatedTotalCost</em>), summary, and chosen option (enumeration <em>Option</em>).</p>
<h2 id="bd-streaming-a-single-object" data-id="streaming-a-single-object">4. Streaming a Single Object</h2>
<div class="bd-anchor" id="streaming-a-single-object"></div>
<div>
<p>First, we show how to stream a single object without reasoning and tool calls. The test method is <em>whenStreaming_thenReceivesParkingRecommendation():</em></p>
<pre><code class="language-java">void whenStreaming_thenReceivesParkingRecommendation() {
     streamParkingRecommendations(PARKING_PROMPT);
  }</code></pre>
<p><em>PARKING_PROMPT</em> asks for a single parking recommendation, and the private method <em>streamParkingRecommendations</em>() does the actual object streaming:</p>
<pre><code class="language-java">Flux&lt;ParkingRecommendation&gt; stream = new StreamingPromptRunnerBuilder(runner)
  .streaming()
  .withPrompt(PARKING_PROMPT)
  .createObjectStream(ParkingRecommendation.class);
stream
  .timeout(Duration.ofSeconds(120))
  .doOnNext(rec -&gt; {
    received.add(rec);
    logger.info(
      "Received parking recommendation: scenario={}, option={}, cost={}, summary={}",
      rec.scenario(),
      rec.chosenOption(),
      rec.estimatedTotalCost(),
      rec.summary());
    }).blockLast(Duration.ofSeconds(240));</code></pre>
<p>Here:</p>
<ul>
<li>We create a <em>Flux&lt;ParkingRecommendation&gt;</em> by calling <em>createObjectStream()</em>. <strong>A <em>Flux</em> is a <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://projectreactor.io/">Reactor</a> type representing an asynchronous sequence of zero or more elements that arrive over time rather than all at once.</strong> In this example, the model emits a <em>ParkingRecommendation</em> object.</li>
<li><em>PARKING_PROMPT</em> instructs the LLM to find the optimal parking option out of three available options: street parking, metered parking, and garage parking. The prompt specifies constraints and costs for each alternative.</li>
<li><strong>The pipeline subscribes with <em>doOnNext()</em> to collect and log each object.</strong></li>
<li><em>blockLast()</em> blocks the calling thread until the stream completes. This is appropriate in a test context, though production code would chain further reactive operators instead of blocking. For example, we would return the <em>Flux</em> directly to a web endpoint that streams the response to the client.</li>
</ul>
<p>We can run the unit test method <em>whenStreaming_thenReceivesParkingRecommendation()</em> like this:</p>
<pre><code class="language-bash">$ mvn test -pl embabel-streaming -P integration -Dtest=StreamingWithThinkingAndToolingIntegrationTest#whenStreaming_thenReceivesParkingRecommendation</code></pre>
<p>After the stream completes, logs confirm the stream delivers a complete <em>ParkingRecommendation </em>object:</p>
<pre><code class="language-plaintext">17:34:13.781 [boundedElastic-1] INFO StreamingWithThinkingAndToolingIntegrationTest - Received recommendation: scenario=Midtown Manhattan parking for 3-hour client meeting with 30-minute arrival buffer, option=GARAGE, cost=90, summary=Choose garage parking. The meeting duration (3 hours) exceeds the metered parking limit (2 hours), eliminating that option. Street parking in Midtown Manhattan is extremely unreliable and searching could make you late for the meeting. The guaranteed spot and ability to stay for the full meeting duration justifies the $90 cost for this professional context.</code></pre>
<p>The object includes all the properties we expect: <em>scenario</em>, <em>chosenOption</em>, <em>estimatedTotalCost</em>, and <em>summary</em>.</p>
<h2 id="bd-streaming-multiple-objects" data-id="streaming-multiple-objects">5. Streaming Multiple Objects</h2>
<div class="bd-anchor" id="streaming-multiple-objects"></div>
<p>The <em>streamParkingRecommendations()</em> method can stream multiple objects. To show it, we request three recommendations with  <em>TIMED_PARKING_PROMPT</em>:</p>
<pre><code class="language-plaintext">void whenStreamingMultipleScenarios_thenReceivesRecommendationPerScenario() {
    streamParkingRecommendations(TIMED_PARKING_PROMPT);
}</code></pre>
<p>When streaming:</p>
<ul>
<li><em>doOnNext()</em> collects and logs each object as it arrives</li>
<li><em>blockLast()</em> waits for the stream to complete</li>
</ul>
<p>We can run the unit test method <em>whenStreamingMultipleScenarios_thenReceivesRecommendationPerScenario</em> like this:</p>
<pre><code class="language-bash">$ mvn test -pl embabel-streaming -P integration -Dtest=StreamingWithThinkingAndToolingIntegrationTest#whenStreamingMultipleScenarios_thenReceivesRecommendationPerScenario</code></pre>
<p><strong>Instead of obtaining a single batched response with all objects, we get each <em>ParkingRecommendation</em> as a separate object as it is received:</strong></p>
<pre><code class="language-plaintext">18:31:24.200 [boundedElastic-1] INFO  StreamingWithThinkingAndToolingIntegrationTest - Received recommendation: scenario=Early morning (before 8am), option=STREET, cost=0, summary=Arrive before 8am to take advantage of free street parking. Meters are not enforced until 8am, providing zero-cost parking. Be prepared to feed the meter or move to a garage if your meeting extends past 8am.
18:31:27.354 [boundedElastic-1] INFO  StreamingWithThinkingAndToolingIntegrationTest - Received recommendation: scenario=Business hours (9am-5pm), option=GARAGE, cost=45, summary=For a 3-hour business meeting with only a 30-minute arrival window, a parking garage is the most reliable option. Street parking in Midtown is extremely competitive during peak hours, and the time spent searching could cause you to miss your meeting. Garage rates typically range $35-55 for 3 hours in Midtown Manhattan.
18:31:28.889 [HttpClient-4-Worker-0] WARN  StreamHelper - Unhandled event type: CONTENT_BLOCK_STOP
18:31:28.895 [boundedElastic-1] INFO  StreamingWithThinkingAndToolingIntegrationTest - Received recommendation: scenario=Evening (after 6pm), option=STREET, cost=0, summary=Street meters become free after 6pm, making this the best option if you're confident your 3-hour meeting will end before 9pm. However, have a backup plan: identify a 24-hour garage nearby in case your meeting runs late, as many garages close at 9pm and you could be locked in or locked out.
</code></pre>
<p>The logged timing of each object creation certifies that complete objects are obtained sequentially and that the collection is filled incrementally.</p>
<p>Note the entry in the log &#8220;Unhandled event type: <em>CONTENT_BLOCK_STOP</em>&#8220;. It just signals &#8220;this content block (a text block, tool call block, etc.) is finished.&#8221; It carries no payload and says that we received a server-side event, but there is no handler wired up for it.</p>
<h2 id="bd-streaming-with-reasoning" data-id="streaming-with-reasoning">6. Streaming with Reasoning</h2>
<div class="bd-anchor" id="streaming-with-reasoning"></div>
<p>First, we must enable deep thinking by configuring <em>LlmOptions</em> with a token budget:</p>
<pre><code class="language-java">void whenStreamingWithThinking_thenReceivesReasoningAndRecommendation() {
    LlmOptions thinkingOptions = new LlmOptions().withThinking(Thinking.withTokenBudget(8000));
    PromptRunner runner = ai.withDefaultLlm().withLlm(thinkingOptions);
    streamParkingRecommendationsWithThinking(runner, TIMED_PARKING_PROMPT);
}</code></pre>
<p>The budget controls how many tokens the model may spend on reasoning before producing the answer, and it must be lower than <em>max_tokens</em> (8192 for <em>claude-sonnet-4-5</em>).</p>
<p>Objects are streamed in the private method <em>streamParkingRecommendationsWithThinking()</em>. <strong>It uses <em>createObjectStreamWithThinking()</em> instead of <em>createObjectStream()</em></strong><em>, </em>and the return type changes accordingly:</p>
<pre><code class="language-java">Flux&lt;StreamingEvent&lt;ParkingRecommendation&gt;&gt; stream = new StreamingPromptRunnerBuilder(runner)
  .streaming()
  .withPrompt(prompt)
  .createObjectStreamWithThinking(ParkingRecommendation.class);</code></pre>
<p><strong><em>StreamingEvent</em> wraps typed objects and reasoning fragments, as the stream interleaves both kinds of events.</strong> The <em>doOnNext()</em> callback distinguishes them via the <em>event.isObject()</em> and <em>event.isThinking() </em>checks, collecting them into separate lists, <em>received</em> for objects and <em>reasoning</em> for thinking fragments:</p>
<pre><code class="language-java">.doOnNext(event -&gt; {
  if (event.isObject()) {
      ParkingRecommendation rec = event.getObject();
      if (rec != null) {
          received.add(rec);
          logger.info("Received recommendation: scenario={}, option={}, cost={}, summary={}",
            rec.scenario(), rec.chosenOption(), rec.estimatedTotalCost(), rec.summary());
      }
  } else if (event.isThinking()) {
      reasoning.add(event.getThinking());
      logger.info("Received reasoning: {}", event.getThinking());
  }
})</code></pre>
<p>We can run the unit test <em>whenStreamingWithThinking_thenReceivesReasoningAndRecommendation()</em> as follows:</p>
<pre><code class="language-bash">$ mvn test -pl embabel-streaming -P integration -Dtest=StreamingWithThinkingAndToolingIntegrationTest#whenStreamingWithThinking_thenReceivesReasoningAndRecommendation</code></pre>
<p>Logs demonstrate that recommendations and reasoning fragments are processed as they arrive.</p>
<pre><code class="language-plaintext">21:34:05.311 [boundedElastic-1] INFO  StreamingWithThinkingAndToolingIntegrationTest - Received reasoning: The user is asking for parking recommendations for Midtown Manhattan across three different time scenarios. I need to analyze each scenario and provide recommendations in JSONL format.
21:34:05.311 [boundedElastic-1] INFO  StreamingWithThinkingAndToolingIntegrationTest - Let me think through each scenario:
...
21:34:13.300 [boundedElastic-1] INFO StreamingWithThinkingAndToolingIntegrationTest - Received recommendation: scenario=Early morning (before 8am), option=STREET, cost=0, summary=Street parking is free before 8am in Midtown. Arrive early to secure a spot while meters are not enforced. No cost advantage to using garage or paid meter.
21:34:14.003 [boundedElastic-1] INFO StreamingWithThinkingAndToolingIntegrationTest - Received reasoning: For business hours, considering reliability vs cost. 30-minute window suggests tight schedule, and 3-hour stay during peak hours means garage offers certainty despite higher cost
21:34:16.867 [boundedElastic-1] INFO StreamingWithThinkingAndToolingIntegrationTest - Received recommendation: scenario=Business hours (9am-5pm, 3-hour stay), option=GARAGE, cost=35, summary=During peak business hours with only a 30-minute arrival window, garage parking ($30-40 for 3 hours) provides guaranteed availability and eliminates time spent searching. Street meters ($12-15 for 3 hours) are cheaper but finding spots in Midtown during business hours is challenging and risky given the tight timeline.
21:34:18.275 [boundedElastic-1] INFO StreamingWithThinkingAndToolingIntegrationTest - Received reasoning: Evening scenario has free street parking but garage closure risk. If arriving at 6pm with 3-hour stay, would exit at 9pm exactly when garages close - cutting it too close. Street parking is free and has no closure risk
21:34:19.337 [HttpClient-4-Worker-0] WARN StreamHelper - Unhandled event type: CONTENT_BLOCK_STOP
21:34:19.359 [boundedElastic-1] INFO StreamingWithThinkingAndToolingIntegrationTest - Received recommendation: scenario=Evening (after 6pm, 3-hour stay), option=STREET, cost=0, summary=Street meters are free after 6pm, making this the clear choice. Additionally, with garages closing at 9pm and a 3-hour stay, there's significant risk of garage closure before departure. Street parking eliminates both cost and time constraints.
</code></pre>
<p>Note that each reasoning block represents a single line, as Embabel aggregates mini-chunks into a single line.</p>
<h2 id="bd-streaming-with-tools-and-reasoning" data-id="streaming-with-tools-and-reasoning">7. Streaming with Tools and Reasoning</h2>
<div class="bd-anchor" id="streaming-with-tools-and-reasoning"></div>
<p>Finally, let&#8217;s combine tool calling with streaming and thinking. For a blocking call, the Baeldung article <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-embabel-ai-agent-tool-call-reasoning">LLM Tool Call Reasoning Using Embabel Agentic AI Framework</a> shows how tool calls benefit from LLM reasoning.</p>
<p>The API is very similar to the reasoning use case, except for the tool registration <em>withToolObject(new ParkingTooling())</em> and a logging inspector for observability:</p>
<pre><code class="language-java">void whenStreamingWithThinkingAndTooling_thenReceivesRecommendationAndReasoning() {
    PromptRunner runner = ai.withDefaultLlm()
      .withToolObject(new ParkingTooling())
      .withToolCallInspectors(new ToolCallLoggingInspector(LogLevel.INFO, logger));
    streamParkingRecommendationsWithThinking(runner, TOOL_PARKING_PROMPT);
}</code></pre>
<p><em>TOOL_PARKING_PROMPT</em> instructs the model to actively use the tools before giving three recommendations, and the <em>streamParkingRecommendationsWithThinking()</em> method streams them.</p>
<p>The pipeline uses the same <em>createObjectStreamWithThinking()</em> and the same <em>event.isObject() / event.isThinking()</em> pattern. The key difference is tool call timing: <strong>the model first calls tools, then reasons over the results, then emits the objects, and finally provides a reasoning summary. </strong>As Spring AI starts a new stream after all tool calls are complete, the reasoning blocks are emitted only after tool calls.</p>
<p>We can run the unit test <em>whenStreamingWithThinkingAndTooling_thenReceivesRecommendationAndReasoning()</em> like this:</p>
<pre><code class="language-bash">$ mvn test -pl embabel-streaming -P integration -Dtest=StreamingWithThinkingAndToolingIntegrationTest#whenStreamingWithThinkingAndTooling_thenReceivesRecommendationAndReasoning</code></pre>
<pre><code class="language-plaintext">12:48:52.342 [HttpClient-4-Worker-0] WARN  StreamHelper - Unhandled event type: CONTENT_BLOCK_STOP
12:48:53.275 [boundedElastic-2] INFO  StreamingWithThinkingAndToolingIntegrationTest - beforeToolCall: tool=reserveGarage, argsLength=28
12:48:53.278 [boundedElastic-2] INFO  Embabel - [suspicious_tharp] calling tool reserveGarage({"arg0":"Midtown Manhattan"})
12:48:53.281 [boundedElastic-2] INFO  Embabel - [suspicious_tharp] tool reserveGarage returned Garage reserved near Midtown Manhattan ($30/hour, guaranteed) in 2ms with payload {"arg0":"Midtown Manhattan"}
12:48:53.284 [boundedElastic-2] INFO  StreamingWithThinkingAndToolingIntegrationTest - afterToolCall: tool=reserveGarage, status=Text, resultLength=61, durationMs=6
12:48:55.299 [boundedElastic-3] INFO  StreamingWithThinkingAndToolingIntegrationTest - beforeToolCall: tool=findStreetParking, argsLength=38
12:48:55.299 [boundedElastic-3] INFO  Embabel - [suspicious_tharp] calling tool findStreetParking({"arg1":30,"arg0":"Midtown Manhattan"})
12:48:55.300 [boundedElastic-3] INFO  Embabel - [suspicious_tharp] tool findStreetParking returned Street parking found near Midtown Manhattan (free) in 1ms with payload {"arg1":30,"arg0":"Midtown Manhattan"}
12:48:55.300 [boundedElastic-3] INFO  StreamingWithThinkingAndToolingIntegrationTest - afterToolCall: tool=findStreetParking, status=Text, resultLength=50, durationMs=1
12:48:56.953 [boundedElastic-4] INFO  StreamingWithThinkingAndToolingIntegrationTest - beforeToolCall: tool=findMeterParking, argsLength=38
12:48:56.954 [boundedElastic-4] INFO  Embabel - [suspicious_tharp] calling tool findMeterParking({"arg1":30,"arg0":"Midtown Manhattan"})
12:48:56.954 [boundedElastic-4] INFO  Embabel - [suspicious_tharp] tool findMeterParking returned No metered parking found within 30 minutes in 0ms with payload {"arg1":30,"arg0":"Midtown Manhattan"}
12:48:56.954 [boundedElastic-4] INFO  StreamingWithThinkingAndToolingIntegrationTest - afterToolCall: tool=findMeterParking, status=Text, resultLength=42, durationMs=1
12:48:58.801 [boundedElastic-1] INFO  StreamingWithThinkingAndToolingIntegrationTest - Received reasoning: I'll help you find the best parking options for your client meeting in Midtown Manhattan. Let me check all available parking options for you.Based on the parking options available, here are my three recommendations with the best option first:
12:49:00.945 [boundedElastic-1] INFO  StreamingWithThinkingAndToolingIntegrationTest - Received recommendation: scenario=Advisor needs guaranteed parking for 3-hour meeting in 30 minutes, option=GARAGE, cost=90, summary=Reserve garage parking at $30/hour for 3 hours ($90 total). This is the BEST option because it's guaranteed and ensures you won't be late for your client meeting. With only 30 minutes until the meeting, reliability is critical.
12:49:03.093 [boundedElastic-1] INFO  StreamingWithThinkingAndToolingIntegrationTest - Received recommendation: scenario=Advisor needs guaranteed parking for 3-hour meeting in 30 minutes, option=STREET, cost=0, summary=Free street parking is available but highly risky. While it costs nothing, finding a spot is uncertain and time-consuming in Midtown Manhattan. Given that arriving late is not acceptable and you only have 30 minutes, this option could jeopardize your meeting.
12:49:03.706 [boundedElastic-1] INFO  StreamingWithThinkingAndToolingIntegrationTest - Received recommendation: scenario=Advisor needs guaranteed parking for 3-hour meeting in 30 minutes, option=METER, cost=0, summary=Metered parking is NOT available within your 30-minute timeframe in Midtown Manhattan. This option is not viable for your situation.
12:49:05.244 [HttpClient-4-Worker-0] WARN  StreamHelper - Unhandled event type: CONTENT_BLOCK_STOP
12:49:05.247 [boundedElastic-1] INFO  StreamingWithThinkingAndToolingIntegrationTest - Received reasoning: **Strong Recommendation: Choose the garage parking.** With only 30 minutes before your client meeting and the absolute requirement not to be late, the $90 guaranteed garage spot is the only responsible choice. The cost is a small price compared to the professional consequences of arriving late to a client meeting.
</code></pre>
<p>Similar to <em>whenStreamingWithThinking_thenReceivesReasoningAndRecommendation(),</em> the stream delivers both a recommendation and a reasoning block (after the tools do their tasks).</p>
<h2 id="bd-conclusion" data-id="conclusion">8. Conclusion</h2>
<div class="bd-anchor" id="conclusion"></div>
<p>In this article, we showed how to use the Embabel Fluent API to produce a stream of typed Java objects, with thinking and tool results handled transparently.</p>
<p>Streaming raw text is straightforward in both Spring AI and LangChain4j, but streaming typed objects is not something either framework handles out of the box. <strong>Embabel addresses this at the framework level, removing the need to manually buffer tokens, parse NDJSON, or filter reasoning blocks.</strong> The same pattern scales from a single object to a collection and from a simple prompt to a multi-tool reasoning chain. For applications where both structure and responsiveness matter, this removes a layer of boilerplate that would otherwise fall on every team building agentic AI applications.</p>
<p>The article code is available on <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/eugenp/tutorials/tree/master/embabel-modules">GitHub</a>.</p>
</div><p>The post <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-embabel-streaming-objects">LLM Streaming in the Embabel Agentic AI Framework</a> first appeared on <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com">Baeldung</a>.</p><Img align="left" border="0" height="1" width="1" alt="" style="border:0;float:left;margin:0;padding:0;width:1px!important;height:1px!important;" hspace="0" src="https://feeds.feedblitz.com/~/i/968282549/0/baeldung">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/968282549/baeldung"><img height="20" src="https://assets.feedblitz.com/i/fblike20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Pin it!" href="https://feeds.feedblitz.com/_/29/968282549/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2024%2f07%2fJava-Featured-14-1024x536.jpg"><img height="20" src="https://assets.feedblitz.com/i/pinterest20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Post to X.com" href="https://feeds.feedblitz.com/_/24/968282549/baeldung"><img height="20" src="https://assets.feedblitz.com/i/x.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by email" href="https://feeds.feedblitz.com/_/19/968282549/baeldung"><img height="20" src="https://assets.feedblitz.com/i/email20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by RSS" href="https://feeds.feedblitz.com/_/20/968282549/baeldung"><img height="20" src="https://assets.feedblitz.com/i/rss20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a rel="NOFOLLOW" title="View Comments" href="https://www.baeldung.com/java-embabel-streaming-objects#respond"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/comments20.png"></a>&#160;<a title="Follow Comments via RSS" href="https://www.baeldung.com/java-embabel-streaming-objects/feed"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/commentsrss20.png"></a>&#160;</div>]]>
</content:encoded>
					
					<wfw:commentRss>https://feeds.feedblitz.com/~/968282549/0/baeldung~LLM-Streaming-in-the-Embabel-Agentic-AI-Framework/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<webfeeds:featuredImage>https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-14-150x150.jpg</webfeeds:featuredImage></item>
<item>
<feedburner:origLink>https://www.baeldung.com/java-weekly-661</feedburner:origLink>
		<title>Java Weekly, Issue 661</title>
		<link>https://feeds.feedblitz.com/~/968274254/0/baeldung~Java-Weekly-Issue</link>
					<comments>https://feeds.feedblitz.com/~/968274254/0/baeldung~Java-Weekly-Issue#respond</comments>
		
		<dc:creator><![CDATA[baeldung]]></dc:creator>
		<pubDate>Wed, 26 Aug 2026 17:15:42 +0000</pubDate>
				<category><![CDATA[Weekly Review]]></category>
		<category><![CDATA[no-ads]]></category>
		<category><![CDATA[no-after-post]]></category>
		<category><![CDATA[no-before-post]]></category>
		<category><![CDATA[no-optins]]></category>
		<guid isPermaLink="false">https://www.baeldung.com/?p=204768</guid>
					<description><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/2016/10/social-Weekly-Reviews-4.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="max-width:100% !important;height:auto !important;float: left; margin-right: 5px;" loading="lazy" /><p>IntelliJ IDEA Conf is back, JDK 27 got its first RC and JDK 28 is already looking solid</p>
<p>The post <a rel="NOFOLLOW" href="https://feeds.feedblitz.com/~/968274254/0/baeldung~Java-Weekly-Issue">Java Weekly, Issue 661</a> first appeared on <a rel="NOFOLLOW" href="https://www.baeldung.com">Baeldung</a>.</p><div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/968274254/baeldung"><img height="20" src="https://assets.feedblitz.com/i/fblike20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Pin it!" href="https://feeds.feedblitz.com/_/29/968274254/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2016%2f10%2fsocial-Weekly-Reviews-4.jpg"><img height="20" src="https://assets.feedblitz.com/i/pinterest20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Post to X.com" href="https://feeds.feedblitz.com/_/24/968274254/baeldung"><img height="20" src="https://assets.feedblitz.com/i/x.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by email" href="https://feeds.feedblitz.com/_/19/968274254/baeldung"><img height="20" src="https://assets.feedblitz.com/i/email20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by RSS" href="https://feeds.feedblitz.com/_/20/968274254/baeldung"><img height="20" src="https://assets.feedblitz.com/i/rss20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a rel="NOFOLLOW" title="View Comments" href="https://www.baeldung.com/java-weekly-661#respond"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/comments20.png"></a>&#160;<a title="Follow Comments via RSS" href="https://www.baeldung.com/java-weekly-661/feed"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/commentsrss20.png"></a>&#160;</div>]]>
</description>
										<content:encoded><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/2016/10/social-Weekly-Reviews-4.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="float: left; margin-right: 5px;" decoding="async" loading="lazy" srcset="https://www.baeldung.com/wp-content/uploads/2016/10/social-Weekly-Reviews-4.jpg 952w, https://www.baeldung.com/wp-content/uploads/2016/10/social-Weekly-Reviews-4-300x157.jpg 300w, https://www.baeldung.com/wp-content/uploads/2016/10/social-Weekly-Reviews-4-768x402.jpg 768w" sizes="auto, (max-width: 580px) 100vw, 580px" /><h2 style="text-align: left;" id="bd-spring-and-java" data-id="spring-and-java">1.<strong> Spring and Java</strong></h2>
<div class="bd-anchor" id="spring-and-java"></div>
<p><strong><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.infoq.com/news/2026/08/java-27-so-far/">&gt;&gt; JDK 27 and JDK 28: What We Know So Far</a></strong> [<span style="color: #993300;">infoq.com</span>]</p>
<p>JDK 27 has reached its first RC with compact object headers on by default, G1 as the default collector everywhere, and structured concurrency marching through its seventh preview. <strong>The JDK 28 train</strong> is already loading up, starting with an incubating Simple JSON API <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f680.png" alt="🚀" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<h4><strong>Also worth reading:</strong></h4>
<ul>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://blog.frankel.ch/security-baked-into-jvm/4/" target="_blank" rel="noopener"><strong>Security Baked Into the JVM: sixteen Subjects on the wire</strong></a> [<span style="color: #800000;">frankel.ch</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://foojay.io/today/scripting-in-small-apps-you-dont-need-a-container-for-a-macro/" target="_blank" rel="noopener"><strong>Scripting in small apps: you don’t need a container for a macro</strong></a> [<span style="color: #800000;">foojay.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://foojay.io/today/the-third-generation-gui-builder-one-workspace-for-every-form/" target="_blank" rel="noopener"><strong>The Third-Generation GUI Builder: One Workspace for Every Form</strong></a> [<span style="color: #800000;">foojay.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://johan-sjolen.github.io/post/compiler-sympathy/compiler-sympathy/" target="_blank" rel="noopener"><strong>Value Classes Still Need Compiler Sympathy</strong></a> [<span style="color: #800000;">johan-sjolen.github.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://inside.java/2026/08/21/quality-heads-up/" target="_blank" rel="noopener"><strong>Quality Outreach Heads-up &#8211; JDK 28: Named Group Information Captured in the TLSHandshake JFR Event</strong></a> [<span style="color: #800000;">inside.java</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://blog.jetbrains.com/idea/2026/08/spring-boot-configuration-management-best-practices/" target="_blank" rel="noopener"><strong>Spring Boot Configuration Management Best Practices</strong></a> [<span style="color: #800000;">jetbrains.com</span>]</li>
</ul>
<h4><strong>Webinars and presentations:</strong></h4>
<ul>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://inside.java/2026/08/20/podcast-067/" target="_blank" rel="noopener"><strong>Episode 67 “Keeping Up With the Java Release Train” [I/O]</strong></a> [<span style="color: #800000;">inside.java</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://spring.io/blog/2026/08/20/a-bootiful-podcast-charles-nutter" target="_blank" rel="noopener"><strong>A Bootiful Podcast: JRuby lead Charles Nutter</strong></a> [<span style="color: #800000;">spring.io</span>]</li>
</ul>
<h4><strong>Time to upgrade:</strong></h4>
<ul>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://spring.io/blog/2026/08/20/spring-boot-4-1-1-available-now" target="_blank" rel="noopener"><strong>Spring Boot 4.1.1 available now</strong></a> and <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://spring.io/blog/2026/08/20/spring-boot-4-0-8-available-now" target="_blank" rel="noopener"><strong>4.0.8</strong></a> [<span style="color: #800000;">spring.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://spring.io/blog/2026/08/21/spring-ai-2-0-1-available-now" target="_blank" rel="noopener"><strong>Spring AI 2.0.1 Available Now</strong></a> [<span style="color: #800000;">spring.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://spring.io/blog/2026/08/20/spring-cloud-2025-1-3-has-been-released" target="_blank" rel="noopener"><strong>Spring Cloud 2025.1.3 (aka Oakwood) has been released</strong></a> [<span style="color: #800000;">spring.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://spring.io/blog/2026/08/20/spring-batch-6-0-5-and-6-1-0-M1-available-now" target="_blank" rel="noopener"><strong>Spring Batch 6.0.5 and 6.1.0-M1 available now</strong></a> [<span style="color: #800000;">spring.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://spring.io/blog/2026/08/26/spring-modulith-2-2-m1-2-1-1-2-0-8-and-1-4-13-released" target="_blank" rel="noopener"><strong>Spring Modulith 2.2 M1, 2.1.1, 2.0.8, and 1.4.13 released</strong></a> [<span style="color: #800000;">spring.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://foojay.io/today/boxlang-1-16-0-released/" target="_blank" rel="noopener"><strong>BoxLang 1.16.0 Released!</strong></a> [<span style="color: #800000;">foojay.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://inside.java/2026/08/25/jipher-cryptography-for-java/" target="_blank" rel="noopener"><strong>Announcing Oracle Jipher 10.37: FIPS 140-3 Cryptography for Java</strong></a> [<span style="color: #800000;">inside.java</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/graalvm/graalvm-ce-builds/releases/tag/graal-25.3.4.1" target="_blank" rel="noopener"><strong>GraalVM Community 25 Innovation 3 (graal 25.3.4.1)</strong></a> [<span style="color: #800000;">github.com/graalvm</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/quarkusio/quarkus/releases/tag/3.39.1" target="_blank" rel="noopener"><strong>Quarkus 3.39.1</strong></a> and <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/quarkusio/quarkus/releases/tag/3.39.0" target="_blank" rel="noopener"><strong>3.39.0</strong></a> [<span style="color: #800000;">github.com/quarkusio</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/elastic/elasticsearch/releases/tag/v9.5.2" target="_blank" rel="noopener"><strong>Elasticsearch 9.5.2</strong></a> [<span style="color: #800000;">github.com/elastic</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/apache/grails-core/releases/tag/v7.2.3" target="_blank" rel="noopener"><strong>Grails 7.2.3</strong></a>, <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/apache/grails-core/releases/tag/v7.1.6" target="_blank" rel="noopener"><strong>7.1.6</strong></a> and <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/apache/grails-core/releases/tag/v7.0.16" target="_blank" rel="noopener"><strong>7.0.16</strong></a> [<span style="color: #800000;">github.com/apache</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/micronaut-projects/micronaut-core/releases/tag/v5.1.12" target="_blank" rel="noopener"><strong>Micronaut Core 5.1.12</strong></a> [<span style="color: #800000;">github.com/micronaut-projects</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/payara/Payara/releases/tag/payara-server-7.2026.8" target="_blank" rel="noopener"><strong>Azul Payara Community 7.2026.8</strong></a> [<span style="color: #800000;">github.com/payara</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/micrometer-metrics/micrometer/releases/tag/v1.17.1" target="_blank" rel="noopener"><strong>Micrometer 1.17.1</strong></a> and <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/micrometer-metrics/micrometer/releases/tag/v1.16.7" target="_blank" rel="noopener"><strong>1.16.7</strong></a> [<span style="color: #800000;">github.com/micrometer-metrics</span>]</li>
</ul>
<h2 style="text-align: left;" id="bd-technical-amp-musings" data-id="technical-amp-musings">2.<strong> Technical &amp; Musings</strong></h2>
<div class="bd-anchor" id="technical-amp-musings"></div>
<p><strong><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://netflixtechblog.medium.com/netflix-conductor-the-next-chapter-41ad21067649">&gt;&gt; Netflix Conductor: The Next Chapter</a></strong> [<span style="color: #993300;">netflixtechblog.com</span>]</p>
<p>Netflix open-sourced Conductor back in 2016, and this post traces its evolution into a mature orchestration engine — plus what’s next for the project now that it has a dedicated maintainer team and a renewed roadmap. Good context for anyone running workflow orchestration at scale.</p>
<h4><strong>Also worth reading:</strong></h4>
<ul>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://lucumr.pocoo.org/2026/8/22/fast-hard-code/" target="_blank" rel="noopener"><strong>Fast and Hard Code</strong></a> [<span style="color: #800000;">pocoo.org</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://nurkiewicz.com/2026/08/your-first-virtual-machine-write-yourself-a-compiler.html" target="_blank" rel="noopener"><strong>Your First Virtual Machine: Write yourself a compiler, Part IV</strong></a> [<span style="color: #800000;">nurkiewicz.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://blog.christianposta.com/human-in-the-loop-authorization-patterns-for-agents/" target="_blank" rel="noopener"><strong>Human-in-the-loop Authorization Patterns for Agents</strong></a> [<span style="color: #800000;">christianposta.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://hamvocke.com/blog/git-revisions-by-text/" target="_blank" rel="noopener"><strong>Find Git Commits by Commit Message Text</strong></a> [<span style="color: #800000;">hamvocke.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.satisfice.com/blog/archives/488189" target="_blank" rel="noopener"><strong>This Fact About KPIs May Surprise You</strong></a> [<span style="color: #800000;">satisfice.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://blog.scottlogic.com/2026/08/21/why-agentic-ai-starts-with-legacy-modernisation.html" target="_blank" rel="noopener"><strong>Why agentic AI starts with legacy modernisation by Suzanne Angell</strong></a> [<span style="color: #800000;">scottlogic.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://netflixtechblog.com/a-tale-of-two-flink-autoscalers-e9f6a1b1492b" target="_blank" rel="noopener"><strong>A Tale of Two Flink Autoscalers</strong></a> [<span style="color: #800000;">netflixtechblog.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://blog.tfnico.com/2026/08/some-reflections-after-year-with-ai.html" target="_blank" rel="noopener"><strong>Some reflections after a year with AI</strong></a> [<span style="color: #800000;">tfnico.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.hanselman.com/blog/migrating-a-synology-nas-to-a-unifi-unas-pro-8-with-robocopy-smb-multichannel-and-surprising-performance-traps" target="_blank" rel="noopener"><strong>Migrating a Synology NAS to a UniFi UNAS Pro 8 with Robocopy, SMB Multichannel, and Surprising Performance Traps</strong></a> [<span style="color: #800000;">hanselman.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.troyhunt.com/a-cautionary-tale-about-data-breach-claims-verification-and-carhartt/" target="_blank" rel="noopener"><strong>A Cautionary Tale About Data Breach Claims, Verification and Carhartt</strong></a> [<span style="color: #800000;">troyhunt.com</span>]</li>
</ul>
<h2 style="text-align: left;" id="bd-pick-of-the-week" data-id="pick-of-the-week">3.<strong> Pick of the Week</strong></h2>
<div class="bd-anchor" id="pick-of-the-week"></div>
<p>JetBrains is bringing IntelliJ IDEA Conf back in just one week, on September 8–9, 2026.</p>
<p>A <strong>free, fully virtual conference</strong> for developers working across the Java and JVM ecosystem:</p>
<p><strong><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/jetbrains-conf-jw-agof" rel="sponsored ">&gt;&gt; IntelliJ IDEA Conf 2026</a></strong> [<span style="color: #993300;">jetbrains.com</span>]</p><p>The post <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-weekly-661">Java Weekly, Issue 661</a> first appeared on <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com">Baeldung</a>.</p><Img align="left" border="0" height="1" width="1" alt="" style="border:0;float:left;margin:0;padding:0;width:1px!important;height:1px!important;" hspace="0" src="https://feeds.feedblitz.com/~/i/968274254/0/baeldung">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/968274254/baeldung"><img height="20" src="https://assets.feedblitz.com/i/fblike20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Pin it!" href="https://feeds.feedblitz.com/_/29/968274254/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2016%2f10%2fsocial-Weekly-Reviews-4.jpg"><img height="20" src="https://assets.feedblitz.com/i/pinterest20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Post to X.com" href="https://feeds.feedblitz.com/_/24/968274254/baeldung"><img height="20" src="https://assets.feedblitz.com/i/x.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by email" href="https://feeds.feedblitz.com/_/19/968274254/baeldung"><img height="20" src="https://assets.feedblitz.com/i/email20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by RSS" href="https://feeds.feedblitz.com/_/20/968274254/baeldung"><img height="20" src="https://assets.feedblitz.com/i/rss20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a rel="NOFOLLOW" title="View Comments" href="https://www.baeldung.com/java-weekly-661#respond"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/comments20.png"></a>&#160;<a title="Follow Comments via RSS" href="https://www.baeldung.com/java-weekly-661/feed"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/commentsrss20.png"></a>&#160;</div>]]>
</content:encoded>
					
					<wfw:commentRss>https://feeds.feedblitz.com/~/968274254/0/baeldung~Java-Weekly-Issue/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<webfeeds:featuredImage>https://www.baeldung.com/wp-content/uploads/2016/10/social-Weekly-Reviews-4-150x150.jpg</webfeeds:featuredImage></item>
<item>
<feedburner:origLink>https://www.baeldung.com/java-fix-jackson-json-parse-error</feedburner:origLink>
		<title>How to Fix Jackson JSON Parse Error Can not construct instance of java.time.LocalDate</title>
		<link>https://feeds.feedblitz.com/~/968126756/0/baeldung~How-to-Fix-Jackson-JSON-Parse-Error-Can-not-construct-instance-of-javatimeLocalDate</link>
					<comments>https://feeds.feedblitz.com/~/968126756/0/baeldung~How-to-Fix-Jackson-JSON-Parse-Error-Can-not-construct-instance-of-javatimeLocalDate#respond</comments>
		
		<dc:creator><![CDATA[Hiks Gerganov]]></dc:creator>
		<pubDate>Sat, 22 Aug 2026 23:26:23 +0000</pubDate>
				<category><![CDATA[Jackson]]></category>
		<category><![CDATA[Java Dates]]></category>
		<category><![CDATA[Exception]]></category>
		<category><![CDATA[LocalDate]]></category>
		<guid isPermaLink="false">https://www.baeldung.com/java-fix-jackson-json-parse-error</guid>
					<description><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-11-1024x536.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="max-width:100% !important;height:auto !important;float: left; margin-right: 5px;" loading="lazy" /><p>Learn why sometimes Jackson can't construct an instance of LocalDate or LocalDateTime and how to fix the error it throws.</p>
<p>The post <a rel="NOFOLLOW" href="https://feeds.feedblitz.com/~/968126756/0/baeldung~How-to-Fix-Jackson-JSON-Parse-Error-Can-not-construct-instance-of-javatimeLocalDate">How to Fix Jackson JSON Parse Error <em>Can not construct instance of java.time.LocalDate</em></a> first appeared on <a rel="NOFOLLOW" href="https://www.baeldung.com">Baeldung</a>.</p><div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/968126756/baeldung"><img height="20" src="https://assets.feedblitz.com/i/fblike20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Pin it!" href="https://feeds.feedblitz.com/_/29/968126756/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2024%2f07%2fJava-Featured-11-1024x536.jpg"><img height="20" src="https://assets.feedblitz.com/i/pinterest20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Post to X.com" href="https://feeds.feedblitz.com/_/24/968126756/baeldung"><img height="20" src="https://assets.feedblitz.com/i/x.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by email" href="https://feeds.feedblitz.com/_/19/968126756/baeldung"><img height="20" src="https://assets.feedblitz.com/i/email20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by RSS" href="https://feeds.feedblitz.com/_/20/968126756/baeldung"><img height="20" src="https://assets.feedblitz.com/i/rss20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a rel="NOFOLLOW" title="View Comments" href="https://www.baeldung.com/java-fix-jackson-json-parse-error#respond"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/comments20.png"></a>&#160;<a title="Follow Comments via RSS" href="https://www.baeldung.com/java-fix-jackson-json-parse-error/feed"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/commentsrss20.png"></a>&#160;</div>]]>
</description>
										<content:encoded><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-11-1024x536.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="float: left; margin-right: 5px;" decoding="async" loading="lazy" srcset="https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-11-1024x536.jpg 1024w, https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-11-300x157.jpg 300w, https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-11-768x402.jpg 768w, https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-11-100x52.jpg 100w, https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-11.jpg 1200w" sizes="auto, (max-width: 580px) 100vw, 580px" /><h2 id="bd-overview" data-id="overview">1. Overview</h2>
<div class="bd-anchor" id="overview"></div>
<p>When working with JSON in Java, <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/jackson-object-mapper-tutorial">Jackson</a> usually handles Java 8 date and time types without much configuration. Yet, we can still encounter problems such as one of the common <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-jackson-deserialize-particular-type">deserialization</a> parse errors:</p>
<pre><code class="language-text">JSON parse error: Can not construct instance of java.time.LocalDate:
no String-argument constructor/factory method to deserialize from String value</code></pre>
<p>In newer Jackson versions, the error text takes another form:</p>
<pre><code class="language-text">Cannot deserialize value of type java.time.LocalDate from String</code></pre>
<p>Although the wording differs slightly, both errors indicate that Jackson is unable to convert the JSON value into a <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-creating-localdate-with-values"><em>LocalDate</em></a> or <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-date-to-localdate-and-localdatetime"><em>LocalDateTime</em></a>.</p>
<p>In this tutorial, we&#8217;ll explore the JSON deserialization exception and ways around it. First, we demonstrate the issue with an example. After that, we go through different reasons for the problem at hand and how they can be addressed.</p>
<h2 id="bd-understanding-the-problem" data-id="understanding-the-problem">2. Understanding the Problem</h2>
<div class="bd-anchor" id="understanding-the-problem"></div>
<p>Let&#8217;s write a basic <em>User</em> class:</p>
<pre><code class="language-java">public class User {
    private String name;
    private LocalDate dob;
    // getters and setters
}</code></pre>
<p>Now, let&#8217;s assume we receive a matching JSON:</p>
<pre><code class="language-json">{
  "name": "x",
  "dob": "2006-06-06"
}</code></pre>
<p>Instead of successfully deserializing the JSON, Jackson throws an exception similar to:</p>
<pre><code class="language-text">Can not construct instance of java.time.LocalDate:
no String-argument constructor/factory method to deserialize from String value</code></pre>
<p>Notably, <strong>the JSON data appears to be valid, because the date already follows the ISO-8601 format expected by <em>LocalDate</em></strong>. The problem usually isn&#8217;t the JSON itself but the configuration of Jackson. In fact, the root cause may be a missing Java Time module, an unsupported date format, or using the wrong Java date-time type for the incoming JSON.</p>
<h2 id="bd-verify-jackson-version" data-id="verify-jackson-version">3. Verify Jackson Version</h2>
<div class="bd-anchor" id="verify-jackson-version"></div>
<p>Support for the Java Time API has evolved considerably across Jackson releases. Before delving into specific technical issues and code changes, <strong>we might consider the versions we&#8217;re using</strong>.</p>
<p>In Jackson <em>2.x</em>, Java Time support is provided by the separate <em>jackson-datatype-jsr310</em> module. <strong>In Jackson <em>3.x</em>, this support is built into <em>jackson-databind</em>, so separate module registration isn’t required</strong>.</p>
<p>If the project uses an outdated Jackson version, upgrading Jackson may resolve deserialization issues without any code changes. When it comes to Jackson <em>2.x</em>, we should also verify that the Java Time module is present and properly configured.</p>
<h2 id="bd-ensure-java-time-support" data-id="ensure-java-time-support">4. Ensure Java Time Support</h2>
<div class="bd-anchor" id="ensure-java-time-support"></div>
<p>The most common cause for the JSON error is that the Jackson configuration doesn&#8217;t support the Java 8 Date and Time API.</p>
<p>Unlike older types such as <em>java.util.Date</em>, classes like <em>LocalDate</em>, <em>LocalDateTime</em>, and <em>Instant</em> are provided through the Jackson Java Time module.</p>
<p>If this module is missing, Jackson attempts to instantiate <em>LocalDate</em> like a regular Java object. Since <em>LocalDate</em> has no default constructor or string constructor, deserialization fails.</p>
<p>So, assuming we decide on Jackson <em>2.x</em>, let&#8217;s include the Java Time module dependency:</p>
<pre><code class="language-xml">&lt;dependency&gt;
    &lt;groupId&gt;com.fasterxml.jackson.datatype&lt;/groupId&gt;
    &lt;artifactId&gt;jackson-datatype-jsr310&lt;/artifactId&gt;
    &lt;version&gt;2.22.1&lt;/version&gt;
&lt;/dependency&gt;</code></pre>
<p>If an <em>ObjectMapper</em> is created manually, it should register the module:</p>
<pre><code class="language-java">ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());</code></pre>
<p>Still, <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/spring-boot-customize-jackson-objectmapper">Spring Boot</a> performs this registration automatically when the module is present on the classpath.</p>
<h2 id="bd-match-json-date-format" data-id="match-json-date-format">5. Match JSON Date Format</h2>
<div class="bd-anchor" id="match-json-date-format"></div>
<p>Another common cause for JSON deserialization errors is the exact date format. If the incoming JSON doesn&#8217;t use the default ISO-8601 format expected by <em>LocalDate</em> and <em>LocalDateTime</em>, we might see an error.</p>
<p>For example, let&#8217;s see a JSON string that can&#8217;t be parsed automatically:</p>
<pre><code class="language-json">{
  "time": "10/20/2020 10:00:10 AM"
}</code></pre>
<p>With the Java Time module registered, Jackson expects an ISO-8601 date-time for a <em>LocalDateTime</em> field by default:</p>
<pre><code class="language-text">2020-10-20T10:00:10</code></pre>
<p>In such cases, when the JSON data uses another format, the field should specify the expected pattern:</p>
<pre><code class="language-java">public class ImportTrans {
    @JsonFormat(pattern = "M/d/yyyy h:mm:ss a")
    private LocalDateTime time;
}</code></pre>
<p>However, this example also contains another hint. The <strong>JSON data can actually contain both a date and a time</strong>, while Java <em>LocalDate</em> fields only store a date.</p>
<h2 id="bd-correct-java-time-type" data-id="correct-java-time-type">6. Correct Java Time Type</h2>
<div class="bd-anchor" id="correct-java-time-type"></div>
<p><em>LocalDate</em> represents only a calendar date. In particular, it doesn&#8217;t contain any information about time of the day.</p>
<p><strong>If the JSON data includes hours, minutes, or seconds, <em>LocalDate</em> is no longer the appropriate target type</strong>:</p>
<pre><code class="language-java">private LocalDate time;</code></pre>
<p>Instead, we should probably use <em>LocalDateTime</em>:</p>
<pre><code class="language-java">private LocalDateTime time;</code></pre>
<p>Furthermore, the matching format can then be declared with <em>@JsonFormat</em>:</p>
<pre><code class="language-java">@JsonFormat(pattern = "M/d/yyyy h:mm:ss a")
private LocalDateTime time;</code></pre>
<p>Choosing the Java type that accurately represents the JSON payload is often the simplest solution.</p>
<h2 id="bd-localdatetime-has-similar-requirements" data-id="localdatetime-has-similar-requirements">7. <em>LocalDateTime</em> Has Similar Requirements</h2>
<div class="bd-anchor" id="localdatetime-has-similar-requirements"></div>
<p>The same type of exception frequently appears when using <em>LocalDateTime</em>:</p>
<pre><code class="language-text">Can not deserialize value of type
java.time.LocalDateTime from String</code></pre>
<p>Let&#8217;s consider the following JSON:</p>
<pre><code class="language-json">{
  "creationTime": "2016-06-16 06:56:00"
}</code></pre>
<p>Same as before, since this format differs from the default ISO-8601 representation, Jackson requires an explicit pattern:</p>
<pre><code class="language-java">@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime creationTime;</code></pre>
<p>The <em>ObjectMapper</em> must also have the Java Time module registered, while the explicit pattern is still required for this non-ISO format.</p>
<h2 id="bd-comparison" data-id="comparison">8. Comparison</h2>
<div class="bd-anchor" id="comparison"></div>
<p>Now that we know different reasons for errors around parsing JSON with date-time values with Jackson, let&#8217;s see an overview of what we found out:</p>
<table class="table-styled" style="width: 100%">
<thead>
<tr>
<th style="width: 16.8878%">Problem</th>
<th style="width: 41.3752%">Typical Error Message</th>
<th style="width: 41.6164%">Likely Cause</th>
</tr>
</thead>
<tbody>
<tr>
<td style="width: 16.8878%">Missing module</td>
<td style="width: 41.3752%"><em>Java 8 date/time type java.time.LocalDate not supported by default</em></td>
<td style="width: 41.6164%">The Java Time module isn&#8217;t registered when using Jackson 2.x</td>
</tr>
<tr>
<td style="width: 16.8878%">Wrong format</td>
<td style="width: 41.3752%"><em>Cannot deserialize value of type java.time.LocalDate from String</em></td>
<td style="width: 41.6164%">The input string doesn&#8217;t match the expected date format</td>
</tr>
<tr>
<td style="width: 16.8878%">Wrong JSON type</td>
<td style="width: 41.3752%"><em>Cannot deserialize value of type java.time.LocalDate from Object value</em></td>
<td style="width: 41.6164%">The JSON value has an incompatible type instead of the expected string</td>
</tr>
</tbody>
</table>
<p>So, we can check the reference table whenever we encounter an unexpected error.</p>
<h2 id="bd-conclusion" data-id="conclusion">9. Conclusion</h2>
<div class="bd-anchor" id="conclusion"></div>
<p>In this article, we explored the error stating that Jackson can&#8217;t construct an instance of <em>LocalDate</em> or <em>LocalDateTime</em>.</p>
<p>Specifically, we established that it generally indicates Jackson can&#8217;t determine how to convert the incoming JSON into a Java date-time object.</p>
<p>In conclusion, once the Java type, JSON payload format, and Jackson configuration are aligned, such deserialization errors should disappear and Java Time types should be handled transparently.</p><p>The post <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-fix-jackson-json-parse-error">How to Fix Jackson JSON Parse Error <em>Can not construct instance of java.time.LocalDate</em></a> first appeared on <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com">Baeldung</a>.</p><Img align="left" border="0" height="1" width="1" alt="" style="border:0;float:left;margin:0;padding:0;width:1px!important;height:1px!important;" hspace="0" src="https://feeds.feedblitz.com/~/i/968126756/0/baeldung">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/968126756/baeldung"><img height="20" src="https://assets.feedblitz.com/i/fblike20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Pin it!" href="https://feeds.feedblitz.com/_/29/968126756/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2024%2f07%2fJava-Featured-11-1024x536.jpg"><img height="20" src="https://assets.feedblitz.com/i/pinterest20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Post to X.com" href="https://feeds.feedblitz.com/_/24/968126756/baeldung"><img height="20" src="https://assets.feedblitz.com/i/x.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by email" href="https://feeds.feedblitz.com/_/19/968126756/baeldung"><img height="20" src="https://assets.feedblitz.com/i/email20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by RSS" href="https://feeds.feedblitz.com/_/20/968126756/baeldung"><img height="20" src="https://assets.feedblitz.com/i/rss20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a rel="NOFOLLOW" title="View Comments" href="https://www.baeldung.com/java-fix-jackson-json-parse-error#respond"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/comments20.png"></a>&#160;<a title="Follow Comments via RSS" href="https://www.baeldung.com/java-fix-jackson-json-parse-error/feed"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/commentsrss20.png"></a>&#160;</div>]]>
</content:encoded>
					
					<wfw:commentRss>https://feeds.feedblitz.com/~/968126756/0/baeldung~How-to-Fix-Jackson-JSON-Parse-Error-Can-not-construct-instance-of-javatimeLocalDate/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<webfeeds:featuredImage>https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-11-150x150.jpg</webfeeds:featuredImage></item>
<item>
<feedburner:origLink>https://www.baeldung.com/java-microks-api-mocking-testing</feedburner:origLink>
		<title>API Mocking and Testing With Microcks</title>
		<link>https://feeds.feedblitz.com/~/968126759/0/baeldung~API-Mocking-and-Testing-With-Microcks</link>
					<comments>https://feeds.feedblitz.com/~/968126759/0/baeldung~API-Mocking-and-Testing-With-Microcks#respond</comments>
		
		<dc:creator><![CDATA[Andrei Branza]]></dc:creator>
		<pubDate>Sat, 22 Aug 2026 23:20:24 +0000</pubDate>
				<category><![CDATA[Testing]]></category>
		<category><![CDATA[popular]]></category>
		<category><![CDATA[Testcontainers]]></category>
		<guid isPermaLink="false">https://www.baeldung.com/?p=204680</guid>
					<description><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-12-1024x536.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="max-width:100% !important;height:auto !important;float: left; margin-right: 5px;" loading="lazy" /><p>Learn how to use Testcontainers integration to spin up Microcks inside a JUnit5 test.</p>
<p>The post <a rel="NOFOLLOW" href="https://feeds.feedblitz.com/~/968126759/0/baeldung~API-Mocking-and-Testing-With-Microcks">API Mocking and Testing With Microcks</a> first appeared on <a rel="NOFOLLOW" href="https://www.baeldung.com">Baeldung</a>.</p><div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/968126759/baeldung"><img height="20" src="https://assets.feedblitz.com/i/fblike20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Pin it!" href="https://feeds.feedblitz.com/_/29/968126759/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2024%2f07%2fJava-Featured-12-1024x536.jpg"><img height="20" src="https://assets.feedblitz.com/i/pinterest20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Post to X.com" href="https://feeds.feedblitz.com/_/24/968126759/baeldung"><img height="20" src="https://assets.feedblitz.com/i/x.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by email" href="https://feeds.feedblitz.com/_/19/968126759/baeldung"><img height="20" src="https://assets.feedblitz.com/i/email20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by RSS" href="https://feeds.feedblitz.com/_/20/968126759/baeldung"><img height="20" src="https://assets.feedblitz.com/i/rss20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a rel="NOFOLLOW" title="View Comments" href="https://www.baeldung.com/java-microks-api-mocking-testing#respond"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/comments20.png"></a>&#160;<a title="Follow Comments via RSS" href="https://www.baeldung.com/java-microks-api-mocking-testing/feed"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/commentsrss20.png"></a>&#160;</div>]]>
</description>
										<content:encoded><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-12-1024x536.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="float: left; margin-right: 5px;" decoding="async" loading="lazy" srcset="https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-12-1024x536.jpg 1024w, https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-12-300x157.jpg 300w, https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-12-768x402.jpg 768w, https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-12-100x52.jpg 100w, https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-12.jpg 1200w" sizes="auto, (max-width: 580px) 100vw, 580px" /><h2 id="bd-introduction" data-id="introduction">1. Introduction</h2>
<div class="bd-anchor" id="introduction"></div>
<p>In this tutorial, we&#8217;ll look at Microcks, an open-source, Kubernetes-native platform for turning API and microservices contracts into live mocks. We&#8217;ll also see how to reuse the same contracts to run conformance tests against a real implemenation.</p>
<p>We&#8217;ll cover the core concepts first, then use the Testcontainers integration to spin up Microcks inside a <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/junit-5">JUnit5</a> test, import an OpenAPI contract, call the generated mock, and validate a running service against it.</p>
<h2 id="bd-what-is-microcks" data-id="what-is-microcks">2. What Is Microcks?</h2>
<div class="bd-anchor" id="what-is-microcks"></div>
<p><strong>Microcks is a CNCF (Cloud Native Computing Foundation) project for API mocking and testing. </strong>It consumes API and microservice artifacts, such as OpenAPI specs, AsyncAPI specs, <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/grpc-introduction">gRPC</a> protobuf files, GraphQL schemas, Postman collections, and SoapUI projects. Then, it turns them into live, stateful mocks in seconds.</p>
<p><strong>Beyond mocking, Microcks reuses these same artifacts to run contract conformance and non-regression tests against a real API implementation. </strong>It also integrates with Jenkins, GitHub Actions and Tekton pipelines through a CLI, so both mocking and testing can be automated across the whole delivery chain.</p>
<p>We can run Microcks as a standalone server, using Docker Compose or a Kubernetes/Helm deployment. For local development and CI, though, it&#8217;s more convenient to embed it directly inside a test using the <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/docker-test-containers">Testcontainers</a> module.</p>
<p>Microcks isn&#8217;t limited to synchronous REST APIs, either. Through its ensemble mode, it can also mock and contract-test SOAP, <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/graphql">GraphQL</a>, and gRPC services, as well as event-driven APIs described with AsyncAPI, over brokers like <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/apache-kafka">Kafka</a>, SQS or SNS. <strong>That means the same tool and the same workflow can cover most of the API styles a typical microservices architecture is likely to use.</strong></p>
<h2 id="bd-setting-up-microcks-with-testcontainers" data-id="setting-up-microcks-with-testcontainers">3. Setting Up Microcks With Testcontainers</h2>
<div class="bd-anchor" id="setting-up-microcks-with-testcontainers"></div>
<p>The <em>microcks-testcontainers </em>library lets us start a lightweight, throwaway Microcks instance for the lifetime of a test class.</p>
<p>First, let&#8217;s add the <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://mvnrepository.com/artifact/io.github.microcks/microcks-testcontainers">Maven</a> dependency:</p>
<pre><code class="language-xml">&lt;dependency&gt;
    &lt;groupId&gt;io.github.microcks&lt;/groupId&gt;
    &lt;artifactId&gt;microcks-testcontainers&lt;/artifactId&gt;
    &lt;version&gt;0.4.4&lt;/version&gt;
&lt;/dependency&gt;</code></pre>
<p>Next, let&#8217;s create and start a <em>MicrocksContainer, </em>pointing it to an OpenAPI contract for our API:</p>
<pre><code class="language-java">MicrocksContainer microcks = new MicrocksContainer(
  DockerImageName.parse("quay.io/microcks/microcks-uber:1.14.0"))
  .withMainArtifacts("apipastries-openapi.yaml");
microcks.start();</code></pre>
<p>The <em>uber </em>image bundles everything Microcks needs without an external MongoDB dependency, which keeps startup fast. We can also import artifacts after startup, using <em>importAsMainArtifact() </em>or <em>importAsSecondaryArtifact() </em>on the running container.</p>
<h2 id="bd-mocking-the-api" data-id="mocking-the-api">4. Mocking the API</h2>
<div class="bd-anchor" id="mocking-the-api"></div>
<p>Once the container has imported the contract, Microcks automatically exposes a mock endpoint for every operation. We can retrieve the base URL and call it like any real API:</p>
<pre><code class="language-java">String baseApiUrl = microcks.getRestMockEndpoint("API Pastries", "0.0.1");
HttpResponse&lt;String&gt; response = client.send(
  HttpRequest.newBuilder(URI.create(baseApiUrl + "/pastries/Millefeuille")).GET().build(),
  HttpResponse.BodyHandlers.ofString());
assertEquals(200, response.statusCode());</code></pre>
<p><strong>Microcks generates realistic responses straight from the examples defined in the OpenAPI contract.</strong> Then, it cycles through them so repeated calls don&#8217;t always return the same payload. This means consumers can be developed and tested against a dependency that doesn&#8217;t exist yet, or isn&#8217;t reacheable from a test environment.</p>
<p>Furthermore, there are ways we can confirm a mock was actually called. We&#8217;ll do this by either calling <em>microcks.verify(&#8220;API Pastries&#8221;,&#8221;0.0.1&#8243;)</em>, or by checking the exact invocation count through <em>microcks.getServiceInvocationsCount(&#8220;API Pastries&#8221;,&#8221;0.0.1&#8243;)</em>.</p>
<h2 id="bd-running-contract-tests" data-id="running-contract-tests">5. Running Contract Tests</h2>
<div class="bd-anchor" id="running-contract-tests"></div>
<p>The same contract can validate a real implementation running on our machine. First, we need to expose the port with Testcontainers.exposeHostPorts() before starting the container, not after. We do this since the Microcks container needs to reach back out to our host:</p>
<pre><code class="language-java">Testcontainers.exposeHostPorts(port);
microcks.start();</code></pre>
<p>Then, let&#8217;s launch a conformance test against our locally running server:</p>
<pre><code class="language-java">TestRequest testRequest = new TestRequest.Builder()
  .serviceId("API Pastries:0.0.1")
  .runnerType(TestRunnerType.OPEN_API_SCHEMA.name())
  .testEndpoint("http://host.testcontainers.internal:" + port)
  .filteredOperations(List.of("GET /pastries/{name}"))
  .timeout(Duration.ofSeconds(2))
  .build();
TestResult testResult = microcks.testEndpoint(testRequest);
assertTrue(testResult.isSuccess());</code></pre>
<p>We scoped the test to a single operation with filteredOperations(). Without it, Microcks also replays the GET /pastries and PATCH /pastries/{name} examples from the contract, which fail against an implementation that doesn&#8217;t cover them yet.</p>
<p><strong>Here, Microcks replays every example from the OpenAPI contract against our running application and checks each response against the schema. </strong>For a more JUnit-friendly failure report, we can use the <em>Assertions </em>helper instead, <em>Assertions.assertSuccess(testResult);</em></p>
<p>This single call runs the same conformance check that a CI pipeline would run against a live deployment, only locally and in milliseconds.</p>
<h2 id="bd-conclusion" data-id="conclusion">6. Conclusion</h2>
<div class="bd-anchor" id="conclusion"></div>
<p>In this article, we introduced Microcks as a tool for turning API contracts into live mocks and reusing those same contracts for conformance testing. We used its Testcontainers integration to start a throwaway Microcks instance inside a JUnit test, import an OpenAPI contract, call the generated mock, and run a contract test against a live implementation.</p>
<p><strong>Because mocks and tests are dervide from the same source contract, both stay in sync with the API definition. </strong>That removes a common source of drift between what an API promises and what it actually does.</p>
<p>As always, the code is available over on <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/eugenp/tutorials/tree/master/testing-modules">Github</a>.</p><p>The post <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-microks-api-mocking-testing">API Mocking and Testing With Microcks</a> first appeared on <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com">Baeldung</a>.</p><Img align="left" border="0" height="1" width="1" alt="" style="border:0;float:left;margin:0;padding:0;width:1px!important;height:1px!important;" hspace="0" src="https://feeds.feedblitz.com/~/i/968126759/0/baeldung">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/968126759/baeldung"><img height="20" src="https://assets.feedblitz.com/i/fblike20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Pin it!" href="https://feeds.feedblitz.com/_/29/968126759/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2024%2f07%2fJava-Featured-12-1024x536.jpg"><img height="20" src="https://assets.feedblitz.com/i/pinterest20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Post to X.com" href="https://feeds.feedblitz.com/_/24/968126759/baeldung"><img height="20" src="https://assets.feedblitz.com/i/x.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by email" href="https://feeds.feedblitz.com/_/19/968126759/baeldung"><img height="20" src="https://assets.feedblitz.com/i/email20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by RSS" href="https://feeds.feedblitz.com/_/20/968126759/baeldung"><img height="20" src="https://assets.feedblitz.com/i/rss20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a rel="NOFOLLOW" title="View Comments" href="https://www.baeldung.com/java-microks-api-mocking-testing#respond"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/comments20.png"></a>&#160;<a title="Follow Comments via RSS" href="https://www.baeldung.com/java-microks-api-mocking-testing/feed"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/commentsrss20.png"></a>&#160;</div>]]>
</content:encoded>
					
					<wfw:commentRss>https://feeds.feedblitz.com/~/968126759/0/baeldung~API-Mocking-and-Testing-With-Microcks/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<webfeeds:featuredImage>https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-12-150x150.jpg</webfeeds:featuredImage></item>
<item>
<feedburner:origLink>https://www.baeldung.com/spring-boot-http-client-ssrf-mitigation-inetaddressfilter</feedburner:origLink>
		<title>HTTP Client SSRF Mitigation with InetAddressFilter in Spring Boot</title>
		<link>https://feeds.feedblitz.com/~/968126762/0/baeldung~HTTP-Client-SSRF-Mitigation-with-InetAddressFilter-in-Spring-Boot</link>
					<comments>https://feeds.feedblitz.com/~/968126762/0/baeldung~HTTP-Client-SSRF-Mitigation-with-InetAddressFilter-in-Spring-Boot#respond</comments>
		
		<dc:creator><![CDATA[Hamid Reza Sharifi]]></dc:creator>
		<pubDate>Sat, 22 Aug 2026 23:16:19 +0000</pubDate>
				<category><![CDATA[Spring Boot]]></category>
		<category><![CDATA[Spring Boot 4]]></category>
		<guid isPermaLink="false">https://www.baeldung.com/?p=204677</guid>
					<description><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-13-1024x536.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="max-width:100% !important;height:auto !important;float: left; margin-right: 5px;" loading="lazy" /><p>Learn how to use the InetAddressFilter class in a Spring-based application to limit the address that an HTTP client can call.</p>
<p>The post <a rel="NOFOLLOW" href="https://feeds.feedblitz.com/~/968126762/0/baeldung~HTTP-Client-SSRF-Mitigation-with-InetAddressFilter-in-Spring-Boot">HTTP Client SSRF Mitigation with InetAddressFilter in Spring Boot</a> first appeared on <a rel="NOFOLLOW" href="https://www.baeldung.com">Baeldung</a>.</p><div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/968126762/baeldung"><img height="20" src="https://assets.feedblitz.com/i/fblike20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Pin it!" href="https://feeds.feedblitz.com/_/29/968126762/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2024%2f07%2fJava-Featured-13-1024x536.jpg"><img height="20" src="https://assets.feedblitz.com/i/pinterest20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Post to X.com" href="https://feeds.feedblitz.com/_/24/968126762/baeldung"><img height="20" src="https://assets.feedblitz.com/i/x.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by email" href="https://feeds.feedblitz.com/_/19/968126762/baeldung"><img height="20" src="https://assets.feedblitz.com/i/email20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by RSS" href="https://feeds.feedblitz.com/_/20/968126762/baeldung"><img height="20" src="https://assets.feedblitz.com/i/rss20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a rel="NOFOLLOW" title="View Comments" href="https://www.baeldung.com/spring-boot-http-client-ssrf-mitigation-inetaddressfilter#respond"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/comments20.png"></a>&#160;<a title="Follow Comments via RSS" href="https://www.baeldung.com/spring-boot-http-client-ssrf-mitigation-inetaddressfilter/feed"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/commentsrss20.png"></a>&#160;</div>]]>
</description>
										<content:encoded><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-13-1024x536.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="float: left; margin-right: 5px;" decoding="async" loading="lazy" srcset="https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-13-1024x536.jpg 1024w, https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-13-300x157.jpg 300w, https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-13-768x402.jpg 768w, https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-13-100x52.jpg 100w, https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-13.jpg 1200w" sizes="auto, (max-width: 580px) 100vw, 580px" /><h2 id="bd-introduction" data-id="introduction">1. Introduction</h2><div class="bd-anchor" id="introduction"></div>
<p>It’s sometimes useful to limit the remote addresses that an HTTP client is permitted to call. It helps prevent applications from connecting to unintended destinations and provides an effective defense against Server-Side Request Forgery (<a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/cs/server-side-request-forgery">SSRF</a>) attacks. <strong>To limit the address that an HTTP client can call, we can use an <em>InetAddressFilter.</em> The filter determines which addresses are allowed for outgoing requests.</strong> In this tutorial, we’ll explore how to use the <em>InetAddressFilter</em> class in a Spring-based application.</p>
<h2 id="bd-understanding-ssrf-in-the-context-of-http-clients" data-id="understanding-ssrf-in-the-context-of-http-clients">2. Understanding SSRF in the Context of HTTP Clients</h2><div class="bd-anchor" id="understanding-ssrf-in-the-context-of-http-clients"></div>
<p><strong>SSRF is a critical security vulnerability that allows an attacker to force a server to make requests to unintended locations. These requests may target internal systems, cloud metadata endpoints, or loopback addresses.</strong> To demonstrate how SSRF can occur in an HTTP client, let&#8217;s consider a simple endpoint that accepts a URL and uses <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/spring-boot-restclient"><em>RestClient</em></a> to retrieve its contents:</p>
<pre><code class="language-java">@GetMapping("/fetch")
public String fetch(@RequestParam String url) {
    return restClient.get()
      .uri(url)
      .retrieve()
      .body(String.class);
}</code></pre>
<p>The endpoint accepts a URL as a request parameter and forwards it to <em>RestClient</em>. The intention is to allow users to retrieve content from public URLs. For example, a legitimate request might look like:</p>
<pre><code class="language-plaintext">curl --location http://127.0.0.1:8080/fetch?url=https://www.baeldung.com</code></pre>
<p>However, an attacker could provide a URL that points to an internal resource instead:</p>
<pre><code class="language-plaintext">curl --location http://127.0.0.1:8080/fetch?url=admin</code></pre>
<p>Instead of contacting a public website, our server now makes requests to its own internal network. This can expose internal admin APIs, databases, Kubernetes services, etc. This class of vulnerability is known as SSRF. Historically, mitigating SSRF in Spring Boot applications required custom <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/spring-rest-template-interceptor#interceptor"><em>ClientHttpRequestInterceptor</em></a> implementations or complex network-level firewalls. <strong>Spring Boot 4.1.0 introduces first-class support for SSRF mitigation via the <em>InetAddressFilter</em> interface</strong>.</p>
<h2 id="bd-maven-dependency" data-id="maven-dependency">3. Maven Dependency</h2><div class="bd-anchor" id="maven-dependency"></div>
<p>Let’s start by importing the <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-restclient"><em>spring-boot-starter-restclient</em></a> dependency to our <em>pom.xml</em>:</p>
<pre><code class="language-xml">&lt;dependency&gt;
    &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
    &lt;artifactId&gt;spring-boot-starter-restclient&lt;/artifactId&gt;
    &lt;version&gt;4.1.1-SNAPSHOT&lt;/version&gt;
&lt;/dependency&gt;</code></pre>
<h2 id="bd-introducing-inetaddressfilter" data-id="introducing-inetaddressfilter">4. Introducing <em>InetAddressFilter</em></h2><div class="bd-anchor" id="introducing-inetaddressfilter"></div>
<p>The <em>InetAddressFilter</em> interface is a <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-8-functional-interfaces">functional interface</a>. Unlike validating the hostname or URL, <em>InetAddressFilter</em> performs its checks after DNS resolution. Spring Boot provides several built-in filters for common scenarios, such as allowing only public addresses (<em>InetAddressFilter.externalAddresses()</em>) or blocking special-purpose network ranges (<em>InetAddressFilter.internalAddresses()</em>). <strong>We can combine these filters using logical operators</strong>:</p>
<pre><code class="language-java">InetAddressFilter.of("192.168.0.0/16")
  .andNot("192.168.1.100");</code></pre>
<p>The API also supports <em>and()</em>, <em>or()</em>, and <em>negate()</em> for composing more complex rules:</p>
<pre><code class="language-java">InetAddressFilter.externalAddresses()
  .or(InetAddressFilter.of("10.20.0.0"));</code></pre>
<p>This enables expressive allowlists and blocklists without custom networking code.</p>
<h2 id="bd-applying-the-filter-globally" data-id="applying-the-filter-globally">5. Applying the Filter Globally</h2><div class="bd-anchor" id="applying-the-filter-globally"></div>
<p><strong>The simplest and most common approach is to declare an <em>InetAddressFilter</em> bean</strong>. Spring Boot then automatically applies it to every auto-configured HTTP client builder (<em>RestClient</em>, <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/spring-5-webclient"><em>WebClient</em></a>, <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/rest-template"><em>RestTemplate</em></a>, etc.). Let&#8217;s configure the <em>InetAddressFilter</em> to allow connections only to external IP addresses:</p>
<pre><code class="language-java">@Configuration(proxyBeanMethods = false)
public class HttpClientSecurityConfig {
    @Bean
    public InetAddressFilter httpClientInetAddressFilter() {
        return InetAddressFilter.externalAddresses();
    }
}</code></pre>
<p>With this single bean, any client created from the auto-configured builders will reject requests whose resolved address is not external. Now, we can create a <em>RestClient</em> without any additional security configuration:</p>
<pre><code class="language-java">@Bean
RestClient restClient(RestClient.Builder builder) {
    return builder.build();
}</code></pre>
<p>Because the <em>RestClient.Builder</em> has already been customized by Spring Boot, the resulting <em>RestClient</em> automatically uses the configured <em>InetAddressFilter</em>. As a result, any request whose resolved destination is not an external address—for example, a loopback or private IP address—is rejected before a connection is established. This approach centralizes the application&#8217;s outbound network policy in a single place and ensures that all auto-configured HTTP clients consistently enforce the same SSRF protection.</p>
<h2 id="bd-applying-the-filter-per-client" data-id="applying-the-filter-per-client">6. Applying the Filter Per-Client</h2><div class="bd-anchor" id="applying-the-filter-per-client"></div>
<p>In some scenarios, applying a global <em>InetAddressFilter</em> may be too restrictive. For example, an application might communicate with both public APIs and specific internal services, each requiring different outbound access rules. In such cases, <strong>we can apply an <em>InetAddressFilter</em> to an individual HTTP client by configuring the underlying <em>HttpClientSettings</em> when creating the client</strong>. Let&#8217;s create a <em>RestClient</em> that only allows requests to external addresses:</p>
<pre><code class="language-java">@Bean
RestClient restClient(RestClient.Builder builder) {
    InetAddressFilter onlyExternalAddresses = InetAddressFilter.externalAddresses();
    HttpClientSettings settings = HttpClientSettings.defaults()
      .withInetAddressFilter(onlyExternalAddresses);
    ClientHttpRequestFactory requestFactory = ClientHttpRequestFactoryBuilder
      .jdk().build(settings);
    return builder
      .requestFactory(requestFactory)
      .build();
}</code></pre>
<p>Here, the filter is attached only to this specific <em>RestClient</em> instance. Other HTTP clients in the application can use different security policies or remain unaffected. This approach is useful when different integrations have different network requirements. For example, a client used to call third-party APIs can be restricted to public addresses, while another client used for communication with trusted internal services can use a more specific allowlist. By configuring the filter at the client level, we can apply fine-grained outbound request controls without changing the behavior of the entire application.</p>
<h2 id="bd-test-1" data-id="test-1">7. Test</h2><div class="bd-anchor" id="test-1"></div>
<p>To verify that the configured <em>InetAddressFilter</em> is applied, we can write a unit test that uses the configured <em>RestClient</em> bean to access a loopback address.<strong> The application is configured with <em>InetAddressFilter.externalAddresses()</em>, which permits only publicly routable IP addresses.</strong> Since <em>127.0.0.1</em> is a loopback address, the request is rejected before an HTTP connection is established. Let&#8217;s create a test case:</p>
<pre><code class="language-java">@Test
void whenCallingLoopbackAddress_thenFilteredHostExceptionIsThrown() {
    assertThatThrownBy(() -&gt;
        restClient.get()
          .uri("https://127.0.0.1:8080")
          .retrieve()
          .toBodilessEntity()
    ).isInstanceOf(FilteredHostException.class)
     .hasMessageContaining("127.0.0.1");
}</code></pre>
<p>When the test executes, the <em>RestClient</em> resolves the destination host and passes the resulting <em>InetAddress</em> to the configured <em>InetAddressFilter</em>. Because the address does not satisfy the <em>externalAddresses()</em> policy, Spring Boot throws a <em>FilteredHostException</em> and aborts the request before opening a network connection.</p>
<h2 id="bd-conclusion" data-id="conclusion">8. Conclusion</h2><div class="bd-anchor" id="conclusion"></div>
<p>In this tutorial, we explored how SSRF can affect applications that make outbound HTTP requests based on user-controlled input. We also looked at how Spring Boot 4.1 simplifies SSRF mitigation with <em>InetAddressFilter</em>. It allows applications to validate the resolved destination address before establishing an outbound connection. The feature integrates with Spring&#8217;s HTTP client infrastructure, including both blocking and reactive clients, and provides a flexible API for composing allowlists and blocklists. By applying <em>InetAddressFilter</em>, we can enforce outbound network access policies at the HTTP client level. This reduces the risk of unauthorized access to internal resources while keeping the application code clean and maintainable.</p>
<p>As always, the source code is available <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/eugenp/tutorials/tree/master/spring-boot-modules/spring-boot-client-2">over on GitHub</a>.</p><p>The post <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/spring-boot-http-client-ssrf-mitigation-inetaddressfilter">HTTP Client SSRF Mitigation with InetAddressFilter in Spring Boot</a> first appeared on <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com">Baeldung</a>.</p><Img align="left" border="0" height="1" width="1" alt="" style="border:0;float:left;margin:0;padding:0;width:1px!important;height:1px!important;" hspace="0" src="https://feeds.feedblitz.com/~/i/968126762/0/baeldung">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/968126762/baeldung"><img height="20" src="https://assets.feedblitz.com/i/fblike20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Pin it!" href="https://feeds.feedblitz.com/_/29/968126762/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2024%2f07%2fJava-Featured-13-1024x536.jpg"><img height="20" src="https://assets.feedblitz.com/i/pinterest20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Post to X.com" href="https://feeds.feedblitz.com/_/24/968126762/baeldung"><img height="20" src="https://assets.feedblitz.com/i/x.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by email" href="https://feeds.feedblitz.com/_/19/968126762/baeldung"><img height="20" src="https://assets.feedblitz.com/i/email20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by RSS" href="https://feeds.feedblitz.com/_/20/968126762/baeldung"><img height="20" src="https://assets.feedblitz.com/i/rss20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a rel="NOFOLLOW" title="View Comments" href="https://www.baeldung.com/spring-boot-http-client-ssrf-mitigation-inetaddressfilter#respond"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/comments20.png"></a>&#160;<a title="Follow Comments via RSS" href="https://www.baeldung.com/spring-boot-http-client-ssrf-mitigation-inetaddressfilter/feed"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/commentsrss20.png"></a>&#160;</div>]]>
</content:encoded>
					
					<wfw:commentRss>https://feeds.feedblitz.com/~/968126762/0/baeldung~HTTP-Client-SSRF-Mitigation-with-InetAddressFilter-in-Spring-Boot/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<webfeeds:featuredImage>https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-13-150x150.jpg</webfeeds:featuredImage></item>
<item>
<feedburner:origLink>https://www.baeldung.com/java-db-scheduler</feedburner:origLink>
		<title>DB-Scheduler: A Persistent, Cluster-Friendly Scheduler for Java</title>
		<link>https://feeds.feedblitz.com/~/968126534/0/baeldung~DBScheduler-A-Persistent-ClusterFriendly-Scheduler-for-Java</link>
					<comments>https://feeds.feedblitz.com/~/968126534/0/baeldung~DBScheduler-A-Persistent-ClusterFriendly-Scheduler-for-Java#respond</comments>
		
		<dc:creator><![CDATA[Graham Cox]]></dc:creator>
		<pubDate>Sat, 22 Aug 2026 23:11:36 +0000</pubDate>
				<category><![CDATA[Persistence]]></category>
		<category><![CDATA[popular]]></category>
		<category><![CDATA[Quartz]]></category>
		<guid isPermaLink="false">https://www.baeldung.com/java-db-scheduler</guid>
					<description><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/2024/11/Persistence-Featured-Image-04-1024x536.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="max-width:100% !important;height:auto !important;float: left; margin-right: 5px;" loading="lazy" /><p>Learn how to use the db-scheduler library to store, manage and execute persistent scheduled tasks in Java.</p>
<p>The post <a rel="NOFOLLOW" href="https://feeds.feedblitz.com/~/968126534/0/baeldung~DBScheduler-A-Persistent-ClusterFriendly-Scheduler-for-Java">DB-Scheduler: A Persistent, Cluster-Friendly Scheduler for Java</a> first appeared on <a rel="NOFOLLOW" href="https://www.baeldung.com">Baeldung</a>.</p><div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/968126534/baeldung"><img height="20" src="https://assets.feedblitz.com/i/fblike20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Pin it!" href="https://feeds.feedblitz.com/_/29/968126534/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2024%2f11%2fPersistence-Featured-Image-04-1024x536.jpg"><img height="20" src="https://assets.feedblitz.com/i/pinterest20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Post to X.com" href="https://feeds.feedblitz.com/_/24/968126534/baeldung"><img height="20" src="https://assets.feedblitz.com/i/x.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by email" href="https://feeds.feedblitz.com/_/19/968126534/baeldung"><img height="20" src="https://assets.feedblitz.com/i/email20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by RSS" href="https://feeds.feedblitz.com/_/20/968126534/baeldung"><img height="20" src="https://assets.feedblitz.com/i/rss20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a rel="NOFOLLOW" title="View Comments" href="https://www.baeldung.com/java-db-scheduler#respond"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/comments20.png"></a>&#160;<a title="Follow Comments via RSS" href="https://www.baeldung.com/java-db-scheduler/feed"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/commentsrss20.png"></a>&#160;</div>]]>
</description>
										<content:encoded><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/2024/11/Persistence-Featured-Image-04-1024x536.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="float: left; margin-right: 5px;" decoding="async" loading="lazy" srcset="https://www.baeldung.com/wp-content/uploads/2024/11/Persistence-Featured-Image-04-1024x536.jpg 1024w, https://www.baeldung.com/wp-content/uploads/2024/11/Persistence-Featured-Image-04-300x157.jpg 300w, https://www.baeldung.com/wp-content/uploads/2024/11/Persistence-Featured-Image-04-768x402.jpg 768w, https://www.baeldung.com/wp-content/uploads/2024/11/Persistence-Featured-Image-04-100x52.jpg 100w, https://www.baeldung.com/wp-content/uploads/2024/11/Persistence-Featured-Image-04-600x314.jpg 600w, https://www.baeldung.com/wp-content/uploads/2024/11/Persistence-Featured-Image-04.jpg 1200w" sizes="auto, (max-width: 580px) 100vw, 580px" /><h2 id="bd-introduction" data-id="introduction"><strong>1. Introduction</strong></h2>
<div class="bd-anchor" id="introduction"></div>
<p>In this tutorial, we’ll take a look at <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/kagkarlsson/db-scheduler">db-scheduler</a>, a simpler alternative to <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/quartz">Quartz</a>. We’ll see what it is, how to use it and what we can do with it.</p>
<h2 id="bd-what-is-db-scheduler" data-id="what-is-db-scheduler"><strong>2. What Is DB-Scheduler?</strong></h2>
<div class="bd-anchor" id="what-is-db-scheduler"></div>
<p><strong>DB-Scheduler is a cluster-aware, persistent scheduling library</strong>. It&#8217;s designed to be simple to include in our application. Our only requirements are Java 17+ and a JDBC connection to a database with a single database table in which we store and manage our tasks.</p>
<p>Using db-scheduler, we can easily support:</p>
<ul>
<li>One-time tasks: tasks that are scheduled to run once at a specific point in time</li>
<li>Simple recurring tasks: tasks that are set up to run on a statically defined regular schedule</li>
<li>Dynamic recurring tasks: tasks that run on a regular schedule, but that we can schedule dynamically at runtime</li>
</ul>
<p>The db-scheduler library will then handle everything for us. <strong>This includes ensuring that these jobs run correctly across a cluster of services without dropping them or running them multiple times.</strong></p>
<h2 id="bd-setting-up" data-id="setting-up"><strong>3. Setting Up</strong></h2>
<div class="bd-anchor" id="setting-up"></div>
<p>Before we can use db-scheduler, we need to first set it up in our application. This includes adding it to our project and getting it running.</p>
<h3 id="bd-1-dependencies" data-id="1-dependencies"><strong>3.1. Dependencies</strong></h3>
<div class="bd-anchor" id="1-dependencies"></div>
<p><strong>Before using db-scheduler, we need to include the <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://mvnrepository.com/artifact/com.github.kagkarlsson/db-scheduler">latest version</a> in our build, which is <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://mvnrepository.com/artifact/com.github.kagkarlsson/db-scheduler/16.12.0">16.12.0</a> at the time of writing.</strong></p>
<p>If we’re using Maven, we can include this dependency in our <em>pom.xml</em> file:</p>
<pre><code class="language-xml">&lt;dependency&gt;
    &lt;groupId&gt;com.github.kagkarlsson&lt;/groupId&gt;
    &lt;artifactId&gt;db-scheduler&lt;/artifactId&gt;
    &lt;version&gt;16.12.0&lt;/version&gt;
&lt;/dependency&gt;</code></pre>
<p>This will bring in everything that we need to be able to use it in our application. The only required dependencies are <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-jspecify-null-safety">JSpecify</a> and <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/slf4j-with-log4j2-logback">SLF4J</a> &#8211; everything else is self-contained.</p>
<h3 id="bd-2-database-schema" data-id="2-database-schema"><strong>3.2. Database Schema</strong></h3>
<div class="bd-anchor" id="2-database-schema"></div>
<p><strong>In order to work, db-scheduler needs a single database table in the database we connect it to.</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/kagkarlsson/db-scheduler#database-compatibility">DDL scripts</a> are provided for most major RDBMS engines, though it might work on others as well. For example, to use with <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/kagkarlsson/db-scheduler/blob/master/db-scheduler/src/test/resources/postgresql_tables.sql">PostgreSQL</a>, we&#8217;d use DDL like this:</p>
<pre><code class="language-sql">CREATE TABLE scheduled_tasks (
  task_name TEXT NOT NULL,
  task_instance TEXT NOT NULL,
  task_data BYTEA,
  execution_time TIMESTAMP WITH TIME ZONE NOT NULL,
  picked BOOLEAN NOT NULL,
  picked_by TEXT,
  last_success TIMESTAMP WITH TIME ZONE,
  last_failure TIMESTAMP WITH TIME ZONE,
  consecutive_failures INT,
  last_heartbeat TIMESTAMP WITH TIME ZONE,
  version BIGINT NOT NULL,
  priority SMALLINT,
  PRIMARY KEY (task_name, task_instance)
);
CREATE INDEX execution_time_idx ON scheduled_tasks (execution_time);
CREATE INDEX last_heartbeat_idx ON scheduled_tasks (last_heartbeat);
CREATE INDEX priority_execution_time_idx on scheduled_tasks (priority desc, execution_time asc);</code></pre>
<p>This creates our <em>scheduled_tasks </em>table with the expected structure, ready for db-scheduler to use.</p>
<h3 id="bd-3-scheduler" data-id="3-scheduler"><strong>3.3. Scheduler</strong></h3>
<div class="bd-anchor" id="3-scheduler"></div>
<p>Finally, before we can use db-scheduler, we need to actually set up a <em>Scheduler </em>instance. <strong>This is the central class that manages scheduling all of our jobs.</strong></p>
<p>We create an instance of this by providing a <em>DataSource </em>pointing to the database containing our <em>scheduled_tasks</em> table, and a collection of all the tasks that we want to manage. We&#8217;ll see later how to create these:</p>
<pre><code class="language-java">Scheduler scheduler = Scheduler.create(dataSource)
  .startTasks(tasks)
  .registerShutdownHook()
  .build();</code></pre>
<p>This comes with a reasonable set of default configuration values:</p>
<ul>
<li>Poll every 10 seconds</li>
<li>Heartbeat every 5 minutes</li>
<li>Consider a task dead if it misses 6 heartbeats</li>
<li>Run jobs across 10 worker threads</li>
</ul>
<p>And many more. We can configure all of these when we create our scheduler:</p>
<pre><code class="language-java">Scheduler scheduler = Scheduler.create(dataSource)
  .startTasks(tasks)
  .registerShutdownHook()
  .pollingInterval(Duration.ofSeconds(2))
  .heartbeatInterval(Duration.ofMinutes(2))
  .missedHeartbeatsLimit(10)
  .threads(5)
  .build();</code></pre>
<p><strong>It&#8217;s important that multiple instances in the same cluster use at least the same heartbeat settings.</strong> If not, db-scheduler might incorrectly consider some jobs to be dead.</p>
<p>Once we have a scheduler, we need to start it running:</p>
<pre><code class="language-java">scheduler.start();</code></pre>
<p>At this point, the scheduler will now manage all of the tasks assigned to it. This includes ensuring they&#8217;re correctly scheduled and running them at the appropriate times.</p>
<h2 id="bd-simple-recurring-tasks" data-id="simple-recurring-tasks"><strong>4. Simple Recurring Tasks</strong></h2>
<div class="bd-anchor" id="simple-recurring-tasks"></div>
<p><strong>The easiest tasks to work with are simple recurring tasks. For these, we need a unique name, a frequency at which the task runs, and the task itself:</strong></p>
<pre><code class="language-java">RecurringTask&lt;Void&gt; task = Tasks.recurring("my-hourly-task", FixedDelay.ofHours(1))
  .execute((instance, context) -&gt; {
    LOG.info("Executed!");
  });</code></pre>
<p>If this is a new task that the scheduler has never seen before, it will be scheduled to run immediately. After that, the scheduler will run it according to the provided schedule. In this case, that means 1 hour after the previous iteration finished. We can also use <em>Daily </em>for running at a particular time every day, and <em>CronSchedule </em>for using a more complicated <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/cron-expressions">cron expression</a>.</p>
<p>Our task itself is provided as an instance of <em>VoidExecutionHandler&lt;T&gt;</em>, which is itself a <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-8-lambda-expressions-tips#functionalInterface">functional interface</a> and can be implemented by a lambda if we wish. The only method of this interface takes two parameters:</p>
<ul>
<li><em>TaskInstance&lt;T&gt; instance</em> &#8211; Details about this instance of the task. Useful if we&#8217;ve got multiple schedules using the same task implementation.</li>
<li><em>ExecutionContext context </em>&#8211; Details about the executor itself. Useful if we want to access the scheduler itself from within our task.</li>
</ul>
<p>Note that we have <em>VoidExecutionHandler</em> and <em>RecurringTask&lt;Void&gt;</em> here. This is because our example task is stateless. We can also support stateful tasks, which have an initial state that can be updated as a result of the task executing. However, these are out of the scope of this article.</p>
<h2 id="bd-one-time-tasks" data-id="one-time-tasks"><strong>5. One-Time Tasks</strong></h2>
<div class="bd-anchor" id="one-time-tasks"></div>
<p><strong>One-time tasks work a bit differently. In this case, we need to distinguish between the task itself and a descriptor that identifies the task:</strong></p>
<pre><code class="language-java">TaskDescriptor&lt;String&gt; taskDescriptor = TaskDescriptor.of("my-onetime-task", String.class);
Task&lt;String&gt; task = Tasks.oneTime(taskDescriptor)
  .execute((inst, ctx) -&gt; {
    LOG.info("Executed! Custom data {}, Instance {}", inst.getData(), inst.getId());
  });
</code></pre>
<p>This task definition accepts some data that we provide when we schedule the task, and can act on that data as appropriate. In this case, the data is a <em>String</em>, but it can be any type that db-scheduler is able to serialize. By default, this uses <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-serialization">Java Serialization</a> but db-scheduler also supports other mechanisms, such as Jackson and Gson.</p>
<p>We then need to register the task with our scheduler. However, we do this by passing the task to the <em>Scheduler.create()</em> method so that db-scheduler knows about it but doesn&#8217;t immediately start running it:</p>
<pre><code class="language-java">Scheduler scheduler = Scheduler.create(dataSource, task)
  .build();
</code></pre>
<p><strong>At this point, we can run our task at any time using our scheduler and task descriptor:</strong></p>
<pre><code class="language-java">scheduler.schedule(taskDescriptor.instance(UUID.randomUUID().toString())
  .data("Hello")
  .scheduledTo(Instant.now().plusSeconds(5))
);
</code></pre>
<p>Here we have to provide a unique instance ID for our task, and indicate when the task should run. We&#8217;ve also provided some data for our task to act on. The scheduler will then ensure that this task runs correctly at the desired time.</p>
<h2 id="bd-dynamic-recurring-tasks" data-id="dynamic-recurring-tasks"><strong>6. Dynamic Recurring Tasks</strong></h2>
<div class="bd-anchor" id="dynamic-recurring-tasks"></div>
<p><strong>Dynamic recurring tasks are tasks that are registered dynamically at runtime, similar to our one-time tasks. However, once registered, they&#8217;ll continue to run on a schedule similar to our simple recurring tasks.</strong></p>
<p>We create and start these exactly the same as for our one-time task, only using <em>Tasks.recurring()</em> instead:</p>
<pre><code class="language-java">TaskDescriptor&lt;String&gt; taskDescriptor = TaskDescriptor.of("my-dynamic-recurring-task", String.class);
Task&lt;String&gt; task = Tasks.recurring(taskDescriptor, new CronSchedule("*/5 * * * * ?", ZoneId.of("UTC")))
  .execute((inst, ctx) -&gt; {
    LOG.info("Executed! Custom data {}, Instance {}", inst.getData(), inst.getId());
  });
scheduler.schedule(taskDescriptor.instance(UUID.randomUUID().toString())
  .data("Hello")
  .scheduledTo(Instant.now().plusSeconds(15))
);
</code></pre>
<p>This will now start our task at the given time and then, once started, it&#8217;ll run at the given schedule. In this case, it first runs 15 seconds after the current time, and then every 5 seconds after that.</p>
<p>If we wish, we can schedule as many different instances of these as we need, and they&#8217;ll all run on their own schedule without interfering with each other.</p>
<h2 id="bd-use-with-spring-boot" data-id="use-with-spring-boot"><strong>7. Use With Spring Boot</strong></h2>
<div class="bd-anchor" id="use-with-spring-boot"></div>
<p><strong>If we&#8217;re using Spring Boot, db-scheduler provides a <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/spring-boot-starters">starter</a> dependency that we can use:</strong></p>
<pre><code class="language-xml">&lt;dependency&gt;
    &lt;groupId&gt;com.github.kagkarlsson&lt;/groupId&gt;
    &lt;artifactId&gt;db-scheduler-spring-boot-4-starter&lt;/artifactId&gt;
    &lt;version&gt;16.12.0&lt;/version&gt;
&lt;/dependency&gt;</code></pre>
<p>If we&#8217;re using Spring Boot 4.x then we need to use <em><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://mvnrepository.com/artifact/com.github.kagkarlsson/db-scheduler-spring-boot-4-starter">db-scheduler-spring-boot-4-starter</a></em>. If we&#8217;re still on Spring Boot 3.x then instead it&#8217;s <em><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://mvnrepository.com/artifact/com.github.kagkarlsson/db-scheduler-spring-boot-starter">db-scheduler-spring-boot-starter</a></em>.</p>
<p>This will automatically create and start our <em>Scheduler </em>instance as a Spring bean. On doing this, it&#8217;ll also automatically discover any tasks that have been created as Spring beans and register them with this scheduler. This means that the only thing we need to do is create the tasks themselves.</p>
<p>If we want to configure the <em>Scheduler </em>in any way, we can do this using properties in our standard way:</p>
<pre><code class="language-properties">db-scheduler.enabled=true
db-scheduler.polling-interval=5s
db-scheduler.heartbeat-interval=2m
db-scheduler.missed-heartbeats-limit=10
db-scheduler.threads=5</code></pre>
<p><strong>Everything else about using db-scheduler, including how we create and schedule tasks, is exactly the same as before</strong>. The starter just makes it simpler to get started in the first place.</p>
<h2 id="bd-conclusion" data-id="conclusion"><strong>8. Conclusion</strong></h2>
<div class="bd-anchor" id="conclusion"></div>
<p>In this article, we took a very quick look at db-scheduler, including how to schedule recurring and one-time tasks. There’s a lot more that we can do with this. Next time we need to manage scheduled jobs for your applications, why not give it a try?</p>
<p>As always, all the code from this article is available over on <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/eugenp/tutorials/tree/master/libraries-7">GitHub</a>.</p><p>The post <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-db-scheduler">DB-Scheduler: A Persistent, Cluster-Friendly Scheduler for Java</a> first appeared on <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com">Baeldung</a>.</p><Img align="left" border="0" height="1" width="1" alt="" style="border:0;float:left;margin:0;padding:0;width:1px!important;height:1px!important;" hspace="0" src="https://feeds.feedblitz.com/~/i/968126534/0/baeldung">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/968126534/baeldung"><img height="20" src="https://assets.feedblitz.com/i/fblike20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Pin it!" href="https://feeds.feedblitz.com/_/29/968126534/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2024%2f11%2fPersistence-Featured-Image-04-1024x536.jpg"><img height="20" src="https://assets.feedblitz.com/i/pinterest20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Post to X.com" href="https://feeds.feedblitz.com/_/24/968126534/baeldung"><img height="20" src="https://assets.feedblitz.com/i/x.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by email" href="https://feeds.feedblitz.com/_/19/968126534/baeldung"><img height="20" src="https://assets.feedblitz.com/i/email20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by RSS" href="https://feeds.feedblitz.com/_/20/968126534/baeldung"><img height="20" src="https://assets.feedblitz.com/i/rss20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a rel="NOFOLLOW" title="View Comments" href="https://www.baeldung.com/java-db-scheduler#respond"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/comments20.png"></a>&#160;<a title="Follow Comments via RSS" href="https://www.baeldung.com/java-db-scheduler/feed"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/commentsrss20.png"></a>&#160;</div>]]>
</content:encoded>
					
					<wfw:commentRss>https://feeds.feedblitz.com/~/968126534/0/baeldung~DBScheduler-A-Persistent-ClusterFriendly-Scheduler-for-Java/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<webfeeds:featuredImage>https://www.baeldung.com/wp-content/uploads/2024/11/Persistence-Featured-Image-04-150x150.jpg</webfeeds:featuredImage></item>
<item>
<feedburner:origLink>https://www.baeldung.com/java-weekly-660</feedburner:origLink>
		<title>Java Weekly, Issue 660</title>
		<link>https://feeds.feedblitz.com/~/968116088/0/baeldung~Java-Weekly-Issue</link>
					<comments>https://feeds.feedblitz.com/~/968116088/0/baeldung~Java-Weekly-Issue#respond</comments>
		
		<dc:creator><![CDATA[baeldung]]></dc:creator>
		<pubDate>Sat, 22 Aug 2026 11:26:18 +0000</pubDate>
				<category><![CDATA[Weekly Review]]></category>
		<category><![CDATA[no-ads]]></category>
		<category><![CDATA[no-after-post]]></category>
		<category><![CDATA[no-before-post]]></category>
		<category><![CDATA[no-optins]]></category>
		<guid isPermaLink="false">https://www.baeldung.com/?p=204721</guid>
					<description><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/2016/10/social-Weekly-Reviews-4.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="max-width:100% !important;height:auto !important;float: left; margin-right: 5px;" loading="lazy" /><p>A clear Hibernate speedup and a new JSON API coming to Java.</p>
<p>The post <a rel="NOFOLLOW" href="https://feeds.feedblitz.com/~/968116088/0/baeldung~Java-Weekly-Issue">Java Weekly, Issue 660</a> first appeared on <a rel="NOFOLLOW" href="https://www.baeldung.com">Baeldung</a>.</p><div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/968116088/baeldung"><img height="20" src="https://assets.feedblitz.com/i/fblike20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Pin it!" href="https://feeds.feedblitz.com/_/29/968116088/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2016%2f10%2fsocial-Weekly-Reviews-4.jpg"><img height="20" src="https://assets.feedblitz.com/i/pinterest20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Post to X.com" href="https://feeds.feedblitz.com/_/24/968116088/baeldung"><img height="20" src="https://assets.feedblitz.com/i/x.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by email" href="https://feeds.feedblitz.com/_/19/968116088/baeldung"><img height="20" src="https://assets.feedblitz.com/i/email20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by RSS" href="https://feeds.feedblitz.com/_/20/968116088/baeldung"><img height="20" src="https://assets.feedblitz.com/i/rss20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a rel="NOFOLLOW" title="View Comments" href="https://www.baeldung.com/java-weekly-660#respond"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/comments20.png"></a>&#160;<a title="Follow Comments via RSS" href="https://www.baeldung.com/java-weekly-660/feed"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/commentsrss20.png"></a>&#160;</div>]]>
</description>
										<content:encoded><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/2016/10/social-Weekly-Reviews-4.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="float: left; margin-right: 5px;" decoding="async" loading="lazy" srcset="https://www.baeldung.com/wp-content/uploads/2016/10/social-Weekly-Reviews-4.jpg 952w, https://www.baeldung.com/wp-content/uploads/2016/10/social-Weekly-Reviews-4-300x157.jpg 300w, https://www.baeldung.com/wp-content/uploads/2016/10/social-Weekly-Reviews-4-768x402.jpg 768w" sizes="auto, (max-width: 580px) 100vw, 580px" /><h2 style="text-align: left;" id="bd-spring-and-java" data-id="spring-and-java">1.<strong> Spring and Java</strong></h2>
<div class="bd-anchor" id="spring-and-java"></div>
<p><strong><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://in.relation.to/2026/08/19/hibernate-immutable-2lc-9x-speedup/">&gt;&gt; When @Immutable Made All the Difference: A 3.2x Speedup with Hibernate Second-Level Cache</a></strong> [<span style="color: #993300;">relation.to</span>]</p>
<p>Hibernate’s second-level cache jumps from 286 seconds to 90 seconds when <code>@Immutable</code>, <code>@Cache(READ_ONLY)</code>, and field-level <code>@Mutability(Immutability.class)</code> work together. This case study also shows why omitting the JSONB field annotation caused an 8.1x slowdown. Interesting read.</p>
<p><strong><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.infoq.com/news/2026/08/java-native-json-api/">&gt;&gt; JEP 540 Proposed to Target JDK 28 with a Simple JSON API</a></strong> [<span style="color: #993300;">infoq.com</span>]</p>
<p>JEP 540 is moving toward JDK 28 with an incubating, dependency-free, deliberately-small JSON API for straightforward parsing and generation.</p>
<h4><strong>Also worth reading:</strong></h4>
<ul>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://blog.frankel.ch/gradle-metadata-renovate-integration/" target="_blank" rel="noopener"><strong>Solving Gradle metadata and Renovate integration</strong></a> [<span style="color: #800000;">frankel.ch</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://foojay.io/today/introducing-boxlang-ai-explorer-a-local-catalog-for-every-ai-pattern/" target="_blank" rel="noopener"><strong>Introducing BoxLang AI Explorer: A Local Catalog for Every AI Pattern</strong></a> [<span style="color: #800000;">foojay.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://foojay.io/today/vibe-coding-maven-and-the-dependencies-you-didnt-choose/" target="_blank" rel="noopener"><strong>Vibe Coding, Maven, and the Dependencies You Didn&#8217;t Choose</strong></a> [<span style="color: #800000;">foojay.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://inside.java/2026/08/14/java-exhaustiveness-guide/" target="_blank" rel="noopener"><strong>Preparing for Change: Safe Switching over Sealed APIs</strong></a> [<span style="color: #800000;">inside.java</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://blogs.oracle.com/java/jdk-21-approaches-end-of-permissive-license" target="_blank" rel="noopener"><strong>JDK 21 approaches end-of-permissive license</strong></a> [<span style="color: #800000;">oracle.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://blog.jetbrains.com/kotlin/2026/08/exploring-compose-html-for-server-side-rendering/" target="_blank" rel="noopener"><strong>Exploring Compose HTML for Server Side Rendering</strong></a> [<span style="color: #800000;">jetbrains.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://marcphilipp.de/blog/2026/08/16/renovate-teaching-an-old-dog-new-tricks/" target="_blank" rel="noopener"><strong>Renovate: teaching an old dog new tricks</strong></a> [<span style="color: #800000;">marcphilipp.de</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.wimdeblauwe.com/blog/2026/08/17/writing-a-thymeleaf-component-library---part-4/" target="_blank" rel="noopener"><strong>Writing a Thymeleaf component library &#8211; part 4</strong></a> [<span style="color: #800000;">wimdeblauwe.com</span>]</li>
</ul>
<h4><strong>Webinars and presentations:</strong></h4>
<ul>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://foojay.io/today/build-secure-ai-chat-applications-with-boxlang-rag-ollama-and-amazon-bedrock-with-dan-card/" target="_blank" rel="noopener"><strong>Build Secure AI Chat Applications with BoxLang, RAG, Ollama, and Amazon Bedrock with Dan Card</strong></a> [<span style="color: #800000;">foojay.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://inside.java/2026/08/15/podcast-066/" target="_blank" rel="noopener"><strong>Episode 66 “JSON API, Valhalla Progress, LTS <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2764.png" alt="❤" class="wp-smiley" style="height: 1em; max-height: 1em;" /> PQC” [IJN]</strong></a> [<span style="color: #800000;">inside.java</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://nipafx.dev/inside-java-newscast-114" target="_blank" rel="noopener"><strong>JSON API, Valhalla Progress, LTS <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2764.png" alt="❤" class="wp-smiley" style="height: 1em; max-height: 1em;" /> PQC &#8211; Inside Java Newscast #114</strong></a> [<span style="color: #800000;">nipafx.dev</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://spring.io/blog/2026/08/17/spring-office-hours-podcast-S5E20" target="_blank" rel="noopener"><strong>Spring Office Hours Podcast: S5E20 &#8211; The Developer&#8217;s Guide to AI with Danny Thompson</strong></a> [<span style="color: #800000;">spring.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://spring.io/blog/2026/08/13/a-bootiful-podcast-andrey-santrosyan" target="_blank" rel="noopener"><strong>A Bootiful Podcast: Redouble AI CTO and founder Andrey Santrosyan</strong></a> [<span style="color: #800000;">spring.io</span>]</li>
</ul>
<h4><strong>Time to upgrade:</strong></h4>
<ul>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://quarkus.io/blog/quarkus-3-38-3-released/" target="_blank" rel="noopener"><strong>Quarkus 3.38.3 &#8211; Maintenance release</strong></a> [<span style="color: #800000;">quarkus.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://quarkus.io/blog/a2a-java-sdk-1-2-0-final-released/" target="_blank" rel="noopener"><strong>A2A Java SDK 1.2.0.Final released</strong></a> [<span style="color: #800000;">quarkus.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://quarkus.io/blog/quarkus-3-38-2-released/" target="_blank" rel="noopener"><strong>Quarkus 3.38.2 &#8211; Maintenance release</strong></a> [<span style="color: #800000;">quarkus.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://toomuchcoding.com/post/2026-08-20-stubborn-0-1-0-release/" target="_blank" rel="noopener"><strong>Stubborn Contract 0.1.0 released!</strong></a> [<span style="color: #800000;">toomuchcoding.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/apache/hive/releases/tag/rel%2Frelease-4.2.1" target="_blank" rel="noopener"><strong>Apache Hive 4.2.1</strong></a> [<span style="color: #800000;">github.com/apache</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/micronaut-projects/micronaut-core/releases/tag/v5.1.11" target="_blank" rel="noopener"><strong>Micronaut Core 5.1.11</strong></a> [<span style="color: #800000;">github.com/micronaut-projects</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/langchain4j/langchain4j/releases/tag/1.19.0" target="_blank" rel="noopener"><strong>LangChain4j 1.19.0</strong></a> [<span style="color: #800000;">github.com/langchain4j</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/helidon-io/helidon/releases/tag/4.5.3" target="_blank" rel="noopener"><strong>Helidon 4.5.3</strong></a> and <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/helidon-io/helidon/releases/tag/3.2.20" target="_blank" rel="noopener"><strong>3.2.20</strong></a> [<span style="color: #800000;">github.com/helidon-io</span>]</li>
</ul>
<h2 style="text-align: left;" id="bd-technical-amp-musings" data-id="technical-amp-musings">2.<strong> Technical &amp; Musings</strong></h2>
<div class="bd-anchor" id="technical-amp-musings"></div>
<p><strong><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://martinfowler.com/rachels-ramblings/citizens-agents-experts.html">&gt;&gt; Citizens Build, Agents Execute, Experts Govern</a></strong> [<span style="color: #993300;">martinfowler.com</span>]</p>
<p>AI agents are making it dramatically easier to build working software, but enterprise delivery still depends on engineering judgment. Of course it does.</p>
<h4><strong>Also worth reading:</strong></h4>
<ul>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://lucumr.pocoo.org/2026/8/19/what-is-reasoning/" target="_blank" rel="noopener"><strong>What Is Reasoning</strong></a> [<span style="color: #800000;">pocoo.org</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://nurkiewicz.com/2026/08/compiling-to-intermediate-representation-write-yourself-a-compiler.html" target="_blank" rel="noopener"><strong>Compiling to intermediate representation: Write yourself a compiler, Part III</strong></a> [<span style="color: #800000;">nurkiewicz.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://foojay.io/today/idempotent-write-paths-keeping-an-integration-pipeline-correct-when-messages-repeat/" target="_blank" rel="noopener"><strong>Idempotent Write Paths: Keeping an Integration Pipeline Correct When Messages Repeat</strong></a> [<span style="color: #800000;">foojay.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://henrikwarne.com/2026/08/15/lessons-learned-from-fixing-flaky-tests-with-claude/" target="_blank" rel="noopener"><strong>Lessons Learned from Fixing Flaky Tests with Claude</strong></a> [<span style="color: #800000;">henrikwarne.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://martinfowler.com/articles/practitioner-voice.html" target="_blank" rel="noopener"><strong>Practitioner Voice: The Writing Category Nobody has Named Yet</strong></a> [<span style="color: #800000;">martinfowler.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://blog.scottlogic.com/2026/08/17/incremental-steps-data-democratisation.html" target="_blank" rel="noopener"><strong>How to take incremental steps towards data democratisation by Andy Scotland</strong></a> [<span style="color: #800000;">scottlogic.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://blog.scottlogic.com/2026/08/14/ai-success-depends-on-data-foundations.html" target="_blank" rel="noopener"><strong>AI success depends on data foundations by James Heward</strong></a> [<span style="color: #800000;">scottlogic.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://netflixtechblog.medium.com/behind-the-scenes-evolving-netflixs-ads-event-pipeline-for-live-part-ii-826ebf9ad9fb" target="_blank" rel="noopener"><strong>Behind the Scenes: Evolving Netflix&#8217;s Ads Event Pipeline for Live &#8211; Part II</strong></a> [<span style="color: #800000;">medium.com</span>]</li>
</ul>
<h2 style="text-align: left;" id="bd-pick-of-the-week" data-id="pick-of-the-week">3.<strong> Pick of the Week</strong></h2>
<div class="bd-anchor" id="pick-of-the-week"></div>
<p><strong><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://alex.draftist.io/blog/the-bedrock-of-software-design-ycqvcedsj">&gt;&gt; The Bedrock of Software Design</a></strong> [<span style="color: #993300;">alex.draftist.io</span>]</p><p>The post <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-weekly-660">Java Weekly, Issue 660</a> first appeared on <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com">Baeldung</a>.</p><Img align="left" border="0" height="1" width="1" alt="" style="border:0;float:left;margin:0;padding:0;width:1px!important;height:1px!important;" hspace="0" src="https://feeds.feedblitz.com/~/i/968116088/0/baeldung">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/968116088/baeldung"><img height="20" src="https://assets.feedblitz.com/i/fblike20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Pin it!" href="https://feeds.feedblitz.com/_/29/968116088/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2016%2f10%2fsocial-Weekly-Reviews-4.jpg"><img height="20" src="https://assets.feedblitz.com/i/pinterest20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Post to X.com" href="https://feeds.feedblitz.com/_/24/968116088/baeldung"><img height="20" src="https://assets.feedblitz.com/i/x.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by email" href="https://feeds.feedblitz.com/_/19/968116088/baeldung"><img height="20" src="https://assets.feedblitz.com/i/email20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by RSS" href="https://feeds.feedblitz.com/_/20/968116088/baeldung"><img height="20" src="https://assets.feedblitz.com/i/rss20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a rel="NOFOLLOW" title="View Comments" href="https://www.baeldung.com/java-weekly-660#respond"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/comments20.png"></a>&#160;<a title="Follow Comments via RSS" href="https://www.baeldung.com/java-weekly-660/feed"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/commentsrss20.png"></a>&#160;</div>]]>
</content:encoded>
					
					<wfw:commentRss>https://feeds.feedblitz.com/~/968116088/0/baeldung~Java-Weekly-Issue/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<webfeeds:featuredImage>https://www.baeldung.com/wp-content/uploads/2016/10/social-Weekly-Reviews-4-150x150.jpg</webfeeds:featuredImage></item>
<item>
<feedburner:origLink>https://www.baeldung.com/java-weekly-659</feedburner:origLink>
		<title>Java Weekly, Issue 659</title>
		<link>https://feeds.feedblitz.com/~/967864352/0/baeldung~Java-Weekly-Issue</link>
					<comments>https://feeds.feedblitz.com/~/967864352/0/baeldung~Java-Weekly-Issue#comments</comments>
		
		<dc:creator><![CDATA[baeldung]]></dc:creator>
		<pubDate>Sat, 15 Aug 2026 10:23:09 +0000</pubDate>
				<category><![CDATA[Weekly Review]]></category>
		<category><![CDATA[no-ads]]></category>
		<category><![CDATA[no-after-post]]></category>
		<category><![CDATA[no-before-post]]></category>
		<category><![CDATA[no-optins]]></category>
		<guid isPermaLink="false">https://www.baeldung.com/?p=204657</guid>
					<description><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/2016/10/social-Weekly-Reviews-4.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="max-width:100% !important;height:auto !important;float: left; margin-right: 5px;" loading="lazy" /><p>Equality in Java is evolving.</p>
<p>The post <a rel="NOFOLLOW" href="https://feeds.feedblitz.com/~/967864352/0/baeldung~Java-Weekly-Issue">Java Weekly, Issue 659</a> first appeared on <a rel="NOFOLLOW" href="https://www.baeldung.com">Baeldung</a>.</p><div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/967864352/baeldung"><img height="20" src="https://assets.feedblitz.com/i/fblike20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Pin it!" href="https://feeds.feedblitz.com/_/29/967864352/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2016%2f10%2fsocial-Weekly-Reviews-4.jpg"><img height="20" src="https://assets.feedblitz.com/i/pinterest20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Post to X.com" href="https://feeds.feedblitz.com/_/24/967864352/baeldung"><img height="20" src="https://assets.feedblitz.com/i/x.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by email" href="https://feeds.feedblitz.com/_/19/967864352/baeldung"><img height="20" src="https://assets.feedblitz.com/i/email20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by RSS" href="https://feeds.feedblitz.com/_/20/967864352/baeldung"><img height="20" src="https://assets.feedblitz.com/i/rss20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a rel="NOFOLLOW" title="View Comments" href="https://www.baeldung.com/java-weekly-659#comments"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/comments20.png"></a>&#160;<a title="Follow Comments via RSS" href="https://www.baeldung.com/java-weekly-659/feed"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/commentsrss20.png"></a>&nbsp;
<div style="clear:left;"><a rel="NOFOLLOW" href="https://www.baeldung.com/java-weekly-659#comments"><h3>Comments</h3></a><ul><li><a rel="NOFOLLOW" href="https://www.baeldung.com/java-weekly-659#comment-15701">In reply to Vincent.   Hey, Vincent.   Thanks for the feedback. ...</a> <i>by Ulisses Lima</i><li><a rel="NOFOLLOW" href="https://www.baeldung.com/java-weekly-659#comment-15700">You have encoding prolem on your URL :    with Helidonâ€ ...</a> <i>by Vincent</i></ul></div>&#160;</div>]]>
</description>
										<content:encoded><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/2016/10/social-Weekly-Reviews-4.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="float: left; margin-right: 5px;" decoding="async" loading="lazy" srcset="https://www.baeldung.com/wp-content/uploads/2016/10/social-Weekly-Reviews-4.jpg 952w, https://www.baeldung.com/wp-content/uploads/2016/10/social-Weekly-Reviews-4-300x157.jpg 300w, https://www.baeldung.com/wp-content/uploads/2016/10/social-Weekly-Reviews-4-768x402.jpg 768w" sizes="auto, (max-width: 580px) 100vw, 580px" /><h2 style="text-align: left" id="bd-spring-and-java" data-id="spring-and-java">1.<strong> Spring and Java</strong></h2>
<div class="bd-anchor" id="spring-and-java"></div>
<p><strong><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://inside.java/2026/08/12/java-mcp-migration/">&gt;&gt; Evolving a Java MCP Server During MCP Specification Upgrades</a></strong> [<span style="color: #993300">inside.java</span>]</p>
<p>A practical guide to evolving a Helidon-based Java MCP server to the stateless. Header-based routing and a temporary adapter keep older clients working while tests exercise both protocol paths. Good stuff.</p>
<p><strong><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.infoq.com/news/2026/08/jep401-value-objects-preview/">&gt;&gt; Project Valhalla&#8217;s First Preview: JEP 401 Redefines == for Java Objects</a></strong> [<span style="color: #993300">infoq.com</span>]</p>
<p>JEP 401 brings identity-free value classes and records to preview, changing <code>==</code> for value objects while identity classes retain reference semantics. Good weekend read.</p>
<h4><strong>Also worth reading:</strong></h4>
<ul>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://blog.frankel.ch/security-baked-into-jvm/3/" target="_blank" rel="noopener"><strong>Security Baked Into the JVM: two Subjects, one call</strong></a> [<span style="color: #800000">frankel.ch</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://foojay.io/today/duckdb-in-spring-batch-replace-in-memory-java-loops-with-one-sql-statement/" target="_blank" rel="noopener"><strong>DuckDB in Spring Batch: Replace In-Memory Java Loops with One SQL Statement</strong></a> [<span style="color: #800000">foojay.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://foojay.io/today/push-v3-one-message-from-your-server-to-every-surface/" target="_blank" rel="noopener"><strong>Push V3: One Message From Your Server to Every Surface</strong></a> [<span style="color: #800000">foojay.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://foojay.io/today/embedding-duckdb-in-a-maven-app-and-using-it-for-things-that-arent-databases/" target="_blank" rel="noopener"><strong>Embedding DuckDB in a Maven App (and Using It for Things That Aren&#8217;t Databases)</strong></a> [<span style="color: #800000">foojay.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://inside.java/2026/08/11/efficient-java-apps-profiling-troubleshooting/" target="_blank" rel="noopener"><strong>The Power of JDK Flight Recorder: Efficient Profiling and Troubleshooting for Java Applications</strong></a> [<span style="color: #800000">inside.java</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://inside.java/2026/08/07/post-quantum-cryptography-in-long-term-support-jdk-releases/" target="_blank" rel="noopener"><strong>Post-Quantum Cryptography in Long-Term Support JDK Releases</strong></a> [<span style="color: #800000">inside.java</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://blog.jetbrains.com/idea/2026/08/how-to-use-ai-agents-in-intellij-idea-with-acp/" target="_blank" rel="noopener"><strong>How to Use AI Agents in IntelliJ IDEA With ACP</strong></a> [<span style="color: #800000">jetbrains.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://blog.jetbrains.com/idea/2026/08/top-5-ai-features-in-intellij-idea/" target="_blank" rel="noopener"><strong>Top 5 AI Features in IntelliJ IDEA</strong></a> [<span style="color: #800000">jetbrains.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://blog.jetbrains.com/idea/2026/08/agent-skills-in-intellij-idea/" target="_blank" rel="noopener"><strong>Agent Skills in IntelliJ IDEA</strong></a> [<span style="color: #800000">jetbrains.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.wimdeblauwe.com/blog/2026/08/10/writing-a-thymeleaf-component-library---part-3/" target="_blank" rel="noopener"><strong>Writing a Thymeleaf component library &#8211; part 3</strong></a> [<span style="color: #800000">wimdeblauwe.com</span>]</li>
</ul>
<h4><strong>Webinars and presentations:</strong></h4>
<ul>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://inside.java/2026/08/06/podcast-065/" target="_blank" rel="noopener"><strong>Episode 65 &#8220;Embracing Virtual Threads with Helidon&#8221; [I/O]</strong></a> [<span style="color: #800000">inside.java</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://quarkus.io/blog/quarkus-insights-256-what-is-floci/" target="_blank" rel="noopener"><strong>Quarkus Insights #256: What is Floci?</strong></a> [<span style="color: #800000">quarkus.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://spring.io/blog/2026/08/06/a-bootiful-podcast-gregory-green/" target="_blank" rel="noopener"><strong>A Bootiful Podcast: Data guru Gregory Green on RabbitMQ, Valkey, Gemfire, Data Flow, and more</strong></a> [<span style="color: #800000">spring.io</span>]</li>
</ul>
<h4><strong>Time to upgrade:</strong></h4>
<ul>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://blog.jetbrains.com/idea/2026/08/intellij-idea-2026-2-1/" target="_blank" rel="noopener"><strong>IntelliJ IDEA 2026.2.1 Is Out!</strong></a> [<span style="color: #800000">jetbrains.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/gradle/gradle/releases/tag/v9.7.0" target="_blank" rel="noopener"><strong>Gradle 9.7.0</strong></a> [<span style="color: #800000">github.com/gradle</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/eclipse-vertx/vert.x/releases/tag/4.5.32" target="_blank" rel="noopener"><strong>Eclipse Vert.x 4.5.32</strong></a> [<span style="color: #800000">github.com/eclipse-vertx</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/elastic/elasticsearch/releases/tag/v9.5.1" target="_blank" rel="noopener"><strong>Elasticsearch 9.5.1</strong></a> and <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/elastic/elasticsearch/releases/tag/v9.4.5" target="_blank" rel="noopener"><strong>9.4.5</strong></a> and <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/elastic/elasticsearch/releases/tag/v8.19.20" target="_blank" rel="noopener"><strong>8.19.20</strong></a> [<span style="color: #800000">github.com/elastic</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/Netflix/zuul/releases/tag/v4.1.4" target="_blank" rel="noopener"><strong>Netflix Zuul 4.1.4</strong></a> [<span style="color: #800000">github.com/Netflix</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/apache/camel/releases/tag/camel-4.18.4" target="_blank" rel="noopener"><strong>Apache Camel 4.18.4</strong></a> and <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/apache/camel/releases/tag/camel-4.14.9" target="_blank" rel="noopener"><strong>4.14.9</strong></a> and <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/apache/camel/releases/tag/camel-4.22.0" target="_blank" rel="noopener"><strong>4.22.0</strong></a> [<span style="color: #800000">github.com/apache</span>]</li>
</ul>
<h2 style="text-align: left" id="bd-technical-amp-musings" data-id="technical-amp-musings">2.<strong> Technical &amp; Musings</strong></h2>
<div class="bd-anchor" id="technical-amp-musings"></div>
<p><strong><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://mnot.net/blog/2026/linting_the_web.html">&gt;&gt; Informing HTTP Extension Design with Data</a></strong> [<span style="color: #993300">mnot.net</span>]</p>
<p>Mark Nottingham tests HTTP extensions against 120 million Common Crawl responses. The results show how invisible failures and weak migration incentives undermine adoption, yielding a practical lesson: design for repeatable deployment, make errors visible, and study real usage before extending a protocol.</p>
<h4><strong>Also worth reading:</strong></h4>
<ul>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://blog.jetbrains.com/research/2026/08/programming-language-migration/" target="_blank" rel="noopener"><strong>Programming Language Migration 2025: Why Developers Switch</strong></a> [<span style="color: #800000">jetbrains.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://marcphilipp.de/blog/2026/08/10/one-required-check-to-rule-them-all/" target="_blank" rel="noopener"><strong>One required check to rule them all</strong></a> [<span style="color: #800000">marcphilipp.de</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://event-driven.io/en/vertical-slices-and-dependencies/" target="_blank" rel="noopener"><strong>Vertical slices, their ownership and external dependencies</strong></a> [<span style="color: #800000">event-driven.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://martinfowler.com/articles/exploring-gen-ai/tdd-in-the-agent-loop.html" target="_blank" rel="noopener"><strong>TDD inside the agent loop &#8211; theater or actual value?</strong></a> [<span style="color: #800000">martinfowler.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://blog.scottlogic.com/2026/08/12/unlocking-your-data-in-collaboration.html" target="_blank" rel="noopener"><strong>Unlocking your data: the value is in collaboration</strong></a> [<span style="color: #800000">scottlogic.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://blog.scottlogic.com/2026/08/10/agile-leadership.html" target="_blank" rel="noopener"><strong>Agile Leadership</strong></a> [<span style="color: #800000">scottlogic.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://blog.scottlogic.com/2026/08/06/how-to-accelerate-agentic-adoption.html" target="_blank" rel="noopener"><strong>How to accelerate agentic adoption</strong></a> [<span style="color: #800000">scottlogic.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://netflixtechblog.com/how-and-why-netflix-built-a-real-time-distributed-graph-part-3-querying-the-graph-with-grpc-0f3468349607" target="_blank" rel="noopener"><strong>How and Why Netflix Built a Real-Time Distributed Graph: Part 3 &#8211; Querying the graph with gRPC</strong></a> [<span style="color: #800000">netflixtechblog.com</span>]</li>
</ul>
<h2 style="text-align: left" id="bd-pick-of-the-week" data-id="pick-of-the-week">3.<strong> Pick of the Week</strong></h2>
<div class="bd-anchor" id="pick-of-the-week"></div>
<p><strong><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://jon.chrt.dev/2026/04/15/things-you-didnt-know-about-indexes.html">&gt;&gt; Things you didn&#8217;t know about indexes</a></strong> [<span style="color: #993300">jon.chrt.dev</span>]</p><p>The post <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-weekly-659">Java Weekly, Issue 659</a> first appeared on <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com">Baeldung</a>.</p><Img align="left" border="0" height="1" width="1" alt="" style="border:0;float:left;margin:0;padding:0;width:1px!important;height:1px!important;" hspace="0" src="https://feeds.feedblitz.com/~/i/967864352/0/baeldung">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/967864352/baeldung"><img height="20" src="https://assets.feedblitz.com/i/fblike20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Pin it!" href="https://feeds.feedblitz.com/_/29/967864352/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2016%2f10%2fsocial-Weekly-Reviews-4.jpg"><img height="20" src="https://assets.feedblitz.com/i/pinterest20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Post to X.com" href="https://feeds.feedblitz.com/_/24/967864352/baeldung"><img height="20" src="https://assets.feedblitz.com/i/x.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by email" href="https://feeds.feedblitz.com/_/19/967864352/baeldung"><img height="20" src="https://assets.feedblitz.com/i/email20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by RSS" href="https://feeds.feedblitz.com/_/20/967864352/baeldung"><img height="20" src="https://assets.feedblitz.com/i/rss20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a rel="NOFOLLOW" title="View Comments" href="https://www.baeldung.com/java-weekly-659#comments"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/comments20.png"></a>&#160;<a title="Follow Comments via RSS" href="https://www.baeldung.com/java-weekly-659/feed"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/commentsrss20.png"></a>&nbsp;
<div style="clear:left;"><a rel="NOFOLLOW" href="https://www.baeldung.com/java-weekly-659#comments"><h3>Comments</h3></a><ul><li><a rel="NOFOLLOW" href="https://www.baeldung.com/java-weekly-659#comment-15701">In reply to Vincent.   Hey, Vincent.   Thanks for the feedback. ...</a> <i>by Ulisses Lima</i><li><a rel="NOFOLLOW" href="https://www.baeldung.com/java-weekly-659#comment-15700">You have encoding prolem on your URL :    with Helidonâ€ ...</a> <i>by Vincent</i></ul></div>&#160;</div>]]>
</content:encoded>
					
					<wfw:commentRss>https://feeds.feedblitz.com/~/967864352/0/baeldung~Java-Weekly-Issue/feed</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
		<webfeeds:featuredImage>https://www.baeldung.com/wp-content/uploads/2016/10/social-Weekly-Reviews-4-150x150.jpg</webfeeds:featuredImage></item>
</channel></rss>

