<?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>Thu, 16 Apr 2026 03:30:58 +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-regex-resolving-patternsyntaxexception</feedburner:origLink>
		<title>Resolving PatternSyntaxException: Unclosed character class</title>
		<link>https://feeds.feedblitz.com/~/953868626/0/baeldung~Resolving-PatternSyntaxException-Unclosed-character-class</link>
					<comments>https://feeds.feedblitz.com/~/953868626/0/baeldung~Resolving-PatternSyntaxException-Unclosed-character-class#respond</comments>
		
		<dc:creator><![CDATA[Neetika Khandelwal]]></dc:creator>
		<pubDate>Thu, 16 Apr 2026 03:30:58 +0000</pubDate>
				<category><![CDATA[Java String]]></category>
		<category><![CDATA[Exception]]></category>
		<category><![CDATA[Regex]]></category>
		<guid isPermaLink="false">https://www.baeldung.com/?p=203471</guid>
					<description><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-15-1024x536.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="max-width:100% !important;height:auto !important;float: left; margin-right: 5px;" fetchpriority="high" /><p>Learn about the PatternSyntaxException: Unclosed character class which is a common yet avoidable issue in Java regular expressions</p>
The post <a rel="NOFOLLOW" href="https://feeds.feedblitz.com/~/953868626/0/baeldung~Resolving-PatternSyntaxException-Unclosed-character-class">Resolving PatternSyntaxException: Unclosed character class</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/953868626/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/953868626/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2024%2f07%2fJava-Featured-15-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/953868626/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/953868626/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/953868626/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-regex-resolving-patternsyntaxexception#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-regex-resolving-patternsyntaxexception/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-15-1024x536.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="float: left; margin-right: 5px;" decoding="async" srcset="https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-15-1024x536.jpg 1024w, https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-15-300x157.jpg 300w, https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-15-768x402.jpg 768w, https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-15-100x52.jpg 100w, https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-15.jpg 1200w" sizes="(max-width: 580px) 100vw, 580px" /><h2 id="bd-overview" data-id="overview">1. Overview</h2>
<div class="bd-anchor" id="overview"></div>
<p>When we work with regular expressions in Java, even a small syntax mistake can break our application at runtime. One of the most common errors we encounter is:</p>
<pre><code class="language-java">java.util.regex.PatternSyntaxException: Unclosed character class</code></pre>
<p>In this tutorial, we&#8217;ll explore why this happens, how to reproduce it, and how to fix it. We also cover a real-world issue involving <em>split()</em> that often triggers this exception.</p>
<h2 id="bd-understanding-character-classes" data-id="understanding-character-classes">2. Understanding Character Classes</h2>
<div class="bd-anchor" id="understanding-character-classes"></div>
<p><strong>A character class in <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/regular-expressions-java">regex</a> allows us to match</strong> <strong data-start="704" data-end="742">any one character from a given set</strong>. This is one of the most commonly used regex constructs in Java.
<br>
Let us first look at a simple example of a character class:</p>
<pre><code class="language-java">"[abc]"</code></pre>
<p>In this pattern, the regex engine matches either <em>a</em>, <em>b</em>, or <em>c</em>. <strong>We should always remember that a character class starts with [ and must end with ]. </strong>We can also define ranges when working with larger sets of characters:</p>
<pre><code class="language-java">"[a-z]"</code></pre>
<p>This pattern matches any lowercase English letter from <em>a</em> to <em>z</em>. <strong>If we forget to close the bracket, Java will throw a runtime exception.</strong></p>
<h2 id="bd-reproducing-the-exception" data-id="reproducing-the-exception">3. Reproducing the Exception</h2>
<div class="bd-anchor" id="reproducing-the-exception"></div>
<p>To better understand the problem, let us intentionally write an invalid regex pattern. This helps us see exactly how Java reacts:</p>
<pre><code class="language-java">public class RegexExample {
    public static void main(String[] args) {
        Pattern.compile("[a-z");
    }
}</code></pre>
<p>In the above example, we try to compile a regex that starts a character class but never closes it. When we run this code, Java throws the following exception:</p>
<pre><code class="language-java">java.util.regex.PatternSyntaxException: Unclosed character class near index 4
[a-z
    ^</code></pre>
<p>This clearly indicates that the regex parser expected a closing ] but did not find one.</p>
<h2 id="bd-fixing-the-exception" data-id="fixing-the-exception">4. Fixing the Exception</h2>
<div class="bd-anchor" id="fixing-the-exception"></div>
<p>Now that we understand the problem, fixing it becomes straightforward. We simply need to close the character class properly:</p>
<pre><code class="language-java">Pattern.compile("[a-z]");</code></pre>
<p>After making this change, the pattern compiles successfully without any errors. <strong data-start="2266" data-end="2357">We should always verify that every opening bracket has a corresponding closing bracket.</strong></p>
<h2 id="bd-common-causes-of-this-exception" data-id="common-causes-of-this-exception">5. Common Causes of This Exception</h2>
<div class="bd-anchor" id="common-causes-of-this-exception"></div>
<p>Let&#8217;s have a look at some of the common causes of <em>PatternSyntaxException</em>.</p>
<h3 data-start="2406" data-end="2440" id="bd-1-missing-closing-bracket" data-id="1-missing-closing-bracket">5.1. Missing Closing Bracket</h3>
<div class="bd-anchor" id="1-missing-closing-bracket"></div>
<p>One of the most frequent mistakes is forgetting to close the character class:</p>
<pre><code class="language-java">Pattern.compile("[0-9");</code></pre>
<p>This pattern is incomplete and results in a runtime exception. We can fix it by adding the missing closing bracket:</p>
<pre><code class="language-java">Pattern.compile("[0-9]");</code></pre>
<p><strong>Even a small omission like this can break the entire regex.</strong></p>
<h3 data-start="2791" data-end="2827" id="bd-2-incorrect-nested-patterns" data-id="2-incorrect-nested-patterns">5.2. Incorrect Nested Patterns</h3>
<div class="bd-anchor" id="2-incorrect-nested-patterns"></div>
<p>Sometimes, while writing a complex regex, we accidentally introduce extra brackets:</p>
<pre><code class="language-java">Pattern.compile("[a-zA-Z[0-9]");</code></pre>
<p>In this pattern, we have an extra [ inside the character class.<strong> Character classes do not support nesting using [ like this, so the regex becomes invalid</strong>. As a result, Java throws a <em>PatternSyntaxException</em>.</p>
<p>To fix this, we should remove the unnecessary bracket and define the character set correctly:</p>
<pre><code class="language-java">Pattern.compile("[a-zA-Z0-9]");</code></pre>
<p>Now the pattern is valid and matches any alphanumeric character. <strong data-start="983" data-end="1081">Instead of nesting, we should combine all required characters within a single character class.</strong></p>
<h2 id="bd-issue-with-split" data-id="issue-with-split">6. Issue with <em data-start="3673" data-end="3682">split()</em></h2>
<div class="bd-anchor" id="issue-with-split"></div>
<p>Let us now look at a practical example that often causes confusion in real projects. Before jumping into the issue, we first define a sample 2D array.</p>
<pre><code class="language-java">String[][] array2d = {
    {"a", "b"},
    {"c", "d"}
};</code></pre>
<p>In many cases, we convert this array into a string using <em data-start="656" data-end="679">Arrays.deepToString()</em> for quick inspection or processing:</p>
<pre><code class="language-java">String str = Arrays.deepToString(array2d);
System.out.println(str);</code></pre>
<p>When we run this, the output looks like:</p>
<pre><code class="language-java">[[a, b], [c, d]]</code></pre>
<p><strong data-start="894" data-end="953">Notice that the output contains nested square brackets.</strong> This is important for understanding the issue. Now, let us attempt to split this string into individual rows. At first glance, the following code looks correct:</p>
<pre><code class="language-java">String[][] split = new String[1][rows];
split[0] = str.split("], [");</code></pre>
<p>However, when we run this code, we encounter a runtime exception:</p>
<pre><code class="language-java">java.util.regex.PatternSyntaxException: Unclosed character class</code></pre>
<p>This happens because <em data-start="1397" data-end="1406">split()</em> expects a <strong data-start="1417" data-end="1426">regex</strong>, not a plain string. The pattern: &#8220;], [&#8221; is interpreted incorrectly, since [ and ] are special characters in regex. <strong data-start="1578" data-end="1683">As a result, the regex engine treats [ as the start of a character class, leading to the exception.</strong>
<br>
To resolve this issue, we need to escape the square brackets so they are treated as literal characters:</p>
<pre><code class="language-java">split[0] = str.split("\\], \\[");</code></pre>
<p>With this change, the regex becomes valid, and the code works as expected. <strong data-start="4534" data-end="4609">Proper escaping ensures that special characters do not break our regex. </strong>Although the fix works, we can further improve the solution for cleaner output. The result of <em data-start="4745" data-end="4768">Arrays.deepToString()</em> contains outer brackets that we may want to remove:</p>
<pre><code class="language-java">String str = Arrays.deepToString(array2d);
str = str.substring(1, str.length() - 1);
String[] result = str.split("\\], \\[");</code></pre>
<p>By trimming the outer brackets, we get a cleaner split result. <strong data-start="5027" data-end="5102">This makes the output easier to process and avoids unwanted characters.</strong></p>
<h2 id="bd-conclusion" data-id="conclusion">7. Conclusion</h2>
<div class="bd-anchor" id="conclusion"></div>
<p>In this article, we saw that the <em>PatternSyntaxException: Unclosed character class</em> is a common yet avoidable issue in Java. It usually occurs due to missing brackets or incorrect handling of special characters like [ and ]. By carefully writing regex patterns, properly escaping characters in methods like <em>split()</em>, and validating inputs, we can build more reliable applications. A small attention to detail in regex can prevent major runtime issues.</p>
<p>As always, the code presented in this article is available <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/eugenp/tutorials/tree/master/core-java-modules/core-java-regex-4">over on GitHub</a>.</p>The post <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-regex-resolving-patternsyntaxexception">Resolving PatternSyntaxException: Unclosed character class</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/953868626/0/baeldung">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/953868626/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/953868626/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2024%2f07%2fJava-Featured-15-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/953868626/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/953868626/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/953868626/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-regex-resolving-patternsyntaxexception#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-regex-resolving-patternsyntaxexception/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/~/953868626/0/baeldung~Resolving-PatternSyntaxException-Unclosed-character-class/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<webfeeds:featuredImage>https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-15-150x150.jpg</webfeeds:featuredImage></item>
<item>
<feedburner:origLink>https://www.baeldung.com/spring-boot-scheduled-db-cron-expression</feedburner:origLink>
		<title>Getting a Cron Expression From Database for a Spring Boot Scheduled Job</title>
		<link>https://feeds.feedblitz.com/~/953867825/0/baeldung~Getting-a-Cron-Expression-From-Database-for-a-Spring-Boot-Scheduled-Job</link>
					<comments>https://feeds.feedblitz.com/~/953867825/0/baeldung~Getting-a-Cron-Expression-From-Database-for-a-Spring-Boot-Scheduled-Job#respond</comments>
		
		<dc:creator><![CDATA[Kai Yuan]]></dc:creator>
		<pubDate>Thu, 16 Apr 2026 03:22:02 +0000</pubDate>
				<category><![CDATA[Spring Boot]]></category>
		<category><![CDATA[Spring Scheduling]]></category>
		<guid isPermaLink="false">https://www.baeldung.com/?p=203448</guid>
					<description><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/2024/11/Spring-Boot-Featured-Image-02-1024x536.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="max-width:100% !important;height:auto !important;float: left; margin-right: 5px;" /><p>Explore two ways to get a scheduled job's cron value from a database in Spring Boot.</p>
The post <a rel="NOFOLLOW" href="https://feeds.feedblitz.com/~/953867825/0/baeldung~Getting-a-Cron-Expression-From-Database-for-a-Spring-Boot-Scheduled-Job">Getting a Cron Expression From Database for a Spring Boot Scheduled Job</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/953867825/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/953867825/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2024%2f11%2fSpring-Boot-Featured-Image-02-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/953867825/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/953867825/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/953867825/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-scheduled-db-cron-expression#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-scheduled-db-cron-expression/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-Boot-Featured-Image-02-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-Boot-Featured-Image-02-1024x536.jpg 1024w, https://www.baeldung.com/wp-content/uploads/2024/11/Spring-Boot-Featured-Image-02-300x157.jpg 300w, https://www.baeldung.com/wp-content/uploads/2024/11/Spring-Boot-Featured-Image-02-768x402.jpg 768w, https://www.baeldung.com/wp-content/uploads/2024/11/Spring-Boot-Featured-Image-02-100x52.jpg 100w, https://www.baeldung.com/wp-content/uploads/2024/11/Spring-Boot-Featured-Image-02-600x314.jpg 600w, https://www.baeldung.com/wp-content/uploads/2024/11/Spring-Boot-Featured-Image-02.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>Spring Boot allows us to easily schedule a job, for example, using the <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/spring-scheduled-tasks"><em>@Scheduled</em></a> annotation. Sometimes, we don&#8217;t want to hardcode the scheduling parameters, such as the cron expression. Instead, we would like to schedule a job using a cron expression from a database.</p>
<p>In this tutorial, we&#8217;ll first explore two approaches to achieve it. Further, we&#8217;ll discuss when to use which.</p>
<h2 id="bd-introduction-to-the-problem" data-id="introduction-to-the-problem">2. Introduction to the Problem</h2>
<div class="bd-anchor" id="introduction-to-the-problem"></div>
<p>When we work with Spring scheduling, the most straightforward option is usually to place the cron expression directly in <em>@Scheduled, </em>for example:</p>
<pre><code class="language-java">@Scheduled(cron = "*/5 * * * * ?")
public void run() {
    // job logic
}</code></pre>
<p>This works well, but it also hardcodes the schedule into the application.</p>
<p>The problem appears when we want to fetch the cron expression from a database. This is because we cannot simply write something like this:</p>
<pre><code class="language-java">private String cronExpression = loadFromDatabase();
@Scheduled(cron = cronExpression)
public void run() {
    // invalid approach
}</code></pre>
<p>If we compile this code, the compiler will complain:</p>
<pre><code class="language-bash">java: element value must be a constant expression</code></pre>
<p>The reason is that <strong>the <em>cron</em> attribute in an annotation cannot be populated from an arbitrary runtime variable.</strong> In practice, we either need an indirection that Spring can resolve for us, or we need to move away from annotation-driven scheduling altogether.</p>
<p>In this tutorial, we&#8217;ll explore both approaches. But let&#8217;s do some preparation before we dive into the solutions.</p>
<h2 id="bd-preparing-data-in-a-database" data-id="preparing-data-in-a-database">3. Preparing Data in a Database</h2>
<div class="bd-anchor" id="preparing-data-in-a-database"></div>
<p>For this tutorial, we use a small <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/spring-boot-h2-database">H2</a> in-memory database. Also, for simplicity, we&#8217;ll skip <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/the-persistence-layer-with-spring-data-jpa">Spring Data JPA</a> configurations</p>
<h3 id="bd-1-creating-a-simple-table" data-id="1-creating-a-simple-table">3.1. Creating a Simple Table</h3>
<div class="bd-anchor" id="1-creating-a-simple-table"></div>
<p>We want our Spring Boot application to <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-h2-automatically-create-schemas">automatically create a database table and insert some data into it</a> when it starts. Therefore, let&#8217;s prepare a <em>schema.sql</em> file:</p>
<pre><code class="language-sql">CREATE TABLE IF NOT EXISTS cron_config (
    id BIGINT PRIMARY KEY,
    cron_expression VARCHAR(255) NOT NULL
);</code></pre>
<p>As we can see, the <em>cron_config</em> table is intentionally minimal. <strong>We only need an identifier and the cron expression itself</strong>.</p>
<p>Next, let&#8217;s create a <em>data.sql</em> file to insert a row into the table:</p>
<pre><code class="language-sql">INSERT INTO cron_config (id, cron_expression) VALUES (1, '*/5 * * * * ?');</code></pre>
<p>We insert a single row so the application has a cron value as soon as it starts. So by default, <strong>the schedule runs every five seconds</strong>.</p>
<h3 id="bd-2-preparing-the-entity-and-the-repository-classes" data-id="2-preparing-the-entity-and-the-repository-classes">3.2. Preparing the <em>Entity</em> and the <em>Repository</em> Classes</h3>
<div class="bd-anchor" id="2-preparing-the-entity-and-the-repository-classes"></div>
<p>The corresponding JPA entity is equally small:</p>
<pre><code class="language-java">@Entity
@Table(name = "cron_config")
public class CronEntity {
    @Id
    private Long id;
    private String cronExpression;
    // ... the default constructor, getters and setters are omitted
}</code></pre>
<p>The repository is just as simple and gives us <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/spring-data-3-crud-repository-interfaces">the CRUD operations</a> we need:</p>
<pre><code class="language-java">public interface CronConfigRepository extends JpaRepository&lt;CronEntity, Long&gt; {
}</code></pre>
<p>With these pieces in place, we can read and update cron values from the database.</p>
<p>Now, let&#8217;s see how to tell Spring to schedule jobs using the cron expression we stored in the database.</p>
<h2 id="bd-using-a-cronloader-bean" data-id="using-a-cronloader-bean">4. Using a <em>cronLoader</em> Bean</h2>
<div class="bd-anchor" id="using-a-cronloader-bean"></div>
<p>In our first approach, we would like to keep the <em>@Scheduled </em>annotation, but avoid placing the cron expression directly in the annotation. Instead, <strong>we&#8217;ll create a Spring Bean to read the cron expression from our database and reference the bean in <em>@Scheduled&#8217;s cron</em> attribute.</strong></p>
<h3 id="bd-1-defining-the-cronloader-bean-to-load-the-cron-expression" data-id="1-defining-the-cronloader-bean-to-load-the-cron-expression">4.1. Defining the <em>cronLoader</em> Bean to Load the Cron Expression</h3>
<div class="bd-anchor" id="1-defining-the-cronloader-bean-to-load-the-cron-expression"></div>
<p>We start with a small configuration class that defines a bean named <em>cronLoader</em>:</p>
<pre><code class="language-java">@Configuration
public class CronLoaderConfig {
    @Bean
    String cronLoader(CronConfigRepository repository) {
        return repository.findById(1L)
          .map(CronEntity::getCronExpression)
          .orElseThrow(() -&gt; new RuntimeException("Cron expression not found in DB"));
    }
}</code></pre>
<p>As the code above shows, this bean is pretty straightforward. <strong>It reads the cron expression from the row with <em>id = 1</em> and returns it as a </strong><em><strong>String</strong>.</em></p>
<h3 id="bd-2-referencing-the-bean-from-scheduled" data-id="2-referencing-the-bean-from-scheduled">4.2. Referencing the Bean from <em>@Scheduled</em></h3>
<div class="bd-anchor" id="2-referencing-the-bean-from-scheduled"></div>
<p>Next, <strong>we can reference that bean through <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/spring-expression-language">SpEL</a> in our scheduled job</strong>:</p>
<pre><code class="language-java">@Component
public class AnnotationScheduledJob {
    private static final Logger log = LoggerFactory.getLogger(AnnotationScheduledJob.class);
    @Scheduled(cron = "#{@cronLoader}")
    public void run() {
        log.info("&#x2705; [{}] Job executed - cron loaded from DB via @Scheduled", now());
    }
}</code></pre>
<p>This is the key idea: <strong>we still use <em>@Scheduled,</em> but the cron expression comes from the <em>cronLoader</em> bean instead of being embedded directly in the annotation.</strong></p>
<p>Also, our job does nothing but print a line with the execution time, so we can verify whether the executions match our cron expression in the database.</p>
<p>Next, let&#8217;s verify if the job scheduling works as we expected.</p>
<h3 id="bd-3-starting-the-application-and-observing-the-console-outputs" data-id="3-starting-the-application-and-observing-the-console-outputs">4.3. Starting the Application and Observing the Console Outputs</h3>
<div class="bd-anchor" id="3-starting-the-application-and-observing-the-console-outputs"></div>
<p>If we start our Spring Boot application, we can see these lines in the console log:</p>
<pre><code class="language-bash">...
... AnnotationScheduledJob : &#x2705; [10:00:05.002] Job executed - cron loaded from DB via @Scheduled
... AnnotationScheduledJob : &#x2705; [10:00:10.001] Job executed - cron loaded from DB via @Scheduled
... AnnotationScheduledJob : &#x2705; [10:00:15.000] Job executed - cron loaded from DB via @Scheduled
... AnnotationScheduledJob : &#x2705; [10:00:20.001] Job executed - cron loaded from DB via @Scheduled
...</code></pre>
<p>Because our <em>data.sql</em> inserts &#8220;<em>*/5 * * * * ?&#8221; </em>as the cron expression, we see the annotation-based job log roughly every five seconds. This gives us a straightforward way to verify that the cron value is being loaded from the database.</p>
<h3 id="bd-4-limitation-of-the-cronloader-bean-approach" data-id="4-limitation-of-the-cronloader-bean-approach">4.4. Limitation of the <em>cronLoader</em> Bean Approach</h3>
<div class="bd-anchor" id="4-limitation-of-the-cronloader-bean-approach"></div>
<p>This approach is convenient, but it comes with an important limitation.</p>
<p>Spring loads the cron value when it creates the <em>cronLoader</em> bean during application startup. After that, the scheduled method continues using the resolved value.</p>
<p><strong>If we update the <em>cron_config</em> table later, the schedule won&#8217;t automatically change for the running application.</strong> In practice, we would typically need to restart the application to pick up the new value.</p>
<p>So, <strong>this approach is a good fit only when loading the schedule once at startup is acceptable.</strong></p>
<h2 id="bd-using-springs-schedulingconfigurer" data-id="using-springs-schedulingconfigurer">5. Using Spring&#8217;s <em>SchedulingConfigurer</em></h2>
<div class="bd-anchor" id="using-springs-schedulingconfigurer"></div>
<p>If we want our scheduled jobs to react to database changes without restarting, we need a more dynamic solution. Next, let&#8217;s dive in.</p>
<h3 id="bd-1-implementing-schedulingconfigurer" data-id="1-implementing-schedulingconfigurer">5.1. Implementing <em>SchedulingConfigurer</em></h3>
<div class="bd-anchor" id="1-implementing-schedulingconfigurer"></div>
<p>Instead of relying on the <em>@Scheduled</em> annotation, <strong>we can implement Spring&#8217;s <em>SchedulingConfigurer</em> and register our own trigger task</strong>.</p>
<p>First, let&#8217;s create a <em>DynamicScheduledConfig</em> configuration class implementing <em>SchedulingConfigurer</em>:</p>
<pre><code class="language-java">@Configuration
public class DynamicScheduledConfig implements SchedulingConfigurer {
    private static final Logger log = LoggerFactory.getLogger(DynamicScheduledConfig.class);
    private final CronConfigRepository repository;
    public DynamicScheduledConfig(CronConfigRepository repository) {
        this.repository = repository;
    }
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.addTriggerTask(() -&gt; log.info(
          "&#x2705; [{}] DynamicScheduledConfig executed - cron re-read from DB per execution",
          now()), triggerContext -&gt; {
            String cronExpression = repository.findById(1L)
              .map(CronEntity::getCronExpression)
              .orElseThrow(() -&gt; new RuntimeException("Cron expression not found in DB"));
            return new CronTrigger(cronExpression).nextExecution(triggerContext);
        });
    }
}</code></pre>
<p>Next, let&#8217;s understand how the <em>configureTasks()</em> method works:</p>
<p>First, we register a task with the <em>addTriggerTask(&#8230;)</em> method. The <em>addTriggerTask()</em> method has two parameters: <strong>a <em>Runnable</em> (the &#8220;What&#8221;) that contains the work we want to execute in this task and a <em>Trigger</em> object (the &#8220;When&#8221;) that specifies when the task should be triggered</strong>.</p>
<p>In our example, our task simply prints a log with the current time.</p>
<p>The <em>Trigger</em> parameter is the &#8220;magic&#8221; part of the implementation. <strong>It calculates the next execution time every time the task finishes:</strong></p>
<ul>
<li>Fetching the cron expression from our database using the injected <em>repository</em></li>
<li>Creating a new <em>CronTrigger</em> object from the cron expression on the fly, and Spring asks that trigger for the next execution time</li>
</ul>
<p>This means that if we change the cron expression in our database, the trigger callback will pick up the new value immediately when it calculates the next execution time. This is the main difference from the <em>cronLoader</em> bean approach: <strong>the cron expression is re-read from the database whenever Spring calculates the next execution time.</strong></p>
<h3 id="bd-2-a-simple-rest-controller-to-update-the-cron-expression-in-our-database" data-id="2-a-simple-rest-controller-to-update-the-cron-expression-in-our-database">5.2. A Simple REST Controller to Update the Cron Expression in Our Database</h3>
<div class="bd-anchor" id="2-a-simple-rest-controller-to-update-the-cron-expression-in-our-database"></div>
<p>For easier testing, let&#8217;s create a simple REST controller that allows us to quickly update the database record by HTTP request:</p>
<pre><code class="language-java">@RestController
public class CronController {
    private static final Logger log = LoggerFactory.getLogger(CronController.class);
    private final CronConfigRepository repository;
    public CronController(CronConfigRepository repository) {
        this.repository = repository;
    }
    @GetMapping("/cron")
    public String updateCron() {
        CronEntity cronEntity = repository.findById(1L)
          .orElseThrow(() -&gt; new RuntimeException("Cron expression not found in database"));
        cronEntity.setCronExpression("*/10 * * * * ?");
        repository.save(cronEntity);
        String msg = "[DB] &#x23f0; Updated cron expression in DB to: */10 * * * * ?";
        log.info(msg);
        return msg;
    }
}</code></pre>
<p>As the example shows, for simplicity, <strong>this endpoint always sets the cron to run every 10 seconds</strong>.</p>
<p>Next, let&#8217;s verify if the <em>SchedulingConfigurer</em> approach can always reschedule the job according to the database change.</p>
<h3 id="bd-3-starting-the-application-and-observing-the-console-outputs-1" data-id="3-starting-the-application-and-observing-the-console-outputs-1">5.3. Starting the Application and Observing the Console Outputs</h3>
<div class="bd-anchor" id="3-starting-the-application-and-observing-the-console-outputs-1"></div>
<p>To make the logs easier to read during the demonstration, we can temporarily comment out the annotation-based scheduling line in <em>AnnotationScheduledJob</em> so that only the dynamic task is running:</p>
<pre><code class="language-java">@Component
public class AnnotationScheduledJob {
    // ...
    // @Scheduled(cron = "#{@cronLoader}")  &lt;-- comment out
    public void run() {
        // ...
    }
}</code></pre>
<p>Next, let&#8217;s launch our Spring Boot application. Once it starts, the scheduled job will also begin. Log outputs similar to these will appear in the console:</p>
<pre><code class="language-bash">... DynamicScheduledConfig : &#x2705; [10:05:05.001] DynamicScheduledConfig executed - cron re-read from DB per execution
... DynamicScheduledConfig : &#x2705; [10:05:10.001] DynamicScheduledConfig executed - cron re-read from DB per execution
... DynamicScheduledConfig : &#x2705; [10:05:15.001] DynamicScheduledConfig executed - cron re-read from DB per execution
... DynamicScheduledConfig : &#x2705; [10:05:20.000] DynamicScheduledConfig executed - cron re-read from DB per execution</code></pre>
<p>Because the <em>data.sql</em> file still seeds <em>&#8220;*/5 * * * * ?&#8221;</em>, the dynamic task initially runs about every five seconds.</p>
<p>Next, let&#8217;s call the <em>&#8220;/cron&#8221;</em> endpoint to update the cron expression. For example, we can launch this <em>curl</em> command to send a GET request:</p>
<pre><code class="language-bash">curl http://localhost:8080/cron</code></pre>
<p>Then, in the Spring Boot application console, we can see this log, meaning the cron expression has been changed to &#8220;every 10 seconds&#8221;:</p>
<pre><code class="language-bash">... CronController : [DB] &#x23f0; Updated cron expression in DB to: */10 * * * * ?</code></pre>
<p>After that, the dynamic task should start following the new interval. In other words, instead of firing every five seconds, subsequent executions should move to a ten-second rhythm:</p>
<pre><code class="language-bash">... DynamicScheduledConfig : &#x2705; [10:05:30.000] DynamicScheduledConfig executed - cron re-read from DB per execution
... DynamicScheduledConfig : &#x2705; [10:05:40.002] DynamicScheduledConfig executed - cron re-read from DB per execution
... DynamicScheduledConfig : &#x2705; [10:05:50.000] DynamicScheduledConfig executed - cron re-read from DB per execution
... DynamicScheduledConfig : &#x2705; [10:05:60.000] DynamicScheduledConfig executed - cron re-read from DB per execution</code></pre>
<p>This demonstrates the main benefit of <em>SchedulingConfigurer:</em> <strong>we can change the cron expression in the database and let the running application adapt without a restart.</strong></p>
<h2 id="bd-conclusion" data-id="conclusion">6. Conclusion</h2>
<div class="bd-anchor" id="conclusion"></div>
<p>In this article, we explored two ways to get a scheduled job&#8217;s cron value from a database in Spring Boot.</p>
<p>With the <em>cronLoader</em> bean approach, we keep the implementation simple and continue using <em>@Scheduled,</em> but <strong>we only load the cron value once during startup.</strong></p>
<p>With <em>SchedulingConfigurer,</em> we take control of task registration and re-read the cron expression from the database whenever Spring calculates the next execution time. <strong>This makes the schedule dynamic and allows runtime updates.</strong></p>
<p>So if we only need a startup-time value, a bean-backed <em>@Scheduled</em> setup is often enough. But if we want truly dynamic scheduling, <em>SchedulingConfigurer</em> is the better choice.</p>
<p>As always, the complete source code for the examples is available <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/eugenp/tutorials/tree/master/spring-scheduling-2">over on GitHub</a>.</p>The post <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/spring-boot-scheduled-db-cron-expression">Getting a Cron Expression From Database for a Spring Boot Scheduled Job</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/953867825/0/baeldung">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/953867825/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/953867825/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2024%2f11%2fSpring-Boot-Featured-Image-02-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/953867825/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/953867825/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/953867825/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-scheduled-db-cron-expression#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-scheduled-db-cron-expression/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/~/953867825/0/baeldung~Getting-a-Cron-Expression-From-Database-for-a-Spring-Boot-Scheduled-Job/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<webfeeds:featuredImage>https://www.baeldung.com/wp-content/uploads/2024/11/Spring-Boot-Featured-Image-02-150x150.jpg</webfeeds:featuredImage></item>
<item>
<feedburner:origLink>https://www.baeldung.com/java-fast-gaussian-blur</feedburner:origLink>
		<title>Fast Gaussian Blur Implementation in Java</title>
		<link>https://feeds.feedblitz.com/~/953643002/0/baeldung~Fast-Gaussian-Blur-Implementation-in-Java</link>
					<comments>https://feeds.feedblitz.com/~/953643002/0/baeldung~Fast-Gaussian-Blur-Implementation-in-Java#respond</comments>
		
		<dc:creator><![CDATA[Nikhil Bhargav]]></dc:creator>
		<pubDate>Sat, 11 Apr 2026 05:45:20 +0000</pubDate>
				<category><![CDATA[Algorithms]]></category>
		<category><![CDATA[Math]]></category>
		<guid isPermaLink="false">https://www.baeldung.com/?p=203451</guid>
					<description><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/2024/11/Algorithms-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>Explore a faster, more computationally efficient solution for implementing Gaussian blur in Java.</p>
The post <a rel="NOFOLLOW" href="https://feeds.feedblitz.com/~/953643002/0/baeldung~Fast-Gaussian-Blur-Implementation-in-Java">Fast Gaussian Blur Implementation 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/953643002/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/953643002/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2024%2f11%2fAlgorithms-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/953643002/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/953643002/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/953643002/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-fast-gaussian-blur#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-fast-gaussian-blur/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/Algorithms-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/Algorithms-Featured-Image-03-1024x536.jpg 1024w, https://www.baeldung.com/wp-content/uploads/2024/11/Algorithms-Featured-Image-03-300x157.jpg 300w, https://www.baeldung.com/wp-content/uploads/2024/11/Algorithms-Featured-Image-03-768x402.jpg 768w, https://www.baeldung.com/wp-content/uploads/2024/11/Algorithms-Featured-Image-03-100x52.jpg 100w, https://www.baeldung.com/wp-content/uploads/2024/11/Algorithms-Featured-Image-03-600x314.jpg 600w, https://www.baeldung.com/wp-content/uploads/2024/11/Algorithms-Featured-Image-03.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>Gaussian blur is a widely used image processing technique for reducing image noise and detail. However, achieving accurate Gaussian blur can be computationally expensive, especially for high-resolution images with large blur radii.</p>
<p>In this tutorial, we&#8217;ll explore a faster, more computationally efficient solution for implementing Gaussian blur in Java.</p>
<h2 id="bd-problem-overview" data-id="problem-overview">2. Problem Overview</h2>
<div class="bd-anchor" id="problem-overview"></div>
<p data-path-to-node="7">We implement a <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/cs/cv-blur-images#gaussian-blur">standard Gaussian blur</a> on a grayscale image by <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/cs/convolution-matrix-multiplication">convolving</a> it with a 2D Gaussian kernel. Here, for each pixel in an image, the algorithm first examines a surrounding grid of pixels (the kernel). Then, it multiplies each pixel&#8217;s intensity by a specific weight. Finally, it sums them up.</p>
<p data-path-to-node="7">For an image with <em><span class="math-inline" data-math="n" data-index-in-node="16">n</span></em> pixels and a blur radius of <em><span class="math-inline" data-math="r" data-index-in-node="48">r</span></em>, our kernel size is <em><span class="math-inline" data-math="(2r + 1) \times (2r + 1)" data-index-in-node="70">(2r + 1)  x  (2r + 1)</span></em>. Thus, the standard 2D convolution algorithm has a <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-collections-complexity">time complexity</a> of <em>O(n.r<sup>2</sup>)</em>. <strong>As the blur radius <em>r</em> grows, the performance degrades quadratically. Thus, it is not optimal for real-time processing over large images.</strong></p>
<h2 id="bd-the-fast-approximation-algorithm" data-id="the-fast-approximation-algorithm">3. The Fast Approximation Algorithm</h2>
<div class="bd-anchor" id="the-fast-approximation-algorithm"></div>
<p>Our fast approximations make two key enhancements to the standard Gaussian 2D blur method.</p>
<h3 id="bd-1-separable-filters" data-id="1-separable-filters">3.1. Separable Filters</h3>
<div class="bd-anchor" id="1-separable-filters"></div>
<p data-path-to-node="12">A 2D Gaussian kernel can be seen and used as two 1D Gaussian vectors. In other words, we can separate them as horizontal and vertical vectors. So, instead of applying a 2D matrix to every pixel of the image, we can achieve the same result by applying a horizontal 1D blur across all rows, followed by a vertical 1D blur down all columns.</p>
<p data-path-to-node="13"><strong>This simple separation reduces our average-case time complexity from <em>O(n.r<sup>2</sup>) </em>to <em>O(n.r)</em>.</strong></p>
<h3 id="bd-2-repeated-box-blurs" data-id="2-repeated-box-blurs">3.2. Repeated Box Blurs</h3>
<div class="bd-anchor" id="2-repeated-box-blurs"></div>
<p data-path-to-node="15">We repeat a specific blur operation (box blur) to achieve the desired effect.</p>
<p data-path-to-node="15">We define box blur as the simplest form of blurring, assigning equal weight to every pixel within the blur radius. Then, we make use of the <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/cs/central-limit-theorem">Central Limit Theorem</a> to approximate a valid and matching <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/cs/gaussian-mixture-models">Gaussian distribution</a>. <strong>According to the Central Limit Theorem, applying a simple Box Blur multiple times closely approximates an accurate Gaussian distribution</strong>. We run five consecutive passes of a box blur to get a visually indistinguishable result from a strict Gaussian blur with a fraction of the computational overhead.</p>
<p data-path-to-node="16">Furthermore, we make all weights in a Box Blur equal, so we don&#8217;t need to re-sum the entire radius for every pixel. This gives us the freedom to use a sliding window or a moving average. <strong>As the window shifts to the right by one pixel, we subtract the leaving pixel and add the entering pixel. This drops our average time complexity to <em>O(n)</em>, making the performance entirely independent of the blur radius <em>r!</em></strong></p>
<h2 id="bd-solution" data-id="solution">4. Solution</h2>
<div class="bd-anchor" id="solution"></div>
<p>Let&#8217;s move to the solution.</p>
<h3 id="bd-1-the-sliding-window-box-blur" data-id="1-the-sliding-window-box-blur">4.1. The Sliding Window Box Blur</h3>
<div class="bd-anchor" id="1-the-sliding-window-box-blur"></div>
<p>First, we define a function, <em>horizontalBoxBlur()</em>, that performs a 1D horizontal blur using the sliding-window technique.</p>
<p>Here, we process the image row by row. <strong>We don&#8217;t recalculate the pixel sum at every position. Instead, we initialize <em>windowSum</em> for the very first pixel in a row. As it moves left to right, it subtracts the value of the pixel beyond the trailing edge of the radius and adds the value of the pixel at the leading edge.</strong></p>
<p>Lastly, we clamp edges to ensure that if the radius extends beyond the image boundaries, our logic duplicates the edge pixels rather than throwing an <em>ArrayIndexOutOfBoundsException</em>.</p>
<pre><code class="language-java">private static void horizontalBoxBlur(int[] source, int[] target, int width, int height, int radius) {
    double scale = 1.0 / (radius * 2 + 1);
    for (int y = 0; y &lt; height; y++) {
        int windowSum = 0;
        int offset = y * width;        
        for (int x = -radius; x &lt;= radius; x++) {
            int safeX = Math.min(Math.max(x, 0), width - 1);
            windowSum += source[offset + safeX];
        }        
        for (int x = 0; x &lt; width; x++) {
            target[offset + x] = (int) Math.round(windowSum * scale);
            int leftX = Math.max(x - radius, 0);
            int rightX = Math.min(x + radius + 1, width - 1);
            windowSum -= source[offset + leftX];
            windowSum += source[offset + rightX];
        }
    }
}</code></pre>
<p><span class="hljs-comment">The <em>verticalBoxBlur()</em> is identical in logic, but here we traverse columns rather than rows (top to bottom)</span>:</p>
<pre><code class="language-java">private static void verticalBoxBlur(int[] source, int[] target, int width, int height, int radius) {
    double scale = 1.0 / (radius * 2 + 1);
    for (int x = 0; x &lt; width; x++) {
        int windowSum = 0;
        for (int y = -radius; y &lt;= radius; y++) {
            int safeY = Math.min(Math.max(y, 0), height - 1);
            windowSum += source[safeY * width + x];
        }
        for (int y = 0; y &lt; height; y++) {
            target[y * width + x] = (int) Math.round(windowSum * scale);
            int topY = Math.max(y - radius, 0);
            int bottomY = Math.min(y + radius + 1, height - 1);
            windowSum -= source[topY * width + x];
            windowSum += source[bottomY * width + x];
        }
    }
}</code></pre>
<h3 id="bd-2-integration" data-id="2-integration">4.2.  Integration</h3>
<div class="bd-anchor" id="2-integration"></div>
<p>This is our orchestrator.</p>
<p>Leveraging the Central Limit Theorem, we apply a horizontal and vertical box blur three times (configurable). This smooths out peaky regions, thus creating a near-perfect approximation of a true Gaussian bell curve. It uses a temp array (<em>temp</em>) to safely ping-pong the data between passes without corrupting the source:</p>
<pre><code class="language-java">public static int[] applyFastGaussianBlur(int[] source, int numPasses, int width, int height, int radius) {
    int[] target = new int[source.length];
    int[] temp = new int[source.length];
    System.arraycopy(source, 0, target, 0, source.length);
    for (int i = 0; i &lt; numPasses; i++) {
        horizontalBoxBlur(target, temp, width, height, radius);
        verticalBoxBlur(temp, target, width, height, radius);
    }
    return target;
}</code></pre>
<h2 id="bd-test-1" data-id="test-1">5. Test</h2>
<div class="bd-anchor" id="test-1"></div>
<h3 id="bd-1-test-using-impulse-image" data-id="1-test-using-impulse-image">5.1. Test Using Impulse Image</h3>
<div class="bd-anchor" id="1-test-using-impulse-image"></div>
<p>First, let&#8217;s test this method using an impulse image (artificial images with a single black pixel). Our main objective is to verify if  our algorithm handles edges correctly and applies a smoothing effect:</p>
<pre><code class="language-java">void givenSharpImage_whenAppliedBlur_thenCenterIsSmoothed() {
    int width = 5;
    int height = 5;
    int numPasses = 5;
    int[] image = new int[width * height];
    image[12] = 255; 
    int[] blurredImage = FastGaussianBlur.applyFastGaussianBlur(image, numPasses, width, height, 1);
    assertTrue(blurredImage[12] &lt; 255);
    assertTrue(blurredImage[12] &gt; 0);
    assertTrue(blurredImage[11] &gt; 0); // Left neighbor
    assertTrue(blurredImage[13] &gt; 0); // Right neighbor
}</code></pre>
<p>We begin by creating a 5&#215;5 image (25 pixels) and set all pixels to 0, making them pure black. Then we set the exact center pixel (index 12) to 255, making it pure white. This sharp point is our impulse or peak. Then we apply the fast blur algorithm with a radius of 1.</p>
<p>Our main claim is that blur, when applied correctly, spreads the brightness of the central pixel outwards into the surrounding black pixels. Further, <em>assertTrue(blurredImage[12] &lt; 255)</em> confirms the center pixel has dimmed because it shared its brightness, and <em>assertTrue(blurredImage[11] &gt; 0)</em> and <em>assertTrue(blurredImage[13] &gt; 0)</em> confirm that the immediate left and right neighbors (both black) have absorbed that dispersed brightness.</p>
<h3 id="bd-2-test-using-real-image" data-id="2-test-using-real-image">5.2. Test Using Real Image</h3>
<div class="bd-anchor" id="2-test-using-real-image"></div>
<p>We take an open-source image and blur it using our algorithm. Here is the sample image:</p>
<img decoding="async" class="aligncenter size-full wp-image-242392" src="https://www.baeldung.com/wp-content/uploads/2026/04/sample.jpg" alt="Kodim17 Original Face" />
<p>Please check the blurred version:</p>
<img decoding="async" class="aligncenter size-full wp-image-242393" src="https://www.baeldung.com/wp-content/uploads/2026/04/sample_blurred.png" alt="Blurred Kodim17 Face" />
<p>We used a single channel of integer values for our impulse image (grayscale) test case. For this case, we use real images. Each real image is packed with 32-bit ARGB (Alpha, Red, Green, Blue) data. So, here we extract the ARGB channels, then blur each of the RGB channels independently, and finally pack them back together:</p>
<pre><code class="language-java">public static BufferedImage blurRealImage(@Nonnull BufferedImage image, int radius, int numPasses) {
    int width = image.getWidth();
    int height = image.getHeight();
    int[] pixels = image.getRGB(0, 0, width, height, null, 0, width);
    int[] a = new int[pixels.length];
    int[] r = new int[pixels.length];
    int[] g = new int[pixels.length];
    int[] b = new int[pixels.length];
    for (int i = 0; i &lt; pixels.length; i++) {
        a[i] = (pixels[i] &gt;&gt; 24) &amp; 0xff;
        r[i] = (pixels[i] &gt;&gt; 16) &amp; 0xff;
        g[i] = (pixels[i] &gt;&gt; 8) &amp; 0xff;
        b[i] = pixels[i] &amp; 0xff;
    }
    r = FastGaussianBlur.applyFastGaussianBlur(r, width, height, radius, numPasses);
    g = FastGaussianBlur.applyFastGaussianBlur(g, width, height, radius, numPasses);
    b = FastGaussianBlur.applyFastGaussianBlur(b, width, height, radius, numPasses);
    int[] resultPixels = new int[pixels.length];
    for (int i = 0; i &lt; pixels.length; i++) {
        resultPixels[i] = (a[i] &lt;&lt; 24) | (r[i] &lt;&lt; 16) | (g[i] &lt;&lt; 8) | b[i];
    }
    BufferedImage result = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
    result.setRGB(0, 0, width, height, resultPixels, 0, width);
    return result;
}</code></pre>
<h2 id="bd-conclusion" data-id="conclusion">6. Conclusion</h2>
<div class="bd-anchor" id="conclusion"></div>
<p>In this article, we learned a faster Gaussian blur method in Java. We made two key enhancements to the standard Gaussian blur implementation to achieve linear time complexity. First, we decomposed a 2D convolution matrix into separable 1D arrays, and second, we used a moving-average sliding window across three box-blur passes. Thus, our solution works in a constant processing time that is independent of the blur radius.</p>
<p>As always, the complete code examples are available <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/eugenp/tutorials/tree/master/algorithms-modules/algorithms-numeric">over on GitHub</a>.</p>The post <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-fast-gaussian-blur">Fast Gaussian Blur Implementation 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/953643002/0/baeldung">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/953643002/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/953643002/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2024%2f11%2fAlgorithms-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/953643002/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/953643002/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/953643002/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-fast-gaussian-blur#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-fast-gaussian-blur/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/~/953643002/0/baeldung~Fast-Gaussian-Blur-Implementation-in-Java/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<webfeeds:featuredImage>https://www.baeldung.com/wp-content/uploads/2024/11/Algorithms-Featured-Image-03-150x150.jpg</webfeeds:featuredImage></item>
<item>
<feedburner:origLink>https://www.baeldung.com/java-weekly-641</feedburner:origLink>
		<title>Java Weekly, Issue 641</title>
		<link>https://feeds.feedblitz.com/~/953606012/0/baeldung~Java-Weekly-Issue</link>
					<comments>https://feeds.feedblitz.com/~/953606012/0/baeldung~Java-Weekly-Issue#respond</comments>
		
		<dc:creator><![CDATA[baeldung]]></dc:creator>
		<pubDate>Fri, 10 Apr 2026 09:51:00 +0000</pubDate>
				<category><![CDATA[Weekly Review]]></category>
		<category><![CDATA[no-ads]]></category>
		<category><![CDATA[no-after-post]]></category>
		<category><![CDATA[no-before-post]]></category>
		<category><![CDATA[no-optins]]></category>
		<guid isPermaLink="false">https://www.baeldung.com/?p=203436</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>Doing things that don't scale has real value. Oh and S3 is now a filesystem :)</p>
The post <a rel="NOFOLLOW" href="https://feeds.feedblitz.com/~/953606012/0/baeldung~Java-Weekly-Issue">Java Weekly, Issue 641</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/953606012/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/953606012/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/953606012/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/953606012/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/953606012/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-641#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-641/feed"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/commentsrss20.png"></a>&#160;</div>]]>
</description>
										<content:encoded><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/2016/10/social-Weekly-Reviews-4.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="float: left; margin-right: 5px;" decoding="async" loading="lazy" srcset="https://www.baeldung.com/wp-content/uploads/2016/10/social-Weekly-Reviews-4.jpg 952w, https://www.baeldung.com/wp-content/uploads/2016/10/social-Weekly-Reviews-4-300x157.jpg 300w, https://www.baeldung.com/wp-content/uploads/2016/10/social-Weekly-Reviews-4-768x402.jpg 768w" sizes="auto, (max-width: 580px) 100vw, 580px" /><h2 style="text-align: left;" id="bd-spring-and-java" data-id="spring-and-java">1.<strong> Spring and Java</strong></h2>
<div class="bd-anchor" id="spring-and-java"></div>
<p><strong><a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.infoq.com/articles/beyond-rag-context-aware/">&gt;&gt; Beyond RAG: Architecting Context-Aware AI Systems with Spring Boot</a></strong> [<span style="color: #993300;">infoq.com</span>]</p>
<p>A solid look at Context-Augmented Generation (CAG) — an architectural layer on top of RAG that adds user identity, session state, and business constraints before the retrieval step. With Boot of course.</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/java-native-memory-access-modes/" target="_blank" rel="noopener"><strong>Thread-Safe Native Memory in Java: VarHandle Access Modes Explained</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/from-zero-to-full-observability-with-dash0/" target="_blank" rel="noopener"><strong>From Zero to Full Observability with Dash0</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-java-really-use-too-much-memory-lets-look-at-the-facts-jeps/" target="_blank" rel="noopener"><strong>Does Java Really Use Too Much Memory? Let&#8217;s Look at the Facts (JEPs)</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://spring.io/blog/2026/04/07/spring-ai-agentic-patterns-6-memory-tools" target="_blank" rel="noopener"><strong>Spring AI Agentic Patterns (Part 6): AutoMemoryTools — Persistent Agent Memory Across Sessions</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://developers.googleblog.com/announcing-adk-for-java-100-building-the-future-of-ai-agents-in-java/" target="_blank" rel="noopener"><strong>Announcing ADK for Java 1.0.0: Building the Future of AI Agents in Java</strong></a> [<span style="color: #800000;">googleblog.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://blog.pollack.ai/p/8a0a3a73-144a-4615-a992-560da556f13c/" target="_blank" rel="noopener"><strong>ACP Java SDK: Building IDE Agents in Java</strong></a> [<span style="color: #800000;">blog.pollack.ai</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/04/02/a-bootiful-podcast-ana-maria-mihalceanu" target="_blank" rel="noopener"><strong>A Bootiful Podcast: Java developer advocate Ana-Maria Mihalceanu</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/04/08/javaone-post-quantum-cryptography/" target="_blank" rel="noopener"><strong>Java and Post-Quantum Cryptography</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://inside.java/2026/04/04/podcast-053/" target="_blank" rel="noopener"><strong>Episode 53 “Analyzing Crashed JVMs”</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://spring.io/blog/2026/04/02/spring-cloud-2025-0-2-aka-northfields-has-been-released" target="_blank" rel="noopener"><strong>Spring Cloud 2025.0.2 (aka Northfields) Has Been Released</strong></a> [<span style="color: #800000;">spring.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://in.relation.to/2026/04/07/orm-73/" target="_blank" rel="noopener"><strong>Hibernate 7.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://www.infoq.com/news/2026/04/helidon-4-4-released/" target="_blank" rel="noopener"><strong>Helidon 4.4.0 Introduces Alignment with OpenJDK Cadence and Support via Java Verified Portfolio</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://github.com/quarkusio/quarkus/releases/tag/3.34.3" target="_blank" rel="noopener"><strong>Quarkus 3.34.3</strong></a> [<span style="color: #800000;">github.com/quarkusio</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/elastic/elasticsearch/releases/tag/v9.3.3" target="_blank" rel="noopener"><strong>Elasticsearch 9.3.3</strong></a>, <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/elastic/elasticsearch/releases/tag/v9.2.8" target="_blank" rel="noopener"><strong>9.2.8</strong></a>, and <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/elastic/elasticsearch/releases/tag/v8.19.14" target="_blank" rel="noopener"><strong>8.19.14</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/beehive-lab/TornadoVM/releases/tag/v4.0.0-jdk25" target="_blank" rel="noopener"><strong>TornadoVM 4.0.0</strong></a> [<span style="color: #800000;">github.com/beehive-lab</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.8" target="_blank" rel="noopener"><strong>Netflix Zuul 3.5.8</strong></a> [<span style="color: #800000;">github.com/Netflix</span>]</li>
</ul>
<h2 style="text-align: left;" id="bd-technical-amp-musings" data-id="technical-amp-musings">2.<strong> Technical &amp; Musings</strong></h2>
<div class="bd-anchor" id="technical-amp-musings"></div>
<p><strong><a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.allthingsdistributed.com/2026/04/s3-files-and-the-changing-face-of-s3.html">&gt;&gt; S3 Files and the changing face of S3</a></strong> [<span style="color: #993300;">allthingsdistributed.com</span>]</p>
<p>AWS&#8217;s new S3 Files feature mounts S3 buckets as network filesystems via EFS, letting you use standard file operations on object storage without copying data around. Bout time <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://martinfowler.com/articles/reduce-friction-ai/feedback-flywheel.html" target="_blank" rel="noopener"><strong>Feedback Flywheel</strong></a> [<span style="color: #800000;">martinfowler.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://martinfowler.com/articles/harness-engineering.html" target="_blank" rel="noopener"><strong>Harness engineering for coding agent users</strong></a> [<span style="color: #800000;">martinfowler.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://blog.frankel.ch/experimenting-ai-subagents/" target="_blank" rel="noopener"><strong>Experimenting with AI subagents</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/4/4/absurd-in-production/" target="_blank" rel="noopener"><strong>Absurd In Production</strong></a> [<span style="color: #800000;">lucumr.pocoo.org</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://netflixtechblog.com/powering-multimodal-intelligence-for-video-search-3e0020cf1202" target="_blank" rel="noopener"><strong>Synchronizing the Senses: Powering Multimodal Intelligence for Video Search</strong></a> [<span style="color: #800000;">netflixtechblog.com</span>]</li>
</ul>
<h2 style="text-align: left;" id="bd-pick-of-the-week" data-id="pick-of-the-week">3.<strong> Pick of the Week</strong></h2>
<div class="bd-anchor" id="pick-of-the-week"></div>
<p><strong><a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.paulgraham.com/ds.html">&gt;&gt; Do Things that Don&#8217;t Scale</a></strong> [<span style="color: #993300;">paulgraham.com</span>]</p>The post <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-weekly-641">Java Weekly, Issue 641</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/953606012/0/baeldung">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/953606012/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/953606012/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/953606012/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/953606012/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/953606012/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-641#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-641/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/~/953606012/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-resttemplate-no-suitable-httpmessageconverter</feedburner:origLink>
		<title>Handle &#8220;No Suitable HttpMessageConverter&#8221; in Spring RestTemplate</title>
		<link>https://feeds.feedblitz.com/~/953488283/0/baeldung~Handle-No-Suitable-HttpMessageConverter-in-Spring-RestTemplate</link>
					<comments>https://feeds.feedblitz.com/~/953488283/0/baeldung~Handle-No-Suitable-HttpMessageConverter-in-Spring-RestTemplate#respond</comments>
		
		<dc:creator><![CDATA[Sudarshan Hiray]]></dc:creator>
		<pubDate>Tue, 07 Apr 2026 23:02:40 +0000</pubDate>
				<category><![CDATA[Spring Web]]></category>
		<category><![CDATA[RestTemplate]]></category>
		<guid isPermaLink="false">https://www.baeldung.com/?p=203399</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 how to prevent one of the most common RestClientExceptions when using RestTeamplate.</p>
The post <a rel="NOFOLLOW" href="https://feeds.feedblitz.com/~/953488283/0/baeldung~Handle-No-Suitable-HttpMessageConverter-in-Spring-RestTemplate">Handle “No Suitable HttpMessageConverter” in Spring RestTemplate</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/953488283/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/953488283/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/953488283/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/953488283/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/953488283/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-resttemplate-no-suitable-httpmessageconverter#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-resttemplate-no-suitable-httpmessageconverter/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 data-path-to-node="1" id="bd-introduction" data-id="introduction"><b data-path-to-node="1" data-index-in-node="0">1. Introduction</b></h2>
<div class="bd-anchor" id="introduction"></div>
<p data-path-to-node="2">When consuming RESTful services in Spring, <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/rest-template"><i data-path-to-node="2" data-index-in-node="43">RestTemplate</i></a> is a reliable workhorse for synchronous <em>HTTP</em> communication. However, one of the most common and frustrating hurdles developers face is the <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/spring-boot-restclient#:~:text=By%20default%2C%20when%20RestClient%20encounters%20a%204xx%20or%205xx%20status%20code%20in%20the%20HTTP%20response%2C%20it%20raises%20an%20exception%20that%E2%80%99s%20a%20subclass%20of%20RestClientException."><em>RestClientException</em></a>. Specifically, the following error message:</p>
<pre><code class="language-java">Could not extract response: no suitable HttpMessageConverter found for response type and content type...</code></pre>
<p data-path-to-node="3"><strong>This error typically occurs when the client receives a response that it doesn&#8217;t know how to deserialize into the desired Java object.</strong> In this article, we’ll explore why this happens and how to configure our application to handle non-standard API responses effectively without encountering any such errors.</p>
<h2 data-path-to-node="5" id="bd-project-setup" data-id="project-setup"><b data-path-to-node="5" data-index-in-node="0">2. Project Setup</b></h2>
<div class="bd-anchor" id="project-setup"></div>
<p data-path-to-node="6">To get started, we&#8217;ll need the standard <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web">Spring Boot Starter Web</a> dependency:</p>
<div class="code-block ng-tns-c2827611141-91 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahcKEwiIvrb72dOTAxUAAAAAHQAAAAAQaw">
<div class="formatted-code-block-internal-container ng-tns-c2827611141-91">
<div class="animated-opacity ng-tns-c2827611141-91">
<pre><code class="language-java">&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;4.0.5&lt;/version&gt;
&lt;/dependency&gt;</code></pre>
</div>
</div>
</div>
<p data-path-to-node="8">For <em>JSON</em> processing, Spring Boot includes <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/jackson"><em>Jackson</em></a> by default. To better understand it, we&#8217;ll ensure <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind">jackson-databind</a> is on our classpath, as it provides the underlying logic for the <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/converter/json/MappingJackson2HttpMessageConverter.html"><em>MappingJackson2HttpMessageConverter</em></a>.</p>
<h2 data-path-to-node="10" id="bd-understanding-and-identifying-the-root-cause" data-id="understanding-and-identifying-the-root-cause"><b data-path-to-node="10" data-index-in-node="0">3. Understanding and Identifying the Root Cause</b></h2>
<div class="bd-anchor" id="understanding-and-identifying-the-root-cause"></div>
<p data-path-to-node="4">To fix this error, we’ll first understand how Spring maps the raw HTTP response to Java objects. The issue is rarely with the data itself, but rather a mismatch in the expected communication protocol. We&#8217;ll now examine the internal conversion mechanism, identify common misleading media types, and learn how to inspect the actual response headers.</p>
<h3 data-path-to-node="11" id="bd-1-how-resttemplate-converts-responses" data-id="1-how-resttemplate-converts-responses"><b data-path-to-node="11" data-index-in-node="0">3.1. How RestTemplate Converts Responses</b></h3>
<div class="bd-anchor" id="1-how-resttemplate-converts-responses"></div>
<p data-path-to-node="12"><i data-path-to-node="12" data-index-in-node="0">RestTemplate</i> relies on a list of <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/spring-httpmessageconverter-rest"><em>HttpMessageConverter</em> beans</a> to transform HTTP request and response bodies. <strong>When a response arrives, Spring looks at the <em>Content-Type</em> header sent by the server. It then iterates through its registered converters to find one that supports both that <em>MediaType</em> and the target Java class.</strong></p>
<h3 data-path-to-node="13" id="bd-2-common-mismatched-media-types" data-id="2-common-mismatched-media-types"><b data-path-to-node="13" data-index-in-node="0">3.2. Common Mismatched Media Types</b></h3>
<div class="bd-anchor" id="2-common-mismatched-media-types"></div>
<p data-path-to-node="14">The issue usually isn&#8217;t that the data is invalid, but that the metadata is misleading. Many legacy or third-party APIs return valid JSON, but set the <span style="margin: 0px;padding: 0px"><em>Content-Type </em>header</span> to something other than <em>application/json</em>. Common mismatched types include <em>text/plain</em>, <em>text/javascript,</em> and <em>application/octet-stream.</em></p>
<p data-path-to-node="16"><strong>The default <span style="margin: 0px;padding: 0px"><em>MappingJackson2HttpMessageConverter </em>only</span> claims to support <em>application/</em><span style="margin: 0px;padding: 0px"><em>json </em>and</span> <em>application/*+json.</em></strong> It ignores any other type of responses, leading to the &#8220;Could not extract response: no suitable HttpMessageConverter found for response type and content type&#8221; error.</p>
<h3 data-path-to-node="17" id="bd-3-checking-api-response-headers" data-id="3-checking-api-response-headers"><b data-path-to-node="17" data-index-in-node="0">3.3. Checking API Response Headers</b></h3>
<div class="bd-anchor" id="3-checking-api-response-headers"></div>
<p data-path-to-node="18">To diagnose this, we must inspect the headers. <strong>If we can&#8217;t access external logs, we can enable debug logging for Spring Web in our <em>application.properties</em></strong>:</p>
<div class="code-block ng-tns-c2827611141-92 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahcKEwiIvrb72dOTAxUAAAAAHQAAAAAQbA">
<div class="formatted-code-block-internal-container ng-tns-c2827611141-92">
<div class="animated-opacity ng-tns-c2827611141-92">
<pre><code class="language-java">logging.level.org.springframework.web.client.RestTemplate=DEBUG</code></pre>
</div>
</div>
</div>
<p data-path-to-node="20">This will reveal the exact <span style="margin: 0px;padding: 0px"><em>Content-Type</em></span> the server is providing, allowing us to target the specific mismatch.</p>
<h2 data-path-to-node="22" id="bd-solving-the-error-configuration-strategies" data-id="solving-the-error-configuration-strategies"><b data-path-to-node="22" data-index-in-node="0">4. Solving the Error: Configuration Strategies</b></h2>
<div class="bd-anchor" id="solving-the-error-configuration-strategies"></div>
<p>In this section, we&#8217;ll create a config class named <em>RestTemplateConverterConfig </em>to inject the <em>RestTemplate </em>bean, which will help us resolve this error. The following section mentions the details on it:</p>
<h3 data-path-to-node="23" id="bd-1-adding-support-for-custom-media-types" data-id="1-adding-support-for-custom-media-types"><b data-path-to-node="23" data-index-in-node="0">4.1. Adding Support for Custom Media Types</b></h3>
<div class="bd-anchor" id="1-adding-support-for-custom-media-types"></div>
<p data-path-to-node="24"><strong>The most surgical fix is to tell the Jackson converter to treat these uncommon media types as JSON</strong>. We can create an instance of <span style="margin: 0px;padding: 0px"><em>MappingJackson2HttpMessageConverter </em></span>and update its supported media types:</p>
<div class="code-block ng-tns-c2827611141-93 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahcKEwiIvrb72dOTAxUAAAAAHQAAAAAQbQ">
<div class="formatted-code-block-internal-container ng-tns-c2827611141-93">
<div class="animated-opacity ng-tns-c2827611141-93">
<pre><code class="language-java">@Configuration
public class RestTemplateConverterConfig {
    @Bean("specificMediaTypesRestTemplate")
    public RestTemplate specificMediaTypesRestTemplate() {
        RestTemplate restTemplate = new RestTemplate();
        List&lt;HttpMessageConverter&lt;?&gt;&gt; converters = restTemplate.getMessageConverters();
        MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter();
        jsonConverter.setSupportedMediaTypes(Arrays.asList(
          MediaType.APPLICATION_JSON,
          MediaType.TEXT_PLAIN,
          MediaType.valueOf("text/javascript")
        ));
        converters.add(jsonConverter);
        restTemplate.setMessageConverters(converters);
        return restTemplate;
    }
}</code></pre>
</div>
</div>
</div>
<p>Here we explicitly list only the media types we expect to encounter. This keeps the converter&#8217;s scope narrow and intentional. Other unexpected content types, such as <em>application/octet-stream, </em>would still fail, which is often the desired behavior in a controlled environment.</p>
<h3 data-path-to-node="26" id="bd-2-manually-registering-converters-in-resttemplate" data-id="2-manually-registering-converters-in-resttemplate"><b data-path-to-node="26" data-index-in-node="0">4.2. Manually Registering Converters in <em>RestTemplate</em></b></h3>
<div class="bd-anchor" id="2-manually-registering-converters-in-resttemplate"></div>
<p data-path-to-node="27">If we want a more permissive setup, within the same <em>RestTemplateConverterConfig</em> class, we&#8217;ll register another Jackson converter with <em>MediaType.ALL. </em>This instructs the <em>RestTemplate</em> to handle any content type the server returns:</p>
<div class="code-block ng-tns-c2827611141-94 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahcKEwiIvrb72dOTAxUAAAAAHQAAAAAQbg">
<div class="formatted-code-block-internal-container ng-tns-c2827611141-94">
<div class="animated-opacity ng-tns-c2827611141-94">
<pre><code class="language-java">@Bean
public RestTemplate restTemplate() {
    RestTemplate restTemplate = new RestTemplate();
    List&lt;HttpMessageConverter&lt;?&gt;&gt; converters = restTemplate.getMessageConverters();
    MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter();
    jsonConverter.setSupportedMediaTypes(Collections.singletonList(MediaType.ALL));
    converters.add(jsonConverter);
    restTemplate.setMessageConverters(converters);
    return restTemplate;
}</code></pre>
</div>
</div>
</div>
<p data-path-to-node="29">Here, we call the <em>getMessageConverters() </em>method and append to the existing list rather than replacing it. This preserves all the default converters Spring registers, such as those for <em>String </em>and <em>byte[]</em>, and simply adds our custom Jackson converter at the end.</p>
<h3 data-path-to-node="29" id="bd-3-using-resttemplateexchange-with-parameterizedtypereference" data-id="3-using-resttemplateexchange-with-parameterizedtypereference"><b data-path-to-node="29" data-index-in-node="0">4.3. Using <em>RestTemplate.exchange()</em> With <em>ParameterizedTypeReference</em></b></h3>
<div class="bd-anchor" id="3-using-resttemplateexchange-with-parameterizedtypereference"></div>
<p data-path-to-node="30">Sometimes the error arises because we are trying to deserialize into a generic collection, like <em>List&lt;User&gt;</em>. <strong>In this example, the <em>User</em> class is a simple POJO with <em>id</em> and <em>name</em> fields that <em>Jackson</em> maps from the <em>JSON</em> response.</strong></p>
<p data-path-to-node="30">Using <em>getForObject() </em>with <em>List.class </em>loses generic type information at runtime due to type erasure. Instead, we should use the <em>restTemplate.exchange() </em>method with a <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/spring-parameterized-type-reference"><em>ParameterizedTypeReference</em></a>:</p>
<pre><code class="language-java">ResponseEntity&lt;List&lt;User&gt;&gt; response = restTemplate.exchange(
  "/users",
  HttpMethod.GET,
  null,
  new ParameterizedTypeReference&lt;List&lt;User&gt;&gt;() {}
);</code></pre>
<p data-path-to-node="33">The anonymous subclass of <em>ParameterizedTypeReference</em> captures the full generic type <em>List&lt;User&gt;</em> at compile time, giving Jackson enough information to correctly deserialize each element in the array into a <em>User</em> object.</p>
<h2 data-path-to-node="0" id="bd-testing-and-verification" data-id="testing-and-verification"><b data-path-to-node="0" data-index-in-node="0">5. Testing and Verification</b></h2>
<div class="bd-anchor" id="testing-and-verification"></div>
<p data-path-to-node="1">To verify our configurations, we’ll use <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/spring-mock-rest-template#:~:text=MockRestServiceServer%20actually%20works%20by%20intercepting%20the%20HTTP%20API%20calls%20using%20a%20MockClientHttpRequestFactory.%20Based%20on%20our%20configuration%2C%20it%20creates%20a%20list%20of%20expected%20requests%20and%20corresponding%20responses."><em>MockRestServiceServer</em></a>. This allows us to simulate the exact mismatched header scenarios that typically trigger the <em>RestClientException </em>without needing a live external API.</p>
<h3 data-path-to-node="2" id="bd-1-testing-the-surgical-fix" data-id="1-testing-the-surgical-fix"><b data-path-to-node="2" data-index-in-node="0">5.1. Testing the Surgical Fix</b></h3>
<div class="bd-anchor" id="1-testing-the-surgical-fix"></div>
<p data-path-to-node="3">In this first scenario, we use the <em>@Qualifier</em> to inject our <em>specificMediaTypesRestTemplate</em>. We&#8217;ll simulate a response that is explicitly labeled as <em>text/plain</em>. <strong>This proves that our surgical inclusion of that specific media type works as intended</strong>:</p>
<div class="code-block ng-tns-c2827611141-138 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahgKEwiIvrb72dOTAxUAAAAAHQAAAAAQzAE">
<div class="formatted-code-block-internal-container ng-tns-c2827611141-138">
<div class="animated-opacity ng-tns-c2827611141-138">
<pre><code class="language-java">@Autowired
@Qualifier("specificMediaTypesRestTemplate")
private RestTemplate specificMediaTypesRestTemplate;
@Test
void givenSpecificMediaTypesRestTemplate_whenTextPlainResponse_thenDeserializeCorrectly() {
    MockRestServiceServer mockServer = MockRestServiceServer.createServer(specificMediaTypesRestTemplate);
    mockServer.expect(requestTo("/user"))
      .andRespond(withSuccess("{\"id\":1,\"name\":\"Sudarshan\"}", MediaType.TEXT_PLAIN));
    User user = specificMediaTypesRestTemplate.getForObject("/user", User.class);
    assertNotNull(user);
    assertEquals("Sudarshan", user.getName());
}</code></pre>
</div>
</div>
</div>
<h3 data-path-to-node="5" id="bd-2-testing-the-permissive-fix" data-id="2-testing-the-permissive-fix"><b data-path-to-node="5" data-index-in-node="0">5.2. Testing the Permissive Fix</b></h3>
<div class="bd-anchor" id="2-testing-the-permissive-fix"></div>
<p data-path-to-node="6">Next, <strong>we test the primary <em>RestTemplate</em> bean configured with <em>MediaType.ALL</em></strong>. This test confirms that<span style="margin: 0px;padding: 0px">, by making the converter permissive, it ignores the misleading <em>text/plain</em> header and defaults to <em>Jackson</em> for </span>deserialization.</p>
<div class="code-block ng-tns-c2827611141-139 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahgKEwiIvrb72dOTAxUAAAAAHQAAAAAQzQE">
<div class="formatted-code-block-internal-container ng-tns-c2827611141-139">
<div class="animated-opacity ng-tns-c2827611141-139">
<pre><code class="language-java">@Test
void givenMockServer_whenTextPlainResponse_thenDeserializeCorrectly() {
    MockRestServiceServer mockServer = MockRestServiceServer.createServer(restTemplate);
    mockServer.expect(requestTo("/user"))
      .andRespond(withSuccess("{\"id\":1,\"name\":\"Sudarshan\"}", MediaType.TEXT_PLAIN));
    User user = restTemplate.getForObject("/user", User.class);
    assertNotNull(user);
    assertEquals("Sudarshan", user.getName());
}</code></pre>
</div>
</div>
</div>
<h3 data-path-to-node="8" id="bd-3-verifying-generic-type-resolution" data-id="3-verifying-generic-type-resolution"><b data-path-to-node="8" data-index-in-node="0">5.3. Verifying Generic Type Resolution</b></h3>
<div class="bd-anchor" id="3-verifying-generic-type-resolution"></div>
<p data-path-to-node="9">Finally, <strong>we verify that our <em>restTemplate.exchange()</em> strategy correctly handles collections</strong>. Even with a mismatched <em>text/plain</em> header, the <em>ParameterizedTypeReference </em>ensures that the generic information <em>List&lt;User&gt;</em> is preserved during the conversion process:</p>
<div class="code-block ng-tns-c2827611141-140 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahgKEwiIvrb72dOTAxUAAAAAHQAAAAAQzgE">
<div class="formatted-code-block-internal-container ng-tns-c2827611141-140">
<div class="animated-opacity ng-tns-c2827611141-140">
<pre><code class="language-java">@Test
void givenMockServer_whenTextPlainResponseForList_thenDeserializeWithParameterizedTypeReference() {
    MockRestServiceServer mockServer = MockRestServiceServer.createServer(restTemplate);
    mockServer.expect(requestTo("/users"))
      .andRespond(
        withSuccess(
          "[{\"id\":1,\"name\":\"Sudarshan\"},{\"id\":2,\"name\":\"Baeldung\"}]",
          MediaType.TEXT_PLAIN));
    ResponseEntity&lt;List&lt;User&gt;&gt; response = restTemplate.exchange(
      "/users",
      HttpMethod.GET,
      null,
      new ParameterizedTypeReference&lt;List&lt;User&gt;&gt;() {}
    );
    assertNotNull(response.getBody());
    assertEquals(2, response.getBody().size());
    assertEquals("Sudarshan", response.getBody().get(0).getName());
}</code></pre>
</div>
</div>
</div>
<h2 data-path-to-node="41" id="bd-conclusion" data-id="conclusion"><b data-path-to-node="41" data-index-in-node="0">6. Conclusion</b></h2>
<div class="bd-anchor" id="conclusion"></div>
<p data-path-to-node="42">In this tutorial, we understood that the &#8220;<em>No Suitable HttpMessageConverter</em>&#8221; error is rarely a sign of broken data; it’s a communication breakdown between the server&#8217;s headers and the client&#8217;s expectations. <strong>By identifying the returned <span style="margin: 0px;padding: 0px"><em>Content-Type</em></span> and explicitly configuring our <span style="margin: 0px;padding: 0px"><em>MappingJackson2HttpMessageConverter </em></span>to support it, we can bridge this gap.</strong></p>
<p data-path-to-node="43">Whether you choose to support all media types via <em>MediaType.ALL</em> or strictly list the exceptions, like <em>text/plain</em>, understanding the converter registration process is key to building resilient Spring clients.</p>
<p data-path-to-node="43">As always, the complete code samples used in this article are available <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/eugenp/tutorials/tree/master/spring-web-modules/spring-resttemplate-3">over on GitHub</a>.</p>The post <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/spring-resttemplate-no-suitable-httpmessageconverter">Handle “No Suitable HttpMessageConverter” in Spring RestTemplate</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/953488283/0/baeldung">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/953488283/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/953488283/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/953488283/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/953488283/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/953488283/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-resttemplate-no-suitable-httpmessageconverter#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-resttemplate-no-suitable-httpmessageconverter/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/~/953488283/0/baeldung~Handle-No-Suitable-HttpMessageConverter-in-Spring-RestTemplate/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-flip-bits-number</feedburner:origLink>
		<title>Flip the Bits of a Number in Java</title>
		<link>https://feeds.feedblitz.com/~/953487332/0/baeldung~Flip-the-Bits-of-a-Number-in-Java</link>
					<comments>https://feeds.feedblitz.com/~/953487332/0/baeldung~Flip-the-Bits-of-a-Number-in-Java#respond</comments>
		
		<dc:creator><![CDATA[Zachary Bouhannana]]></dc:creator>
		<pubDate>Tue, 07 Apr 2026 22:58:58 +0000</pubDate>
				<category><![CDATA[Java Numbers]]></category>
		<category><![CDATA[Java Integer]]></category>
		<category><![CDATA[Java Operators]]></category>
		<category><![CDATA[Math]]></category>
		<guid isPermaLink="false">https://www.baeldung.com/java-flip-bits-number</guid>
					<description><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/2021/09/Java-8-Featured-1024x536.png" class="webfeedsFeaturedVisual wp-post-image" alt="Contact Us Featured" style="max-width:100% !important;height:auto !important;float: left; margin-right: 5px;" loading="lazy" /><p>Learn standard and alternative ways to invert the value of all bits or only the significant bits of a number in Java.</p>
The post <a rel="NOFOLLOW" href="https://feeds.feedblitz.com/~/953487332/0/baeldung~Flip-the-Bits-of-a-Number-in-Java">Flip the Bits of a Number 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/953487332/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/953487332/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2021%2f09%2fJava-8-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/953487332/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/953487332/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/953487332/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-flip-bits-number#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-flip-bits-number/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-8-Featured-1024x536.png" class="webfeedsFeaturedVisual wp-post-image" alt="Contact Us Featured" style="float: left; margin-right: 5px;" decoding="async" loading="lazy" srcset="https://www.baeldung.com/wp-content/uploads/2021/09/Java-8-Featured-1024x536.png 1024w, https://www.baeldung.com/wp-content/uploads/2021/09/Java-8-Featured-300x157.png 300w, https://www.baeldung.com/wp-content/uploads/2021/09/Java-8-Featured-768x402.png 768w, https://www.baeldung.com/wp-content/uploads/2021/09/Java-8-Featured-100x52.png 100w, https://www.baeldung.com/wp-content/uploads/2021/09/Java-8-Featured.png 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>Bit manipulation is a fundamental concept in programming that involves working with individual bits of binary data. One common operation is flipping all bits in an integer, converting every <em>0</em> to <em>1</em> and every <em>1</em> to <em>0</em>.</p>
<p>In this tutorial, we&#8217;ll explain what bit flipping means and explore several Java methods to flip the bits of an integer. For completeness, we&#8217;ll cover both full 32-bit flipping and flipping only the significant bits.</p>
<h2 id="bd-understanding-bit-flipping" data-id="understanding-bit-flipping">2. Understanding Bit Flipping</h2>
<div class="bd-anchor" id="understanding-bit-flipping"></div>
<p>Before we learn how to flip bits in an integer, it&#8217;s best to look at a visual example.</p>
<p>To begin with, let&#8217;s consider the decimal number <em>21</em> and, more specifically, its binary representation:</p>
<pre><code class="language-java">10101</code></pre>
<p>The goal is to invert each bit so that every <em>0</em> becomes a <em>1</em> and every <em>1</em> becomes a <em>0</em>:</p>
<pre><code class="language-java">01010</code></pre>
<p>This corresponds to the decimal value <em>10</em> (<em>8+2</em>).</p>
<p>During this transformation, each bit at position <em>i</em> in the original number gets inverted in the result. However, there&#8217;s an important distinction to make. <strong>When we flip all 32 bits of an integer, i.e., its full size, the result differs from flipping only the significant bits</strong>. For instance, flipping all 32 bits of the integer <em>21</em> produces <em>-22</em> due to <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-compute-twos-complement">two&#8217;s complement</a> representation, whereas flipping only the significant bits (<em>10101</em> -&gt; <em>01010</em>) yields <em>10</em>.</p>
<p>In the following sections, let&#8217;s explore both scenarios in detail.</p>
<h2 id="bd-using-the-bitwise-not-operator" data-id="using-the-bitwise-not-operator">3. Using the Bitwise NOT Operator</h2>
<div class="bd-anchor" id="using-the-bitwise-not-operator"></div>
<p>The most direct approach to flip bits is the bitwise NOT operator <em>~</em>. This <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-operators#unary-operators">unary operator</a> inverts every bit in the integer&#8217;s binary representation:</p>
<pre><code class="language-java">public static int flipAllBits(int n) {
    return ~n;
}</code></pre>
<p>The operator flips all 32 bits of the integer. <strong>This means that <em>~</em> inverts every bit, including leading zeros, turning a positive number into a negative one due to the two&#8217;s complement representation in Java</strong>.</p>
<p>Let&#8217;s verify the results using a <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/junit-5">JUnit 5</a> test and <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/introduction-to-assertj">AssertJ</a> matchers:</p>
<pre><code class="language-java">@Test
void givenPositiveInteger_whenFlipAllBits_thenReturnsNegativeComplement() {
    assertThat(flipAllBits(21)).isEqualTo(-22);
    assertThat(flipAllBits(0)).isEqualTo(-1);
    assertThat(flipAllBits(-1)).isEqualTo(0);
}</code></pre>
<p>As we can see, flipping all 32 bits of <em>21</em> gives us <em>-22</em>, not <em>10</em>. This is because Java&#8217;s <em>int</em> type is a signed 32-bit integer.</p>
<p>To get a result like <em>10</em> from <em>21</em>, we need to flip only the significant bits. Let&#8217;s cover this case next.</p>
<h2 id="bd-flipping-only-the-significant-bits" data-id="flipping-only-the-significant-bits">4. Flipping Only the Significant Bits</h2>
<div class="bd-anchor" id="flipping-only-the-significant-bits"></div>
<p>In many practical scenarios, we want to flip only the bits that are actually used in the binary representation of the number, excluding leading zeros. For instance, flipping the significant bits of <em>21</em> (<em>10101</em>) should give us <em>10</em> (<em>01010</em>).</p>
<h3 id="bd-1-using-a-mask-with-bit-length-calculation" data-id="1-using-a-mask-with-bit-length-calculation">4.1. Using a Mask With Bit Length Calculation</h3>
<div class="bd-anchor" id="1-using-a-mask-with-bit-length-calculation"></div>
<p>The idea is straightforward: we create a mask with a <em>1</em> at each significant bit position, then <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-xor-operator">XOR</a> the number with this mask. The XOR operation flips only the bits where the mask has a <em>1</em>:</p>
<pre><code class="language-java">public static int flipSignificantBits(int n) {
    if (n == 0) {
        return 0;
    }
    int bitLength = Integer.SIZE - Integer.numberOfLeadingZeros(n);
    int mask = (1 &lt;&lt; bitLength) - 1;
    return n ^ mask;
}</code></pre>
<p>First, we handle the edge case where <em>n</em> is <em>0</em>. Then, we calculate the number of significant bits using <em>Integer.numberOfLeadingZeros()</em>. With this value, we create a <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-bitmasking">mask</a> by shifting <em>1</em> left by <em>bitLength</em> positions and subtracting <em>1</em>, which gives us a sequence of 1s matching the significant bit length.</p>
<p><strong>Finally, the XOR operation (<em>^</em>) flips only the significant bits, since XOR with <em>1</em> inverts a bit while XOR with <em>0</em> leaves it unchanged</strong>.</p>
<p>Let&#8217;s verify this with a test:</p>
<pre><code class="language-java">@Test
void givenPositiveInteger_whenFlipSignificantBits_thenReturnsFlippedValue() {
    assertThat(flipSignificantBits(21)).isEqualTo(10);
    assertThat(flipSignificantBits(26)).isEqualTo(5);
    assertThat(flipSignificantBits(0)).isEqualTo(0);
    assertThat(flipSignificantBits(1)).isEqualTo(0);
    assertThat(flipSignificantBits(7)).isEqualTo(0);
}</code></pre>
<p>To illustrate, let&#8217;s trace through the example with <em>26</em> (binary <em>11010</em>):</p>
<pre><code class="language-java">n     = 11010  (26)
mask  = 11111  (31)
n ^ mask = 00101  (5)</code></pre>
<p>This approach effectively and efficiently flips only the significant bits.</p>
<h3 id="bd-2-using-integerhighestonebit" data-id="2-using-integerhighestonebit">4.2. Using <em>Integer.highestOneBit()</em></h3>
<div class="bd-anchor" id="2-using-integerhighestonebit"></div>
<p>We can also use the built-in <em>Integer.highestOneBit()</em> method to build the mask. This method returns a value with only the highest bit of the input set:</p>
<pre><code class="language-java">public static int flipSignificantBitsUsingHighestOneBit(int n) {
    if (n == 0) {
        return 0;
    }
    int mask = (Integer.highestOneBit(n) &lt;&lt; 1) - 1;
    return n ^ mask;
}</code></pre>
<p>Here, <em>Integer.highestOneBit(n)</em> returns the value of the most significant bit. <strong>By shifting it left by one position and subtracting <em>1</em>, we create a mask with a <em>1</em> at each significant bit</strong>. Then, a XOR operation with this mask again flips only those bits.</p>
<h3 id="bd-3-using-the-bitwise-not-with-a-mask" data-id="3-using-the-bitwise-not-with-a-mask">4.3. Using the Bitwise NOT With a Mask</h3>
<div class="bd-anchor" id="3-using-the-bitwise-not-with-a-mask"></div>
<p>Instead of XOR, we can also combine the bitwise NOT operator with a mask to get the same result:</p>
<pre><code class="language-java">public static int flipSignificantBitsUsingNot(int n) {
    if (n == 0) {
        return 0;
    }
    int bitLength = Integer.SIZE - Integer.numberOfLeadingZeros(n);
    int mask = (1 &lt;&lt; bitLength) - 1;
    return ~n &amp; mask;
}</code></pre>
<p>This function first computes the bitwise NOT of <em>n</em>, which flips all 32 bits. Then, the AND operation with the mask zeroes out all the bits beyond the significant ones. Simply put, <strong>the result is equivalent to flipping only the significant bits</strong>.</p>
<h2 id="bd-alternative-methods" data-id="alternative-methods">5. Alternative Methods</h2>
<div class="bd-anchor" id="alternative-methods"></div>
<p>Apart from the standard bitwise operators, there are other, more unorthodox ways to flip all 32 bits of an integer.</p>
<h3 id="bd-1-using-arithmetic-negation" data-id="1-using-arithmetic-negation">5.1. Using Arithmetic Negation</h3>
<div class="bd-anchor" id="1-using-arithmetic-negation"></div>
<p>Due to the two&#8217;s complement representation, flipping all bits of <em>n</em> is equivalent to computing <em>-n &#8211; 1</em>:</p>
<pre><code class="language-java">public static int flipBitsArithmetic(int n) {
    return -n - 1;
}</code></pre>
<p>This works because, in two&#8217;s complement, the negation of <em>n</em> is the bitwise complement plus <em>1</em> (<em>-n = ~n + 1</em>). <strong>Therefore, <em>~n = -n &#8211; 1</em>, which gives the same result as the bitwise NOT operator</strong>.</p>
<h3 id="bd-2-using-xor-with--1" data-id="2-using-xor-with--1">5.2. Using XOR With <em>-1</em></h3>
<div class="bd-anchor" id="2-using-xor-with--1"></div>
<p>Another way to flip all bits is to XOR the number with <em>-1</em>. In binary, we represent <em>-1</em> as all 1s (<em>11111111&#8230;1</em> in 32 bits). Notably, <em>~0</em> also evaluates to <em>-1</em>, so we can use either interchangeably:</p>
<pre><code class="language-java">public static int flipBitsXorMinusOne(int n) {
    return n ^ -1;
}</code></pre>
<p>Since XOR with <em>1</em> flips a bit, performing XOR with a value where all bits are <em>1</em> effectively flips every bit in the integer. <strong>This produces the same result as the ~ operator</strong>.</p>
<h2 id="bd-conclusion" data-id="conclusion">6. Conclusion</h2>
<div class="bd-anchor" id="conclusion"></div>
<p>In this article, we explored several approaches for flipping bits of an integer in Java. We started with the bitwise NOT operator for full 32-bit flipping. Next, we looked at mask-based methods for flipping only the significant bits using XOR and AND operations. Finally, we covered alternative approaches using arithmetic negation and XOR.</p>
<p>As always, all the source code is available <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/eugenp/tutorials/tree/master/core-java-modules/core-java-lang-math-5">over on GitHub</a>.</p>The post <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-flip-bits-number">Flip the Bits of a Number 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/953487332/0/baeldung">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/953487332/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/953487332/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2021%2f09%2fJava-8-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/953487332/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/953487332/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/953487332/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-flip-bits-number#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-flip-bits-number/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/~/953487332/0/baeldung~Flip-the-Bits-of-a-Number-in-Java/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<webfeeds:featuredImage>https://www.baeldung.com/wp-content/uploads/2021/09/Java-8-Featured-150x150.png</webfeeds:featuredImage></item>
<item>
<feedburner:origLink>https://www.baeldung.com/spring-security-7-mfa</feedburner:origLink>
		<title>Multi-Factor Authentication in Spring Security 7</title>
		<link>https://feeds.feedblitz.com/~/953487335/0/baeldung~MultiFactor-Authentication-in-Spring-Security</link>
					<comments>https://feeds.feedblitz.com/~/953487335/0/baeldung~MultiFactor-Authentication-in-Spring-Security#respond</comments>
		
		<dc:creator><![CDATA[Sagar Verma]]></dc:creator>
		<pubDate>Tue, 07 Apr 2026 22:52:17 +0000</pubDate>
				<category><![CDATA[Spring Security]]></category>
		<category><![CDATA[Authentication]]></category>
		<guid isPermaLink="false">https://www.baeldung.com/?p=203362</guid>
					<description><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/2017/08/Spring-Security-2.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="max-width:100% !important;height:auto !important;float: left; margin-right: 5px;" loading="lazy" /><p>Spring Security 7 introduces built-in support for multi-factor authentication, allowing developers to enforce multiple authentication steps using the existing authorization model.</p>
The post <a rel="NOFOLLOW" href="https://feeds.feedblitz.com/~/953487335/0/baeldung~MultiFactor-Authentication-in-Spring-Security">Multi-Factor Authentication in Spring Security 7</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/953487335/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/953487335/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2017%2f08%2fSpring-Security-2.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/953487335/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/953487335/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/953487335/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-security-7-mfa#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-security-7-mfa/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-Security-2.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-Security-2.jpg 952w, https://www.baeldung.com/wp-content/uploads/2017/08/Spring-Security-2-300x157.jpg 300w, https://www.baeldung.com/wp-content/uploads/2017/08/Spring-Security-2-768x402.jpg 768w" sizes="auto, (max-width: 580px) 100vw, 580px" /><h2 data-section- data-start="52" data-end="66" id="bd-v7scl5" data-id="v7scl5">1. Overview</h2>
<div class="bd-anchor" id="v7scl5"></div>
<p><a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/spring-security-basic-authentication">Authentication</a> is the first line of defense in all web applications. Traditionally, applications rely on a username and password to verify a user&#8217;s identity. However, experts no longer consider relying on a single authentication factor secure for modern systems.</p>
<p><strong>Multi-Factor Authentication (MFA)</strong> <strong>addresses this by requiring users to verify their identity using multiple independent factors before accessing a system.</strong></p>
<p><a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://docs.spring.io/spring-security/reference/whats-new.html">Spring Security 7</a> introduces built-in support for <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://spring.io/blog/2025/10/21/multi-factor-authentication-in-spring-security-7">multi-factor authentication</a>, allowing developers to enforce multiple authentication steps using the existing authorization model. In this article, we’ll explore how MFA works in Spring Security 7 and how to implement it in a Spring Boot application.</p>
<h2 data-section- data-start="1736" data-end="1779" id="bd-f626pv" data-id="f626pv">2. Understanding MFA in Spring Security 7</h2>
<div class="bd-anchor" id="f626pv"></div>
<p><strong>Spring Security 7</strong> <strong>introduces a new way to model authentication factors using authorities</strong>. <strong>Instead of treating MFA as a separate authentication mechanism, Spring Security progressively grants authorities for each successful authentication factor.</strong></p>
<p>Multi-Factor Authentication (MFA) strengthens security by requiring users to verify their identity using multiple independent factors. These factors typically fall into three categories: something the user knows, such as a password or PIN, something the user has, such as a mobile device or email token, and something the user is, such as a fingerprint or other biometric data. By combining these factors, applications significantly reduce the risk of compromised credentials and unauthorized access.</p>
<p>Each time a user successfully authenticates with a specific factor, Spring Security adds a corresponding authority to the authentication object. This authority represents the factor that has already been verified during the authentication process. Some common examples include <strong><em>FACTOR_PASSWORD</em> for password-based authentication, <em>FACTOR_X509</em> for certificate-based authentication, and <em>FACTOR_OTT</em> for one-time token authentication.</strong> These authorities are represented internally by the <em>FactorGrantedAuthority</em> class and become part of the authenticated user&#8217;s security context.</p>
<p>This design allows authorization rules to verify that the required authentication factors are satisfied before granting access to protected resources.</p>
<h2 data-section- data-start="2865" data-end="2883" id="bd-p5u09" data-id="p5u09">3. Project Setup</h2>
<div class="bd-anchor" id="p5u09"></div>
<p data-start="2885" data-end="2977">Before implementing multi-factor authentication, we’ll set up a simple <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/spring-boot">Spring Boot</a> application <span style="margin: 0px;padding: 0px">using <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://start.spring.io/" target="_blank" rel="noopener">Spring Initializr</a></span> with Spring Security 7. First, we need to configure the required dependencies.</p>
<p data-start="2885" data-end="2977">We include Spring Boot starters for <em><a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web/4.0.3">web</a>, <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-security/4.0.3/dependencies">security</a>, <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-test/4.0.3/dependencies">starter-test</a>, <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-webmvc-test/4.0.3">webmvc-test</a>, </em>and <em><a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://mvnrepository.com/artifact/org.springframework.security/spring-security-test/7.0.0">security-testing</a></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;4.0.3&lt;/version&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
    &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
    &lt;artifactId&gt;spring-boot-starter-security&lt;/artifactId&gt;
    &lt;version&gt;4.0.3&lt;/version&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
    &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
    &lt;artifactId&gt;spring-boot-starter-test&lt;/artifactId&gt;
    &lt;version&gt;4.0.3&lt;/version&gt;
    &lt;scope&gt;test&lt;/scope&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
    &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
    &lt;artifactId&gt;spring-boot-starter-webmvc-test&lt;/artifactId&gt;
    &lt;version&gt;4.0.3&lt;/version&gt;
    &lt;scope&gt;test&lt;/scope&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
    &lt;groupId&gt;org.springframework.security&lt;/groupId&gt;
    &lt;artifactId&gt;spring-security-test&lt;/artifactId&gt;
    &lt;version&gt;7.0.0&lt;/version&gt;
    &lt;scope&gt;test&lt;/scope&gt;
&lt;/dependency&gt;</code></pre>
<p data-start="0" data-end="308">This configuration adds the core dependencies required for our application. It includes Spring Boot’s web support for building REST endpoints, the Spring Security framework for implementing authentication and authorization, and Spring Security testing utilities for writing security-focused unit tests.</p>
<p data-start="310" data-end="458" data-is-last-node="" data-is-only-node="">With these dependencies in place, the application now has everything required to configure and enable multi-factor authentication.</p>
<h2 data-section- data-start="4204" data-end="4254" id="bd-vp91pr" data-id="vp91pr">4. Enabling Multi-Factor Authentication Globally</h2>
<div class="bd-anchor" id="vp91pr"></div>
<p>Spring Security 7 introduces a convenient annotation called <em>@EnableMultiFactorAuthentication</em>. <strong>This annotation allows developers to define which authentication factors are required for all protected endpoints.</strong></p>
<p data-start="4502" data-end="4598">The following configuration enables MFA globally using password and X509 authentication factors:</p>
<pre><code class="language-java">@Configuration
@EnableWebSecurity
@EnableMultiFactorAuthentication(
  authorities = { FactorGrantedAuthority.PASSWORD_AUTHORITY, FactorGrantedAuthority.X509_AUTHORITY }
)
public class GlobalMfaSecurityConfig {
    @Bean
    @Order(3)
    SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
        http.securityMatcher("/**").authorizeHttpRequests(auth -&gt;auth.requestMatchers("/public")
          .permitAll().anyRequest().authenticated()).formLogin(withDefaults());
        return http.build();
    }
}</code></pre>
<p data-start="0" data-end="257">This configuration enables Spring Security for the application and enables multi-factor authentication globally. As part of the setup, it specifies that the user must complete two authentication factors before the system considers them fully authenticated.</p>
<p data-start="259" data-end="629" data-is-last-node="" data-is-only-node="">In this case, the required factors are password and X.509 certificate authentication. Once the configuration is active, every secured endpoint in the application requires both factors for access to be granted. Applying MFA globally like this helps avoid inconsistencies and reduces the risk of missing MFA rules in individual authorization configurations.</p>
<h2 data-section- data-start="5594" data-end="5633" id="bd-kbel6w" data-id="kbel6w">5. Applying MFA to Specific Endpoints</h2>
<div class="bd-anchor" id="kbel6w"></div>
<p data-start="5635" data-end="5774">In many applications, MFA should be required only for sensitive endpoints, such as account settings, financial operations, or admin actions. <strong>Spring Security provides <i>the AuthorizationManagerFactory</i> API to define MFA rules programmatically.</strong></p>
<p data-start="5919" data-end="5985">The following configuration requires MFA only for admin endpoints:</p>
<pre><code class="language-java">@Configuration
@EnableWebSecurity
public class AdminMfaSecurityConfig {
    @Bean
    @Order(1)
    SecurityFilterChain adminSecurityFilterChain(HttpSecurity http) throws Exception {
        AuthorizationManagerFactory&lt;Object&gt; mfa = AuthorizationManagerFactories.multiFactor()
          .requireFactors(
            FactorGrantedAuthority.PASSWORD_AUTHORITY,
            FactorGrantedAuthority.X509_AUTHORITY)
          .build();
        http.securityMatcher("/admin/**").authorizeHttpRequests(auth -&gt;auth.requestMatchers("/admin/**")
          .access(mfa.hasRole("ADMIN")).anyRequest().authenticated()).formLogin(withDefaults());
        return http.build();
    }
}</code></pre>
<p data-start="0" data-end="262">In this configuration, multi-factor authentication is applied only to requests that match the <em data-start="94" data-end="103">/admin/</em>** endpoints. When a user attempts to access these routes, Spring Security checks whether the required authentication factors are present.</p>
<p data-start="264" data-end="571" data-is-last-node="" data-is-only-node="">In addition to completing both authentication factors, the user must also have the <em data-start="347" data-end="354">ADMIN</em> role. This approach provides fine-grained control over security rules, allowing developers to enforce MFA only on sensitive endpoints while keeping the rest of the application accessible with standard authentication.</p>
<h2 data-section- data-start="7060" data-end="7109" id="bd-oeaajp" data-id="oeaajp">6. Implementing Time-Based Authentication Rules</h2>
<div class="bd-anchor" id="oeaajp"></div>
<p data-start="7111" data-end="7296">Some applications require users to re-authenticate before performing sensitive actions. For example, a banking application may require a fresh login before updating payment information. Spring Security 7 supports time-based MFA rules.</p>
<p data-start="7391" data-end="7497">The following configuration requires the user to authenticate the password factor within the last five minutes:</p>
<pre><code class="language-java">@Configuration
@EnableWebSecurity
public class TimeBasedMfaSecurityConfig {
    @Bean
    @Order(2)
    SecurityFilterChain profileSecurityFilterChain(HttpSecurity http) throws Exception {
        AuthorizationManagerFactory&lt;Object&gt; recentLogin = AuthorizationManagerFactories.
          multiFactor().requireFactor(
            factor -&gt; factor.passwordAuthority().validDuration(Duration.ofMinutes(5)))
          .build();
        http.securityMatcher("/profile", "/profile/**").authorizeHttpRequests(
          auth -&gt; auth.requestMatchers("/profile", "/profile/**")
            .access(recentLogin.authenticated())
            .anyRequest().
            authenticated()).formLogin(withDefaults());
        return http.build();
    }
}</code></pre>
<p data-start="0" data-end="258">This rule allows users to navigate most parts of the application using their existing authenticated session. However, when a user attempts to access endpoints under <em>*/profile/**</em>, the system verifies whether the password authentication was completed recently.</p>
<p data-start="260" data-end="546" data-is-last-node="" data-is-only-node=""><strong>If the password factor is older than five minutes, Spring Security requires the user to authenticate again before granting access. This approach commonly allows users to perform sensitive operations, ensuring they complete critical actions only after a recent, verified authentication step.</strong></p>
<h2 data-section- data-start="8828" data-end="8866" id="bd-k4s5ze" data-id="k4s5ze">7. Implementing User-Based MFA Rules</h2>
<div class="bd-anchor" id="k4s5ze"></div>
<p data-start="8868" data-end="9025">Sometimes MFA rules apply only to specific users. For example, administrators may be required to use MFA while regular users can log in with a single factor. Spring Security allows implementing custom authorization managers to support such scenarios.</p>
<p data-start="9159" data-end="9218">The following example enforces MFA only for the admin user:</p>
<pre><code class="language-java">@Component
public class AdminMfaAuthorizationManager implements AuthorizationManager&lt;Object&gt; {
    AuthorizationManager&lt;Object&gt; mfa =
      AllAuthoritiesAuthorizationManager.hasAllAuthorities(FactorGrantedAuthority.OTT_AUTHORITY,
        FactorGrantedAuthority.PASSWORD_AUTHORITY);
    @Override
    public AuthorizationResult authorize(Supplier&lt;? extends Authentication&gt; authentication, Object context) {
        Authentication auth = authentication.get();
        if (auth != null &amp;&amp; "admin".equals(auth.getName())) {
            return mfa.authorize(authentication, context);
        }
        return new AuthorizationDecision(true);
    }
}</code></pre>
<p data-start="0" data-end="245">This logic checks the authenticated user&#8217;s identity and applies MFA rules conditionally. If the authenticated user is an admin, the system verifies that the user has completed both required authentication factors before granting access.</p>
<p data-start="247" data-end="515" data-is-last-node="" data-is-only-node="">For all other users, the system allows the request without enforcing additional MFA checks. This approach is useful when introducing MFA gradually, allowing organizations to enforce stronger security for high-privilege users first before extending it to the entire user base.</p>
<h2 data-section- data-start="10148" data-end="10179" id="bd-15wz0nu" data-id="15wz0nu">8. Writing Unit Tests for MFA</h2>
<div class="bd-anchor" id="15wz0nu"></div>
<p data-start="0" data-end="247">Testing authentication flows is essential to ensure that security rules behave as expected. Without proper tests, it becomes difficult to verify whether authentication requirements such as roles, permissions, or MFA factors are correctly enforced.</p>
<p data-start="249" data-end="541" data-is-last-node="" data-is-only-node="">Spring Security provides dedicated testing utilities that make it easier to simulate authenticated users and validate authorization behavior. These tools allow developers to write focused tests that verify that security configurations function correctly without requiring a full authentication setup.</p>
<h3 data-section- data-start="10349" data-end="10375" id="bd-dkifrs" data-id="dkifrs">8.1. Controller Example</h3>
<div class="bd-anchor" id="dkifrs"></div>
<p data-start="10377" data-end="10425">Before writing tests, we define a simple controller that exposes the endpoints secured by our MFA configurations:</p>
<pre><code class="language-java">@RestController
public class DemoController {
    @GetMapping("/public")
    public String publicEndpoint() {
        return "public endpoint";
    }
    @GetMapping("/profile")
    public String profileEndpoint() {
        return "profile endpoint";
    }
    @GetMapping("/admin/dashboard")
    public String adminDashboard() {
        return "admin dashboard";
    }
}</code></pre>
<p>This controller exposes three endpoints <em>/public, /profile, </em>and <em>/admin/dashboard</em> that help demonstrate different MFA enforcement strategies.</p>
<h3 data-section- data-start="10640" data-end="10665" id="bd-1buszc5" data-id="1buszc5">8.2. MFA Security Test</h3>
<div class="bd-anchor" id="1buszc5"></div>
<p data-start="10667" data-end="10736">This test verifies how the system behaves when it enforces multi-factor authentication globally:</p>
<pre><code class="language-java">@SpringBootTest(classes = Application.class)
@AutoConfigureMockMvc
class GlobalMfaSecurityTest {
    @Autowired
    MockMvc mockMvc;
    @Test
    void givenUserWithoutMfa_whenAccessProfile_thenForbidden() throws Exception {
        mockMvc.perform(get("/profile").with(user("user").roles("USER")))
          .andExpect(status().is3xxRedirection())
          .andExpect(header().string("Location", containsString("/login")));
    }
}</code></pre>
<p>This test simulates a user attempting to access the admin endpoint without completing the required MFA factors. Since the authentication request only contains the basic role and does not include the necessary factor authorities, the request does not satisfy the configured security rules. As a result, Spring Security returns a 403 Forbidden response because the user has not completed all required authentication factors.</p>
<h3 data-section- data-start="11803" data-end="11819" id="bd-f2307e" data-id="f2307e">8.3. Admin Endpoint MFA Test</h3>
<div class="bd-anchor" id="f2307e"></div>
<p data-section-id="f2307e" data-start="11803" data-end="11819">Next, we&#8217;ll verify that the system enforces MFA for admin endpoints:</p>
<pre><code class="language-java">@SpringBootTest(classes = Application.class)
@AutoConfigureMockMvc
class AdminMfaSecurityTest {
    @Autowired
    MockMvc mockMvc;
    @Test
    void givenAdminWithoutMfa_whenAccessAdminEndpoint_thenForbidden() throws Exception {
        mockMvc.perform(get("/admin/dashboard").with(user("admin").roles("ADMIN")))
          .andExpect(status().is3xxRedirection())
          .andExpect(header().string("Location", containsString("/login")));
    }
}</code></pre>
<p>This test simulates an administrator attempting to access the <em>/admin/dashboard</em> endpoint. Although the user has the required ADMIN role, the request does not include the required MFA authorities. Because the authentication factors are incomplete, Spring Security redirects the request to the login page. This confirms that MFA enforcement works correctly for privileged endpoints.</p>
<h3 id="bd-4-time-based-mfa-security-test" data-id="4-time-based-mfa-security-test">8.4. Time-Based MFA Security Test</h3>
<div class="bd-anchor" id="4-time-based-mfa-security-test"></div>
<p>Some operations require users to authenticate recently to ensure no one has compromised the session. The following test verifies that the profile endpoint requires a recent authentication:</p>
<pre><code class="language-java">@SpringBootTest(classes = Application.class)
@AutoConfigureMockMvc
class TimeBasedMfaSecurityTest {
    @Autowired
    MockMvc mockMvc;
    @Test
    void givenUserWithoutRecentAuthentication_whenAccessProfile_thenForbidden() throws Exception {
        mockMvc.perform(get("/profile").with(user("user").roles("USER")))
          .andExpect(status().is3xxRedirection())
          .andExpect(header().string("Location", containsString("/login")));
    }
}</code></pre>
<p>This test checks that the <em>/profile</em> endpoint requires a recent authentication. Since the simulated request does not include the necessary MFA factor information, Spring Security redirects the request to the login page. This confirms that the system correctly enforces the time-based MFA rule.</p>
<h2 data-section- data-start="11803" data-end="11819" id="bd-f2307e-1" data-id="f2307e-1">9. Conclusion</h2>
<div class="bd-anchor" id="f2307e-1"></div>
<p>Multi-Factor Authentication (MFA) is a critical security measure for modern applications, helping reduce the risk of unauthorized access by requiring multiple verification factors.</p>
<p>Spring Security 7 provides built-in support for MFA, allowing developers to enforce multiple authentication steps using the existing authorization model. In this article, we explored how <em>FactorGrantedAuthority</em> models MFA, how to enable it globally with <em>@EnableMultiFactorAuthentication</em>, and how to apply it selectively to specific endpoints using <em>AuthorizationManagerFactory</em>. We also covered time-based rules, custom user-based policies, and testing MFA behavior using Spring Security test utilities.</p>
<p>By leveraging these features, developers can build secure and flexible authentication flows. As security threats continue to evolve, implementing MFA is no longer optional but an essential step in protecting user data and critical systems. As always, the code for this example is available <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/eugenp/tutorials/tree/master/spring-security-modules/spring-security-mfa">over on GitHub</a>.</p>The post <a href="http://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/spring-security-7-mfa">Multi-Factor Authentication in Spring Security 7</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/953487335/0/baeldung">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/953487335/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/953487335/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2017%2f08%2fSpring-Security-2.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/953487335/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/953487335/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/953487335/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-security-7-mfa#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-security-7-mfa/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/~/953487335/0/baeldung~MultiFactor-Authentication-in-Spring-Security/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<webfeeds:featuredImage>https://www.baeldung.com/wp-content/uploads/2017/08/Spring-Security-2-150x150.jpg</webfeeds:featuredImage></item>
<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;" loading="lazy" /><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" loading="lazy" srcset="https://www.baeldung.com/wp-content/uploads/2021/09/Java-5-Featured-1024x536.png 1024w, https://www.baeldung.com/wp-content/uploads/2021/09/Java-5-Featured-300x157.png 300w, https://www.baeldung.com/wp-content/uploads/2021/09/Java-5-Featured-768x402.png 768w, https://www.baeldung.com/wp-content/uploads/2021/09/Java-5-Featured-100x52.png 100w, https://www.baeldung.com/wp-content/uploads/2021/09/Java-5-Featured.png 1200w" sizes="auto, (max-width: 580px) 100vw, 580px" /><h2 id="bd-introduction" data-id="introduction">1. Introduction</h2>
<div class="bd-anchor" id="introduction"></div>
<p>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[popular]]></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;" loading="lazy" /><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>
		<category><![CDATA[popular]]></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#comments</comments>
		
		<dc:creator><![CDATA[Hamid Reza Sharifi]]></dc:creator>
		<pubDate>Tue, 31 Mar 2026 15:46:13 +0000</pubDate>
				<category><![CDATA[Spring MVC]]></category>
		<category><![CDATA[popular]]></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#comments"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/comments20.png"></a>&#160;<a title="Follow Comments via RSS" href="https://www.baeldung.com/spring-boot-spa-redirect-404/feed"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/commentsrss20.png"></a>&nbsp;
<div style="clear:left;"><a rel="NOFOLLOW" href="https://www.baeldung.com/spring-boot-spa-redirect-404#comments"><h3>Comments</h3></a><ul><li><a rel="NOFOLLOW" href="https://www.baeldung.com/spring-boot-spa-redirect-404#comment-15687">In reply to fantaman.   Hey, Fantaman.   Thanks for the ...</a> <i>by Ulisses Lima</i><li><a rel="NOFOLLOW" href="https://www.baeldung.com/spring-boot-spa-redirect-404#comment-15686">Should the backend not redirect (instead of forward) to ...</a> <i>by fantaman</i></ul></div>&#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#comments"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/comments20.png"></a>&#160;<a title="Follow Comments via RSS" href="https://www.baeldung.com/spring-boot-spa-redirect-404/feed"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/commentsrss20.png"></a>&nbsp;
<div style="clear:left;"><a rel="NOFOLLOW" href="https://www.baeldung.com/spring-boot-spa-redirect-404#comments"><h3>Comments</h3></a><ul><li><a rel="NOFOLLOW" href="https://www.baeldung.com/spring-boot-spa-redirect-404#comment-15687">In reply to fantaman.   Hey, Fantaman.   Thanks for the ...</a> <i>by Ulisses Lima</i><li><a rel="NOFOLLOW" href="https://www.baeldung.com/spring-boot-spa-redirect-404#comment-15686">Should the backend not redirect (instead of forward) to ...</a> <i>by fantaman</i></ul></div>&#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>2</slash:comments>
		
		
		<webfeeds:featuredImage>https://www.baeldung.com/wp-content/uploads/2017/08/Spring-MVC-1-150x150.jpg</webfeeds:featuredImage></item>
</channel></rss>

