<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="http://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>Tue, 15 Sep 2026 05:32:46 +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-gson-deserialization-inaccessibleobjectexception</feedburner:origLink>
		<title>Gson Deserialization and the InaccessibleObjectException</title>
		<link>https://feeds.feedblitz.com/~/969124883/0/baeldung~Gson-Deserialization-and-the-InaccessibleObjectException</link>
					<comments>https://feeds.feedblitz.com/~/969124883/0/baeldung~Gson-Deserialization-and-the-InaccessibleObjectException#respond</comments>
		
		<dc:creator><![CDATA[Marcin Buczkowski]]></dc:creator>
		<pubDate>Tue, 15 Sep 2026 05:32:46 +0000</pubDate>
				<category><![CDATA[JSON]]></category>
		<category><![CDATA[Gson]]></category>
		<guid isPermaLink="false">https://www.baeldung.com/java-gson-deserialization-inaccessibleobjectexception</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;" fetchpriority="high" /><p>Learn how to resolve an InaccessibleObjectException when working with Gson and modern Java versions.</p>
<p>The post <a rel="NOFOLLOW" href="https://feeds.feedblitz.com/~/969124883/0/baeldung~Gson-Deserialization-and-the-InaccessibleObjectException">Gson Deserialization and the InaccessibleObjectException</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/969124883/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/969124883/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/969124883/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/969124883/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/969124883/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-gson-deserialization-inaccessibleobjectexception#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-gson-deserialization-inaccessibleobjectexception/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" 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="(max-width: 580px) 100vw, 580px" /><h2 id="bd-overview" data-id="overview">1. Overview</h2>
<div class="bd-anchor" id="overview"></div>
<p>Starting with version 9, Java places a strong emphasis on encapsulation. The major feature behind this is the <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-modularity" target="_blank" rel="noopener">Java Platform Module System (JPMS)</a>. It controls how our own packages are exposed and, at the same time, restricts access to Java&#8217;s internal classes. However, many libraries rely heavily on reflection to access private members. So we need ways to relax these restrictions in a controlled manner.</p>
<p>In this tutorial, we&#8217;ll learn how to avoid the <em>InaccessibleObjectException</em> when <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/gson-deserialization-guide" target="_blank" rel="noopener">deserializing JSON with Gson</a>. We&#8217;ll focus on modular projects and date handling.</p>
<h2 id="bd-gson-status" data-id="gson-status">2. Gson Status</h2>
<div class="bd-anchor" id="gson-status"></div>
<p>Gson offers convenient tools for serializing objects to JSON and deserializing them back, and it relies on accessing private fields via reflection. With strong encapsulation in place, this no longer works seamlessly, either for our own objects or for Java&#8217;s internal classes. The latest Gson versions have made a small move towards public APIs, specifically for <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-record-keyword" target="_blank" rel="noopener">records</a> and <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-8-date-time-intro" target="_blank" rel="noopener">dates</a>.</p>
<p>Gson is currently in maintenance mode. <strong>Therefore, we shouldn&#8217;t expect any new features, only bug fixes and security fixes.</strong></p>
<h2 id="bd-project-setup" data-id="project-setup">3. Project Setup</h2>
<div class="bd-anchor" id="project-setup"></div>
<p>Let&#8217;s examine the <em>pom.xml</em> we&#8217;ll use. We need Java 17 to demonstrate strong encapsulation and for its full support of records. Therefore, we set it in the <em>properties</em> section of <em>pom.xml</em>:</p>
<pre><code class="language-xml">&lt;maven.compiler.release&gt;17&lt;/maven.compiler.release&gt;</code></pre>
<p>Next, let&#8217;s check the Gson version. We should use the <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://mvnrepository.com/artifact/com.google.code.gson/gson" target="_blank" rel="noopener">latest one</a>:</p>
<pre><code class="language-xml">&lt;dependency&gt;
    &lt;groupId&gt;com.google.code.gson&lt;/groupId&gt;
    &lt;artifactId&gt;gson&lt;/artifactId&gt;
    &lt;version&gt;2.14.0&lt;/version&gt;
&lt;/dependency&gt;</code></pre>
<h2 id="bd-gson-and-java-modules" data-id="gson-and-java-modules">4. Gson and Java Modules</h2>
<div class="bd-anchor" id="gson-and-java-modules"></div>
<p>Let&#8217;s create a simple Java project named <em>gson-module</em>. <strong>We declare the <em>gson.exception</em> module in the <em>module-info.java</em> file:</strong></p>
<pre><code class="language-java">module gson.exception {
    requires com.google.gson;
    requires org.slf4j;
    exports gson.exception;
}</code></pre>
<p>With the <em>requires</em> statement, we state that our module needs Gson (and SLF4J for logging). Then, we make our own package <em>gson.exception</em> available to other modules with the <em>exports</em> statement.</p>
<p>Now let&#8217;s add some classes that describe a conference. The first is a good old POJO:</p>
<pre><code class="language-java">public class ConferencePojo {
    private String name;
    private int numberOfParticipants;
    // standard setters and getters
}</code></pre>
<p>This object stores the name and number of participants of a conference. It has private fields and public getters and setters.</p>
<p>Next, we prepare an equivalent Java record:</p>
<pre><code class="language-java">public record ConferenceRecord(String name, int numberOfParticipants) {
}</code></pre>
<p>With a record, we don&#8217;t need to declare the fields or write getters and setters.</p>
<h3 id="bd-1-gson-failure-with-pojo" data-id="1-gson-failure-with-pojo">4.1. Gson Failure With POJO</h3>
<div class="bd-anchor" id="1-gson-failure-with-pojo"></div>
<p>Gson easily deserializes a POJO such as <em>ConferencePojo</em> in a <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-classpath-vs-modulepath" target="_blank" rel="noopener">classpath project, but not in a module path</a> one. To prove that, we&#8217;ll run the <em>GsonModuleMain</em> application inside our modular project. Let&#8217;s look at its <em>main</em> method:</p>
<pre><code class="language-java">public static void main(String[] args) {
    String moduleName = GsonModuleMain.class.getModule()
      .getName();
    if (moduleName == null) {
        log.info("Mode: [ Class Path ] (Class in the Unnamed Module)");
    } else {
        log.info("Mode: [ Module Path ] - Module name: " + moduleName);
    }
    Gson gson = new Gson();
    String json = "{\"name\":\"Java Conference\"}";
    try {
        ConferencePojo pojo = gson.fromJson(json, ConferencePojo.class);
        log.info("Deserialization successful! Object " + pojo);
    } catch (Exception e) {
        log.error("Expected exception caught!", e);
    }
}</code></pre>
<p>At the beginning, we log whether the JVM actually loaded our class from the module path. Then we try to deserialize the POJO. Let&#8217;s examine the result:</p>
<pre><code class="language-plaintext">10:40:06.766 [main] INFO gson.exception.GsonModuleMain -- Mode: [ Module Path ] - Module name: gson.exception
10:40:06.868 [main] ERROR gson.exception.GsonModuleMain -- Expected exception caught!
com.google.gson.JsonIOException: Failed making field 'gson.exception.ConferencePojo#name' accessible; either increase its visibility or write a custom TypeAdapter for its declaring type.
See https://github.com/google/gson/blob/main/Troubleshooting.md#reflection-inaccessible-to-module-gson
...
Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make field private java.lang.String gson.exception.ConferencePojo.name accessible: module gson.exception does not "opens gson.exception" to module com.google.gson
...</code></pre>
<p><strong>Gson throws a <em>JsonIOException</em> caused by an <em>InaccessibleObjectException</em>.</strong> From the two messages, we learn what happened and get hints on how to solve the problem. In short, within a modular project, Gson can&#8217;t access the private fields of our class unless we let it.</p>
<h3 id="bd-2-success-with-records" data-id="2-success-with-records">4.2. Success With Records</h3>
<div class="bd-anchor" id="2-success-with-records"></div>
<p>With records, we&#8217;ll get a completely different result. Let&#8217;s use a <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/junit-5" target="_blank" rel="noopener">JUnit 5</a> test to demonstrate it:</p>
<pre><code class="language-java">@Test
void givenModularAndExportedPackage_whenDeserializingRecord_thenSuccess() {
    String json = """
        {
            "name": "Java Conference",
            "numberOfParticipants": 150
        }
        """;
    Gson gson = new Gson();
    ConferenceRecord result = assertDoesNotThrow(() -&gt; {
        return gson.fromJson(json, ConferenceRecord.class);
    });
    assertNotNull(result);
    assertEquals("Java Conference", result.name());
}</code></pre>
<p>This time, Gson successfully deserializes the JSON and creates the record. <strong>Since version 2.10, Gson uses a record&#8217;s canonical constructor when instantiating the object, unlike classes, where Gson needs access to private fields.</strong></p>
<h2 id="bd-how-to-deserialize-a-pojo" data-id="how-to-deserialize-a-pojo">5. How to Deserialize a POJO</h2>
<div class="bd-anchor" id="how-to-deserialize-a-pojo"></div>
<p>If we still want to use a POJO, let&#8217;s follow the hints from the exception messages. We have four ways to fix this.</p>
<h3 id="bd-1-make-fields-public" data-id="1-make-fields-public">5.1. Make Fields Public</h3>
<div class="bd-anchor" id="1-make-fields-public"></div>
<p>Let&#8217;s create a copy of <em>ConferencePojo</em> with public fields:</p>
<pre><code class="language-java">public class ConferencePojoPublic {
    public String name;
    public int numberOfParticipants;
}</code></pre>
<p>Now Java lets Gson access the fields with reflection, and deserialization succeeds. However, we lose encapsulation this way.</p>
<h3 id="bd-2-opens-to-expose-private-fields" data-id="2-opens-to-expose-private-fields">5.2. <em>opens</em> to Expose Private Fields</h3>
<div class="bd-anchor" id="2-opens-to-expose-private-fields"></div>
<p>To let Gson work with our private fields, we can open our package to it. Let&#8217;s create a new project, <em>gson-module-opens</em>, and look at its <em>module-info.java</em> file:</p>
<pre><code class="language-java">module gson.exception {
    requires com.google.gson;
    requires org.slf4j;
    opens gson.exception to com.google.gson;
    exports gson.exception;
}</code></pre>
<p><strong>With the statement <em>opens gson.exception to com.google.gson</em>, we allow Gson to access the private fields in the <em>gson.exception</em> package.</strong> Let&#8217;s run our <em>GsonModuleMain</em> application again:</p>
<pre><code class="language-plaintext">19:08:55.369 [main] INFO gson.exception.GsonModuleMain -- Mode: [ Module Path ] - Module name: gson.exception
19:08:55.410 [main] INFO gson.exception.GsonModuleMain -- Deserialization successful! Object gson.exception.ConferencePojo@675d3402</code></pre>
<p>This time, the program doesn&#8217;t throw an exception and deserializes the JSON successfully, even in the modular project.</p>
<h3 id="bd-3-using-the-typeadapter-abstract-class" data-id="3-using-the-typeadapter-abstract-class">5.3. Using the <em>TypeAdapter</em> Abstract Class</h3>
<div class="bd-anchor" id="3-using-the-typeadapter-abstract-class"></div>
<p>If we can&#8217;t use <em>opens</em>, we can extend Gson&#8217;s <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.javadoc.io/doc/com.google.code.gson/gson/latest/com.google.gson/com/google/gson/TypeAdapter.html" target="_blank" rel="noopener"><em>TypeAdapter</em></a> abstract class for our POJO. All we need to do is implement its <em>write</em> and <em>read</em> methods. As we focus on deserialization, let&#8217;s look only at the <em>read</em> method:</p>
<pre><code class="language-java">@Override
public ConferencePojo read(JsonReader in) throws IOException {
    String name = null;
    int numberOfParticipants = 0;
    in.beginObject();
    while (in.hasNext()) {
        String key = in.nextName();
        if ("name".equals(key)) {
            name = in.nextString();
        } else if ("numberOfParticipants".equals(key)) {
            numberOfParticipants = in.nextInt();
        } else {
            in.skipValue();
        }
    }
    in.endObject();
    ConferencePojo result = new ConferencePojo();
    result.setName(name);
    result.setNumberOfParticipants(numberOfParticipants);
    return result;
}</code></pre>
<p>The <em>read</em> method returns an instance of <em>ConferencePojo</em>. It loops over all the entries of the <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.javadoc.io/doc/com.google.code.gson/gson/latest/com.google.gson/com/google/gson/stream/JsonReader.html" target="_blank" rel="noopener"><em>JsonReader</em></a> and picks out the fields by their JSON names.</p>
<p>Note that we create the <em>ConferencePojo</em> object with its default constructor and fill it in with setters. <strong>This is the crucial point: to use a <em>TypeAdapter</em>, we need a public API for creating the object.</strong> In our case, that&#8217;s the setters, but a constructor, public fields, a factory, or a builder would work as well.</p>
<p>Now let&#8217;s test the adapter:</p>
<pre><code class="language-java">@Test
void whenAdapterForPojo_thenSuccess() {
    Gson gson = new GsonBuilder()
      .registerTypeAdapter(ConferencePojo.class, new ConferencePojoAdapter())
      .create();
    String json = """
        {
            "name": "Java Conference",
            "numberOfParticipants": 100
        }
        """;
    ConferencePojo result = gson.fromJson(json, ConferencePojo.class);
    assertNotNull(result);
    assertEquals("Java Conference", result.getName());
}</code></pre>
<p>Note that we need to register the adapter with <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://javadoc.io/doc/com.google.code.gson/gson/latest/com.google.gson/com/google/gson/GsonBuilder.html" target="_blank" rel="noopener"><em>GsonBuilder</em></a>.</p>
<h3 id="bd-4-the---add-opens-argument-as-a-last-resort" data-id="4-the---add-opens-argument-as-a-last-resort">5.4. The <em>&#8211;add-opens</em> Argument as a Last Resort</h3>
<div class="bd-anchor" id="4-the---add-opens-argument-as-a-last-resort"></div>
<p>When we can&#8217;t modify the module&#8217;s source code, we still have one option left. <strong>We can open the package when the program starts by passing the <em>&#8211;add-opens</em> argument to the JVM.</strong> Let&#8217;s look at the argument for our <em>gson-module</em> project, which doesn&#8217;t open its package:</p>
<pre><code class="language-plaintext">--add-opens gson.exception/gson.exception=com.google.gson</code></pre>
<p>Starting from the left, we have the module name <em>gson.exception</em>, as declared in the <em>module-info.java</em> file. Next comes the package we want to open, <em>gson.exception</em>. Finally, we name the module we grant the access to, <em>com.google.gson</em>.</p>
<p>This is the launch-time equivalent of the <em>opens</em> statement, and with it, <em>GsonModuleMain</em> from <em>gson-module</em> deserializes the POJO successfully. However, we should treat it as a last resort, since the argument lives outside the code and we have to repeat it in every launch configuration. Our article on <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-illegal-reflective-access" target="_blank" rel="noopener">illegal reflective access</a> covers the background in more detail.</p>
<h2 id="bd-gson-and-time" data-id="gson-and-time">6. Gson and Time</h2>
<div class="bd-anchor" id="gson-and-time"></div>
<p><strong>Besides problems with modular projects, we can run into the same exception when deserializing JSON into the date and time classes from the <em>java.time</em> API, such as <em>LocalDate</em>, <em>Instant</em>, or <em>Duration</em>.</strong> With strong encapsulation and an older Gson version, we get a <em>JsonIOException</em> with the message &#8220;Failed making field &#8216;java.time.LocalDate#year&#8217; accessible&#8221;, again caused by an <em>InaccessibleObjectException</em>. This time, Gson tries to reach the private fields of a Java internal class. Moreover, we can&#8217;t solve this problem with the <em>opens</em> statement, as it can only open our own packages, not Java&#8217;s internals. <strong>However, Gson 2.14.0 has restored support for these classes.</strong></p>
<h3 id="bd-1-localdate-and-structured-json" data-id="1-localdate-and-structured-json">6.1. <em>LocalDate</em> and Structured JSON</h3>
<div class="bd-anchor" id="1-localdate-and-structured-json"></div>
<p>Let&#8217;s add a <em>conferenceStart</em> field in a new <em>ConferencePojoWithDate</em> class. We&#8217;re continuing in the <em>gson-module-opens</em> project, as the other fields are private:</p>
<pre><code class="language-java">public class ConferencePojoWithDate {
    private String name;
    private int numberOfParticipants;
    private LocalDate conferenceStart;
    // standard setters and getters
}</code></pre>
<p>Now let&#8217;s prepare the JSON. We need to use a nested structure for <em>conferenceStart</em>:</p>
<pre><code class="language-json">{
    "name": "Java Conference",
    "numberOfParticipants": 500,
    "conferenceStart": {
        "year": 2026,
        "month": 8,
        "day": 17
    }
}</code></pre>
<p><strong>Note that the keys <em>year</em>, <em>month</em>, and <em>day</em> exactly match the names of the private fields of <em>LocalDate</em>.</strong> The same is true for the other time classes. For example, for <em>Duration</em>, the nested JSON provides the seconds and nanoseconds and looks like this:</p>
<pre><code class="language-json">"duration": {
    "seconds": 7200,
    "nanos": 0
}</code></pre>
<p>Gson kept this naming convention for backward compatibility. It doesn&#8217;t (and isn&#8217;t allowed to) access the private fields of Java&#8217;s internal classes anymore. Instead, the authors implemented built-in <em>TypeAdapter</em>s that use the public <em>java.time</em> API to transfer the data.</p>
<p>We should be especially careful to use the correct field names. If Gson doesn&#8217;t find a matching key in the JSON, it silently falls back to the default value of zero. For <em>LocalDate</em>, a zero month then triggers a completely different exception, a <em>DateTimeException</em> from the date validation in <em>java.time</em>.</p>
<p><strong>Next, we can&#8217;t deserialize a date in ISO format out of the box.</strong> So, a plain string value such as the following fails with a <em>JsonSyntaxException</em>:</p>
<pre><code class="language-json">"conferenceStart":"2026-08-17"</code></pre>
<p>To handle dates encoded as strings, we need to implement a custom <em>TypeAdapter</em>.</p>
<p>Finally, let&#8217;s emphasize that the same rules apply to records: we can deserialize nested time structures out of the box, and we need a <em>TypeAdapter</em> otherwise.</p>
<h2 id="bd-conclusion" data-id="conclusion">7. Conclusion</h2>
<div class="bd-anchor" id="conclusion"></div>
<p>In this article, we looked at using Gson in modern, modular Java. <strong>We saw that it no longer works as easily as it did with Java 8 and the classpath.</strong></p>
<p>We examined the problem in a modular project and looked at several ways to make Gson fit the rules of the JPMS. As our first measure, we made the class fields public. Next, we gave Gson access to private fields with the <em>opens</em> statement, or with the equivalent <em>&#8211;add-opens</em> JVM argument.</p>
<p>We then implemented a <em>TypeAdapter</em> that creates the object through its public API. <strong>We also saw that Gson works with records out of the box, using their canonical constructors.</strong></p>
<p>Finally, we checked how Gson handles the classes from the <em>java.time</em> package. <strong>We noted that the newest version can deserialize nested time objects as expected again.</strong></p>
<p><strong>The bottom line is that we have two main ways to avoid the <em>InaccessibleObjectException</em>.</strong> The first is to open our code to Gson&#8217;s reflection, and with the <em>opens</em> statement, we can grant that access to Gson only. The second is to switch to records and stay within the rules of the JPMS. In addition, if we have a public API for creating the object, we can implement a <em>TypeAdapter</em>.</p><p>The post <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-gson-deserialization-inaccessibleobjectexception">Gson Deserialization and the InaccessibleObjectException</a> first appeared on <a href="http://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/969124883/0/baeldung">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/969124883/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/969124883/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/969124883/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/969124883/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/969124883/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-gson-deserialization-inaccessibleobjectexception#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-gson-deserialization-inaccessibleobjectexception/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/~/969124883/0/baeldung~Gson-Deserialization-and-the-InaccessibleObjectException/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/java-jackson-fix-no-creator-exception</feedburner:origLink>
		<title>Resolving Exception: Cannot Deserialize From Object Value (No Delegate- Or Property-Based Creator)</title>
		<link>https://feeds.feedblitz.com/~/969076403/0/baeldung~Resolving-Exception-Cannot-Deserialize-From-Object-Value-No-Delegate-Or-PropertyBased-Creator</link>
					<comments>https://feeds.feedblitz.com/~/969076403/0/baeldung~Resolving-Exception-Cannot-Deserialize-From-Object-Value-No-Delegate-Or-PropertyBased-Creator#respond</comments>
		
		<dc:creator><![CDATA[Martin Blažević]]></dc:creator>
		<pubDate>Mon, 14 Sep 2026 04:21:09 +0000</pubDate>
				<category><![CDATA[Jackson]]></category>
		<category><![CDATA[Exception]]></category>
		<guid isPermaLink="false">https://www.baeldung.com/java-jackson-fix-no-creator-exception</guid>
					<description><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/2021/09/Java-5-Featured-1024x536.png" class="webfeedsFeaturedVisual wp-post-image" alt="" style="max-width:100% !important;height:auto !important;float: left; margin-right: 5px;" /><p>During JSON deserialization, Jackson may throw an InvalidDefinitionException when it can't determine how to create an instance of the target class. In this article, you'll learn how to fix this in Jackson 2.x and 3.x.</p>
<p>The post <a rel="NOFOLLOW" href="https://feeds.feedblitz.com/~/969076403/0/baeldung~Resolving-Exception-Cannot-Deserialize-From-Object-Value-No-Delegate-Or-PropertyBased-Creator">Resolving Exception: Cannot Deserialize From Object Value (No Delegate- Or Property-Based Creator)</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/969076403/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/969076403/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2021%2f09%2fJava-5-Featured-1024x536.png"><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/969076403/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/969076403/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/969076403/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-fix-no-creator-exception#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-fix-no-creator-exception/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/2021/09/Java-5-Featured-1024x536.png" class="webfeedsFeaturedVisual wp-post-image" alt="" style="float: left; margin-right: 5px;" decoding="async" loading="lazy" srcset="https://www.baeldung.com/wp-content/uploads/2021/09/Java-5-Featured-1024x536.png 1024w, https://www.baeldung.com/wp-content/uploads/2021/09/Java-5-Featured-300x157.png 300w, https://www.baeldung.com/wp-content/uploads/2021/09/Java-5-Featured-768x402.png 768w, https://www.baeldung.com/wp-content/uploads/2021/09/Java-5-Featured-100x52.png 100w, https://www.baeldung.com/wp-content/uploads/2021/09/Java-5-Featured.png 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><a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/jackson">Jackson</a> is a Java library commonly used to convert between Java objects and JSON. <strong>During JSON deserialization, Jackson may throw an <em>InvalidDefinitionException</em> when it can&#8217;t determine how to create an instance of the target class.</strong> This can happen even when the JSON structure matches the class fields.</p>
<p>In this tutorial, we&#8217;ll reproduce the exception using Jackson 2.17.2 and explore several ways to resolve it.</p>
<h2 id="bd-reproducing-the-exception" data-id="reproducing-the-exception">2. Reproducing the Exception</h2>
<div class="bd-anchor" id="reproducing-the-exception"></div>
<p>Let&#8217;s start with an immutable <em>Notification</em> class that contains a parameterized constructor:</p>
<pre><code class="language-java">public class Notification {
    private final String message;
    private final int priority;
    public Notification(String message, int priority) {
        this.message = message;
        this.priority = priority;
    }
    // getters
}</code></pre>
<p>Next, let&#8217;s try to deserialize a JSON object into the <em>Notification</em> class:</p>
<pre><code class="language-java">String json = "{\"message\":\"Server maintenance\",\"priority\":2}";
ObjectMapper mapper = new ObjectMapper();
mapper.readValue(json, Notification.class);</code></pre>
<p>Although the JSON properties match the fields in <em>Notification</em>, <strong>Jackson can&#8217;t determine how they map to the constructor parameters</strong>. The constructor doesn&#8217;t specify which JSON property Jackson should use for each parameter.</p>
<p>As a result, deserialization fails with an <em>InvalidDefinitionException</em>:</p>
<pre><code class="language-plaintext">Cannot construct instance of `com.baeldung.invaliddefinitionexception.Notification` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)</code></pre>
<p><strong>The exception indicates that Jackson needs a suitable mechanism to create the <em>Notification</em> instance.</strong> We can address this in several ways.</p>
<h2 id="bd-adding-a-default-constructor" data-id="adding-a-default-constructor">3. Adding a Default Constructor</h2>
<div class="bd-anchor" id="adding-a-default-constructor"></div>
<p>One way to resolve the exception is to <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/jackson-exception#111-the-problem-no-default-constructor"><strong>provide a no-argument constructor</strong></a>:</p>
<pre><code class="language-java">public class NotificationWithDefaultConstructor {
    private String message;
    private int priority;
    public NotificationWithDefaultConstructor() {
    }
    // getters and setters
}</code></pre>
<p>By default, <strong>Jackson relies on a no-argument constructor</strong> to instantiate the target class. It can then <strong>populate the object&#8217;s properties during deserialization</strong>:</p>
<pre><code class="language-java">NotificationWithDefaultConstructor notification = objectMapper.readValue(json, NotificationWithDefaultConstructor.class);
assertEquals("Server maintenance", notification.getMessage());
assertEquals(2, notification.getPriority());</code></pre>
<p><strong>This approach works well for mutable classes, where Jackson can set the properties after creating the instance.</strong></p>
<h2 id="bd-defining-a-property-based-creator" data-id="defining-a-property-based-creator">4. Defining a Property-Based Creator</h2>
<div class="bd-anchor" id="defining-a-property-based-creator"></div>
<p>For immutable classes, we can <strong>explicitly define how Jackson should use the parameterized constructor</strong>:</p>
<pre><code class="language-java">import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
public class NotificationWithCreator {
    private final String message;
    private final int priority;
    @JsonCreator
    public NotificationWithCreator(
      @JsonProperty("message") String message, 
      @JsonProperty("priority") int priority) {
        this.message = message;
        this.priority = priority;
    }
    
    // getters
}</code></pre>
<p>In this case, the <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/jackson-deserialization-multi-param-constructor#deserialization-using-jsoncreator"><em>@JsonCreator</em> annotation</a> tells Jackson to use the annotated constructor to create the object. <strong>The <em>@JsonProperty</em> annotations specify which JSON property corresponds to each constructor parameter</strong>.</p>
<p>With the constructor configured as a creator, we can deserialize the JSON while keeping the class immutable:</p>
<pre><code class="language-java">NotificationWithCreator notification = objectMapper.readValue(json, NotificationWithCreator.class);
assertEquals("Server maintenance", notification.getMessage());
assertEquals(2, notification.getPriority());</code></pre>
<p>In addition, we should make sure to import the annotations from the <em>com.fasterxml.jackson.annotation </em>package, which Jackson 3.x also uses. Jackson won&#8217;t recognize creator annotations imported from the legacy <em>org.codehaus.jackson</em> package.</p>
<h3 id="bd-1-factory-methods-as-creators" data-id="1-factory-methods-as-creators">4.1. Factory Methods as Creators</h3>
<div class="bd-anchor" id="1-factory-methods-as-creators"></div>
<p>Factory methods can also be creators. If Jackson doesn&#8217;t recognize our factory method as a creator, it will throw the same <em>InvalidDefinitionException</em>.</p>
<p>To resolve the issue, we annotate the method and its parameters in the same way as we do with parameterized constructors:</p>
<pre><code class="language-java">@JsonCreator
public static NotificationWithFactory create(
  @JsonProperty("message") String message,
  @JsonProperty("priority") int priority) {
    return new NotificationWithFactory(message, priority);
}</code></pre>
<p>Now, this method can also act as a creator.</p>
<h2 id="bd-discovering-constructor-parameter-names" data-id="discovering-constructor-parameter-names">5. Discovering Constructor Parameter Names</h2>
<div class="bd-anchor" id="discovering-constructor-parameter-names"></div>
<p>Finally, instead of adding Jackson annotations to the target class, we can configure Jackson to discover constructor parameter names.</p>
<h3 id="bd-1-using-parameternamesmodule" data-id="1-using-parameternamesmodule">5.1. Using <em>ParameterNamesModule</em></h3>
<div class="bd-anchor" id="1-using-parameternamesmodule"></div>
<p>In Jackson 2.x, we can use <em>ParameterNamesModule</em> to discover constructor parameter names without adding <em>@JsonProperty</em> annotations:</p>
<pre><code class="language-java">ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new ParameterNamesModule());
Notification notification = mapper.readValue(json, Notification.class);
assertEquals("Server maintenance", notification.getMessage());
assertEquals(2, notification.getPriority());</code></pre>
<p><strong>We need to compile the class with the Java <em>-parameters</em> option so that the parameter names are available at runtime.</strong> <strong>In Jackson 3.x, this functionality is built into <em>jackson-databind</em> and enabled by default,</strong> so we don&#8217;t need to register a separate module.</p>
<h3 id="bd-2-using-paranamermodule" data-id="2-using-paranamermodule">5.2. Using <em>ParanamerModule</em></h3>
<div class="bd-anchor" id="2-using-paranamermodule"></div>
<p>Another option in Jackson 2.x is to use <em>ParanamerModule</em>. First, we need to add the <em>jackson-module-paranamer</em> dependency to our project:</p>
<pre><code class="language-xml">&lt;dependency&gt;
    &lt;groupId&gt;com.fasterxml.jackson.module&lt;/groupId&gt;
    &lt;artifactId&gt;jackson-module-paranamer&lt;/artifactId&gt;
    &lt;version&gt;${jackson.version}&lt;/version&gt;
&lt;/dependency&gt;</code></pre>
<p>Next, we register <em>ParanamerModule</em> with the <em>ObjectMapper</em>:</p>
<pre><code class="language-java">ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new ParanamerModule());
Notification notification =
    mapper.readValue(json, Notification.class);
assertEquals("Server maintenance", notification.getMessage());
assertEquals(2, notification.getPriority());</code></pre>
<p>Once registered, <strong><em>ParanamerModule</em> </strong><span style="margin: 0px;padding: 0px"><strong>gives Jackson the constructor parameter names</strong>, so it can match the </span>message and priority to the corresponding JSON properties.</p>
<p>However, <em>Paranamer</em> is discontinued and supports Jackson 2.x only, which limits this approach for newer projects.</p>
<h2 id="bd-conclusion" data-id="conclusion">6. Conclusion</h2>
<div class="bd-anchor" id="conclusion"></div>
<p>In this article, we reproduced a Jackson deserialization exception that occurs when Jackson can&#8217;t determine how to create the target object. We then explored several approaches to resolve it.</p>
<p>These include adding a default constructor, defining a property-based creator with <em>@JsonCreator</em> and <em>@JsonProperty</em>, and letting Jackson discover constructor parameter names. Static factory methods can also serve as creators.</p><p>The post <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-jackson-fix-no-creator-exception">Resolving Exception: Cannot Deserialize From Object Value (No Delegate- Or Property-Based Creator)</a> first appeared on <a href="http://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/969076403/0/baeldung">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/969076403/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/969076403/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2021%2f09%2fJava-5-Featured-1024x536.png"><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/969076403/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/969076403/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/969076403/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-fix-no-creator-exception#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-fix-no-creator-exception/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/~/969076403/0/baeldung~Resolving-Exception-Cannot-Deserialize-From-Object-Value-No-Delegate-Or-PropertyBased-Creator/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<webfeeds:featuredImage>https://www.baeldung.com/wp-content/uploads/2021/09/Java-5-Featured-150x150.png</webfeeds:featuredImage></item>
<item>
<feedburner:origLink>https://www.baeldung.com/java-weekly-663</feedburner:origLink>
		<title>Java Weekly, Issue 663</title>
		<link>https://feeds.feedblitz.com/~/969048446/0/baeldung~Java-Weekly-Issue</link>
					<comments>https://feeds.feedblitz.com/~/969048446/0/baeldung~Java-Weekly-Issue#respond</comments>
		
		<dc:creator><![CDATA[baeldung]]></dc:creator>
		<pubDate>Sun, 13 Sep 2026 11:00:00 +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=204876</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 better spec-driven development and the brain as example architecture.</p>
<p>The post <a rel="NOFOLLOW" href="https://feeds.feedblitz.com/~/969048446/0/baeldung~Java-Weekly-Issue">Java Weekly, Issue 663</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/969048446/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/969048446/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/969048446/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/969048446/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/969048446/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-663#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-663/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="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://foojay.io/today/from-spec-driven-development-to-living-specifications-in-java-projects/">&gt;&gt; From Spec-Driven Development to Living Specifications in Java Projects</a></strong> [<span style="color: #993300;">foojay.io</span>]</p>
<p>An interesting Java-focused piece exploreing a more durable model: bringing specifications closer to the code so they remain useful, testable, and alive as the system evolves.</p>
<h4><strong>Also worth reading:</strong></h4>
<ul>
<li><strong>&gt;&gt;</strong> <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://inside.java/2026/09/03/java-acceleration-curve25519-field-operations/" target="_blank" rel="noopener"><strong>Acceleration of Curve25519 Field Operations with Java Software and Intrinsics</strong></a> [<span style="color: #800000;">inside.java</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://blog.jetbrains.com/idea/2026/09/debug-past-an-http-403-without-breaking-spring-security/" target="_blank" rel="noopener"><strong>Debug Past an HTTP 403 Without Breaking Spring Security</strong></a> [<span style="color: #800000;">jetbrains.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.wimdeblauwe.com/blog/2026/09/06/testing-your-auto-configuration-against-a-missing-optional-dependency/" target="_blank" rel="noopener"><strong>Testing your auto-configuration against a missing optional dependency</strong></a> [<span style="color: #800000;">wimdeblauwe.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://foojay.io/today/no-database-operations-found-what-writing-a-spring-boot-analyzer-taught-me-about-spring/" target="_blank" rel="noopener"><strong>No Database Operations Found: What Writing a Spring Boot Analyzer Taught Me About Spring</strong></a> [<span style="color: #800000;">foojay.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://foojay.io/today/masking-a-jvm-thread-dump-without-breaking-the-analysis/" target="_blank" rel="noopener"><strong>Masking a JVM thread dump without breaking the analysis</strong></a> [<span style="color: #800000;">foojay.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://foojay.io/today/bringing-raspberry-pico-to-quarkus-with-firmata/" target="_blank" rel="noopener"><strong>Bringing Raspberry Pico to Quarkus with Firmata</strong></a> [<span style="color: #800000;">foojay.io</span>]</li>
<li><strong>&gt;&gt; </strong><a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://foojay.io/today/building-an-agentic-warehouse-management-system-part-1-where-ai-agents-add-value/" target="_blank" rel="noopener"><strong>Building an Agentic Warehouse Management System &#8211; Part One</strong></a>, <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://foojay.io/today/building-an-agentic-warehouse-management-system-part-2-java-and-spring-ai/" target="_blank" rel="noopener"><strong>Part Two</strong></a>, and <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://foojay.io/today/building-an-agentic-warehouse-management-system-part-3-tools-decisions-and-actions/" target="_blank" rel="noopener"><strong>Part Three</strong></a> [<span style="color: #800000;">foojay.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://donraab.medium.com/my-ten-year-quest-to-evolve-java-collections-beyond-java-stream-310f0c287be0" target="_blank" rel="noopener"><strong>My Ten Year Quest to Evolve Java Collections Beyond Java Stream</strong></a> [<span style="color: #800000;">medium.com</span>]</li>
</ul>
<h4><strong>Webinars and presentations:</strong></h4>
<ul>
<li><strong>&gt;&gt;</strong> <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://inside.java/2026/09/04/memory-management-principles-java/" target="_blank" rel="noopener"><strong>Principles of Memory Management in Java</strong></a> [<span style="color: #800000;">inside.java</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://quarkus.io/blog/quarkus-insights-258-quarkus-feature-flags/" target="_blank" rel="noopener"><strong>Quarkus Insights #258: Quarkus Feature Flags</strong></a> [<span style="color: #800000;">quarkus.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://spring.io/blog/2026/09/03/a-bootiful-podcast-catherine-edelvais" target="_blank" rel="noopener"><strong>A Bootiful Podcast: BellSoft&#8217;s Catherine Edelveis on hardened runtime images, container security, 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="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://blog.jetbrains.com/kotlin/2026/09/kotlin-2-4-20-released/" target="_blank" rel="noopener"><strong>Kotlin 2.4.20 Released</strong></a> [<span style="color: #800000;">jetbrains.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://blog.jetbrains.com/kotlin/2026/09/kotlin-toolchain-0-12-multiplatform-library-publishing-wasm-apps-and-more/" target="_blank" rel="noopener"><strong>Kotlin Toolchain 0.12: Multiplatform Library Publishing, Wasm Apps, and More</strong></a> [<span style="color: #800000;">jetbrains.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://quarkus.io/blog/quarkus-3-39-2-released/" target="_blank" rel="noopener"><strong>Quarkus 3.39.2, 3.33.3.2 LTS, 3.27.5.2 LTS &#8211; Maintenance releases</strong></a> [<span style="color: #800000;">quarkus.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://spring.io/blog/2026/09/09/spring-tools-5-4-0-released" target="_blank" rel="noopener"><strong>Spring Tools 5.4.0 released</strong></a> [<span style="color: #800000;">spring.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/jetty/jetty.project/releases/tag/jetty-12.1.13" target="_blank" rel="noopener"><strong>Jetty 12.1.13</strong></a> and <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/jetty/jetty.project/releases/tag/jetty-12.0.39" target="_blank" rel="noopener"><strong>12.0.39</strong></a> [<span style="color: #800000;">github.com/jetty</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/eclipse-vertx/vert.x/releases/tag/5.1.8" target="_blank" rel="noopener"><strong>Vert.x 5.1.8</strong></a> [<span style="color: #800000;">github.com/eclipse-vertx</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/elastic/elasticsearch/releases/tag/v9.5.3" target="_blank" rel="noopener"><strong>Elasticsearch 9.5.3</strong></a> [<span style="color: #800000;">github.com/elastic</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/micronaut-projects/micronaut-core/releases/tag/v5.1.14" target="_blank" rel="noopener"><strong>Micronaut Core 5.1.14</strong></a>, <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/micronaut-projects/micronaut-core/releases/tag/v4.10.27" target="_blank" rel="noopener"><strong>4.10.27</strong></a>, and <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/micronaut-projects/micronaut-core/releases/tag/v3.10.11" target="_blank" rel="noopener"><strong>3.10.11</strong></a> [<span style="color: #800000;">github.com/micronaut-projects</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="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.allthingsdistributed.com/2026/09/the-oldest-architecture-in-computing.html">&gt;&gt; The oldest architecture in computing</a></strong> [<span style="color: #993300;">allthingsdistributed.com</span>]</p>
<p>Werner Vogels looks to the brain for a model of how useful agent memory should work. A fascinating argument that the next breakthroughs in trusted, autonomous agents may come from studying the oldest computing architecture we know.</p>
<h4><strong>Also worth reading:</strong></h4>
<ul>
<li><strong>&gt;&gt;</strong> <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://lucumr.pocoo.org/2026/9/7/astra-why/" target="_blank" rel="noopener"><strong>Astra for Coding: Why Are We Doing This Again?</strong></a> [<span style="color: #800000;">lucumr.pocoo.org</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://netflixtechblog.medium.com/the-lifecycle-of-llm-as-a-judge-building-aligning-and-monitoring-at-scale-c95bd8283508" target="_blank" rel="noopener"><strong>The Lifecycle of LLM-as-a-Judge: Building, Aligning, and Monitoring at Scale</strong></a> [<span style="color: #800000;">netflixtechblog.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://foojay.io/today/did-your-ai-agent-run-the-debugger-one-jvm-bug-two-agent-runs/" target="_blank" rel="noopener"><strong>Did Your AI Agent Ever Run a Debugger? One JVM Bug, Two Agent Runs</strong></a> [<span style="color: #800000;">foojay.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://blog.frankel.ch/building-ai-agent-from-scratch/" target="_blank" rel="noopener"><strong>Build an AI Agent (From Scratch)</strong></a> [<span style="color: #800000;">frankel.ch</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://lucumr.pocoo.org/2026/9/5/latent-powers/" target="_blank" rel="noopener"><strong>Latent Powers</strong></a> [<span style="color: #800000;">lucumr.pocoo.org</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://blog.jetbrains.com/platform/2026/09/the-evolution-of-wsl-support-in-jetbrains-ides/" target="_blank" rel="noopener"><strong>The Evolution of WSL Support in JetBrains IDEs</strong></a> [<span style="color: #800000;">jetbrains.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.infoq.com/presentations/context-engineering-redis-llm-architecture/" target="_blank" rel="noopener"><strong>Beyond Prompting: Context Engineering for Production-Grade AI</strong></a> [<span style="color: #800000;">infoq.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://foojay.io/today/from-opentelemetry-to-duckdb/" target="_blank" rel="noopener"><strong>From OpenTelemetry to DuckDB</strong></a> [<span style="color: #800000;">foojay.io</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="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://blog.cloudflare.com/dns-cache-memory-optimization-1111/">&gt;&gt; How we saved 100 terabytes of memory by optimizing 1.1.1.1’s DNS cache</a></strong> [<span style="color: #993300;">blog.cloudflare.com</span>]</p><p>The post <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-weekly-663">Java Weekly, Issue 663</a> first appeared on <a href="http://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/969048446/0/baeldung">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/969048446/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/969048446/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/969048446/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/969048446/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/969048446/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-663#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-663/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/~/969048446/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-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;" loading="lazy" /><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" loading="lazy" 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="auto, (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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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>The post <a href="http://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="http://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;" loading="lazy" /><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="http://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="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://en.wikipedia.org/wiki/HTTP/2">HTTP/2</a>, asynchronous communication, and <a href="http://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="http://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="http://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="http://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="http://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>The post <a href="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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>The post <a href="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-weekly-662">Java Weekly, Issue 662</a> first appeared on <a href="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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>
</div><p>The post <a href="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-weekly-661">Java Weekly, Issue 661</a> first appeared on <a href="http://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="http://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="http://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="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-creating-localdate-with-values"><em>LocalDate</em></a> or <a href="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://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>The post <a href="http://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="http://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="http://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="http://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="http://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="http://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="http://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="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/spring-5-webclient"><em>WebClient</em></a>, <a href="http://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>The post <a href="http://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="http://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>
</channel></rss>

