<?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>Fri, 03 Apr 2026 18:40:45 +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-aot-class-loading-linking</feedburner:origLink>
		<title>Ahead-of-Time Class Loading &#038; Linking</title>
		<link>https://feeds.feedblitz.com/~/953194679/0/baeldung~AheadofTime-Class-Loading-Linking</link>
					<comments>https://feeds.feedblitz.com/~/953194679/0/baeldung~AheadofTime-Class-Loading-Linking#respond</comments>
		
		<dc:creator><![CDATA[Polivakha Mikhail]]></dc:creator>
		<pubDate>Fri, 03 Apr 2026 18:40:45 +0000</pubDate>
				<category><![CDATA[JVM]]></category>
		<category><![CDATA[JVM Flags]]></category>
		<guid isPermaLink="false">https://www.baeldung.com/?p=203357</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;" fetchpriority="high" /><p>JEP 514 and JEP 515 are both part of the OpenJDK Project Leyden effort to improve Java startup and warmup performance. Learn how they work together.</p>
The post <a rel="NOFOLLOW" href="https://feeds.feedblitz.com/~/953194679/0/baeldung~AheadofTime-Class-Loading-Linking">Ahead-of-Time Class Loading & Linking</a> first appeared on <a rel="NOFOLLOW" href="https://www.baeldung.com">Baeldung</a>.<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/953194679/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/953194679/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/953194679/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/953194679/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/953194679/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-aot-class-loading-linking#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-aot-class-loading-linking/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" 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="(max-width: 580px) 100vw, 580px" /><h2 id="bd-introduction" data-id="introduction">1. Introduction</h2>
<div class="bd-anchor" id="introduction"></div>
<p>JDK 24 introduced AOT Cache with <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://openjdk.org/jeps/483">JEP 483</a>. This cache allows applications to start faster by pre-loading and also pre-linking classes. However, the workflow of creating the cache effectively required two separate <i>java</i> invocations.</p>
<p>As a result, JDK 25 improves on that with two new JEPs. First, <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://openjdk.org/jeps/514">JEP 514</a> simplifies the AOT cache creation into a single command. And second, <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://openjdk.org/jeps/515">JEP 515</a> extends the cache to store method execution profiles, improving application warmup time.</p>
<p>In this article, we&#8217;ll explore both new JEPs and see how they work together. It is also important to note that we&#8217;re going ot need JDK 25 to take advantage of these features.</p>
<h2 id="bd-how-aot-cache-worked-in-jdk-24" data-id="how-aot-cache-worked-in-jdk-24">2. How AOT Cache Worked in JDK 24</h2>
<div class="bd-anchor" id="how-aot-cache-worked-in-jdk-24"></div>
<p>Before we delve into the JDK 25 ways of doing AOT Caches, let&#8217;s quickly recap how AOT caching worked with JDK 24.</p>
<p>To create an AOT cache back then, we had to invoke the <i>java</i> utility twice, and thus create two separate <em>java</em> processes. The first invocation runs the application in record mode. It means that Runtime observes how the application behaves during a training run and saves that information into an AOT configuration file:</p>
<pre><code class="language-bash">$ java -XX:AOTMode=record -XX:AOTConfiguration=app.aotconf -cp app.jar com.example.App</code></pre>
<p>The second invocation uses that configuration generated on the previous step to actually build the cache:</p>
<pre><code class="language-bash">$ java -XX:AOTMode=create -XX:AOTConfiguration=app.aotconf  -XX:AOTCache=app.aot</code></pre>
<p>And finally, we can run the application with the generated cache, which, theoretically, should significantly reduce startup time:</p>
<pre><code class="language-bash">$ java -XX:AOTCache=app.aot -cp app.jar com.example.App</code></pre>
<p>This workflow, while it of course works, leaves us with a temporary configuration file and requires managing two separate commands. The experienced readers may note that a similar clumsy process with two phases was with AppCDS archives (effectively, a predecessor to AOT Cache). So, JEP 514 addresses exactly that for AOT Caches now.</p>
<h2 id="bd-one-shot-aot-cache-creation-jep-514" data-id="one-shot-aot-cache-creation-jep-514">3. One-Shot AOT Cache Creation (JEP 514)</h2>
<div class="bd-anchor" id="one-shot-aot-cache-creation-jep-514"></div>
<p>JEP 514 introduces a new command-line non-standard (<i>-XX</i>) VM option: <i>AOTCacheOutput</i>. When we use this option alone, without any other AOT flags, the launcher automatically splits the invocation into two internal sub-invocations—one for training and one for cache creation.</p>
<p>So, instead of the two-step workflow above, we can simply do:</p>
<pre><code class="language-bash">$ java -XX:AOTCacheOutput=app.aot -cp app.jar com.example.App</code></pre>
<p>This single command replaces the two commands that were initially used to create the AOT Cache. The JVM runs the application as a training exercise, records the dynamics, and then just creates the AOT cache in one shot.</p>
<p>The production command (providing the cache to the production workload) remains the same since JDK 24:</p>
<pre><code class="language-bash">$ java -XX:AOTCache=app.aot -cp app.jar com.example.App</code></pre>
<p>But here is the thing &#8211; <strong>there is still a two-phase procedure done in the background</strong>. Effectively, the <i>java</i> launcher creates two subprocesses to complete the cache creation. That is important, and it has its implications.</p>
<h2 id="bd-the-downsides-of-the-one-shot-approach" data-id="the-downsides-of-the-one-shot-approach">4. The Downsides of the One-Shot Approach</h2>
<div class="bd-anchor" id="the-downsides-of-the-one-shot-approach"></div>
<p>One may think that a two-process setup is just the obvious choice, and it is the way to go &#8211; not quite.</p>
<p>As mentioned, these are two <em>distinct</em> java processes that are going to get launched, and both of them have their own heaps. And because they are both launched by the java launcher process (literally the one that is created by calling the <i>java</i> binary), the peak memory consumption is potentially doubled. So, if we specify <i>-Xmx4g</i>, the one-step workflow, potentially, at most, will need 8GB of heap memory in total to complete.</p>
<p>So, the one-step workflow is great for most scenarios, but the two-step approach also has its place, in particular in memory-constrained environments. It may easily be the case that the cloud VM that is going to host our application will not have sufficient RAM resources to serve the double-sized heap. In that case, the explicit two-step workflow is the preferred option.</p>
<h2 id="bd-aot-method-profiling-jep-515" data-id="aot-method-profiling-jep-515">5. AOT Method Profiling (JEP 515)</h2>
<div class="bd-anchor" id="aot-method-profiling-jep-515"></div>
<p>While JEP 514 simplifies the process of AOT cache creation, JEP 515 enhances what information the cache stores.</p>
<p>To understand JEP 515, we need to recall how HotSpot reaches peak performance. The JIT compiler identifies hot methods (the methods that are executed relatively frequently) and then compiles them to optimized native code. But in order to do this, it has to collect some profiling information for those methods. And this process takes time. Usually, this time is called a <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/jvm-start-up">warmup period</a>, and during this period, the application runs slower than it potentially can.</p>
<p>And frankly, it is often the case that the execution patterns of our application are roughly the same. Our production workloads often took similar <i>if</i> branches under the same circumstances. So the profiling information won&#8217;t really change from one app launch to another. Thus, it also makes sense to cache it ahead of time.</p>
<p>So, JEP 515 solves this by extending the AOT cache to include method execution profiles from the training run. <strong>When the application starts in production, those profiles are instantly available, so the JIT compiler can begin generating optimized code right away, without waiting for warmup.</strong></p>
<p>The cool thing is that we don&#8217;t need to change the launch command, let alone the application code, to benefit from this feature. Profiling data is automatically collected during the training run and then stored in the AOT cache. So, this just works out-of-the-box with the one-step workflow from JEP 514:</p>
<pre><code class="language-bash"># Training + cache creation (profiles are included automatically)
$ java -XX:AOTCacheOutput=app.aot -cp app.jar com.example.App
# Production run (benefits from both cached classes and cached profiling info)
$ java -XX:AOTCache=app.aot -cp app.jar com.example.App
</code></pre>
<p>In the case above, the JVM starts with the code cache that already contains certain profiling information.</p>
<h2 id="bd-runtime-profiling-vs-cached-profiling" data-id="runtime-profiling-vs-cached-profiling">6. Runtime Profiling vs. Cached Profiling</h2>
<div class="bd-anchor" id="runtime-profiling-vs-cached-profiling"></div>
<p>An important note here is that cached profiles don&#8217;t prevent additional profiling during production. The HotSpot JVM continues to profile and optimize the application as it runs, combining the benefits of AOT profiles, online profiling, and JIT compilation.</p>
<p><strong>It is important since an application&#8217;s behavior in production can still possibly diverge from what was observed during the training run</strong>. Cached profiles just give the JIT a quick start, allowing it to compile some methods sooner. As the app runs, the HotSpot re-evaluates its understanding of workload patterns and then recompiles methods if needed.</p>
<h2 id="bd-conclusion" data-id="conclusion">7. Conclusion</h2>
<div class="bd-anchor" id="conclusion"></div>
<p>JEP 514 and JEP 515 are both part of the <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://openjdk.org/projects/leyden">OpenJDK Project Leyden</a> effort to improve Java startup and warmup performance. JEP 514 brings a practical quality-of-life improvement — collapsing the two-step AOT cache creation into a single command. While often the preferred approach, still, in memory-constrained environments, the two-phase process might be the right way to go.</p>
<p>JEP 515 enriches the cached data by including method profiles, so the JIT compiler can start compiling from the very start of the app.</p>The post <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-aot-class-loading-linking">Ahead-of-Time Class Loading & Linking</a> first appeared on <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com">Baeldung</a>.<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/953194679/0/baeldung">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/953194679/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/953194679/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/953194679/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/953194679/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/953194679/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-aot-class-loading-linking#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-aot-class-loading-linking/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/~/953194679/0/baeldung~AheadofTime-Class-Loading-Linking/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/jackson-deserialization-multi-param-constructor</feedburner:origLink>
		<title>JSON Deserialization with Multiple Parameters Constructor Using Jackson</title>
		<link>https://feeds.feedblitz.com/~/953193365/0/baeldung~JSON-Deserialization-with-Multiple-Parameters-Constructor-Using-Jackson</link>
					<comments>https://feeds.feedblitz.com/~/953193365/0/baeldung~JSON-Deserialization-with-Multiple-Parameters-Constructor-Using-Jackson#respond</comments>
		
		<dc:creator><![CDATA[Michael Krimgen]]></dc:creator>
		<pubDate>Fri, 03 Apr 2026 18:35:46 +0000</pubDate>
				<category><![CDATA[Jackson]]></category>
		<category><![CDATA[Java Constructor]]></category>
		<category><![CDATA[Serialization]]></category>
		<guid isPermaLink="false">https://www.baeldung.com/?p=203337</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;" /><p>Learn how to deserialize JSON into a Java object using multi-parameter constructors.</p>
The post <a rel="NOFOLLOW" href="https://feeds.feedblitz.com/~/953193365/0/baeldung~JSON-Deserialization-with-Multiple-Parameters-Constructor-Using-Jackson">JSON Deserialization with Multiple Parameters Constructor Using Jackson</a> first appeared on <a rel="NOFOLLOW" href="https://www.baeldung.com">Baeldung</a>.<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/953193365/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/953193365/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/953193365/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/953193365/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/953193365/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/jackson-deserialization-multi-param-constructor#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/jackson-deserialization-multi-param-constructor/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-introduction" data-id="introduction">1. Introduction</h2>
<div class="bd-anchor" id="introduction"></div>
<p>In this tutorial, we&#8217;ll learn how to deserialize JSON into Java objects using multi-parameter constructors with <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/jackson">Jackson</a>.</p>
<p><strong>By default, Jackson requires a default constructor that doesn&#8217;t accept any parameters.</strong> The fields are set using setter methods or reflection. If we want Jackson to use a non-default constructor, we need to annotate that constructor with the <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/jackson-annotations"><em>@JsonCreator</em> annotation</a>. This annotation can be applied to constructors and static factory methods of records and enums. In this tutorial, we&#8217;ll have a look at all these cases.</p>
<p>We&#8217;ll also look at the options Jackson provides to reduce the number of annotations needed for deserialization.</p>
<h2 id="bd-setup" data-id="setup">2. Setup</h2>
<div class="bd-anchor" id="setup"></div>
<h3 id="bd-1-maven-dependencies" data-id="1-maven-dependencies">2.1. Maven Dependencies</h3>
<div class="bd-anchor" id="1-maven-dependencies"></div>
<p>In addition to the basic <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core">Jackson dependency</a>, we need <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://mvnrepository.com/artifact/com.fasterxml.jackson.module/jackson-module-parameter-names">Jackson&#8217;s parameter names module</a>:</p>
<pre><code class="language-xml">&lt;dependency&gt;
    &lt;groupId&gt;com.fasterxml.jackson.core&lt;/groupId&gt;
    &lt;artifactId&gt;jackson-core&lt;/artifactId&gt;
    &lt;version&gt;2.17.2&lt;/version&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
    &lt;groupId&gt;com.fasterxml.jackson.module&lt;/groupId&gt;
    &lt;artifactId&gt;jackson-module-parameter-names&lt;/artifactId&gt;
    &lt;version&gt;2.17.2&lt;/version&gt;
&lt;dependency&gt;
</code></pre>
<h3 id="bd-2-java-classes" data-id="2-java-classes">2.2. Java Classes</h3>
<div class="bd-anchor" id="2-java-classes"></div>
<p>Throughout the tutorial, we&#8217;ll use the <em>Ticket</em> class:</p>
<pre><code class="language-java">public class Ticket {
    @JsonProperty("event")
    private String eventName;
    private String guest;
    private final Currency currency;
    private final int price;
    public Ticket() {
        this.price = 0;
        this.currency = Currency.EUR;
    }
    public void setGuest(String guest) {
        this.guest = guest;
    }
    
    // getters for all attributes
}</code></pre>
<p>Note that we defined a setter method only for the guest attributes, while providing getters for all attributes. Here, we intentionally omit the setters for the three other attributes to demonstrate the behavior of the deserialization. Also, we use <em>@JsonProperty</em> on the <em>eventName</em> attribute to demonstrate the different ways Jackson offers to serialize a field.</p>
<p>Here&#8217;s the currency enum:</p>
<pre><code class="language-java">public enum Currency {
    EUR("Euro", "cent"),
    GBP("Pound sterling", "penny"),
    CHF("Swiss franc", "Rappen");
    private String fullName;
    private String fractionalUnit;
    Currency(String fullName, String fractionalUnit) {
        this.fullName = fullName;
        this.fractionalUnit = fractionalUnit;
    }
}</code></pre>
<h3 id="bd-3-json-to-deserialize" data-id="3-json-to-deserialize">2.3. JSON To Deserialize</h3>
<div class="bd-anchor" id="3-json-to-deserialize"></div>
<p>Here&#8217;s the JSON that we want to deserialize in the examples:</p>
<pre><code class="language-json">{
  "event": "Devoxx",
  "guest": "Maria Monroe",
  "currency": "EUR",
  "price": 50
}</code></pre>
<h2 id="bd-default-deserialization" data-id="default-deserialization">3. Default Deserialization</h2>
<div class="bd-anchor" id="default-deserialization"></div>
<p>We need to define a default, no-argument constructor because the class has a final attribute. <strong>If we only define a constructor that takes the currency and price as arguments, Jackson won’t be able to deserialize the object:</strong></p>
<pre><code class="language-java">public Ticket(Currency currency, int price) {
    this.price = price;
    this.currency = currency;
}</code></pre>
<p>Jackson will <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/jackson-exception">throw an exception</a>:</p>
<pre><code class="language-bash">com.fasterxml.jackson.databind.exc.MismatchedInputException: 
  Cannot construct instance of `com.baeldung.jackson.multiparameterconstructor.Ticket` 
  (no Creators, like default constructor, exist): cannot deserialize from Object value</code></pre>
<h2 id="bd-deserialization-using-jsoncreator" data-id="deserialization-using-jsoncreator">4. Deserialization Using <em>@JsonCreator</em></h2>
<div class="bd-anchor" id="deserialization-using-jsoncreator"></div>
<p>To indicate which constructor should be used for deserialization, we can use the <em>@JsonCreator</em> annotation.</p>
<h3 id="bd-1-defining-a-constructor-with-jsoncreator-and-jsonproperty" data-id="1-defining-a-constructor-with-jsoncreator-and-jsonproperty">4.1. Defining a Constructor With <em>@JsonCreator</em> and <em>@JsonProperty</em></h3>
<div class="bd-anchor" id="1-defining-a-constructor-with-jsoncreator-and-jsonproperty"></div>
<p>If we want to use the two-argument constructor, we need to annotate it with <em>@JsonCreator</em> and annotate the parameters with <em>@JsonProperty</em>:</p>
<pre><code class="language-java">@JsonCreator
public Ticket(@JsonProperty("currency") Currency currency, @JsonProperty("price") int price) {
    this.price = price;
    this.currency = currency;
}</code></pre>
<p>Jackson will deserialize the JSON as follows:</p>
<ul>
<li>The two attributes, <em>currency</em> and <em>price,</em> are set in the constructor.</li>
<li>The <em>guest</em> attribute is set using its setter method.</li>
<li>The <em>eventName</em> attribute doesn&#8217;t have a setter method and is set using reflection.</li>
</ul>
<p><strong>If there is no setter method for an attribute, Jackson sets the attribute using reflection based on its name.</strong> If the Java attribute name differs from the JSON field name, we can use the <em>@JsonProperty</em> annotation to define the JSON field name. In our example, we annotate the <em>eventName</em> attribute with <em>@JsonProperty(&#8220;event&#8221;)</em> to indicate that the JSON field name is event<em>,</em> while the Java attribute name is <em>eventName</em>.</p>
<p>We can annotate only one constructor with <em>@JsonCreator</em>. If we annotate a second constructor in addition to the one we have already defined:</p>
<pre><code class="language-java">@JsonCreator
public Ticket(@JsonProperty("currency") Currency currency, @JsonProperty("price") int price, @JsonProperty("guest") String guest) {
    this.price = price;
    this.currency = currency;
    this.guest = guest;
}</code></pre>
<p>Jackson will throw an exception:</p>
<pre><code class="language-bash">com.fasterxml.jackson.databind.JsonMappingException: 
  com.fasterxml.jackson.databind.exc.InvalidDefinitionException: 
    Conflicting property-based creators: 
    already had explicitly marked creator [constructor for `com.baeldung.jackson.multiparameterconstructor.Ticket` (2 args), 
    annotations: {interface com.fasterxml.jackson.annotation.JsonCreator=@com.fasterxml.jackson.annotation.JsonCreator(mode=DEFAULT)}, 
    encountered another: [constructor for `com.baeldung.jackson.multiparameterconstructor.Ticket` (3 args), 
    annotations: {interface com.fasterxml.jackson.annotation.JsonCreator=@com.fasterxml.jackson.annotation.JsonCreator(mode=DEFAULT)}</code></pre>
<h3 id="bd-2-constructor-without-jsonproperty" data-id="2-constructor-without-jsonproperty">4.2. Constructor Without <em>@JsonProperty</em></h3>
<div class="bd-anchor" id="2-constructor-without-jsonproperty"></div>
<p>Jackson uses reflection to map JSON field names to Java class attributes. This works for class attributes but doesn&#8217;t work for method parameter names. Therefore, if we define a constructor without <em>@JsonProperty</em> annotations:</p>
<pre><code class="language-java">@JsonCreator
public Ticket(Currency currency, int price, String guest) {
    this.price = price;
    this.currency = currency;
    this.guest = guest;
}</code></pre>
<p>We get an exception:</p>
<pre><code class="language-bash">com.fasterxml.jackson.databind.exc.InvalidDefinitionException: 
  Invalid type definition for type `com.baeldung.jackson.multiparameterconstructor.Ticket`: 
  Argument #0 of constructor [constructor for `com.baeldung.jackson.multiparameterconstructor.Ticket` (2 args), 
  annotations: {interface com.fasterxml.jackson.annotation.JsonCreator=@com.fasterxml.jackson.annotation.JsonCreator(mode=DEFAULT)} 
  has no property name (and is not Injectable): can not use as property-based Creator</code></pre>
<p>Java does not retain method parameter names at runtime, so we need to annotate the parameters with <em>@JsonProperty</em> to specify the JSON field name that should be mapped to each parameter.</p>
<p><strong>If we want to avoid annotating the parameters with <em>@JsonProperty</em>, we can register the <em>ParameterNamesModul</em>e and add the <em>parameters</em> flag to the compiler.</strong></p>
<p>First, we need to add the <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://mvnrepository.com/artifact/com.fasterxml.jackson.module/jackson-module-parameter-names">Maven dependency</a>:</p>
<pre><code class="language-xml">&lt;dependency&gt;
    &lt;groupId&gt;com.fasterxml.jackson.module&lt;/groupId&gt;
    &lt;artifactId&gt;jackson-module-parameter-names&lt;/artifactId&gt;
    &lt;version&gt;2.21.1&lt;/version&gt;
&lt;/dependency&gt;</code></pre>
<p>Then, we need to register the <em>ParameterNamesModule </em>with the object mapper:</p>
<pre><code class="language-java">ObjectMapper mapper = JsonMapper.builder()
  .constructorDetector(ConstructorDetector.USE_PROPERTIES_BASED)
  .addModule(new ParameterNamesModule(JsonCreator.Mode.PROPERTIES))
  .build();</code></pre>
<p>And add the <em>parameters</em> flag to the compiler:</p>
<pre><code class="language-xml">&lt;plugin&gt;
    &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
    &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;
    &lt;configuration&gt;
        &lt;compilerArgs&gt;
            &lt;arg&gt;-parameters&lt;/arg&gt;
        &lt;/compilerArgs&gt;
    &lt;/configuration&gt;
&lt;/plugin&gt;</code></pre>
<h3 id="bd-3configuration-with-constructordetector" data-id="3configuration-with-constructordetector">4.3. Configuration With <em>ConstructorDetector</em></h3>
<div class="bd-anchor" id="3configuration-with-constructordetector"></div>
<p>We still need to add the <em>@JsonCreator</em> annotation to mark the constructor that we want to use for deserialization.</p>
<p>As of Jackson 2.12, we can register a <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-jackson-constructordetector-deserialization">ConstructorDetector </a>to specify the constructor that should be used for deserialization without the need to annotate it with <em>@JsonCreator:</em></p>
<pre><code class="language-java">ObjectMapper mapper = JsonMapper.builder()
  .constructorDetector(ConstructorDetector.USE_PROPERTIES_BASED)
  .addModule(new ParameterNamesModule(JsonCreator.Mode.PROPERTIES))
  .constructorDetector(ConstructorDetector.USE_PROPERTIES_BASED)
  .build();</code></pre>
<p><strong>Notably,  if we configure Jackson to detect the constructor and also annotate one of multiple constructors with <em>@JsonCreator</em>, then the annotated constructor has preference over a constructor that would be detected otherwise.</strong></p>
<h2 id="bd-records" data-id="records">5. Records</h2>
<div class="bd-anchor" id="records"></div>
<p>Jackson can deserialize records using the canonical constructor, which is present by default. Let&#8217;s consider the following record:</p>
<pre><code class="language-java">public record Guest(@JsonProperty("firstname") String firstname, @JsonProperty("surname") String surname) {}</code></pre>
<p>And the following JSON:</p>
<pre><code class="language-json">{
  "firstname": "Maria",
  "surname": "Monroe"
}</code></pre>
<p><strong>Jackson can deserialize JSON to Java records without the need for a no-argument constructor.</strong> If we register the <em>ParameterNamesModule</em> and compile with the <em>parameters</em> flag, we don&#8217;t need to annotate the record components with <em>@JsonProperty</em>:</p>
<pre><code class="language-java">public record Guest(String firstname, String surname) {}</code></pre>
<p>In some cases, we might want to customize the canonical constructor:</p>
<pre><code class="language-java">public Guest(String firstname, String surname) {
    this.firstname = firstname;
    this.surname = surname;
    // some validation
}</code></pre>
<p>Again, we don&#8217;t need to annotate the constructor with <em>@JsonCreator</em> because Jackson will use the canonical constructor by default.</p>
<p>One case where we do need the <em>@JsonCreator</em> annotation is when we want to add a static factory method:</p>
<pre><code class="language-java">@JsonCreator
public static Guest fromJson(String firstname, String surname) {
    // some validation
    return new Guest(firstname, surname);
}</code></pre>
<p>A difference to using a constructor is that a static factory method can have additional arguments:</p>
<pre><code class="language-java">@JsonCreator
public static Guest fromJson(String firstname, String surname, int id) {
    // some validation
    return new Guest(firstname, surname);
}</code></pre>
<p>Whereas a non-canonical constructor won&#8217;t be used even if it&#8217;s annotated with <em>@JsonCreator</em>:</p>
<pre><code class="language-java">@JsonCreator
public Guest(String firstname, String surname, int id) {
    this(firstname, surname)
    // some validation
}</code></pre>
<p>Jackson will ignore this constructor and use the canonical constructor instead.</p>
<h2 id="bd-enums" data-id="enums">6. Enums</h2>
<div class="bd-anchor" id="enums"></div>
<p><em>@JsonCreator</em> can also be used to deserialize enums. By default, Jackson <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/jackson-serialize-enums">deserializes enums</a> using their name.</p>
<p>We can change the default behavior by annotating the enum with <em>@JsonFormat</em>:</p>
<pre><code class="language-java">@JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum Currency {
    EUR("Euro", "cent"),
    GBP("Pound sterling", "penny"),
    CHF("Swiss franc", "Rappen");
    private String fullName;
    private String fractionalUnit;
    Currency(String fullName, String fractionalUnit) {
        this.fullName = fullName;
        this.fractionalUnit = fractionalUnit;
    }
    
    // getters for all attributes
}</code></pre>
<p>The enum value <em>EUR</em> will then be serialized to the following JSON:</p>
<pre><code class="language-json">{
  "fullName": "Euro",
  "fractionalUnit": "cent"
}</code></pre>
<p>However, the deserialization will fail with the following exception:</p>
<pre><code class="language-bash">com.fasterxml.jackson.databind.exc.MismatchedInputException: 
  Cannot deserialize value of type `com.baeldung.jackson.multiparameterconstructor.Currency` 
  from Object value (token `JsonToken.START_OBJECT`)</code></pre>
<p><strong>That&#8217;s because Jackson attempts to deserialize the enum based on its name: <em>EUR</em>.</strong> We might think that annotating the constructor with <em>@JsonCreator</em> would solve the problem:</p>
<pre><code class="language-java">@JsonCreator
Currency(String fullName, String fractionalUnit) {
    this.fullName = fullName;
    this.fractionalUnit = fractionalUnit;
}</code></pre>
<p><strong>That doesn&#8217;t work because enum constructors are private and cannot be used by Jackson.</strong> The solution is to define a
<br>
static factory method and annotate it with <em>@JsonCreator</em>:</p>
<pre><code class="language-java">@JsonCreator
public static Currency fromJsonString(String fullName, String fractionalUnit) {
    for (Currency c : Currency.values()) {
        if (c.fullName.equalsIgnoreCase(fullName) &amp;&amp; c.fractionalUnit.equalsIgnoreCase(fractionalUnit)) {
            return c;
        }
    }
    throw new IllegalArgumentException("Unknown currency: " + fullName + " " + franctionalUnit);
}</code></pre>
<h2 id="bd-conclusion" data-id="conclusion">7. Conclusion</h2>
<div class="bd-anchor" id="conclusion"></div>
<p>In this article, we&#8217;ve learned how to deserialize JSON into a Java object using multi-parameter constructors. We&#8217;ve seen how to use the <em>@JsonCreator</em> in Java classes, enums, and records. In addition, we&#8217;ve learnt that the parameter names module and the constructor detector setting help reduce the number of necessary annotations.</p>
<p>As usual, the code in this article is available <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/eugenp/tutorials/tree/master/jackson-modules/jackson-custom-conversions">over on GitHub</a>.</p>The post <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/jackson-deserialization-multi-param-constructor">JSON Deserialization with Multiple Parameters Constructor Using Jackson</a> first appeared on <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com">Baeldung</a>.<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/953193365/0/baeldung">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/953193365/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/953193365/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/953193365/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/953193365/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/953193365/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/jackson-deserialization-multi-param-constructor#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/jackson-deserialization-multi-param-constructor/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/~/953193365/0/baeldung~JSON-Deserialization-with-Multiple-Parameters-Constructor-Using-Jackson/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-jmod-file-format</feedburner:origLink>
		<title>JMOD File Format in Java</title>
		<link>https://feeds.feedblitz.com/~/953193368/0/baeldung~JMOD-File-Format-in-Java</link>
					<comments>https://feeds.feedblitz.com/~/953193368/0/baeldung~JMOD-File-Format-in-Java#respond</comments>
		
		<dc:creator><![CDATA[Olayemi Michael]]></dc:creator>
		<pubDate>Fri, 03 Apr 2026 18:29:17 +0000</pubDate>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[JAR]]></category>
		<guid isPermaLink="false">https://www.baeldung.com/java-jmod-file-format</guid>
					<description><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-10-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 what a JMOD file is, how it differs from a JAR file, and when to use it.</p>
The post <a rel="NOFOLLOW" href="https://feeds.feedblitz.com/~/953193368/0/baeldung~JMOD-File-Format-in-Java">JMOD File Format in Java</a> first appeared on <a rel="NOFOLLOW" href="https://www.baeldung.com">Baeldung</a>.<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/953193368/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/953193368/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2024%2f07%2fJava-Featured-10-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/953193368/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/953193368/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/953193368/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-jmod-file-format#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-jmod-file-format/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-10-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-10-1024x536.jpg 1024w, https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-10-300x157.jpg 300w, https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-10-768x402.jpg 768w, https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-10-100x52.jpg 100w, https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-10.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>In this tutorial, we&#8217;ll deep dive into what JMOD is and how it differs from JAR files. Then, we&#8217;ll create a sample modular project, package it as a JMOD file, and use <em>jlink</em> to generate a minimal Java runtime tailored specifically to the application.</p>
<h2 id="bd-whats-jmod" data-id="whats-jmod">2. What&#8217;s JMOD?</h2>
<div class="bd-anchor" id="whats-jmod"></div>
<p>Before Java 9, Java applications were packaged primarily as <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-create-jar">JAR files</a> with build tools such as Maven and Gradle. With the introduction of the <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-modularity">Java Platform Module System</a> in Java 9, Java gained a formal module system and introduced the JMOD file format.</p>
<p><strong>A JMOD file is a packaging format for Java modules that are intended to be used during compile and link time, but not directly at runtime</strong>.</p>
<p>Unlike JAR files, we can&#8217;t place JMOD files on the classpath or module path when running an application.</p>
<p>Like JAR files, JMOD files can contain compiled class files and resources. However, JMOD files can also include additional artifacts such as native libraries, configuration files, and legal notices.</p>
<h3 id="bd-1-its-relationship-with-jpms" data-id="1-its-relationship-with-jpms">2.1. Its Relationship With JPMS</h3>
<div class="bd-anchor" id="1-its-relationship-with-jpms"></div>
<p>Moreover, JMOD is tightly related to JPMS. It serves as a packaging format for modules that may need more than just compiled bytecode files.</p>
<p>In the JPMS architecture, source code is compiled into bytecode. Then, the bytecode is packaged into modules (JAR or JMOD). Then, at link time, we can use <em>jlink</em> to assemble modules into a custom runtime image.</p>
<p>Link time is the phase between compilation and execution. During this phase, the Java linker analyzes module dependencies and bundles only the required modules into a runtime image. JMOD files are specifically designed to participate in the linking process.</p>
<h3 id="bd-2-the-purpose-of-jmod-and-how-it-differs-from-modular-jars" data-id="2-the-purpose-of-jmod-and-how-it-differs-from-modular-jars">2.2. The Purpose of JMOD and How It Differs From Modular JARs</h3>
<div class="bd-anchor" id="2-the-purpose-of-jmod-and-how-it-differs-from-modular-jars"></div>
<p>While JPMS supports modular JAR files, JMOD was introduced to address the limitations of JAR packaging. A modular JAR contains compiled classes and resources and can be used directly at runtime.</p>
<p>On the other hand, a JMOD file may contain native code and additional metadata. It&#8217;s intended for link-time processing and can&#8217;t be executed directly. Unlike a JAR file, it isn&#8217;t meant to be published to repositories such as Maven Central.</p>
<p>Its primary purpose is to support the creation of custom runtime images using <em>jlink</em>. For instance, packaging an application together with a full JRE can significantly increase distribution size. Instead, JMOD enables the creation of a custom Java runtime that contains only the modules required by the application. This results in a smaller and more learner-friendly distribution size.</p>
<h2 id="bd-practical-example-creating-a-custom-jre" data-id="practical-example-creating-a-custom-jre">3. Practical Example: Creating a Custom JRE</h2>
<div class="bd-anchor" id="practical-example-creating-a-custom-jre"></div>
<p>To better understand how the JMOD file format works, let&#8217;s build a simple modular Java application and use it to create a custom runtime image.</p>
<h3 id="bd-1-sample-application" data-id="1-sample-application">3.1. Sample Application</h3>
<div class="bd-anchor" id="1-sample-application"></div>
<p>Let&#8217;s bootstrap a simple Java project that logs &#8220;<em>Hello Baeldung!</em>&#8221; to the console:</p>
<pre><code class="language-java">public class Hello {
    private static final Logger LOG = Logger.getLogger(Main.class.getName());
    public static void main(String[] args) {
        LOG.info("Hello Baeldung!");
    }
}</code></pre>
<p>In the code above, we define a class named <em>Hello</em> and use the <em>java.util.logging</em> API to log a message to the console.</p>
<p>Next, let&#8217;s make the project a Java module by adding a <em>module-info.java</em> file at the root of the module source directory:</p>
<pre><code class="language-java">module com.baeldung.jmod_sample {
    requires java.logging;
}</code></pre>
<p>Here, <em>com.baeldung.jmod_sample</em> is the module name. While every module implicitly depends on <em>java.base</em>, additional modules such as <em>java.logging</em> must be implicitly declared.</p>
<p>Next, let&#8217;s compile our program:</p>
<pre><code class="language-bash">$ javac -d output $(find -name \*.java)</code></pre>
<p>The command above locates all <em>.java</em> files inside the <em>src</em> directory and compiles them. Then, it outputs the generated <em>.class</em> files into the <em>output</em> directory.</p>
<h3 id="bd-2-packaging-to-jmod" data-id="2-packaging-to-jmod">3.2. Packaging to JMOD</h3>
<div class="bd-anchor" id="2-packaging-to-jmod"></div>
<p>Next, let&#8217;s prepare our modular application for a custom runtime creation by packaging it into a JMOD file.</p>
<p>To create a JMOD file, we can use the <em>jmod create</em> command:</p>
<pre><code class="language-bash">$ jmod create \
  --class-path output/ \
  --main-class com.baeldung.jmod_sample.Hello \
  --module-version 1.0.0 -p output hello.jmod</code></pre>
<p>Here, <em>&#8211;class-path output/</em> specifies the directory containing the compiled classes. Also, we define the entry point of the module and the name of the generated JMOD file.</p>
<p>After executing the command, a <em>hello.jmod</em> file is created in the current directory.</p>
<p>Next, let&#8217;s inspect the JMOD file to see what it contains by running the <em>jmod describe</em> command:</p>
<pre><code class="language-bash">$ jmod describe hello.jmod</code></pre>
<p>This outputs the content of the file to the console:</p>
<pre><code class="language-bash">com.baeldung.jmod_sample@1.0.0
requires java.base mandated
requires java.logging
contains com.baeldung.jmod_sample
main-class com.baeldung.jmod_sample.Hello</code></pre>
<p>This confirms that the JMOD file correctly encapsulates the compile module and its metadata, making it ready for use during link time with <em>jlink</em>.</p>
<h3 id="bd-3-creating-a-custom-runtime-using-jlink" data-id="3-creating-a-custom-runtime-using-jlink">3.3. Creating a Custom Runtime Using <em>jlink</em></h3>
<div class="bd-anchor" id="3-creating-a-custom-runtime-using-jlink"></div>
<p>Now that we have generated our JMOD file, let&#8217;s use it create a custom Java runtime using <em>jlink</em>:</p>
<pre><code class="language-bash">$ jlink \
  --module-path $JAVA_HOME/jmods:hello.jmod \
  --add-modules com.baeldung.jmod_sample \
  --launcher hello=com.baeldung.jmod_sample/com.baeldung.jmod_sample.Hello \
  --strip-debug \
  --compress=2 \
  --no-header-files \
  --no-man-pages \
  --output custom-runtime-min</code></pre>
<p>Here, the  <em>&#8211;module-path $JAVA_HOME/jmods:hello.jmod</em> specifies where jlink should locate require modules. Next, the <em>&#8211;add-modules</em> option indicates the root module to include in the runtime image.</p>
<p>Then we use the <em>launcher</em> option to create a launcher script that runs the <em>Hello</em> class. After executing the command, <em>jlink</em> produces a new directory named &#8220;<em>custom-runtme-min</em>&#8220;.</p>
<p>We can check the size of the generated runtime image:</p>
<pre><code class="language-bash">$ du -sh custom-runtime-min</code></pre>
<p>Here&#8217;s the output:</p>
<pre><code class="language-bash">35M     custom-runtime-min/</code></pre>
<p>The resulting runtime is approximately 35 MB, significantly smaller than a full JDK installation, which typically exceeds 400 MB.</p>
<p>Let&#8217;s verify which modules were bundled into the runtime image:</p>
<pre><code class="language-bash">$ ./custom-runtime-min/bin/java --list-modules</code></pre>
<p>Here&#8217;s the output:</p>
<pre><code class="language-bash">com.baeldung.jmod_sample@1.0.0
java.base@25.0.2
java.logging@25.0.2</code></pre>
<p>This confirms that only the required modules were included.</p>
<p>Finally, let&#8217;s run the generate launcher:</p>
<pre><code class="language-bash">$ ./custom-runtime-min/bin/hello</code></pre>
<p>The command above produces:</p>
<pre><code class="language-bash">Mar 01, 2026 10:15:38 AM com.baeldung.jmod_sample.Hello main
INFO: Hello Baeldung!</code></pre>
<p>The application runs successfully using the custom runtime image.</p>
<h2 id="bd-conclusion" data-id="conclusion">4. Conclusion</h2>
<div class="bd-anchor" id="conclusion"></div>
<p>In this article, we learned what a JMOD file is, what it can contain, how it differs from a  JAR file, and when it should be used. Also, we built a simple modular Java application, packaged it into a JMOD file, and used it with <em>jlink</em> to generate a lean, custom Java runtime image tailored specifically to our application.</p>
<p>As usual, the complete source code for the example is available <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/eugenp/tutorials/tree/master/core-java-modules/core-java-9-jigsaw">over on GitHub</a>.</p>The post <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-jmod-file-format">JMOD File Format in Java</a> first appeared on <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com">Baeldung</a>.<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/953193368/0/baeldung">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/953193368/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/953193368/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2024%2f07%2fJava-Featured-10-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/953193368/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/953193368/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/953193368/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-jmod-file-format#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-jmod-file-format/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/~/953193368/0/baeldung~JMOD-File-Format-in-Java/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<webfeeds:featuredImage>https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-10-150x150.jpg</webfeeds:featuredImage></item>
<item>
<feedburner:origLink>https://www.baeldung.com/java-weekly-640</feedburner:origLink>
		<title>Java Weekly, Issue 640</title>
		<link>https://feeds.feedblitz.com/~/953174849/0/baeldung~Java-Weekly-Issue</link>
					<comments>https://feeds.feedblitz.com/~/953174849/0/baeldung~Java-Weekly-Issue#respond</comments>
		
		<dc:creator><![CDATA[baeldung]]></dc:creator>
		<pubDate>Fri, 03 Apr 2026 13:52:02 +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=203370</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>Instrument your code quickly and document your high-level technical context carfully.</p>
The post <a rel="NOFOLLOW" href="https://feeds.feedblitz.com/~/953174849/0/baeldung~Java-Weekly-Issue">Java Weekly, Issue 640</a> first appeared on <a rel="NOFOLLOW" href="https://www.baeldung.com">Baeldung</a>.<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/953174849/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/953174849/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/953174849/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/953174849/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/953174849/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-640#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-640/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.frankel.ch/tip-opentelemetry-projects/">&gt;&gt; One tip for successful OpenTelemetry projects</a></strong> [<span style="color: #993300;">frankel.ch</span>]</p>
<p>Adopting OpenTelemetry doesn&#8217;t have to mean instrumenting the entire codebase. Here&#8217;s a pragmatic way to get <strong>observability up and running fast</strong>.</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://foojay.io/today/grails-isnt-done-yet-part-2-eol-spring-boot-and-what-comes-next/" target="_blank" rel="noopener"><strong>Grails Isn&#8217;t Done Yet (Part 2): EOL, Spring Boot, and What Comes Next</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.jetbrains.com/idea/2026/03/using-spring-data-jpa-with-kotlin/" target="_blank" rel="noopener"><strong>Using Spring Data JPA with Kotlin</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/idea/2026/03/ai-assisted-java-application-development-with-agent-skills/" target="_blank" rel="noopener"><strong>AI-Assisted Java Application Development with Agent Skills</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.jooq.org/managing-sensitive-data-in-jooq-3-21-logs/" target="_blank" rel="noopener"><strong>Managing Sensitive Data in jOOQ 3.21+ Logs</strong></a> [<span style="color: #800000;">jooq.org</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://spring.io/blog/2026/03/26/a-bootiful-podcast-dgm" target="_blank" rel="noopener"><strong>A Bootiful Podcast: Daniel Garnier-Moiroux on MCP Security</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://toomuchcoding.com/publication/2026-03-30-goto-scc-contract/" target="_blank" rel="noopener"><strong>A Typo Led to the Creation of Spring Cloud Contract</strong></a> [<span style="color: #800000;">toomuchcoding.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://nipafx.dev/inside-java-newscast-109/" target="_blank" rel="noopener"><strong>Analysing Crashed JVMs &#8211; Inside Java Newscast #109</strong></a> [<span style="color: #800000;">nipafx.dev</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/03/27/spring-modulith-2-1-m4-2-0-5-and-1-4-10-released" target="_blank" rel="noopener"><strong>Spring Modulith 2.1 M4, 2.0.5, and 1.4.10 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/03/26/spring-ai-2-0-0-M4-and-1-1-4-and-1-0-5-available" target="_blank" rel="noopener"><strong>Spring AI 2.0.0-M4, 1.1.4 and 1.0.5 are 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://blog.jetbrains.com/amper/2026/03/amper-0-10/" target="_blank" rel="noopener"><strong>Amper 0.10 – JDK Provisioning, a Maven Converter, Custom Compiler Plugins, 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://github.com/eclipse/jetty.project/releases/tag/jetty-12.1.8" target="_blank" rel="noopener"><strong>Jetty 12.1.8</strong></a> and <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/eclipse/jetty.project/releases/tag/jetty-12.0.34" target="_blank" rel="noopener"><strong>12.0.34</strong></a> [<span style="color: #800000;">github.com/eclipse</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.0.10" target="_blank" rel="noopener"><strong>Eclipse Vert.x 5.0.10</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/quarkusio/quarkus/releases/tag/3.34.2" target="_blank" rel="noopener"><strong>Quarkus 3.34.2</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/micronaut-projects/micronaut-core/releases/tag/v4.10.20" target="_blank" rel="noopener"><strong>Micronaut 4.10.20</strong></a> and <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/micronaut-projects/micronaut-core/releases/tag/v4.10.19" target="_blank" rel="noopener"><strong>4.10.19</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/Netflix/zuul/releases/tag/v3.5.7" target="_blank" rel="noopener"><strong>Netflix Zuul 3.5.7</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/grails/grails-core/releases/tag/v7.0.10" target="_blank" rel="noopener"><strong>Grails 7.0.10</strong></a> [<span style="color: #800000;">github.com/grails</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/articles/reduce-friction-ai/encoding-team-standards.html">&gt;&gt; Encoding Team Standards</a></strong> [<span style="color: #993300;">martinfowler.com</span>]</p>
<p>Instead of relying on tacit knowledge held by senior engineers, encode your team&#8217;s coding standards as executable AI instructions stored in version control. Words to live (or code) by <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.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.scottlogic.com/2026/04/01/beyond-the-hype-is-ai-taking-fun-out-of-software-development.html" target="_blank" rel="noopener"><strong>Beyond the Hype: Is AI taking the fun out of software development?</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://event-driven.io/en/intro_to_example_mapping/" target="_blank" rel="noopener"><strong>The one where Oskar explains Example Mapping</strong></a> [<span style="color: #800000;">event-driven.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://foojay.io/today/best-practices-for-working-with-ai-agents-subagents-skills-and-mcp/" target="_blank" rel="noopener"><strong>5 Best Practices for Working with AI Agents, Subagents, Skills and MCP</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://dandreamsofcoding.com/2026/03/31/understanding-performance/" target="_blank" rel="noopener"><strong>Understanding Performance</strong></a> [<span style="color: #800000;">dandreamsofcoding.com</span>]</li>
</ul>
<h2 style="text-align: left;" id="bd-pick-of-the-week" data-id="pick-of-the-week">3.<strong> Pick of the Week</strong></h2>
<div class="bd-anchor" id="pick-of-the-week"></div>
<p><strong><a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://kk.org/thetechnium/1000-true-fans/">&gt;&gt; 1,000 True Fans</a></strong> [<span style="color: #800000;">kk.org</span>]</p>The post <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-weekly-640">Java Weekly, Issue 640</a> first appeared on <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com">Baeldung</a>.<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/953174849/0/baeldung">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/953174849/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/953174849/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/953174849/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/953174849/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/953174849/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-640#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-640/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/~/953174849/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/spring-boot-spa-redirect-404</feedburner:origLink>
		<title>Configure Spring Boot to Redirect 404 to a Single Page Application</title>
		<link>https://feeds.feedblitz.com/~/952480355/0/baeldung~Configure-Spring-Boot-to-Redirect-to-a-Single-Page-Application</link>
					<comments>https://feeds.feedblitz.com/~/952480355/0/baeldung~Configure-Spring-Boot-to-Redirect-to-a-Single-Page-Application#respond</comments>
		
		<dc:creator><![CDATA[Hamid Reza Sharifi]]></dc:creator>
		<pubDate>Tue, 31 Mar 2026 15:46:13 +0000</pubDate>
				<category><![CDATA[Spring MVC]]></category>
		<guid isPermaLink="false">https://www.baeldung.com/?p=203319</guid>
					<description><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/2017/08/Spring-MVC-1.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 configure Spring Boot so that all unknown routes are redirected to the SPA's index.html</p>
The post <a rel="NOFOLLOW" href="https://feeds.feedblitz.com/~/952480355/0/baeldung~Configure-Spring-Boot-to-Redirect-to-a-Single-Page-Application">Configure Spring Boot to Redirect 404 to a Single Page Application</a> first appeared on <a rel="NOFOLLOW" href="https://www.baeldung.com">Baeldung</a>.<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/952480355/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/952480355/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2017%2f08%2fSpring-MVC-1.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/952480355/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/952480355/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/952480355/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-spa-redirect-404#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-spa-redirect-404/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/2017/08/Spring-MVC-1.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/2017/08/Spring-MVC-1.jpg 952w, https://www.baeldung.com/wp-content/uploads/2017/08/Spring-MVC-1-300x157.jpg 300w, https://www.baeldung.com/wp-content/uploads/2017/08/Spring-MVC-1-768x402.jpg 768w" 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>Single-page applications (SPAs) such as those built with <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/spring-boot-react-crud">React</a>, <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/spring-boot-angular-web">Angular</a>, or <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/spring-boot-vue-js">Vue</a> often rely on client-side routing. When served from a Spring Boot backend, refreshing the page or accessing a wrong link sends a request for a non-existent server path. Spring Boot then returns a 404 error.</p>
<p>To make the SPA work correctly, we need to forward all unmatched requests to <em>index.html</em> with HTTP status 200. This lets the frontend router handle the path.</p>
<p>In this tutorial, we&#8217;ll learn how to configure Spring Boot so that all unknown routes are redirected to the SPA&#8217;s <em>index.html</em>.</p>
<h2 id="bd-maven-dependency" data-id="maven-dependency">2. 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-web"><em>spring-boot-starter-web</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-web&lt;/artifactId&gt;
    &lt;version&gt;3.3.2&lt;/version&gt;
&lt;/dependency&gt;</code></pre>
<h2 id="bd-setting-up-a-basic-spa-with-spring-boot" data-id="setting-up-a-basic-spa-with-spring-boot">3. Setting Up a Basic SPA with Spring Boot</h2>
<div class="bd-anchor" id="setting-up-a-basic-spa-with-spring-boot"></div>
<p>Let&#8217;s consider an SPA deployed with Spring Boot, where the compiled frontend files are placed inside the <em>resources</em> directory:</p>
<pre><code class="language-plaintext">src/main/resources/static</code></pre>
<p>For example, a minimal <em>index.html</em> could look like:</p>
<pre><code class="language-xml">&lt;!DOCTYPE html&gt;
&lt;html lang="en"&gt;
&lt;head&gt;
    &lt;meta charset="UTF-8"&gt;
    &lt;title&gt;Baeldung&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;h1&gt;Home Page&lt;/h1&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre>
<p>Next, we create a simple controller to forward the root path:</p>
<pre><code class="language-java">@Controller
public class HomeController {
    @RequestMapping("/")
    public String getHome(){
        return "forward:/index.html";
    }
}</code></pre>
<p>When a user accesses the root path <em>http://localhost:8080/</em><span style="margin: 0px;padding: 0px">, </span>Spring Boot serves <em>index.html</em> correctly.</p>
<p>However, if the user refreshes a client-side route like <em>http://localhost:8080/dashboard,</em> Spring Boot tries to find a server mapping for <em>/dashboard</em> and returns <em>404 Not Found</em>. Instead, we want Spring Boot to return <em>index.html</em> so the SPA router can handle the route.</p>
<h2 id="bd-redirecting-404-not-founderrors" data-id="redirecting-404-not-founderrors">4. Redirecting 404 Not Found Errors</h2>
<div class="bd-anchor" id="redirecting-404-not-founderrors"></div>
<p>In this section, we describe some solutions for redirecting unmatched requests to <em>index.html</em>.</p>
<h3 id="bd-1-using-a-controller-to-forward-unknown-routes" data-id="1-using-a-controller-to-forward-unknown-routes">4.1. Using a Controller to Forward Unknown Routes</h3>
<div class="bd-anchor" id="1-using-a-controller-to-forward-unknown-routes"></div>
<p>Let&#8217;s create a controller that forwards all unmapped paths to <em>index.html</em>:</p>
<pre><code class="language-java">@Controller
public class SpaForwardController {
    @RequestMapping(value = "/{path:[^\\.]*}")
    public String redirect() {
        return "forward:/";
    }
}</code></pre>
<p>The unmatched requests without a file extension are forwarded to &#8220;/&#8221;, which returns <em>index.html</em>.</p>
<p><strong>If a specific mapping exists (for example, <em>@GetMapping(&#8220;/dashboard&#8221;)</em>), Spring selects it with higher precedence, and the catch-all pattern is ignored</strong>. For any other path without a matching handler (such as <em>/settings</em>), the request falls through to the catch-all mapping and gets forwarded to <em>index.html</em>.</p>
<p>Also, we need to support deeper routes like <em>/dashboard/settings</em>. To do this, we can expand the controller mapping:</p>
<pre><code class="language-java">@Controller
public class SpaForwardController {
    @RequestMapping(value = {
        "/{path:[^\\.]*}",
        "/{path:[^\\.]*}/**/{subpath:[^\\.]*}"
    })
    public String redirect() {
        return "forward:/";
    }
}</code></pre>
<h3 id="bd-2-using-a-custom-error-controller" data-id="2-using-a-custom-error-controller">4.2. Using a Custom Error Controller</h3>
<div class="bd-anchor" id="2-using-a-custom-error-controller"></div>
<p><strong>Another approach is to intercept 404 errors and redirect them to the SPA entry point</strong>:</p>
<pre><code class="language-java">@Controller
public class SpaErrorController implements ErrorController {
    @RequestMapping("/error")
    public String handleError() {
        return "forward:/index.html";
    }
}</code></pre>
<p>This method ensures that any unknown route eventually loads the SPA.</p>
<p>However, this approach may also intercept real backend 404 errors, which may not always be desirable.</p>
<h3 id="bd-3-using-webmvcconfigurer" data-id="3-using-webmvcconfigurer">4.3. Using <em>WebMvcConfigurer</em></h3>
<div class="bd-anchor" id="3-using-webmvcconfigurer"></div>
<p><strong>Another approach is to centralize error handling and avoid the need to explicitly match route patterns</strong>.</p>
<p>We can achieve this by implementing the <em>WebMvcConfigurer</em> interface and registering a custom error page:</p>
<pre><code class="language-java">@Configuration
public class WebApplicationConfig implements WebMvcConfigurer {
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/notFound")
          .setViewName("forward:/index.html");
    }
    @Bean
    public WebServerFactoryCustomizer&lt;ConfigurableServletWebServerFactory&gt; containerCustomizer() {
        return container -&gt; {
            container.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/notFound"));
        };
    }
}
</code></pre>
<p>In this configuration, any request that results in a <em>404 Not Found</em> error is redirected to <em>/notFound</em>. This endpoint then forwards the request to <em>index.html</em>.</p>
<p>However, it also means that all 404 errors—including those from backend APIs—are redirected to the SPA, which may not always be desirable.</p>
<h2 id="bd-test-1" data-id="test-1">5. Test</h2>
<div class="bd-anchor" id="test-1"></div>
<p>After starting the Spring Boot application, we can verify the configuration by accessing different URLs.</p>
<p>First, we request the root path:</p>
<pre><code class="language-plaintext">$ curl -i http://localhost:8080/</code></pre>
<p>The response returns <em>200 </em>along with the contents of <em>index.html</em>:</p>
<pre><code class="language-plaintext">HTTP/1.1 200
&lt;!DOCTYPE html&gt;
&lt;html lang="en"&gt;
&lt;head&gt;
    &lt;meta charset="UTF-8"&gt;
    &lt;title&gt;Baeldung&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;h1&gt;Home Page&lt;/h1&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre>
<p>Next, we simulate accessing a client-side route:</p>
<pre><code class="language-plaintext">$ curl -i http://localhost:8080/dashboard</code></pre>
<p>Instead of returning a <em>404 Not Found</em>, the application responds with <em>200</em> and serves <em>index.html</em>. This confirms that the request is forwarded and handled by the SPA router.</p>
<h2 id="bd-conclusion" data-id="conclusion">6. Conclusion</h2>
<div class="bd-anchor" id="conclusion"></div>
<p>In this article, we explored how to forward unknown routes to <em>index.html</em> when serving a single-page application with Spring Boot. We examined multiple approaches, including using a custom controller, configuring <em>WebMvcConfigurer</em>, and handling errors via a custom error mapping.</p>The post <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/spring-boot-spa-redirect-404">Configure Spring Boot to Redirect 404 to a Single Page Application</a> first appeared on <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com">Baeldung</a>.<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/952480355/0/baeldung">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/952480355/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/952480355/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2017%2f08%2fSpring-MVC-1.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/952480355/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/952480355/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/952480355/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-spa-redirect-404#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-spa-redirect-404/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/~/952480355/0/baeldung~Configure-Spring-Boot-to-Redirect-to-a-Single-Page-Application/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<webfeeds:featuredImage>https://www.baeldung.com/wp-content/uploads/2017/08/Spring-MVC-1-150x150.jpg</webfeeds:featuredImage></item>
<item>
<feedburner:origLink>https://www.baeldung.com/java-sonars-transient-serializable-warning</feedburner:origLink>
		<title>Fix Sonar&#8217;s &#8220;Make Transient or Serializable&#8221; Warning in Java</title>
		<link>https://feeds.feedblitz.com/~/952480358/0/baeldung~Fix-Sonars-Make-Transient-or-Serializable-Warning-in-Java</link>
					<comments>https://feeds.feedblitz.com/~/952480358/0/baeldung~Fix-Sonars-Make-Transient-or-Serializable-Warning-in-Java#respond</comments>
		
		<dc:creator><![CDATA[Andrei Branza]]></dc:creator>
		<pubDate>Tue, 31 Mar 2026 15:43:00 +0000</pubDate>
				<category><![CDATA[DevOps]]></category>
		<category><![CDATA[Serialization]]></category>
		<category><![CDATA[Sonar]]></category>
		<guid isPermaLink="false">https://www.baeldung.com/?p=203315</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 about Transient or Serializable in Java to overcome Sonar's related warnings.</p>
The post <a rel="NOFOLLOW" href="https://feeds.feedblitz.com/~/952480358/0/baeldung~Fix-Sonars-Make-Transient-or-Serializable-Warning-in-Java">Fix Sonar’s “Make Transient or Serializable” Warning in Java</a> first appeared on <a rel="NOFOLLOW" href="https://www.baeldung.com">Baeldung</a>.<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/952480358/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/952480358/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/952480358/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/952480358/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/952480358/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-sonars-transient-serializable-warning#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-sonars-transient-serializable-warning/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>When working with Java&#8217;s native <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-serialization">serialization</a> combined with SonarQube&#8217;s code evaluation tool, sometimes we encounter <strong>&#8220;Fields in a &#8216;Serializable&#8217; class should either be &#8216;transient&#8217; or &#8216;Serializable'&#8221; (<a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://next.sonarqube.com/sonarqube/coding_rules?open=java%3AS1948&amp;rule_key=java%3AS1948">rule key: java:S1948</a>) </strong>warning. This rule is an important guardrail and it prevents a common runtime failure: the <em>NotSerializableException.</em></p>
<p>In this tutorial, we&#8217;ll explore why this warning occurs. Also, we&#8217;ll talk about the underlying mechanics of <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/get-started-with-java-series">Java</a> serialization, and the best strategies to resolve it.</p>
<h2 id="bd-understanding-the-serialization-contract" data-id="understanding-the-serialization-contract">2. Understanding the Serialization Contract</h2>
<div class="bd-anchor" id="understanding-the-serialization-contract"></div>
<p>To make a Java object serializable, its class must implement the <em>java.io.Serializable</em> <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-interfaces">interface</a>. This is a <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-marker-interfaces">marker interface</a> that tells the JVM the object&#8217;s state is converted into a byte stream for storage or network transfer.</p>
<p>As such, the fundamental rule of this contract is recursive: <strong>if a class is serializable, all its non-static and non-transient member fields must also be serializable.</strong> If the serialization mechanism encounters a field that doesn&#8217;t implement <em>Serializable</em> and isn&#8217;t marked as <em>transient</em>, the process will fail at runtime. <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/sonar-qube">Sonar</a> flags these fields during static analysis and helps us catch this error before the code even runs.</p>
<p><strong>In addition, it&#8217;s important to remember that serialization isn&#8217;t just about the top-level class; it&#8217;s about the entire object graph.</strong></p>
<h2 id="bd-reproducing-the-sonar-warning" data-id="reproducing-the-sonar-warning">3. Reproducing the Sonar Warning</h2>
<div class="bd-anchor" id="reproducing-the-sonar-warning"></div>
<p>Let&#8217;s look at a typical scenario that triggers the java:s1948 warning. First, let&#8217;s add the <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://mvnrepository.com/artifact/org.slf4j/slf4j-api/2.0.17">SLF4J dependency</a> to our pom.xml:</p>
<pre><code class="language-java">&lt;dependency&gt;
    &lt;groupId&gt;org.slf4j&lt;/groupId&gt;
     &lt;artifactId&gt;slf4j-api&lt;/artifactId&gt;
     &lt;version&gt;2.0.17&lt;/version&gt;
&lt;/dependency&gt;</code></pre>
<p>Now, let&#8217;s create a <em>User</em> class that we want to store in a distributed session or cache. This class also contains a reference to another class, <em>Address, </em>which does not implement the <em>Serializable </em>interface. We&#8217;ll start with a simple implementation:</p>
<pre><code class="language-java">public class User implements Serializable {
    private static final long serialVersionUID = 1L;
         
    private String username;
    private Address address; // Sonar Warning: Make "address" transient or serializable
    private final Logger logger = LoggerFactory.getLogger(User.class); // Sonar Warning
         
     public User(String username, Address address) {
        this.username = username;
        this.address = address;
     }
}</code></pre>
<p>In this example, the <em>User</em> class correctly implements <em>Serializable</em>. However, if the <em>Address</em> class is defined without the interface, Sonar will flag the <em>address</em> field. Similarly, since the SLF4J <em>Logger</em> does not implement <em>Serializable</em>, it will also trigger the warning. <strong>Furthermore, if we try to serialize an instance of <em>User</em>, the JVM will throw a <em>NotSerializableException</em> at runtime.</strong> This is exactly what Sonar is trying to help us avoid. Now, let&#8217;s look at some ways we can tackle this warning.</p>
<h2 id="bd-making-the-field-serializable" data-id="making-the-field-serializable">4. Making the Field Serializable</h2>
<div class="bd-anchor" id="making-the-field-serializable"></div>
<p><strong>The most straightforward fix is to ensure that the nested class also implements the <em>Serializable</em> interface</strong>. This is the preferred approach when the field represents a core part of the object&#8217;s state that must be preserved. As such, if we own the source code of the nested object, we should simply update the class definition:</p>
<pre><code class="language-java">public class Address implements Serializable {
    private static final long serialVersionUID = 1L;
        
    private String street;
    private String city;
        
    public Address(String street, String city) {
        this.street = street;
        this.city = city;
    }
}</code></pre>
<p>By adding implements <em>Serializable</em> and providing a <em>serialVersionUID</em>, we satisfy the contract requirements.<strong> It&#8217;s a best practice to always include <em>serialVersionUID</em> to ensure compatibility during the deserialization process. </strong>Especially if the class structure evolves over time.</p>
<h2 id="bd-using-the-staticmodifier" data-id="using-the-staticmodifier">5. Using the <em>static </em>Modifier</h2>
<div class="bd-anchor" id="using-the-staticmodifier"></div>
<p>Another effective way to resolve the warning for certain fields is to declare them as <em>static</em>. <strong>In Java, static fields are not serialized because they belong to the class itself rather than a specific instance.</strong> Since they are excluded from the serialization process by the JVM, SonarQube does not flag them.</p>
<p>This is the standard solution for loggers and constants:</p>
<pre><code class="language-java">public class User implements Serializable {
    private static final long serialVersionUID = 1L;
       
    private static final Logger logger = LoggerFactory.getLogger(User.class); // No Warning
    private String username;
    private Address address;
    // getters, setters ...
 }</code></pre>
<p>By making the logger static, the warning disappears, and we follow the common Java pattern for logger declarations. This approach is ideal for any field that is shared across all instances of the class and does not represent the unique state of an individual object.</p>
<h2 id="bd-leveraging-the-transient-keyword" data-id="leveraging-the-transient-keyword">6. Leveraging the <em>transient </em>Keyword</h2>
<div class="bd-anchor" id="leveraging-the-transient-keyword"></div>
<p><strong>If a field is instance-specific but shouldn&#8217;t be serialized</strong> (like a reference to a temporary cache, or a non-serializable third-party object) we use the <em>transient</em> keyword. This modifier tells the JVM to skip the field during the serialization process:</p>
<pre><code class="language-java">public class User implements Serializable {
    private static final long serialVersionUID = 1L;
       
    private String username;
    private Address address;
    private transient List&lt;String&gt; temporaryCache; // Warning Resolved
    // getters and setters ...
}</code></pre>
<p>We need to take into consideration that when an object is deserialized, all transient fields are initialized to their default values: <em>null</em> for objects and <em>0</em> for primitives. As such, if a transient field is required for the object to function after being restored, we must re-initialize it. A way to achieve this is to use the <em>readObject</em> method:</p>
<pre><code class="language-java">private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
    in.defaultReadObject();
    this.temporaryCache = new ArrayList&lt;&gt;();
}</code></pre>
<h2 id="bd-handling-framework-dependencies" data-id="handling-framework-dependencies">7. Handling Framework Dependencies</h2>
<div class="bd-anchor" id="handling-framework-dependencies"></div>
<p>In modern Java frameworks like <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/spring-tutorial">Spring</a>, this warning often appears in <em>@SessionScoped</em> beans when injecting a <em>@Service</em> or <em>@Repository</em>. Since these services are managed by the container and typically aren&#8217;t serializable, they should be marked as transient:</p>
<pre><code class="language-java">@SessionScoped
public class UserPreferences implements Serializable {
    @Autowired
    private transient PreferenceService service; // Fixed by marking it with transient
}</code></pre>
<p><strong>Spring handles the dependency injection, so it will re-inject the service when the bean is restored from the session, provided the framework&#8217;s proxy mechanism supports it.</strong> This keeps our session-scoped beans serializable while allowing them to interact with stateless services.</p>
<p>Furthermore, we might encounter situations where we use third-party library classes that do not implement <em>Serializable</em>. If we cannot modify their source code, we have two main options:</p>
<ul>
<li>Wrap the object: Create a serializable DTO that holds only the necessary primitive data.\</li>
<li>Custom Serialization: Use <em>transient</em> for the third-party object and manually handle its state during serialization using the <em>writeObject</em> and <em>readObject</em> methods.</li>
</ul>
<p>For example, if we have a non-serializable <em>Metadata</em> object, we can store its state as a serializable <em>Map</em> or and reconstruct it upon deserialization. This keeps our domain models serializable while still utilizing powerful third-party tools.</p>
<h2 id="bd-conclusion" data-id="conclusion">8. Conclusion</h2>
<div class="bd-anchor" id="conclusion"></div>
<p>In this tutorial, we&#8217;ve covered how to handle the Sonar warning &#8220;Make Transient or Serializable&#8221;. Although the warning is helpful to ensure runtime stability in Java applications, it can cause confusion. As such, by understanding the recursive nature of Java serialization, we can choose the correct fix based on the field&#8217;s role in our application.</p>
<p>Implement <em>Serializable </em>if the field is a core part of the object&#8217;s state. Use <em>static </em>for loggers, constants and shared class-level members. Mark as <em>transient </em>if the field is a resource, or temporary data. Refactor the design if we&#8217;re trying to serialize stateless services or third-party objects that aren&#8217;t meant to be persisted.</p>The post <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-sonars-transient-serializable-warning">Fix Sonar’s “Make Transient or Serializable” Warning in Java</a> first appeared on <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com">Baeldung</a>.<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/952480358/0/baeldung">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/952480358/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/952480358/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/952480358/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/952480358/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/952480358/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-sonars-transient-serializable-warning#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-sonars-transient-serializable-warning/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/~/952480358/0/baeldung~Fix-Sonars-Make-Transient-or-Serializable-Warning-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/apache-seata-distributed-transaction-management</feedburner:origLink>
		<title>Distributed Transaction Management Using Apache Seata</title>
		<link>https://feeds.feedblitz.com/~/951988322/0/baeldung~Distributed-Transaction-Management-Using-Apache-Seata</link>
					<comments>https://feeds.feedblitz.com/~/951988322/0/baeldung~Distributed-Transaction-Management-Using-Apache-Seata#respond</comments>
		
		<dc:creator><![CDATA[Graham Cox]]></dc:creator>
		<pubDate>Fri, 27 Mar 2026 20:56:55 +0000</pubDate>
				<category><![CDATA[Data]]></category>
		<category><![CDATA[Persistence]]></category>
		<category><![CDATA[popular]]></category>
		<category><![CDATA[Transactions]]></category>
		<guid isPermaLink="false">https://www.baeldung.com/apache-seata-distributed-transaction-management</guid>
					<description><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/2024/11/Persistence-Featured-Image-03-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 Apache Seata to implement distributed database transactions across multiple Spring applications.</p>
The post <a rel="NOFOLLOW" href="https://feeds.feedblitz.com/~/951988322/0/baeldung~Distributed-Transaction-Management-Using-Apache-Seata">Distributed Transaction Management Using Apache Seata</a> first appeared on <a rel="NOFOLLOW" href="https://www.baeldung.com">Baeldung</a>.<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/951988322/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/951988322/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2024%2f11%2fPersistence-Featured-Image-03-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/951988322/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/951988322/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/951988322/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/apache-seata-distributed-transaction-management#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/apache-seata-distributed-transaction-management/feed"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/commentsrss20.png"></a>&#160;</div>]]>
</description>
										<content:encoded><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/2024/11/Persistence-Featured-Image-03-1024x536.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="float: left; margin-right: 5px;" decoding="async" loading="lazy" srcset="https://www.baeldung.com/wp-content/uploads/2024/11/Persistence-Featured-Image-03-1024x536.jpg 1024w, https://www.baeldung.com/wp-content/uploads/2024/11/Persistence-Featured-Image-03-300x157.jpg 300w, https://www.baeldung.com/wp-content/uploads/2024/11/Persistence-Featured-Image-03-768x402.jpg 768w, https://www.baeldung.com/wp-content/uploads/2024/11/Persistence-Featured-Image-03-100x52.jpg 100w, https://www.baeldung.com/wp-content/uploads/2024/11/Persistence-Featured-Image-03-600x314.jpg 600w, https://www.baeldung.com/wp-content/uploads/2024/11/Persistence-Featured-Image-03.jpg 1200w" sizes="auto, (max-width: 580px) 100vw, 580px" /><h2 id="bd-introduction" data-id="introduction"><strong>1. Introduction</strong></h2>
<div class="bd-anchor" id="introduction"></div>
<p>In this tutorial, we&#8217;re going to take a look at <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://seata.apache.org/">Apache Seata</a>, formally from Alibaba but now part of the <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://incubator.apache.org/">Apache Incubator</a> project. We’ll see what it is, how to use it and what we can do with it.</p>
<h2 id="bd-why-distributed-transactions" data-id="why-distributed-transactions"><strong>2. Why Distributed Transactions?</strong></h2>
<div class="bd-anchor" id="why-distributed-transactions"></div>
<p><strong>To write robust applications, we often make use of <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-transactions">database transactions</a> to ensure that any changes to our data are atomic.</strong> That is, either the entire change happens, or none of it does. This helps ensure that our data remains in a valid state at all times.</p>
<p>When we have a single service that manages our data, this is easy to achieve. We start a new transaction when a request comes into our system. All data changes occur within this transaction, and we commit only if the entire request succeeds.</p>
<a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/wp-content/uploads/2026/03/single-service.png"><img loading="lazy" decoding="async" class="alignnone wp-image-242131 size-full" src="https://www.baeldung.com/wp-content/uploads/2026/03/single-service.png" alt="Sequence diagram showing calls between various different services within the same application, all happening within the same database transaction." width="691" height="532" /></a>
<p>Here, if something goes wrong when recording the bill for the user, the order and inventory changes are reverted, and the system remains in the correct state.</p>
<p>If we move towards running this as many distributed services, suddenly our transactions are distributed as well:</p>
<a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/wp-content/uploads/2026/03/distributed-services.png"><img loading="lazy" decoding="async" class="alignnone wp-image-242132 size-full" src="https://www.baeldung.com/wp-content/uploads/2026/03/distributed-services.png" alt="Sequence diagram showing calls between various different services each within separate applications. Each application has it's own database transaction that isn't shared." width="981" height="594" /></a>
<p><strong>This is exactly the same flow, but by splitting our inventory, order and billing services into separate applications, we&#8217;ve also split them into separate transactions.</strong> Now, if recording the bill fails, the inventory and order changes have already been committed and cannot easily be reverted.</p>
<p>This is where distributed transactions come in. If we have a way to maintain our database transactions across multiple applications, we get both the benefits of splitting our system up, as well as the benefits of a single transaction for the entire user action.</p>
<h2 id="bd-what-is-apache-seata" data-id="what-is-apache-seata"><strong>3. What Is Apache Seata?</strong></h2>
<div class="bd-anchor" id="what-is-apache-seata"></div>
<p><strong>Apache Seata is an open source project, originally part of Alibaba group, that helps us to manage distributed transactions in our Java microservices applications.</strong></p>
<p>When using Seata, we run an additional service that acts as the Transaction Coordinator. When a request comes into our application, the originating service, acting as the Transaction Manager, starts a new distributed transaction within the transaction coordinator. All other services then take part in this same transaction until it either gets persisted or reverted:</p>
<a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/wp-content/uploads/2026/03/distributed-transactions-1.png"><img loading="lazy" decoding="async" class="alignnone wp-image-242133 size-large" src="https://www.baeldung.com/wp-content/uploads/2026/03/distributed-transactions-1-1024x751.png" alt="Sequence diagram showing calls between various different services each within separate applications. Each application has it's own database transaction but all take part in a larger distributed transaction." width="1024" height="751" /></a>
<p><strong>Here, our flow is essentially the same, but we&#8217;ve also added in our transaction coordinator and wrapped everything in a single distributed transaction.</strong> This will ensure that all three databases either commit or rollback together, and so our overall system remains in a valid state.</p>
<h2 id="bd-seata-server" data-id="seata-server"><strong>4. Seata Server</strong></h2>
<div class="bd-anchor" id="seata-server"></div>
<p><strong>Before we can use Seata, we need to ensure that we have a running Seata Server. This acts as the transaction coordinator in our overall system.</strong></p>
<p>The easiest way to get this working is as a <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://hub.docker.com/r/apache/seata-server">Docker container</a> that we can run in our environment. For example, we can include it in a <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/ops/docker-compose">Docker Compose</a> file as follows:</p>
<pre><code class="language-yaml">services:
  seata-server:
    image: apache/seata-server:2.6.0
</code></pre>
<p>By default, this listens on port 8091 and uses the local filesystem within the container to track distributed transactions.</p>
<p>We&#8217;re then ready to set up our application to work with Seata.</p>
<h2 id="bd-using-spring-boot" data-id="using-spring-boot"><strong>5. Using Spring Boot</strong></h2>
<div class="bd-anchor" id="using-spring-boot"></div>
<p><strong>Seata provides a <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://mvnrepository.com/artifact/org.apache.seata/seata-spring-boot-starter">Spring Boot starter</a> that we can use to set it up.</strong> If we’re using Maven, we can include this dependency in our <em>pom.xml</em> file:</p>
<pre><code class="language-xml">&lt;dependency&gt;
    &lt;groupId&gt;org.apache.seata&lt;/groupId&gt;
    &lt;artifactId&gt;seata-spring-boot-starter&lt;/artifactId&gt;
    &lt;version&gt;2.6.0&lt;/version&gt;
&lt;/dependency&gt;
</code></pre>
<h3 id="bd-1-configuring-seata" data-id="1-configuring-seata"><strong>5.1. Configuring Seata</strong></h3>
<div class="bd-anchor" id="1-configuring-seata"></div>
<p><strong>We then need to provide a configuration file for Seata.</strong> This needs to be present on the classpath, so we&#8217;ll create it as <em>src/main/resources/seata.conf</em>:</p>
<pre><code class="language-apache">transport {
  type = "TCP"
  server = "NIO"
  heartbeat = true
  thread-factory {
    boss-thread-prefix = "NettyBoss"
    worker-thread-prefix = "NettyServerNIOWorker"
    server-executor-thread-size = 100
    share-boss-worker = false
    client-selector-thread-size = 1
    client-selector-thread-prefix = "NettyClientSelector"
    client-worker-thread-prefix = "NettyClientWorkerThread"
  }
  shutdown {
    wait = 3
  }
  serialization = "seata"
  compressor = "none"
}
service {
  vgroupMapping.my_tx_group = "default"
  default.grouplist = "seata-server:8091"
  enableDegrade = false
  disableGlobalTransaction = false
}
client {
  rm {
    asyncCommitBufferLimit = 10000
    lock {
      retryInterval = 10
      retryTimes = 30
      retryPolicyBranchRollbackOnConflict = true
    }
    reportRetryCount = 5
    tableMetaCheckEnable = false
    reportSuccessEnable = false
    sagaBranchRegisterEnable = false
  }
  tm {
    commitRetryCount = 5
    rollbackRetryCount = 5
    defaultGlobalTransactionTimeout = 60000
    degradeCheck = false
  }
  undo {
    dataValidation = true
    logSerialization = "jackson"
    logTable = "undo_log"
    compress {
      enable = true
      type = "zip"
      threshold = "64k"
    }
  }
  log {
    exceptionRate = 100
  }
}</code></pre>
<p>Most of this is standard, but note we have to configure the host and port of the Seata server in the field <em>service.default.grouplist</em>.</p>
<p><strong>We also need to add some configuration to Spring to enable it to work with Seata.</strong> We do this within our <em>application.properties </em>file:</p>
<pre><code class="language-properties">seata.enabled=true
seata.application-id=${spring.application.name}
seata.tx-service-group=my_tx_group
seata.registry.type=file
seata.registry.file.name=seata.conf
seata.config.type=file
seata.config.file.name=seata.conf
seata.service.vgroup-mapping.my_tx_group=default
seata.service.grouplist.default=seata-server:8091
seata.data-source-proxy-mode=AT
seata.enable-auto-data-source-proxy=true
</code></pre>
<p>This also contains the host and port of the Seata server in the <em>seata.service.grouplist.default</em> property. We also need to ensure that several of the properties match up with the Seata configuration file, and that the <em>seata.registry.file.name </em>and <em>seata.config.file.name </em>properties point to our <em>seata.conf</em> file.</p>
<p><strong>Finally, if we&#8217;re <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://seata.apache.org/docs/user/mode/at">using AT mode</a> as configured here, we&#8217;ll need to create a special <em>undo_log</em> table in our service database:</strong></p>
<pre><code class="language-sql">CREATE TABLE IF NOT EXISTS undo_log (
    id            BIGSERIAL    NOT NULL,
    branch_id     BIGINT       NOT NULL,
    xid           VARCHAR(128) NOT NULL,
    context       VARCHAR(128) NOT NULL,
    rollback_info BYTEA        NOT NULL,
    log_status    INT          NOT NULL,
    log_created   TIMESTAMP(0) NOT NULL,
    log_modified  TIMESTAMP(0) NOT NULL,
    CONSTRAINT pk_undo_log PRIMARY KEY (id),
    CONSTRAINT ux_undo_log UNIQUE (xid, branch_id)
);</code></pre>
<p>We configure the exact table name in our <em>seata.conf</em> file.</p>
<p>At this point, Seata integrates with our service. If we start our project now, we&#8217;ll see several log messages indicating this:</p>
<pre><code class="language-plaintext">2026-03-14T07:53:37.728Z  INFO 1 --- [apache-seata-a] [           main] o.a.s.s.b.a.SeataAutoConfiguration       : Automatically configure Seata
2026-03-14T07:53:37.802Z  INFO 1 --- [apache-seata-a] [           main] ServiceLoader$InnerEnhancedServiceLoader : Load compatible class io.seata.spring.annotation.ScannerChecker
2026-03-14T07:53:37.984Z  INFO 1 --- [apache-seata-a] [           main] ServiceLoader$InnerEnhancedServiceLoader : Load compatible class io.seata.integration.tx.api.remoting.RemotingParser
2026-03-14T07:53:37.996Z  INFO 1 --- [apache-seata-a] [           main] o.a.s.s.a.GlobalTransactionScanner       : Initializing Global Transaction Clients ...
.....
2026-03-14T07:53:45.533Z  INFO 1 --- [apache-seata-a] [           main] o.a.s.c.rpc.netty.RmNettyRemotingClient  : RM will register :jdbc:postgresql://postgres:5432/seata
2026-03-14T07:53:45.540Z  INFO 1 --- [apache-seata-a] [           main] o.a.s.c.rpc.netty.NettyPoolableFactory   : NettyPool create channel to transactionRole:RMROLE,address:172.18.0.2:8091,msg:&lt; RegisterRMRequest{resourceIds='jdbc:postgresql://postgres:5432/seata', version='2.6.0', applicationId='apache-seata-a', transactionServiceGroup='my_tx_group', extraData='null'} &gt;
2026-03-14T07:53:45.586Z  INFO 1 --- [apache-seata-a] [           main] o.a.s.c.rpc.netty.RmNettyRemotingClient  : register RM success. client version:2.6.0, server version:2.6.0,channel:[id: 0x0a28dceb, L:/172.18.0.6:39884 - R:172.18.0.2/172.18.0.2:8091]
2026-03-14T07:53:45.590Z  INFO 1 --- [apache-seata-a] [           main] o.a.s.c.rpc.netty.NettyPoolableFactory   : register success, cost 34 ms, version:2.6.0,role:RMROLE,channel:[id: 0x0a28dceb, L:/172.18.0.6:39884 - R:172.18.0.2/172.18.0.2:8091]
2026-03-14T07:53:45.634Z  INFO 1 --- [apache-seata-a] [           main] .s.s.a.d.SeataAutoDataSourceProxyCreator : Auto proxy data source 'dataSource' by 'AT' mode.</code></pre>
<h3 id="bd-2-global-transactions" data-id="2-global-transactions"><strong>5.2. Global Transactions</strong></h3>
<div class="bd-anchor" id="2-global-transactions"></div>
<p>Once Spring fully integrates with Seata, we can start using it. <strong>We do this with the <em>@GlobalTransaction</em> annotation, which we use to mark the start of a transaction that should be distributed between services:</strong></p>
<pre><code class="language-java">@PostMapping("/a/{mode}")
@GlobalTransactional
public void handle() {
    // Controller logic here
}</code></pre>
<p>We can use this anywhere that we&#8217;d typically use the <em>@Transactional </em>annotation, and this will start a new database transaction. This transaction registers with Seata and can span multiple services instead of remaining local.</p>
<p><strong>Note that we only include this annotation at the start of the global transaction.</strong> Subsequent services in the same transaction needn&#8217;t include it. We&#8217;ll manage them differently, as we’ll see shortly.</p>
<p>If we wish, we can also provide some configuration for our transaction in a familiar way to the standard <em>@Transactional</em> annotation:</p>
<pre><code class="language-java">@GlobalTransactional(rollbackFor = MyException.class, timeoutMills = 10000)</code></pre>
<p>Here, we indicate that the transaction should roll back for any subclasses of <em>MyException</em>, with a 10-second timeout.</p>
<h3 id="bd-3-transaction-propagation" data-id="3-transaction-propagation"><strong>5.3. Transaction Propagation</strong></h3>
<div class="bd-anchor" id="3-transaction-propagation"></div>
<p>Unfortunately, if we try this now, then we&#8217;ll discover that the transactions don&#8217;t propagate correctly. We&#8217;d see log messages in our service indicating that it&#8217;s registered with Seata, but subsequent services wouldn&#8217;t do anything.</p>
<p><strong>Seata manages this by passing a special <em>XID </em>value between services. Typically, this goes in the HTTP header <em>TX_XID </em>on the calls between our services.</strong></p>
<p>If we&#8217;re using standard Spring then we need to manage this ourselves. This includes adding it to all outgoing HTTP calls and receiving it on all incoming calls.</p>
<p><strong>If we&#8217;re using <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/spring-boot-restclient">Spring RestClient</a> then we can write a <em>ClientHttpRequestInterceptor</em> implementation that will do this for us:</strong></p>
<pre><code class="language-java">public class SeataXidClientInterceptor implements ClientHttpRequestInterceptor {
    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)
        throws IOException {
        String xid = RootContext.getXID();
        if (StringUtils.hasText(xid)) {
            request.getHeaders().add(RootContext.KEY_XID, xid);
        }
        return execution.execute(request, body);
    }
}</code></pre>
<p>This simply adds our XID value to the outgoing HTTP request.</p>
<p>We must then ensure that our <em>RestClient</em> always uses this:</p>
<pre><code class="language-java">@Bean
public RestClient restClient() {
    return RestClient.builder()
        .requestInterceptor(new SeataXidClientInterceptor())
        .build();
}
</code></pre>
<p>We can do the exact same with any other HTTP clients too &#8211; e.g. <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/spring-5-webclient">WebClient</a> or <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/rest-template">RestTemplate</a>.</p>
<p>At this point, all of our outbound calls will indicate the XID for our global transactions. <strong>However, we still need to consume them in our downstream services. We can do this with a <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/spring-boot-add-filter">servlet filter</a>:</strong></p>
<pre><code class="language-java">@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class SeataXidFilter implements Filter {
    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
        throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) req;
        String xid = httpRequest.getHeader(RootContext.KEY_XID);
        boolean bound = false;
        if (StringUtils.hasText(xid) &amp;&amp; !xid.equals(RootContext.getXID())) {
            RootContext.bind(xid);
            bound = true;
        }
        try {
            chain.doFilter(req, res);
        } finally {
            if (bound) {
                RootContext.unbind();
            }
        }
    }
}</code></pre>
<p>This does the exact opposite &#8211; if there&#8217;s an XID present on the incoming HTTP request then bind it to the local service before continuing with the request, and ensure that we unbind it at the end.</p>
<p>At this point, our transaction now correctly spans our services and the entire set will commit or roll back together.</p>
<h2 id="bd-using-spring-cloud" data-id="using-spring-cloud"><strong>6. Using Spring Cloud</strong></h2>
<div class="bd-anchor" id="using-spring-cloud"></div>
<p><strong>Unlike Spring Boot, Spring Cloud can handle some of this automatically for us.</strong></p>
<p>In a Spring Cloud setup, we need to use a <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://mvnrepository.com/artifact/com.alibaba.cloud/spring-cloud-starter-alibaba-seata">different dependency</a> in our project. We also need to be careful with the versions here &#8211; the newest <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://mvnrepository.com/artifact/com.alibaba.cloud/spring-cloud-starter-alibaba-seata/2025.1.0.0">2025.1.0.0 version</a> only works with Spring Boot 4, whereas the <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://mvnrepository.com/artifact/com.alibaba.cloud/spring-cloud-starter-alibaba-seata/2025.0.0.0">2025.0.0.0 version</a> requires Spring Boot 3.</p>
<p>This dependency comes as a BOM that we can import into our dependency management section to manage versions, and then as the actual starter dependency:</p>
<pre><code class="language-xml">&lt;dependencyManagement&gt;
    &lt;dependencies&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;com.alibaba.cloud&lt;/groupId&gt;
            &lt;artifactId&gt;spring-cloud-alibaba-dependencies&lt;/artifactId&gt;
            &lt;version&gt;2025.0.0.0&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;
...
&lt;dependencies&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;com.alibaba.cloud&lt;/groupId&gt;
        &lt;artifactId&gt;spring-cloud-starter-alibaba-seata&lt;/artifactId&gt;
    &lt;/dependency&gt;
&lt;/dependencies&gt;</code></pre>
<p><strong>We still need to do the same configuration as before, using our <em>seata.conf</em> and <em>application.properties </em>files. However, the framework handles most transaction propagation for us.</strong></p>
<p>The Spring Cloud Starter will automatically set our service up so that any incoming HTTP requests will join a global transaction if required. This removes the need for our servlet filter.</p>
<p>The starter also configures <em>RestTemplate </em>beans to automatically forward the <em>XID </em>value to downstream services, so if we&#8217;re using this, then we don&#8217;t need additional setup here either. Unfortunately, it doesn&#8217;t work with <em>RestClient </em>or <em>WebClient</em>, so if we&#8217;re using those, then we&#8217;ll still need to configure it manually.</p>
<h2 id="bd-summary" data-id="summary"><strong>7. Summary</strong></h2>
<div class="bd-anchor" id="summary"></div>
<p>In this article, we&#8217;ve taken a quick look at Apache Seata. We&#8217;ve seen what it is, and how we can use it in our applications. Next time you&#8217;re writing transactional services, why not give it a go?</p>The post <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/apache-seata-distributed-transaction-management">Distributed Transaction Management Using Apache Seata</a> first appeared on <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com">Baeldung</a>.<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/951988322/0/baeldung">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/951988322/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/951988322/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2024%2f11%2fPersistence-Featured-Image-03-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/951988322/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/951988322/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/951988322/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/apache-seata-distributed-transaction-management#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/apache-seata-distributed-transaction-management/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/~/951988322/0/baeldung~Distributed-Transaction-Management-Using-Apache-Seata/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<webfeeds:featuredImage>https://www.baeldung.com/wp-content/uploads/2024/11/Persistence-Featured-Image-03-150x150.jpg</webfeeds:featuredImage></item>
<item>
<feedburner:origLink>https://www.baeldung.com/java-weekly-639</feedburner:origLink>
		<title>Java Weekly, Issue 639</title>
		<link>https://feeds.feedblitz.com/~/951970496/0/baeldung~Java-Weekly-Issue</link>
					<comments>https://feeds.feedblitz.com/~/951970496/0/baeldung~Java-Weekly-Issue#respond</comments>
		
		<dc:creator><![CDATA[baeldung]]></dc:creator>
		<pubDate>Fri, 27 Mar 2026 15:14:09 +0000</pubDate>
				<category><![CDATA[Weekly Review]]></category>
		<category><![CDATA[no-ads]]></category>
		<category><![CDATA[no-after-post]]></category>
		<category><![CDATA[no-before-post]]></category>
		<category><![CDATA[no-optins]]></category>
		<guid isPermaLink="false">https://www.baeldung.com/?p=203293</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>Our Spring Sale is live, Java 26 is almost out and OAuth is getting a core issue fixed. A good week</p>
The post <a rel="NOFOLLOW" href="https://feeds.feedblitz.com/~/951970496/0/baeldung~Java-Weekly-Issue">Java Weekly, Issue 639</a> first appeared on <a rel="NOFOLLOW" href="https://www.baeldung.com">Baeldung</a>.<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/951970496/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/951970496/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/951970496/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/951970496/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/951970496/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-639#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-639/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/java-for-scripting/">&gt;&gt; JavaScript (No, Not That One): Modern Automation with Java</a></strong> [<span style="color: #993300;">foojay.io</span>]</p>
<p>Modern Java is a thing to behold :). It has quietly become <strong>quite a capable scripting language</strong> — single-file execution, JBang, and Picocli make it a practical alternative to Bash or Python for automation. Good 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://foojay.io/today/spring-boot-actuator-health-for-microprofile-developers/" target="_blank" rel="noopener"><strong>Spring Boot Actuator Health for MicroProfile Developers</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/how-we-built-a-java-ai-agent-by-connecting-the-dots-the-ecosystem-already-had/" target="_blank" rel="noopener"><strong>How We Built a Java AI Agent by Connecting the Dots the Ecosystem Already Had</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/grails-isnt-done-yet-part-1-inside-the-asf-reboot/" target="_blank" rel="noopener"><strong>Grails Isn&#8217;t Done Yet (Part 1): Inside the ASF Reboot</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/does-language-still-matter-in-the-age-of-ai-yes-but-the-tradeoff-has-changed/" target="_blank" rel="noopener"><strong>Does Language Still Matter in the Age of AI? Yes — But the Tradeoff Has Changed</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/how-is-leyden-improving-java-performance-part-3-of-3/" target="_blank" rel="noopener"><strong>How is Leyden improving Java Performance? Part 3 of 3</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/03/19/jdk26-security-enhancements/" target="_blank" rel="noopener"><strong>JDK 26 Security Enhancements</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-polaris/" target="_blank" rel="noopener"><strong>Apache Polaris is powered by Quarkus</strong></a> [<span style="color: #800000;">quarkus.io</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://spring.io/blog/2026/03/19/a-bootiful-podcast-cay-horstmann" target="_blank" rel="noopener"><strong>A Bootiful Podcast: Cay Horstmann, legendary Java professor, author, lecturer</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://inside.java/2026/03/26/podcast-052/" target="_blank" rel="noopener"><strong>Episode 52 &#8220;Carrier Classes &amp; Discussing Syntax&#8221; [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://blog.jetbrains.com/kotlin/2026/03/kotlinconf-26-speakers-in-conversation-with-josh-long/" target="_blank" rel="noopener"><strong>KotlinConf&#8217;26 Speakers: In Conversation with Josh Long</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://inside.java/2026/03/25/javaone-javafx/" target="_blank" rel="noopener"><strong>JavaOne and JavaFX</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://www.youtube.com/watch?v=FUFsul26rgA" target="_blank" rel="noopener"><strong>Moritz Halbritter on Spring Boot</strong></a> [<span style="color: #800000;">youtube.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.youtube.com/watch?v=Kourq_Lz03U" target="_blank" rel="noopener"><strong>The IntelliJ IDEA Documentary</strong></a> [<span style="color: #800000;">youtube.com</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/03/26/spring-boot-4-1-0-M4-available-now" target="_blank" rel="noopener"><strong>Spring Boot 4.1.0-M4</strong></a>, <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://spring.io/blog/2026/03/26/spring-boot-4-0-5-available-now" target="_blank" rel="noopener"><strong>4.0.5</strong></a>, and <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://spring.io/blog/2026/03/26/spring-boot-3-5-13-available-now" target="_blank" rel="noopener"><strong>3.5.13</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/03/23/spring-cloud-config-5-0-2-4-3-2-4-2-6-4-1-9-3-1-13-released" target="_blank" rel="noopener"><strong>Spring Cloud Config 5.0.2, 4.3.2, 4.2.6, 4.1.9, 3.1.13 Released, includes fix for CVE-2026-22739</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/03/20/spring-boot-4-1-0-M3-available-now" target="_blank" rel="noopener"><strong>Spring Boot 4.1.0-M3</strong></a>, <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://spring.io/blog/2026/03/19/spring-boot-4-0-4-available-now" target="_blank" rel="noopener"><strong>4.0.4</strong></a>, and <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://spring.io/blog/2026/03/19/spring-boot-3-5-12-available-now" target="_blank" rel="noopener"><strong>3.5.12</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/03/19/spring-security-6-5-9-and-7-0-4-and-7-1-0-M3-available-now" target="_blank" rel="noopener"><strong>Spring Security 6.5.9, 7.0.4, and 7.1.0-M3 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/03/18/spring-batch-6-0-3-and-5-2-5-available-now" target="_blank" rel="noopener"><strong>Spring Batch 6.0.3 and 5.2.5 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://blog.jetbrains.com/idea/2026/03/intellij-idea-2026-1/" target="_blank" rel="noopener"><strong>IntelliJ IDEA 2026.1</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-34-released/" target="_blank" rel="noopener"><strong>Quarkus 3.34</strong></a>, <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://quarkus.io/blog/quarkus-3-33-released/" target="_blank" rel="noopener"><strong>3.33 LTS</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-27-3-released/" target="_blank" rel="noopener"><strong>Quarkus 3.27.3</strong></a> and <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://quarkus.io/blog/quarkus-3-20-6-released/" target="_blank" rel="noopener"><strong>3.20.6</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://in.relation.to/2026/03/24/hibernate-reactive-4_3_0_Final/" target="_blank" rel="noopener"><strong>Hibernate Reactive 4.3.0.Final</strong></a> [<span style="color: #800000;">in.relation.to</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://in.relation.to/2026/03/20/hibernate-search-8-3-0-Final/" target="_blank" rel="noopener"><strong>Hibernate Search 8.3.0.Final</strong></a> [<span style="color: #800000;">in.relation.to</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.3.2" target="_blank" rel="noopener"><strong>Elasticsearch 9.3.2</strong></a> and <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/elastic/elasticsearch/releases/tag/v9.2.7" target="_blank" rel="noopener"><strong>9.2.7</strong></a> and <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/elastic/elasticsearch/releases/tag/v8.19.13" target="_blank" rel="noopener"><strong>8.19.13</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/v3.5.1" target="_blank" rel="noopener"><strong>Netflix Zuul 3.5.1</strong></a> and <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/Netflix/zuul/releases/tag/v3.5.2" target="_blank" rel="noopener"><strong>3.5.2</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/apache/camel/releases/tag/camel-4.18.1" target="_blank" rel="noopener"><strong>Apache Camel 4.18.1</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/eclipse-vertx/vert.x/releases/tag/5.0.9" target="_blank" rel="noopener"><strong>Eclipse Vert.x 5.0.9</strong></a> and <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/eclipse-vertx/vert.x/releases/tag/4.5.26" target="_blank" rel="noopener"><strong>4.5.26</strong></a> [<span style="color: #800000;">github.com/eclipse-vertx</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/bliki/ArchitectureDecisionRecord.html">&gt;&gt; Bliki: Architecture Decision Record</a></strong> [<span style="color: #993300;">martinfowler.com</span>]</p>
<p>This is a lightweight document capturing <strong>a log of architectural decisions</strong> along with its context and trade-offs, stored in version control alongside code. Quite useful and often missed.</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/software-architect-elevator/" target="_blank" rel="noopener"><strong>The Software Architect Elevator</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/3/20/some-things-just-take-time/" target="_blank" rel="noopener"><strong>Some Things Just Take Time</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.jbrains.ca/permalink/your-inbox-as-options-not-obligations" target="_blank" rel="noopener"><strong>Your Inbox As Options, Not Obligations</strong></a> [<span style="color: #800000;">jbrains.ca</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.mnot.net/blog/2026/03/25/using_ai" target="_blank" rel="noopener"><strong>Using AI to Evaluate Internet Standards (Part Two)</strong></a> [<span style="color: #800000;">mnot.net</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://foojay.io/today/testbox-7-real-time-feedback-a-browser-based-ide-and-modern-testing-workflows-on-the-jvm/" target="_blank" rel="noopener"><strong>TestBox 7: Real-Time Feedback, a Browser-Based IDE, and Modern Testing Workflows on the JVM</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>And our sale is about to end:</p>
<p><a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/members/pricing"><strong>&gt;&gt; All Access for 4 More Days</strong></a></p>The post <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-weekly-639">Java Weekly, Issue 639</a> first appeared on <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com">Baeldung</a>.<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/951970496/0/baeldung">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/951970496/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/951970496/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/951970496/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/951970496/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/951970496/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-639#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-639/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/~/951970496/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/spring-ai-testing-mcp-tools</feedburner:origLink>
		<title>Testing Model Context Protocol (MCP) Tools in Spring AI</title>
		<link>https://feeds.feedblitz.com/~/951832256/0/baeldung~Testing-Model-Context-Protocol-MCP-Tools-in-Spring-AI</link>
					<comments>https://feeds.feedblitz.com/~/951832256/0/baeldung~Testing-Model-Context-Protocol-MCP-Tools-in-Spring-AI#respond</comments>
		
		<dc:creator><![CDATA[Manfred Ng]]></dc:creator>
		<pubDate>Wed, 25 Mar 2026 05:12:43 +0000</pubDate>
				<category><![CDATA[Spring AI]]></category>
		<category><![CDATA[Testing]]></category>
		<category><![CDATA[LLM]]></category>
		<guid isPermaLink="false">https://www.baeldung.com/?p=203238</guid>
					<description><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/2024/11/Spring-Featured-Image-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>Explore how to test MCP tools on MCP servers in Spring AI using different test strategies.</p>
The post <a rel="NOFOLLOW" href="https://feeds.feedblitz.com/~/951832256/0/baeldung~Testing-Model-Context-Protocol-MCP-Tools-in-Spring-AI">Testing Model Context Protocol (MCP) Tools in Spring AI</a> first appeared on <a rel="NOFOLLOW" href="https://www.baeldung.com">Baeldung</a>.<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/951832256/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/951832256/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2024%2f11%2fSpring-Featured-Image-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/951832256/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/951832256/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/951832256/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-testing-mcp-tools#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-ai-testing-mcp-tools/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/Spring-Featured-Image-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/11/Spring-Featured-Image-11-1024x536.jpg 1024w, https://www.baeldung.com/wp-content/uploads/2024/11/Spring-Featured-Image-11-300x157.jpg 300w, https://www.baeldung.com/wp-content/uploads/2024/11/Spring-Featured-Image-11-768x402.jpg 768w, https://www.baeldung.com/wp-content/uploads/2024/11/Spring-Featured-Image-11-100x52.jpg 100w, https://www.baeldung.com/wp-content/uploads/2024/11/Spring-Featured-Image-11-600x314.jpg 600w, https://www.baeldung.com/wp-content/uploads/2024/11/Spring-Featured-Image-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><strong><a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/spring-ai-model-context-protocol-mcp">Model Context Protocol (MCP)</a> is an open standard protocol that defines how a large language model (LLM) discovers and invokes external tools to extend its capabilities.</strong> MCP is a client-server architecture that allows the MCP client, usually an LLM integrated application, to interact with one or more MCP servers that expose tools for invocation.</p>
<p>Testing tools exposed by MCP servers are crucial to validate that they are correctly registered on MCP servers and are discoverable by MCP clients. Unlike LLM responses, which are non-deterministic, MCP tools behave deterministically because they&#8217;re just normal application code, which enables us to write automated tests to verify correctness.</p>
<p>In this tutorial, we&#8217;ll explore how to test MCP tools on MCP servers in <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/spring-ai">Spring AI</a> using different test strategies.</p>
<h2 id="bd-maven-dependencies" data-id="maven-dependencies">2. Maven Dependencies</h2>
<div class="bd-anchor" id="maven-dependencies"></div>
<p>We&#8217;ll test the MCP tools in a Spring Boot application. Hence, we must add the <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://mvnrepository.com/artifact/org.springframework.ai/spring-ai-starter-mcp-server">Spring AI MCP server</a> dependency to our <em>pom.xml</em>:</p>
<pre><code class="language-xml">&lt;dependency&gt;
    &lt;groupId&gt;org.springframework.ai&lt;/groupId&gt;
    &lt;artifactId&gt;spring-ai-starter-mcp-server&lt;/artifactId&gt;
    &lt;version&gt;1.1.2&lt;/version&gt;
&lt;/dependency&gt;</code></pre>
<p>We&#8217;ll also require the <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-test">Spring Boot Test</a> dependency for our testing:</p>
<pre><code class="language-xml">&lt;dependency&gt;
    &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
    &lt;artifactId&gt;spring-boot-starter-test&lt;/artifactId&gt;
    &lt;scope&gt;test&lt;/scope&gt;
&lt;/dependency&gt;</code></pre>
<h2 id="bd-creating-a-sample-mcp-tool" data-id="creating-a-sample-mcp-tool">3. Creating a Sample MCP Tool</h2>
<div class="bd-anchor" id="creating-a-sample-mcp-tool"></div>
<p>In this section, we&#8217;ll implement a simple MCP tool using Spring AI and demonstrate different testing strategies.</p>
<p>First, let&#8217;s create a simple <em>ExchangeRateService</em> that uses a third-party open-source service, <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://frankfurter.dev/">Frankfurter</a>, to fetch the currency exchange rate using an HTTP GET request. This API requires a mandatory query parameter <em>base</em>:</p>
<pre><code class="language-java">@Service
public class ExchangeRateService {
    private static final String FRANKFURTER_URL = "https://api.frankfurter.dev/v1/latest?base={base}";
    private final RestClient restClient;
    public ExchangeRateService(RestClient.Builder restClientBuilder) {
        this.restClient = restClientBuilder.build();
    }
    public ExchangeRateResponse getLatestExchangeRate(String base) {
        if (base == null || base.isBlank()) {
            throw new IllegalArgumentException("base is required");
        }
        return restClient.get()
          .uri(FRANKFURTER_URL, base.trim().toUpperCase())
          .retrieve()
          .body(ExchangeRateResponse.class);
    }
}
</code></pre>
<p>The API response looks something similar to:</p>
<pre><code class="language-">{
  "amount": 1,
  "base": "GBP",
  "date": "2026-03-06",
  "rates": {
    "AUD": 1.9034,
    "BRL": 7.0366,
    ......
  }
}</code></pre>
<p>Thus, we create the following Java record to map the JSON response:</p>
<pre><code class="language-java">public record ExchangeRateResponse(double amount, String base, String date, Map&lt;String, Double&gt; rates) {
}</code></pre>
<p>Now, let&#8217;s create an MCP tool that invokes the <em>ExchangeRateService</em> to return currency exchange rates based on the base currency.</p>
<p><strong>The tool description explains what the parameter is for, such that MCP clients know what they should provide when calling it:</strong></p>
<pre><code class="language-java">@Component
public class ExchangeRateMcpTool {
    private final ExchangeRateService exchangeRateService;
    public ExchangeRateMcpTool(ExchangeRateService exchangeRateService) {
        this.exchangeRateService = exchangeRateService;
    }
    @McpTool(description = "Get latest exchange rates for a base currency")
    public ExchangeRateResponse getExchangeRate(
        @McpToolParam(description = "Base currency code, e.g. GBP, USD", required = true) String base) {
        return exchangeRateService.getLatestExchangeRate(base);
    }
}</code></pre>
<h2 id="bd-unit-test" data-id="unit-test">4. Unit Test</h2>
<div class="bd-anchor" id="unit-test"></div>
<p><strong>We could verify the <em>ExchangeRateMcpTool</em> logic in isolation by unit test. Therefore, we mock the external dependency so that we can provide a mocked response.</strong></p>
<p>The verification process is fairly simple to validate that the service gets invoked correctly, and also the response is returned as expected:</p>
<pre><code class="language-java">class ExchangeRateMcpToolUnitTest {
    @Test
    void whenBaseIsNotBlank_thenGetExchangeRateShouldReturnResponse() {
        ExchangeRateService exchangeRateService = mock(ExchangeRateService.class);
        ExchangeRateResponse expected = new ExchangeRateResponse(1.0, "GBP", "2026-03-08",
          Map.of("USD", 1.27, "EUR", 1.17));
        when(exchangeRateService.getLatestExchangeRate("gbp")).thenReturn(expected);
        ExchangeRateMcpTool tool = new ExchangeRateMcpTool(exchangeRateService);
        ExchangeRateResponse actual = tool.getExchangeRate("gbp");
        assertThat(actual).isEqualTo(expected);
        verify(exchangeRateService).getLatestExchangeRate("gbp");
    }
}</code></pre>
<h2 id="bd-creating-an-mcp-test-client" data-id="creating-an-mcp-test-client">5. Creating an MCP Test Client</h2>
<div class="bd-anchor" id="creating-an-mcp-test-client"></div>
<p><strong>If we want to test the MCP tools end-to-end, we could create an MCP client that connects to the MCP server.</strong></p>
<p>HTTP-based MCP servers expose different endpoints depending on the protocol configuration property <em>spring.ai.mcp.server.protocol</em> in the <em>application.yml</em>. Spring AI uses the SSE by default if we don&#8217;t set the property explicitly:</p>
<table class="table-styled" style="border-collapse: collapse;width: 50%">
<tbody>
<tr>
<th>Protocol</th>
<th>Endpoint</th>
</tr>
<tr>
<td>Server-Sent Events (SSE)</td>
<td>/sse</td>
</tr>
<tr>
<td style="width: 60%">Streamable HTTP</td>
<td style="width: 40%">/mcp</td>
</tr>
</tbody>
</table>
<p>In addition to the different endpoints, each protocol requires a different <em>McpClientTransport</em> instance to create the <em>McpSyncClient</em>.</p>
<p>Since Spring AI does not provide a factory class that automatically creates the client based on the protocol, we create a test component, <em>TestMcpClientFactory, </em>handling the <em>McpSyncClient</em> creation, to simplify our testing:</p>
<pre><code class="language-java">@Component
public class TestMcpClientFactory {
    private final String protocol;
    public TestMcpClientFactory(@Value("${spring.ai.mcp.server.protocol:sse}") String protocol) {
        this.protocol = protocol;
    }
    public McpSyncClient create(String baseUrl) {
        String resolvedProtocol = protocol.trim().toLowerCase();
        return switch (resolvedProtocol) {
            case "sse" -&gt; McpClient.sync(HttpClientSseClientTransport.builder(baseUrl)
              .sseEndpoint("/sse")
              .build()
            ).build();
            case "streamable" -&gt; McpClient.sync(HttpClientStreamableHttpTransport.builder(baseUrl)
              .endpoint("/mcp")
              .build()
            ).build();
            default -&gt; throw new IllegalArgumentException("Unknown MCP protocol: " + protocol);
        };
    }
}</code></pre>
<p>We support the SSE and streamable protocol only in our factory class to demonstrate the idea.</p>
<h2 id="bd-verifying-tool-registration" data-id="verifying-tool-registration">6. Verifying Tool Registration</h2>
<div class="bd-anchor" id="verifying-tool-registration"></div>
<p><strong>The MCP server exposes an HTTP endpoint to list all available tools that MCP clients can invoke. As such, we could initialize an MCP client to verify the tool&#8217;s registration on the MCP server.</strong></p>
<div>The following is our base code for initializing and closing an <em>McpSyncClient</em>:</div>
<pre><code class="language-">@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class ExchangeRateMcpToolIntegrationTest {
    @LocalServerPort
    private int port;
    @Autowired
    private TestMcpClientFactory testMcpClientFactory;
    @MockBean
    private ExchangeRateService exchangeRateService;
    private McpSyncClient client;
    @BeforeEach
    void setUp() {
        client = testMcpClientFactory.create("http://localhost:" + port);
        client.initialize();
    }
    @AfterEach
    void cleanUp() {
        client.closeGracefully();
    }
}</code></pre>
<p>Once we initialize an MCP client, we invoke the client <em>listTools()</em> method to find out all tools that an MCP server has registered:</p>
<pre><code class="language-java">@Test
void whenMcpClientListTools_thenTheToolIsRegistered() {
    boolean registered = client.listTools().tools().stream()
      .anyMatch(tool -&gt; Objects.equals(tool.name(), "getLatestExchangeRate"));
    assertThat(registered).isTrue();
}</code></pre>
<p>The test returns a list of registered tools, and we assert that <em>getLatestExchangeRate</em> is one of them to confirm successful registration.</p>
<h2 id="bd-testing-tool-invocation" data-id="testing-tool-invocation">7. Testing Tool Invocation</h2>
<div class="bd-anchor" id="testing-tool-invocation"></div>
<p><strong>In addition, we could also verify the MCP tool by invoking it from an MCP client. </strong>We mock the <em>ExchangeRateService</em> in this test to avoid making a genuine HTTP call to the Frankfurter API<em>.</em></p>
<p>The invocation flow includes discovering the tools from the MCP server, building a <em>CallToolRequest</em> with all required arguments, and calling it to obtain the response from the server:</p>
<pre><code class="language-java">@Test
void whenMcpClientCallTool_thenTheToolReturnsMockedResponse() {
    when(exchangeRateService.getLatestExchangeRate("GBP")).thenReturn(
      new ExchangeRateResponse(1.0, "GBP", "2026-03-08", Map.of("USD", 1.27))
    );
    McpSchema.Tool exchangeRateTool = client.listTools().tools().stream()
      .filter(tool -&gt; "getLatestExchangeRate".equals(tool.name()))
      .findFirst()
      .orElseThrow();
    String argumentName = exchangeRateTool.inputSchema().properties().keySet().stream()
      .findFirst()
      .orElseThrow();
    McpSchema.CallToolResult result = client.callTool(
      new McpSchema.CallToolRequest("getLatestExchangeRate", Map.of(argumentName, "GBP"))
    );
    assertThat(result).isNotNull();
    assertThat(result.isError()).isFalse();
    assertTrue(result.toString().contains("GBP"));
}</code></pre>
<p>The assertions ensure the tool call returns a valid response without errors.</p>
<h2 id="bd-conclusions" data-id="conclusions">8. Conclusions</h2>
<div class="bd-anchor" id="conclusions"></div>
<p>In this article, we created a sample MCP server tool, validated its correctness, ensured the MCP server registered with it, and tested the tool invocation via an MCP client.</p>
<p>With both unit tests and integration tests in place, we can be confident that the tool is working correctly and is exposed properly so that MCP clients can invoke it.</p>The post <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/spring-ai-testing-mcp-tools">Testing Model Context Protocol (MCP) Tools in Spring AI</a> first appeared on <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com">Baeldung</a>.<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/951832256/0/baeldung">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/951832256/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/951832256/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2024%2f11%2fSpring-Featured-Image-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/951832256/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/951832256/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/951832256/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-testing-mcp-tools#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-ai-testing-mcp-tools/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/~/951832256/0/baeldung~Testing-Model-Context-Protocol-MCP-Tools-in-Spring-AI/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<webfeeds:featuredImage>https://www.baeldung.com/wp-content/uploads/2024/11/Spring-Featured-Image-11-150x150.jpg</webfeeds:featuredImage></item>
<item>
<feedburner:origLink>https://www.baeldung.com/java-weekly-638</feedburner:origLink>
		<title>Java Weekly, Issue 638</title>
		<link>https://feeds.feedblitz.com/~/951217484/0/baeldung~Java-Weekly-Issue</link>
					<comments>https://feeds.feedblitz.com/~/951217484/0/baeldung~Java-Weekly-Issue#respond</comments>
		
		<dc:creator><![CDATA[baeldung]]></dc:creator>
		<pubDate>Thu, 19 Mar 2026 20:28:01 +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=203218</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>Our Spring Sale is live, Java 26 is almost out and OAuth is getting a core issue fixed. A good week</p>
The post <a rel="NOFOLLOW" href="https://feeds.feedblitz.com/~/951217484/0/baeldung~Java-Weekly-Issue">Java Weekly, Issue 638</a> first appeared on <a rel="NOFOLLOW" href="https://www.baeldung.com">Baeldung</a>.<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/951217484/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/951217484/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/951217484/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/951217484/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/951217484/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-638#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-638/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://spring.io/blog/2026/03/18/mcp-apps">&gt;&gt; Blending Chat with Rich UIs with Spring AI and MCP Apps</a></strong> [<span style="color: #993300">spring.io</span>]</p>
<p>If you&#8217;ve been wondering how to move beyond pure chat interfaces without sacrificing the conversational layer, this is a practical starting point.</p>
<p><strong><a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://blog.jetbrains.com/idea/2026/03/java-26-in-intellij-idea/">&gt;&gt; Java 26 in IntelliJ IDEA</a></strong> [<span style="color: #993300">jetbrains.com</span>]</p>
<p><strong>Java 26 lands</strong> with five finalized JEPs — including HTTP/3 support (nice) and GC improvements — plus four preview features. And, of course, IntelliJ IDEA&#8217;s deep integration means you can explore all of it right away. Good 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://blog.jetbrains.com/ai/2026/03/koog-comes-to-java/" target="_blank" rel="noopener"><strong>Koog Comes to Java: The Enterprise AI Agent Framework From JetBrains</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/news/2026/03/hubspot-ai-code-review-agent/" target="_blank" rel="noopener"><strong>HubSpot&#8217;s Sidekick: Multi-Model AI Code Review with 90% Faster Feedback and 80% Engineer Approval</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://www.infoq.com/news/2026/03/java26-released/" target="_blank" rel="noopener"><strong>Java 26 Delivers Language Innovation, Library Improvements, Performance and Security</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/how-is-leyden-improving-java-performance-part-1-of-3/" target="_blank" rel="noopener"><strong>How is Leyden improving Java Performance? Part 1 of 3</strong></a> and <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://foojay.io/today/how-is-leyden-improving-java-performance-part-2-of-3/" target="_blank" rel="noopener"><strong>Part 2 of 3</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/java-26-is-here-and-with-it-a-solid-foundation-for-the-future/" target="_blank" rel="noopener"><strong>Java 26 Is Here, And With It a Solid Foundation for the Future</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/language-learning-flashcard-system-part-1/" target="_blank" rel="noopener"><strong>Language Learning Flashcard System &#8212; Part 1</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/03/13/jms-secure-scalable-jvm/" target="_blank" rel="noopener"><strong>Secure, Scalable JVM Diagnostics for Kubernetes with JMS</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/kotlin/2026/03/introducing-tracy-the-ai-observability-library-for-kotlin/" target="_blank" rel="noopener"><strong>Introducing Tracy: The AI Observability Library for Kotlin</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/03/17/jdk-26-in-2-mins/" target="_blank" rel="noopener"><strong>Java 26 in definitely UNDER 3 minutes</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/03/12/a-bootiful-podcast-soby-chacko" target="_blank" rel="noopener"><strong>A Bootiful Podcast: Spring Messaging Legend Soby Chacko</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://www.infoq.com/podcasts/release-software-jreleaser/" target="_blank" rel="noopener"><strong>Andres Almiray on How to Release Any Software to Any OS with JReleaser</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://toomuchcoding.com/post/2026-03-14-generate-break-fix-recording/" target="_blank" rel="noopener"><strong>Watch AI Build a Microservice. Watch Me Break It in 60 s &#8211; Lightning Session recording</strong></a> [<span style="color: #800000">toomuchcoding.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://foojay.io/today/foojay-podcast-92/" target="_blank" rel="noopener"><strong>Foojay Podcast #92: Java 26 Is Here: What&#8217;s New, What&#8217;s Gone, and Why It Matters in 2026</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/03/12/podcast-051/" target="_blank" rel="noopener"><strong>Episode 51 &#8220;Unboxing Java 26 for Developers&#8221;</strong></a> [<span style="color: #800000">inside.java</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://blogs.oracle.com/java/the-arrival-of-java-26" target="_blank" rel="noopener"><strong>The Arrival of Java 26</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/03/13/spring-framework-6-2-17-and-7-0-6-available-now" target="_blank" rel="noopener"><strong>Spring Framework 6.2.17 and 7.0.6 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/03/17/spring-ai-2-0-0-M3-and-1-1-3-and-1-0-4-available" target="_blank" rel="noopener"><strong>Spring AI 2.0.0-M3, 1.1.3 and 1.0.4 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/03/18/spring-integration-7-1-0-m3-available" target="_blank" rel="noopener"><strong>Spring Integration 7.1.0-M3 Available</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/03/17/spring-ws-5-0-1-available-now" target="_blank" rel="noopener"><strong>Spring Web Services 5.0.1</strong></a> and <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://spring.io/blog/2026/03/17/spring-ws-4-1-3-available-now" target="_blank" rel="noopener"><strong>4.1.3</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://blog.jetbrains.com/idea/2026/03/intellij-idea-2025-3-4/" target="_blank" rel="noopener"><strong>IntelliJ IDEA 2025.3.4</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/03/kotlin-2-3-20-released/" target="_blank" rel="noopener"><strong>Kotlin 2.3.20</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://foojay.io/today/boxlang-1-11-0-release/" target="_blank" rel="noopener"><strong>BoxLang 1.11.0</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://github.com/grails/grails-core/releases/tag/v7.0.9" target="_blank" rel="noopener"><strong>Grails 7.0.9</strong></a> [<span style="color: #800000">github.com/grails</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/v4.10.18" target="_blank" rel="noopener"><strong>Micronaut 4.10.18</strong></a> and <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/micronaut-projects/micronaut-core/releases/tag/v3.8.13" target="_blank" rel="noopener"><strong>3.8.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/payara/Payara/releases/tag/payara-server-7.2026.3" target="_blank" rel="noopener"><strong>Payara 7.2026.3</strong></a> [<span style="color: #800000">github.com/payara</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/articles/reduce-friction-ai/context-anchoring.html">&gt;&gt; Context Anchoring</a></strong> [<span style="color: #993300">martinfowler.com</span>]</p>
<p>AI coding sessions degrade as context drifts — and Fowler&#8217;s team tackles this head-on with a document-driven anchoring strategy. Definitely worth being on your weekend reading list.</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/writing-agent-skill/" target="_blank" rel="noopener"><strong>Writing an agent skill</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://blog.scottlogic.com/2026/03/15/if-ai-writes-the-code-who-builds-the-next-open-source-project.html" target="_blank" rel="noopener"><strong>If AI Writes the Code, Who Builds the Next Open Source Project?</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://event-driven.io/en/interactive_rubber_ducking_with_gen_ai/" target="_blank" rel="noopener"><strong>Interactive Rubber Ducking with GenAI</strong></a> [<span style="color: #800000">event-driven.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://4comprehension.com/tdocker-tui/" target="_blank" rel="noopener"><strong>tdocker: A Terminal UI for Everyday Docker Commands</strong></a> [<span style="color: #800000">4comprehension.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.infoq.com/news/2026/03/booking-evolution-ai-manuel/" target="_blank" rel="noopener"><strong>QCon London 2026: Behind Booking.com&#8217;s AI Evolution: The Unpolished Story</strong></a> [<span style="color: #800000">infoq.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>The first sale of the year:</p>
<p><a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/members/pricing">&gt;&gt; All Access and Pro, <strong>both at 30% off until the end of the month</strong></a></p>
<p>We only do three of these every year <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" />
<br>
</p>The post <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-weekly-638">Java Weekly, Issue 638</a> first appeared on <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com">Baeldung</a>.<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/951217484/0/baeldung">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/951217484/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/951217484/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/951217484/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/951217484/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/951217484/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-638#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-638/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/~/951217484/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-h2-export-backup</feedburner:origLink>
		<title>Performing Export and Backup of H2 Databases</title>
		<link>https://feeds.feedblitz.com/~/951207752/0/baeldung~Performing-Export-and-Backup-of-H-Databases</link>
					<comments>https://feeds.feedblitz.com/~/951207752/0/baeldung~Performing-Export-and-Backup-of-H-Databases#respond</comments>
		
		<dc:creator><![CDATA[Hiks Gerganov]]></dc:creator>
		<pubDate>Thu, 19 Mar 2026 15:56:59 +0000</pubDate>
				<category><![CDATA[Persistence]]></category>
		<category><![CDATA[H2]]></category>
		<guid isPermaLink="false">https://www.baeldung.com/java-h2-export-backup</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 to create reliable backups of H2 databses and export data for recovery, inspection, or reuse.</p>
The post <a rel="NOFOLLOW" href="https://feeds.feedblitz.com/~/951207752/0/baeldung~Performing-Export-and-Backup-of-H-Databases">Performing Export and Backup of H2 Databases</a> first appeared on <a rel="NOFOLLOW" href="https://www.baeldung.com">Baeldung</a>.<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/951207752/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/951207752/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/951207752/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/951207752/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/951207752/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-h2-export-backup#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-h2-export-backup/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>Although <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/h2-production-database-features-limitations">H2 databases</a> were initially developed to function <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-in-memory-databases">in-memory</a> only, the engine now supports secondary storage and even server modes. Because of this, use cases have also increased, leading to two closely related needs: creating reliable backups for recovery and exporting data for inspection or reuse. Although both move data out of the database, they serve different purposes and rely on different mechanisms. Still, H2 meets these needs through <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/sql/">SQL</a> commands directly inside the engine. This way, the database can keep running while maintenance is underway.</p>
<p>In this tutorial, <strong>we explain backup and export mechanisms for H2</strong>. First, we go through the basic concepts of both actions. After that, we understand backup methods, see why copying database files is unreliable, and how the built-in commands operate while the database is online. Finally, we cover CSV and SQL-based exports and briefly note additional complementary techniques that fit naturally into H2-based workflows.</p>
<h2 id="bd-h2-backup-and-export-concepts" data-id="h2-backup-and-export-concepts">2. H2 Backup and Export Concepts</h2>
<div class="bd-anchor" id="h2-backup-and-export-concepts"></div>
<p>Before delving into specifics, it&#8217;s important to understand how backups and exports differ for H2. We also consider the environment and operating conditions.</p>
<h3 id="bd-1-backups-and-exports" data-id="1-backups-and-exports">2.1. Backups and Exports</h3>
<div class="bd-anchor" id="1-backups-and-exports"></div>
<p>In general, <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/cs/backups-in-computing">backups</a> preserve entire instances for later restoration. In the case of H2, this means creating a package that includes all tables, any created indices, and metadata. Backups relate to a particular point in time and primarily exist for recovery scenarios, such as data loss or environment rebuilds.</p>
<p>On the other hand, <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/sql/export-schema-without-data">exporting</a> usually focuses on data portability instead of recovery. Usually, an export is in a text-based format such as a CSV file or SQL script. Critically, the data within an export often contains only specific tables or query results. Although we can use exports for analysis and partial migration, they rarely provide the same guarantees as a full backup in terms of content. For instance, an export might only include part of the tables, no metadata, or other limitations.</p>
<h3 id="bd-2-online-operations" data-id="2-online-operations">2.2. Online Operations</h3>
<div class="bd-anchor" id="2-online-operations"></div>
<p>Many H2 databases run continuously in embedded mode as part of an application. In these cases, backups and exports should be able to complete successfully while data is being read and written.</p>
<p>To that end, <strong>the recommended approaches for the H2 engine rely on SQL commands executed through normal database connections</strong>. Thus, the engine itself can ensure consistency instead of relying on external file operations that are unaware of the internal state.</p>
<h2 id="bd-backing-up-an-online-h2-database" data-id="backing-up-an-online-h2-database">3. Backing Up an Online H2 Database</h2>
<div class="bd-anchor" id="backing-up-an-online-h2-database"></div>
<p>For offline scenarios where downtime is acceptable, shutting down the database cleanly and then copying files can be a viable option. However, this approach is usually reserved for controlled maintenance windows and isn&#8217;t a real substitute for online backups in continuously running systems.</p>
<p>Since uninterrupted operation can be critical in many cases, having a backup solution for an H2 database that&#8217;s currently in use can be crucial.</p>
<h3 id="bd-1-database-file-copying-unsafe" data-id="1-database-file-copying-unsafe">3.1. Database File Copying (Unsafe)</h3>
<div class="bd-anchor" id="1-database-file-copying-unsafe"></div>
<p>Because, like other database engines, H2 often stores data in files, copying those files may appear to be an easy backup solution. However, when the database is running, pages may be in the middle of an update. Thus, <strong>copying files at any given moment can lead to internal inconsistencies, such as partially written rows or mismatched tables, depending on the query</strong>.</p>
<p>Another issue is long-term reliability. Unlike standardized languages and formats, the H2 engine database files may change across versions. Due to that, a separate copy of a database file may fail to open after an upgrade, which limits its usefulness as a dependable backup.</p>
<h3 id="bd-2-online-backups-with-backup-to" data-id="2-online-backups-with-backup-to">3.2. Online Backups With <em>BACKUP TO</em></h3>
<div class="bd-anchor" id="2-online-backups-with-backup-to"></div>
<p>To avoid offline backups and address problems related to database files, H2 provides a special command. Specifically, <strong>the <em>BACKUP TO</em> SQL statement creates a ZIP archive with a consistent snapshot of the database at a given point in time, even while the database is running</strong>:</p>
<pre><code class="language-java">// JDBC-based online backup
String backupFile =
    "backup-" + java.time.LocalDateTime.now()
      .format(java.time.format.DateTimeFormatter.ofPattern("yyyyMMdd-HHmmss"))
    + ".zip";
try (Connection con = DriverManager.getConnection(
       "jdbc:h2:./db/mydb", "user", "password");
     PreparedStatement ps =
       con.prepareStatement("BACKUP TO '" + backupFile + "'")) {
  ps.executeUpdate();
}</code></pre>
<p>Because the backup is executed by the database engine, it avoids the consistency risks associated with copying filesystem objects. Further, we can run such commands via both plain JDBC or with frameworks such as Spring Data using native queries, keeping backup logic close to application code.</p>
<h2 id="bd-exporting-data-from-h2" data-id="exporting-data-from-h2">4. Exporting Data From H2</h2>
<div class="bd-anchor" id="exporting-data-from-h2"></div>
<p>Conversely, exports can be a bit more flexible, since they usually don&#8217;t have the rigorous requirements of a backup.</p>
<h3 id="bd-1-csv-exports-with-csvwrite" data-id="1-csv-exports-with-csvwrite">4.1. CSV Exports With <em>CSVWRITE</em></h3>
<div class="bd-anchor" id="1-csv-exports-with-csvwrite"></div>
<p>For data inspection or sharing, the H2 engine supports the <em>CSVWRITE</em> function. It writes the result of an SQL query directly to a CSV file, making it easy to extract data in a widely supported format:</p>
<pre><code class="language-sql">CALL CSVWRITE(
  '&lt;BACKUP_FILE_PATH&gt;',
  'SELECT * FROM &lt;TABLE_NAME&gt;'
);</code></pre>
<p>In this case, since the export is a <em>SELECT</em> statement, it can also include filters, joins, and ordering. <strong>This makes <em>CSVWRITE</em> particularly useful for reporting, debugging, and transferring subsets of data to other tools</strong> such as spreadsheets or analytics systems.</p>
<p>Importantly, this export is fairly simplistic in that it deals mainly with data and doesn&#8217;t really handle metadata in depth.</p>
<h3 id="bd-2-logical-exports-with-script" data-id="2-logical-exports-with-script">4.2. Logical Exports With <em>SCRIPT</em></h3>
<div class="bd-anchor" id="2-logical-exports-with-script"></div>
<p>When both schema and data are needed, the H2 engine command <strong><em>SCRIPT</em> can be used to get a logical export as <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-h2-executing-sql-scripts">SQL statements</a></strong>. Just like with other tools that produce SQL statements, these output scripts can recreate tables and insert data when executed later:</p>
<pre><code class="language-sql">SCRIPT SIMPLE TO '&lt;BACKUP_SQL_SCRIPT_PATH&gt;'
TABLE PUBLIC.&lt;TABLE_NAME&gt;;</code></pre>
<p>Unlike CSV exports, SQL scripts preserve structural information. Because of this, migrations, reproducible test setups, and version-controlled snapshots of database state are often facilitated by this export method. For instance, <strong>SQL scripts produced by <em>SCRIPT</em> can be restored using <em>RUNSCRIPT</em></strong>, providing a simple logical backup-and-restore loop for development or testing environments.</p>
<h2 id="bd-summary" data-id="summary">5. Summary</h2>
<div class="bd-anchor" id="summary"></div>
<p>In this article, we looked at ways to back up or export data from H2 databases.</p>
<p>In summary, online backups rely on the <em>BACKUP TO</em> command to produce consistent, restorable archives without stopping the database. On the other hand, data exports rely on <em>CSVWRITE</em> for portable, query-driven CSV files and <em>SCRIPT</em> for schema-aware SQL output. Together, these tools cover recovery, portability, and inspection needs while avoiding the risks associated with direct file copying.</p>
<p>In conclusion, H2 provides built-in, engine-managed mechanisms for both backups and exports.</p>The post <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-h2-export-backup">Performing Export and Backup of H2 Databases</a> first appeared on <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com">Baeldung</a>.<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/951207752/0/baeldung">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/951207752/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/951207752/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/951207752/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/951207752/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/951207752/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-h2-export-backup#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-h2-export-backup/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/~/951207752/0/baeldung~Performing-Export-and-Backup-of-H-Databases/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-convert-byte-short-array</feedburner:origLink>
		<title>Converting Byte Array to Short Array and Vice-Versa in Java</title>
		<link>https://feeds.feedblitz.com/~/951207755/0/baeldung~Converting-Byte-Array-to-Short-Array-and-ViceVersa-in-Java</link>
					<comments>https://feeds.feedblitz.com/~/951207755/0/baeldung~Converting-Byte-Array-to-Short-Array-and-ViceVersa-in-Java#respond</comments>
		
		<dc:creator><![CDATA[Eugene Kovko]]></dc:creator>
		<pubDate>Thu, 19 Mar 2026 15:49:34 +0000</pubDate>
				<category><![CDATA[Java Array]]></category>
		<category><![CDATA[Java Bytecode]]></category>
		<guid isPermaLink="false">https://www.baeldung.com/java-convert-byte-short-array</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>Explore the conversion between bytes and shorts and also possible issues with byte ordering in Java.</p>
The post <a rel="NOFOLLOW" href="https://feeds.feedblitz.com/~/951207755/0/baeldung~Converting-Byte-Array-to-Short-Array-and-ViceVersa-in-Java">Converting Byte Array to Short Array and Vice-Versa in Java</a> first appeared on <a rel="NOFOLLOW" href="https://www.baeldung.com">Baeldung</a>.<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/951207755/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/951207755/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/951207755/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/951207755/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/951207755/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-convert-byte-short-array#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-convert-byte-short-array/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>While converting one type of number to another is a pretty straightforward operation. <strong>In some cases, we might have problems with the representation of numbers due to differences in <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-integers-little-big-endian">byte orderings</a>.</strong> Thus, we should always consider it during processing and conversion, especially if we receive raw data from outside. In this tutorial, we&#8217;ll learn how to convert <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-primitives#2-byte">bytes</a> to <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-primitives#2-byte">shorts</a> and vice versa. We also discuss the problem and the reason for this difference in representation, and we will see how to address it in code.</p>
<h2 id="bd-byte-order" data-id="byte-order">2. Byte Order</h2>
<div class="bd-anchor" id="byte-order"></div>
<div>A combination of zeros and ones represents all the numbers in a computer. However, there is a difference between the <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/cs/big-endian-vs-little-endian">two types of representation</a>. One of them is called big-endian, the other is called little-endian. In big-endian, we use the most significant bytes on the left, so it&#8217;s written from left to right. At the same time, in little-endian, the least significant bytes are on the left, so the order is inverted:<a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/wp-content/uploads/2026/03/img_69ba08de63e8e.svg"><img decoding="async" class="size-full wp-image-240910 aligncenter" src="https://www.baeldung.com/wp-content/uploads/2026/03/img_69ba08de63e8e.svg" alt="" /></a></div>
<p>&nbsp;</p>
<div><strong>The reason for this difference is that little-endian could be more performant and computer-friendly on some architectures.</strong> At the same time, big-endian is more readable and more human-friendly. <strong>Big-endian is the representation we usually think about when we talk about binary numbers.</strong> Thus, we can have a situation where the information produced by one system wouldn&#8217;t match the byte-ordering of the system it should be used in.</div>
<h2 id="bd-bytes-to-shorts" data-id="bytes-to-shorts">3. Bytes to Shorts</h2>
<div class="bd-anchor" id="bytes-to-shorts"></div>
<div>When we use numbers in the same byte order, it&#8217;s pretty straightforward to convert them. We can use several approaches. <strong>For example, we can address this conversion using loops.</strong> In this case, we have to combine two bytes; we only need to move them slightly using <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-bitwise-operators#bitwise-shift-operators">bitwise shifts</a>:</div>
<div>
<pre><code class="language-java">public static short[] bytesToShortsBigEndianUsingLoop(byte[] bytes) {
    int n = bytes.length / 2;
    short[] shorts = new short[n];
    for (int i = 0; i &lt; n; i++) {
        shorts[i] = (short) (((bytes[2 * i] &amp; 0xFF) &lt;&lt; 8) | (bytes[2 * i + 1] &amp; 0xFF));
    }
    return shorts;
}</code></pre>
</div>
<div>Please note that, in this case, we don&#8217;t handle odd-sized arrays, since it&#8217;s just a demonstration. In production code, we should consider the possibility that the input would contain an odd number of bytes. We can also use the <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-8-streams">Stream API</a> to do this. While it&#8217;s not the most perfect solution, in some cases, it might be more readable and simpler to implement:</div>
<div>
<pre><code class="language-java">public static short[] bytesToShortsBigEndianUsingStream(byte[] bytes) {
    int n = bytes.length / 2;
    short[] shorts = new short[n];
    IntStream.range(0, n).forEach(i -&gt;
        shorts[i] = (short) (((bytes[2 * i] &amp; 0xFF) &lt;&lt; 8) | (bytes[2 * i + 1] &amp; 0xFF)));
    return shorts;
}</code></pre>
</div>
<div>The Stream API solution isn&#8217;t perfect because it uses <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-functional-programming#fundamental_principles_and_concepts">side effects and accesses variables</a> outside the stream pipeline, which isn&#8217;t aligned with <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/cs/functional-programming">functional programming</a>. While it works, it has a few conceptual and stylistic issues.</div>
<div></div>
<div>As we can see, converting bytes into shorts with the same byte order is pretty straightforward. The same is true when we need to change the byte order as well:</div>
<div>
<pre><code class="language-java">public static short[] bytesToShortsLittleEndianUsingLoop(byte[] bytes) {
    int n = bytes.length / 2;
    short[] shorts = new short[n];
    for (int i = 0; i &lt; n; i++) {
        shorts[i] = (short) ((bytes[2 * i] &amp; 0xFF) | ((bytes[2 * i + 1] &amp; 0xFF) &lt;&lt; 8));
    }
    return shorts;
}</code></pre>
</div>
<p>The logic is pretty simple: we have to swap the bytes so that the first one takes the least significant positions and the second the most significant ones.</p>
<h2 id="bd-shorts-to-bytes" data-id="shorts-to-bytes">4. Shorts to Bytes</h2>
<div class="bd-anchor" id="shorts-to-bytes"></div>
<p>The opposite operation is pretty similar. We cannot use <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-upcasting-vs-downcasting#downcasting-in-java">downcasting,</a> as our goal is to use individual bytes. Thus, we have to extract bytes with <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-bitmasking">masks</a> and bit shifts:</p>
<pre><code class="language-java">public static byte[] shortsToBytesBigEndianUsingLoop(short[] shorts) {
    byte[] bytes = new byte[shorts.length * 2];
    for (int i = 0; i &lt; shorts.length; i++) {
        short value = shorts[i];
        bytes[2 * i] = (byte) ((value &gt;&gt;&gt; 8) &amp; 0xFF);
        bytes[2 * i + 1] = (byte) (value &amp; 0xFF);
    }
    return bytes;
}</code></pre>
<p>Little-endian would require mostly the same code, but we should flip the order in which we write the bytes:</p>
<pre><code class="language-java">public static byte[] shortsToBytesLittleEndianUsingLoop(short[] shorts) {
    byte[] bytes = new byte[shorts.length * 2];
    for (int i = 0; i &lt; shorts.length; i++) {
        short value = shorts[i];
        bytes[2 * i] = (byte) (value &amp; 0xFF);
        bytes[2 * i + 1] = (byte) ((value &gt;&gt;&gt; 8) &amp; 0xFF);
    }
    return bytes;
}</code></pre>
<p>It&#8217;s important to remember that the byte order affects only the bytes inside the multi-byte values. We don&#8217;t need to change the order of bytes or the order of values themselves.</p>
<h2 id="bd-bytebuffer" data-id="bytebuffer">5. <em>ByteBuffer</em></h2>
<div class="bd-anchor" id="bytebuffer"></div>
<p>To simplify the process, we will use existing classes to handle the conversion out of the box. <strong>With the <em><a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-bytebuffer">ByteBuffer</a></em> and <em><a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-bytebuffer">ByteOrder</a></em> classes, the conversion:</strong></p>
<pre><code class="language-java">public static short[] bytesToShortsLittleEndian(byte[] bytes) {
    short[] shorts = new short[bytes.length / 2];
    ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(shorts);
    return shorts;
}</code></pre>
<p>Here we wrap the bytes with a buffer and change the interpretation of the bytes (if required), without changing the actual order. <strong>As implied by the method name, we don&#8217;t copy or modify the original array, so any mutation may affect the result and processing.</strong> Reading the shorts also makes things easier, since we can pass an empty array to read the data into. However, we have the same limitation with odd-sized arrays. Thus, even with library methods, we should be careful about the amount of data we work with.</p>
<p>To use big-endian order, we can either provide an explicit value to the order method or omit it and use the default (big-endian). The default configuration isn&#8217;t platform-dependent and defined by the <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/jvm-vs-jre-vs-jdk#jvm">JVM</a>. <strong>However, explicit configuration is always preferable, as it makes the code more readable and helps avoid bugs.</strong> With <em>ByteBuffer</em>, writing shorts into a byte array using little-endian also becomes a pretty trivial task:</p>
<pre><code class="language-java">public static byte[] shortsToBytesLittleEndian(short[] shorts) {
    ByteBuffer buffer = ByteBuffer.allocate(shorts.length * 2).order(ByteOrder.LITTLE_ENDIAN);
    buffer.asShortBuffer().put(shorts);
    return buffer.array();
}</code></pre>
<p>Java provides many convenient classes that can make our code cleaner, and <em>ByteBuffer</em> is a good example. While we won&#8217;t use it daily, it&#8217;s useful to know it exists.</p>
<h2 id="bd-conclusion" data-id="conclusion">6. Conclusion</h2>
<div class="bd-anchor" id="conclusion"></div>
<p>In this article, we discussed the conversion between bytes and shorts and also reviewed possible issues with byte order.<strong> While we might assume that the number representation is the same across platforms, that&#8217;s not the case.</strong> The difference in byte order might introduce some hard-to-debug problems. We always need to consider it while working with data, especially when we work with data from different systems.</p>The post <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-convert-byte-short-array">Converting Byte Array to Short Array and Vice-Versa in Java</a> first appeared on <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com">Baeldung</a>.<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/951207755/0/baeldung">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/951207755/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/951207755/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/951207755/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/951207755/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/951207755/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-convert-byte-short-array#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-convert-byte-short-array/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/~/951207755/0/baeldung~Converting-Byte-Array-to-Short-Array-and-ViceVersa-in-Java/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>
</channel></rss>

