<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="https://feeds.feedblitz.com/feedblitz_rss.xslt"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:webfeeds="http://webfeeds.org/rss/1.0"  xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">
<channel>
	<title>Baeldung</title>
	<atom:link href="https://www.baeldung.com/feed" rel="self" type="application/rss+xml" />
	<link>https://www.baeldung.com</link>
	<description>Java, Spring and Web Development tutorials</description>
	<lastBuildDate>Mon, 01 Jun 2026 22:08:16 +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/alibaba-nacos-basics</feedburner:origLink>
		<title>Introduction to Alibaba Nacos</title>
		<link>https://feeds.feedblitz.com/~/957626876/0/baeldung~Introduction-to-Alibaba-Nacos</link>
					<comments>https://feeds.feedblitz.com/~/957626876/0/baeldung~Introduction-to-Alibaba-Nacos#respond</comments>
		
		<dc:creator><![CDATA[Graham Cox]]></dc:creator>
		<pubDate>Mon, 01 Jun 2026 22:08:16 +0000</pubDate>
				<category><![CDATA[Architecture]]></category>
		<category><![CDATA[Microservices]]></category>
		<guid isPermaLink="false">https://www.baeldung.com/alibaba-nacos-basics</guid>
					<description><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-12-1024x536.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="max-width:100% !important;height:auto !important;float: left; margin-right: 5px;" fetchpriority="high" /><p>Learn what Alibaba Nacos is, how to set it up, and how to use it for service discovery, centralized configuration management, and coordination in distributed applications.</p>
The post <a rel="NOFOLLOW" href="https://feeds.feedblitz.com/~/957626876/0/baeldung~Introduction-to-Alibaba-Nacos">Introduction to Alibaba Nacos</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/957626876/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/957626876/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2024%2f07%2fJava-Featured-12-1024x536.jpg"><img height="20" src="https://assets.feedblitz.com/i/pinterest20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Post to X.com" href="https://feeds.feedblitz.com/_/24/957626876/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/957626876/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/957626876/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/alibaba-nacos-basics#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/alibaba-nacos-basics/feed"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/commentsrss20.png"></a>&#160;</div>]]>
</description>
										<content:encoded><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-12-1024x536.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="float: left; margin-right: 5px;" decoding="async" loading="lazy" srcset="https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-12-1024x536.jpg 1024w, https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-12-300x157.jpg 300w, https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-12-768x402.jpg 768w, https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-12-100x52.jpg 100w, https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-12.jpg 1200w" sizes="auto, (max-width: 580px) 100vw, 580px" /><h2 id="bd-introduction" data-id="introduction"><strong>1. Introduction</strong></h2>
<div class="bd-anchor" id="introduction"></div>
<p>When it comes to big data and many potential parties interested in it, distribution is critical. To that end, there are simple and complex solutions.</p>
<p>In this tutorial, we&#8217;ll take a look at <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://nacos.io/">Alibaba Nacos</a>. First, we see what it is. After that, we go over different ways to configure and use Nacos. Finally, we demonstrate what we can do with the platform.</p>
<h2 id="bd-what-is-nacos" data-id="what-is-nacos"><strong>2. What Is Nacos?</strong></h2>
<div class="bd-anchor" id="what-is-nacos"></div>
<p>Nacos is a platform offering various tools:</p>
<ul>
<li>dynamic service discovery</li>
<li>configuration management</li>
<li>distributed locking</li>
</ul>
<p><strong>It&#8217;s mainly used for building highly distributed systems</strong>.</p>
<p>At its core, Nacos provides a service discovery system enabling us to dynamically start and stop instances of different services, and still have other services able to reach them. This is particularly valuable in microservices applications where we might have a larger number of applications that each have a varied number of running instances.</p>
<p>Nacos also offers tools for managing the configuration of applications, providing a way to configure everything in a single place and have the suite of running instances automatically reflect this. Furthermore, we also have tools for distributed locking, enabling distributed applications to share finite resources without conflict.</p>
<p>As expected, there are some more recently introduced features for working with AI Agents &#8211; including MCP Servers, Skills, Prompts, and <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.agentcard.net/">AgentCard</a> discovery. However, these are out of scope for this article.</p>
<h2 id="bd-running-nacos" data-id="running-nacos"><strong>3. Running Nacos</strong></h2>
<div class="bd-anchor" id="running-nacos"></div>
<p>The easiest way to get started quickly with Nacos is by using <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/ops/docker-guide">Docker</a>.</p>
<p>In particular, <strong>we can start a standalone Nacos instance using a fairly simple <em>docker-compose.yml</em> file</strong>:</p>
<pre><code class="language-yaml">services:
  nacos:
    image: nacos/nacos-server:latest
    environment:
      - MODE=standalone
      - NACOS_AUTH_TOKEN=U2VjdXJlTmFjb3NBdXRoVG9rZW5Gb3JEZW1vUHVycG9zZXMxMjM=
      - NACOS_AUTH_IDENTITY_KEY=serverIdentity
      - NACOS_AUTH_IDENTITY_VALUE=nacos-demo-node
    ports:
      - "8080:8080"
      - "8848:8848"
      - "9848:9848"</code></pre>
<p>The <em>NACOS_AUTH_TOKEN</em> variable must contain a string that&#8217;s at least 32 characters long and then base-64 encoded. On the other hand, <em>NACOS_AUTH_IDENTITY_KEY</em> and <em>NACOS_AUTH_IDENTITY_VALUE</em> can contain any values that identify the current Nacos instance.</p>
<p>At this point, we can run the setup:</p>
<pre><code class="language-shell">$ docker compose up
.....
nacos-1  | 2026-04-27 14:20:53,304 INFO Nacos Console started successfully in 311 ms</code></pre>
<p>Once started, we can access the console on <em><a href="http://localhost:8080">http://localhost:8080</a></em>.</p>
<p><strong>On first access, we need to configure a password for the <em>nacos</em> user</strong>:</p>
<a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/wp-content/uploads/2026/06/nacos-configure-user.png"><img decoding="async" class="alignnone wp-image-203893 size-medium" src="https://www.baeldung.com/wp-content/uploads/2026/06/nacos-configure-user-282x300.png" alt="Nacos user configuration" width="282" height="300" srcset="https://www.baeldung.com/wp-content/uploads/2026/06/nacos-configure-user-282x300.png 282w, https://www.baeldung.com/wp-content/uploads/2026/06/nacos-configure-user-962x1024.png 962w, https://www.baeldung.com/wp-content/uploads/2026/06/nacos-configure-user-768x817.png 768w, https://www.baeldung.com/wp-content/uploads/2026/06/nacos-configure-user-100x106.png 100w, https://www.baeldung.com/wp-content/uploads/2026/06/nacos-configure-user-600x639.png 600w, https://www.baeldung.com/wp-content/uploads/2026/06/nacos-configure-user.png 964w" sizes="(max-width: 282px) 100vw, 282px" /></a>
<p>&nbsp;</p>
<p>Now, let&#8217;s log into the management console:</p>
<a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/wp-content/uploads/2026/06/nacos-configuration-scaled.png"><img decoding="async" class="alignnone wp-image-203894 size-large" src="https://www.baeldung.com/wp-content/uploads/2026/06/nacos-configuration-1024x591.png" alt="Nacos management" width="580" height="335" srcset="https://www.baeldung.com/wp-content/uploads/2026/06/nacos-configuration-1024x591.png 1024w, https://www.baeldung.com/wp-content/uploads/2026/06/nacos-configuration-300x173.png 300w, https://www.baeldung.com/wp-content/uploads/2026/06/nacos-configuration-768x444.png 768w, https://www.baeldung.com/wp-content/uploads/2026/06/nacos-configuration-1536x887.png 1536w, https://www.baeldung.com/wp-content/uploads/2026/06/nacos-configuration-2048x1183.png 2048w, https://www.baeldung.com/wp-content/uploads/2026/06/nacos-configuration-100x58.png 100w, https://www.baeldung.com/wp-content/uploads/2026/06/nacos-configuration-600x347.png 600w" sizes="(max-width: 580px) 100vw, 580px" /></a>
<p>&nbsp;</p>
<p>Running Nacos in this way, we get a set of default data already present to work with, but we can use this UI to configure a custom environment.</p>
<h2 id="bd-using-nacos-with-java-sdk" data-id="using-nacos-with-java-sdk"><strong>4. Using Nacos With Java SDK</strong></h2>
<div class="bd-anchor" id="using-nacos-with-java-sdk"></div>
<p>Now that we&#8217;ve got Nacos running, we can use it from applications.</p>
<p><strong>To do this, we first need to add <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://mvnrepository.com/artifact/com.alibaba.nacos/nacos-client">the client dependency</a> to the project</strong>. At the time of writing, the latest version is <a class="vbtn release" href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://mvnrepository.com/artifact/com.alibaba.nacos/nacos-client/3.2.1">3.2.1</a>.</p>
<p>If using Maven, we can include this dependency in the <em>pom.xml</em> file:</p>
<pre><code class="language-xml">&lt;dependency&gt;
    &lt;groupId&gt;com.alibaba.nacos&lt;/groupId&gt;
    &lt;artifactId&gt;nacos-client&lt;/artifactId&gt;
    &lt;version&gt;3.2.1&lt;/version&gt;
&lt;/dependency&gt;</code></pre>
<p>To leverage Nacos within the application, we need to know the address of the Nacos server we&#8217;re working with, the namespace we&#8217;re going to use if it&#8217;s not the default, and any other configuration properties for the service in question:</p>
<pre><code class="language-java">Properties properties = new Properties();
properties.setProperty(PropertyKeyConst.SERVER_ADDR, "localhost:8848");
properties.setProperty(PropertyKeyConst.NAMESPACE, "public");</code></pre>
<p>Now, we can then create a client for each of the Nacos services that we require:</p>
<pre><code class="language-java">ConfigService configService = NacosFactory.createConfigService(properties);
NamingService namingService = NacosFactory.createNamingService(properties);
LockService lockService = NacosFactory.createLockService(properties);</code></pre>
<p>These service clients are then ready for us to use.</p>
<h2 id="bd-configuration-management" data-id="configuration-management"><strong>5. Configuration Management</strong></h2>
<div class="bd-anchor" id="configuration-management"></div>
<p>Nacos enables the management of configuration settings in a single, central place, so services can make use of them automatically.</p>
<h3 id="bd-1-managing-configuration" data-id="1-managing-configuration"><strong>5.1. Managing Configuration</strong></h3>
<div class="bd-anchor" id="1-managing-configuration"></div>
<p>In particular, <strong>we can manage the configuration settings from within the management console by selecting the <em>Configurations</em> entry on the sidebar</strong>:</p>
<a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/wp-content/uploads/2026/06/nacos-configuration-scaled.png"><img loading="lazy" decoding="async" class="alignnone wp-image-203894 size-large" src="https://www.baeldung.com/wp-content/uploads/2026/06/nacos-configuration-1024x591.png" alt="Nacos configurations management" width="580" height="335" srcset="https://www.baeldung.com/wp-content/uploads/2026/06/nacos-configuration-1024x591.png 1024w, https://www.baeldung.com/wp-content/uploads/2026/06/nacos-configuration-300x173.png 300w, https://www.baeldung.com/wp-content/uploads/2026/06/nacos-configuration-768x444.png 768w, https://www.baeldung.com/wp-content/uploads/2026/06/nacos-configuration-1536x887.png 1536w, https://www.baeldung.com/wp-content/uploads/2026/06/nacos-configuration-2048x1183.png 2048w, https://www.baeldung.com/wp-content/uploads/2026/06/nacos-configuration-100x58.png 100w, https://www.baeldung.com/wp-content/uploads/2026/06/nacos-configuration-600x347.png 600w" sizes="auto, (max-width: 580px) 100vw, 580px" /></a>
<p>&nbsp;</p>
<p>This section gives us a list of all the configuration entries that are currently in the system, as well as letting us add new ones.</p>
<p>New entries are added using the <em>New Config</em> button at the top:</p>
<a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/wp-content/uploads/2026/06/new-config-scaled.png"><img loading="lazy" decoding="async" class="alignnone wp-image-203895 size-large" src="https://www.baeldung.com/wp-content/uploads/2026/06/new-config-1024x686.png" alt="Nacos create configuration" width="580" height="389" srcset="https://www.baeldung.com/wp-content/uploads/2026/06/new-config-1024x686.png 1024w, https://www.baeldung.com/wp-content/uploads/2026/06/new-config-300x201.png 300w, https://www.baeldung.com/wp-content/uploads/2026/06/new-config-768x514.png 768w, https://www.baeldung.com/wp-content/uploads/2026/06/new-config-1536x1028.png 1536w, https://www.baeldung.com/wp-content/uploads/2026/06/new-config-2048x1371.png 2048w, https://www.baeldung.com/wp-content/uploads/2026/06/new-config-100x67.png 100w, https://www.baeldung.com/wp-content/uploads/2026/06/new-config-600x402.png 600w" sizes="auto, (max-width: 580px) 100vw, 580px" /></a>
<p>&nbsp;</p>
<p>From here, we enter values for each configuration element:</p>
<ul>
<li>Data ID: ID of the configuration entry, typically in the same format as a fully qualified class name</li>
<li>Group: group the configuration entry belongs to, typically representing the product the configuration is for</li>
<li>Format: format that the configuration entry is in, typically one of <em>Text</em>, <em>JSON</em>, <em>XML</em>, <em>YAML</em>, <em>HTML</em>, <em>Properties</em>, or <em>TOML</em></li>
<li>Content: actual configuration entry, in the specified format</li>
</ul>
<p>In addition, we can specify description, application, and tags. However, these are only metadata about the entry and don&#8217;t influence its use at all.</p>
<p>Conveniently, we can see historical versions of configurations:</p>
<a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/wp-content/uploads/2026/06/nacos-config-history-scaled.png"><img loading="lazy" decoding="async" class="alignnone wp-image-203896 size-large" src="https://www.baeldung.com/wp-content/uploads/2026/06/nacos-config-history-1024x334.png" alt="Nacos configuration history" width="580" height="189" srcset="https://www.baeldung.com/wp-content/uploads/2026/06/nacos-config-history-1024x334.png 1024w, https://www.baeldung.com/wp-content/uploads/2026/06/nacos-config-history-300x98.png 300w, https://www.baeldung.com/wp-content/uploads/2026/06/nacos-config-history-768x250.png 768w, https://www.baeldung.com/wp-content/uploads/2026/06/nacos-config-history-1536x501.png 1536w, https://www.baeldung.com/wp-content/uploads/2026/06/nacos-config-history-2048x668.png 2048w, https://www.baeldung.com/wp-content/uploads/2026/06/nacos-config-history-100x33.png 100w, https://www.baeldung.com/wp-content/uploads/2026/06/nacos-config-history-600x196.png 600w" sizes="auto, (max-width: 580px) 100vw, 580px" /></a>
<p>&nbsp;</p>
<p>Thus, we have the ability to edit or delete configuration settings, as well as see the details of the entry and the history of all changes to it.</p>
<h3 id="bd-2-fetching-configuration" data-id="2-fetching-configuration"><strong>5.2. Fetching Configuration</strong></h3>
<div class="bd-anchor" id="2-fetching-configuration"></div>
<p>Once we&#8217;ve got the configuration set up, we need to be able to use it. To that end, <strong>we set configurations via the <em>ConfigService</em> that we created earlier</strong>.</p>
<p>Specifically, perhaps the easiest way is to simply call <em>getConfig()</em> passing in the data ID and group, as well as a timeout in milliseconds:</p>
<pre><code class="language-java">String config = configService.getConfig("com.baeldung.nacos.Example", "DEFAULT_GROUP", 1000);</code></pre>
<p>This way, we immediately get the value of this configuration setting. In the event that the configuration doesn&#8217;t exist, or Nacos can&#8217;t be reached, we get <em>null</em> back instead.</p>
<p>However, this only gives us the raw value. Normally, we need to already know what type it is to know what to do with it. To avoid this, <strong>we can instead use <em>getConfigWithResult()</em> to get back a richer object that includes the type of config setting (text, JSON, or similar), so that we know how to handle that</strong>:</p>
<pre><code class="language-java">ConfigQueryResult config = configService.getConfigWithResult("com.baeldung.nacos.Example", "DEFAULT_GROUP", 1000);
String configType = config.getConfigType();
String configValue = config.getContent();</code></pre>
<p>This way, we always get a result, even if the config setting doesn&#8217;t exist or the Nacos server is unreachable. In those cases, we get a valid <em>ConfigQueryResult</em> object that contains <em>null</em> for the content and config type.</p>
<h3 id="bd-3-listening-to-configuration-changes" data-id="3-listening-to-configuration-changes"><strong>5.3. Listening to Configuration Changes</strong></h3>
<div class="bd-anchor" id="3-listening-to-configuration-changes"></div>
<p>As well as simply fetching the configuration value at a single point in time, <strong>we can register a callback for whenever the value changes</strong>. This way, we can be responsive to configuration changes without needing to manually poll the values ourselves.</p>
<p>In particular, <strong>let&#8217;s register a listener for a specific configuration setting using <em>addListener()</em></strong>:</p>
<pre><code class="language-java">configService.addListener("com.baeldung.nacos.Example", "DEFAULT_GROUP", new AbstractListener() {
    @Override
    public void receiveConfigInfo(String configInfo) {
        LOG.info("Received config info: {}", configInfo);
    }
});
</code></pre>
<p>This block runs every time the config setting changes, with the new value. Unfortunately, this only happens when the value changes, not immediately.</p>
<p><strong>As an alternative, we can use <em>getConfigAndSignListener()</em> to retrieve the current configuration and immediately register a listener</strong>:</p>
<pre><code class="language-java">String config = configService.getConfigAndSignListener("com.baeldung.nacos.Example", "DEFAULT_GROUP", 1000, new AbstractListener() {
    @Override
    public void receiveConfigInfo(String configInfo) {
        LOG.info("Received config info: {}", configInfo);
    }
});
</code></pre>
<p>Thus, we get the current config for use right now, and to also respond whenever the configuration changes as needed. In a way, this is a shorthand for both <em>getConfig()</em> and <em>addListener()</em> in a single call.</p>
<h2 id="bd-service-discovery" data-id="service-discovery"><strong>6. Service Discovery</strong></h2>
<div class="bd-anchor" id="service-discovery"></div>
<p>On top of configuration, <strong>Nacos also provides service discovery of distributed services</strong>. This works by services registering their address and port against a well-known name, and then enabling clients to look up these by name later on.</p>
<h3 id="bd-1-registering-a-service" data-id="1-registering-a-service"><strong>6.1. Registering a Service</strong></h3>
<div class="bd-anchor" id="1-registering-a-service"></div>
<p>To begin with, we register services using the <em>NamingService</em> that we constructed earlier.  <strong>We do this using the <em>registerInstance()</em> method, passing in the service name and address</strong>:</p>
<pre><code class="language-java">namingService.registerInstance("BaeldungTest", "localhost", 8848);</code></pre>
<p>Alternatively, we can pass in an <em>Instance</em> class containing some more details about the service:</p>
<pre><code class="language-java">Instance instance = new Instance();
instance.setIp("localhost");
instance.setPort(8848);
instance.setEnabled(true);
instance.setHealthy(true);
Map&lt;String, String&gt; metadata = new HashMap&lt;&gt;();
metadata.put("Example", "value");
instance.setMetadata(metadata);
namingService.registerInstance("BaeldungTest", instance);
</code></pre>
<p>Notably, if we do this, <strong>we need to ensure that the <em>enabled</em> and <em>healthy</em> flags are set</strong>, since they default to <em>false</em>, and therefore the service won&#8217;t be available for discovery.</p>
<p>If we need to update the service registration &#8211; for example, to change whether the service is healthy &#8211; then we can simply re-register the same service name and address with the new details. Nacos detects that these are the same details and updates them instead of creating a new registration.</p>
<h3 id="bd-2-unregistering-a-service" data-id="2-unregistering-a-service"><strong>6.2. Unregistering a Service</strong></h3>
<div class="bd-anchor" id="2-unregistering-a-service"></div>
<p>Importantly, <strong>the <em>NamingService</em> client automatically unregisters any services that it registered when it closes down</strong>. This means that we don&#8217;t need to do anything special, and as soon as the service shuts down, Nacos should remove it automatically. Still, this depends on other factors such as heartbeat and ephemeral instances.</p>
<p>However, sometimes we need to do this ourselves without shutting down the entire service. To do so, we turn to <em>deregisterInstance()</em>:</p>
<pre><code class="language-java">namingService.deregisterInstance("BaeldungTest", "localhost", 8848);</code></pre>
<p>This takes the service name and either the address and port, or the <em>Instance</em> class, as with <em>registerInstance()</em>. With that information, <em>deregisterInstance</em><em>()</em> immediately removes this address from the Nacos server to prevent discovery.</p>
<h3 id="bd-3-discovering-service-instances" data-id="3-discovering-service-instances"><strong>6.3. Discovering Service Instances</strong></h3>
<div class="bd-anchor" id="3-discovering-service-instances"></div>
<p>Once services are registered, we need to be able to discover them to actually leverage what they offer. Nacos offers several ways that we can achieve this.</p>
<p><strong>Perhaps the most useful way to service discovery is <em>selectOneHealthyInstance()</em></strong>. The method takes the service name and randomly returns one <em>healthy</em> registered instance:</p>
<pre><code class="language-java">Instance baeldungTest = namingService.selectOneHealthyInstance("BaeldungTest");
String address = baeldungTest.getIp();
int port = baeldungTest.getPort();
</code></pre>
<p>If nothing is registered for the given service name, the code throws an <em>IllegalStateException</em> to indicate that fact, since this means there are no services that we can use right now.</p>
<p>Alternatively, <strong><em>selectInstances()</em> and <em>getAllInstances()</em> are able to return every registered instance instead of just one of them</strong>:</p>
<pre><code class="language-java">List&lt;Instance&gt; allInstances = namingService.getAllInstances("BaeldungTest");
List&lt;Instance&gt; allHealthyInstances = namingService.selectInstances("BaeldungTest", true);</code></pre>
<p>Notably, <strong><em>selectInstances()</em> and <em>selectOneHealthyInstance()</em> only return services that are marked as <em>enabled</em>, and where the <em>healthy</em> flag is as expected</strong>. <em>getAllInstances()</em> returns every instance regardless of these flags.</p>
<h3 id="bd-4-listening-to-service-discovery-changes" data-id="4-listening-to-service-discovery-changes"><strong>6.4. Listening to Service Discovery Changes</strong></h3>
<div class="bd-anchor" id="4-listening-to-service-discovery-changes"></div>
<p>In addition to selecting an instance when we need to, we can register a callback to be triggered whenever there&#8217;s a change to the instances for a given service name:</p>
<pre><code class="language-java">namingService.subscribe("BaeldungTest", (event) -&gt; {
    NamingChangeEvent namingChangeEvent = (NamingChangeEvent) event;
    LOG.info("Added Instances: {}", namingChangeEvent.getAddedInstances());
    LOG.info("Removed Instances: {}", namingChangeEvent.getRemovedInstances());
    LOG.info("Modified Instances: {}", namingChangeEvent.getModifiedInstances());
});
</code></pre>
<p>We can then do whatever we want with this information &#8211; for example, we might want to maintain a local cache of instances so that we don&#8217;t need to make a call to Nacos every time we want to look one up.</p>
<h2 id="bd-distributed-locks" data-id="distributed-locks"><strong>7. Distributed Locks</strong></h2>
<div class="bd-anchor" id="distributed-locks"></div>
<p>Another important feature that Nacos has is support for distributed locking of resources. Specifically, <strong>Nacos enables access control to resources so that they can&#8217;t be accessed by different services or threads at the same time</strong>.</p>
<p>To obtain locks, we use the <em>LockService</em> that we created earlier and <strong>call the <em>lock()</em> method, providing a definition of the lock that we want</strong>:</p>
<pre><code class="language-java">Boolean result = lockService.lock(new NLock("Baeldung", 5000L));</code></pre>
<p>When obtaining a lock, we need to provide the identifier of the resource and a maximum time period for the lock, measured in milliseconds. Critically, we receive a result indicating whether we got the lock or not.</p>
<p>Locks release either after the provided time period or by explicitly unlocking them with the <em>unlock()</em> method:</p>
<pre><code class="language-java">lockService.unlock(new NLock("Baeldung", 5000L));</code></pre>
<p>Unlike with service registrations, <strong>locks aren&#8217;t automatically removed when the client disconnects</strong>, so we need to ensure that we manage this sensibly.</p>
<h2 id="bd-summary" data-id="summary"><strong>8. Summary</strong></h2>
<div class="bd-anchor" id="summary"></div>
<p>In this article, we took a quick look at Alibaba Nacos, we saw what it is and how we can use it in applications.</p>
<p>In summary, Nacos is a platform for managing distributed systems by providing service discovery, centralized configuration, and coordination capabilities.</p>
<p>As usual, all of the examples from this article are available <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/eugenp/tutorials/tree/master/microservices-modules/nacos">over on GitHub</a>.</p>The post <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/alibaba-nacos-basics">Introduction to Alibaba Nacos</a> first appeared on <a href="https://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/957626876/0/baeldung">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/957626876/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/957626876/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2024%2f07%2fJava-Featured-12-1024x536.jpg"><img height="20" src="https://assets.feedblitz.com/i/pinterest20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Post to X.com" href="https://feeds.feedblitz.com/_/24/957626876/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/957626876/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/957626876/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/alibaba-nacos-basics#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/alibaba-nacos-basics/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/~/957626876/0/baeldung~Introduction-to-Alibaba-Nacos/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<webfeeds:featuredImage>https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-12-150x150.jpg</webfeeds:featuredImage></item>
<item>
<feedburner:origLink>https://www.baeldung.com/java-sock-merchant-problem</feedburner:origLink>
		<title>How to Solve the Sock Merchant Problem in Java</title>
		<link>https://feeds.feedblitz.com/~/957603419/0/baeldung~How-to-Solve-the-Sock-Merchant-Problem-in-Java</link>
					<comments>https://feeds.feedblitz.com/~/957603419/0/baeldung~How-to-Solve-the-Sock-Merchant-Problem-in-Java#respond</comments>
		
		<dc:creator><![CDATA[Nikhil Bhargav]]></dc:creator>
		<pubDate>Mon, 01 Jun 2026 07:59:55 +0000</pubDate>
				<category><![CDATA[Algorithms]]></category>
		<category><![CDATA[Java Set]]></category>
		<guid isPermaLink="false">https://www.baeldung.com/java-sock-merchant-problem</guid>
					<description><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/2024/11/Algorithms-Featured-Image-01-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 two approaches to solving the Sock Merchant Problem in Java.</p>
The post <a rel="NOFOLLOW" href="https://feeds.feedblitz.com/~/957603419/0/baeldung~How-to-Solve-the-Sock-Merchant-Problem-in-Java">How to Solve the Sock Merchant Problem 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/957603419/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/957603419/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2024%2f11%2fAlgorithms-Featured-Image-01-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/957603419/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/957603419/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/957603419/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-sock-merchant-problem#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-sock-merchant-problem/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-01-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-01-1024x536.jpg 1024w, https://www.baeldung.com/wp-content/uploads/2024/11/Algorithms-Featured-Image-01-300x157.jpg 300w, https://www.baeldung.com/wp-content/uploads/2024/11/Algorithms-Featured-Image-01-768x402.jpg 768w, https://www.baeldung.com/wp-content/uploads/2024/11/Algorithms-Featured-Image-01-100x52.jpg 100w, https://www.baeldung.com/wp-content/uploads/2024/11/Algorithms-Featured-Image-01-600x314.jpg 600w, https://www.baeldung.com/wp-content/uploads/2024/11/Algorithms-Featured-Image-01.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 study two Java solutions for the Sock Merchant problem.</p>
<h2 id="bd-the-sock-merchant-problem" data-id="the-sock-merchant-problem">2. The Sock Merchant Problem</h2>
<div class="bd-anchor" id="the-sock-merchant-problem"></div>
<p>In the Sock Merchant problem, we have a merchant with a large pile of socks for sale that must be paired by color. We represent the socks&#8217; colors by an array of integers, <em>socks</em>. <strong>The merchant&#8217;s goal is to determine how many pairs of matching socks there are.</strong></p>
<p>Therefore, we have three inputs:</p>
<ul>
<li><em>n:</em> the number of socks in the collection</li>
<li><em>socks</em>: the array holding the colors of <em>n</em> socks</li>
<li><em>k</em>: the maximal color ID in this array, meaning 1 &lt;= s<em>ocks</em>[<em>i</em>] &lt;= <em>k</em> (for 0 &lt;=<em> i</em> &lt; n).</li>
</ul>
<p>For example, let&#8217;s say we have <em>n </em>= 7 socks with soc<em>ks</em> = [11, 22, 22, 11, 111, 33, 222] and <em>k</em>=222:</p>
<img decoding="async" class="aligncenter size-full wp-image-243945" src="https://www.baeldung.com/wp-content/uploads/2026/06/sockMerchant-1.png" alt="Visualatizaton of Socks color" />
<p>Here, we have only 5 colors. with one pair of color 11 and one of color 222. There are three odd socks left, one of each color. Hence, we return 2 as the number of pairs.</p>
<h2 id="bd-array-based-solution" data-id="array-based-solution">3. Array-Based Solution</h2>
<div class="bd-anchor" id="array-based-solution"></div>
<p data-path-to-node="7"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-common-array-operations">An array-based solution</a> works best when we know <em>k</em> is small. Here, we use an array <em>counts</em> to count the occurrences of each sock. Then, we iterate through it, dividing each count by two to calculate the total number of pairs:</p>
<pre><code class="language-java">public int countPairsWithArray(int n, int[] socks, int k) {
    int[] counts = new int[k];
    int pairs = 0;
    for (int i = 0; i &lt; n; i++) {
        counts[socks[i]]++;
    }
    for (int count : counts) {
        pairs += count / 2;
    }
    return pairs;
}</code></pre>
<p>Technically, we could omit <em>n</em> from the argument list and use <em>socks.length</em> in the code. We kept <em>n</em> in the method signature to follow the problem formulation more closely and make the solution easier to read.</p>
<p>This solution has time and space complexities of <em>O(n + k)</em>. If <em>k</em> is <em>O(n)</em>, the complexity simplifies to <em>O(n)</em>.</p>
<h2 id="bd-hashset-based-solution" data-id="hashset-based-solution">4. HashSet-Based Solution</h2>
<div class="bd-anchor" id="hashset-based-solution"></div>
<p><strong>An array-based solution degrades performance when the range of color IDs is unbounded, unknown, or very large. </strong>For instance<strong>,</strong> the <em>counts</em> array for a very large <em>k</em> could not only be sparse (mostly 0s) if the number of unique colors is much smaller, but also too large to fit in the memory.</p>
<p>For such cases, we use <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-hashset">HashSet</a>. Here, our HashSet <em>unmatchedSocks </em>stores unmatched socks. As we iterate through the input array,we check if the current sock&#8217;s color is already in <em>unmatchedSocks</em>:</p>
<ul>
<li>if it isn&#8217;t, we add it</li>
<li>otherwise, we have successfully found a pair!</li>
</ul>
<p>Whenever we find a pair, we increment our pair counter and remove that color from  <em>unmatchedSocks, s</em>o that the next pair of that color can be identified correctly:</p>
<pre><code class="language-java">public int countPairsWithSet(int[] socks) {
    Set&lt;Integer&gt; unmatchedSocks = new HashSet&lt;&gt;();
    int pairs = 0;
    for (int sock : socks) {
        if (unmatchedSocks.contains(sock)) {
            pairs++;
            unmatchedSocks.remove(sock);
        } else {
            unmatchedSocks.add(sock);
        }
    }
    return pairs;
}</code></pre>
<p>The HashSet-based solution&#8217;s average time complexity is <em>O(n)</em> since we iterate through the set exactly once, and HashSet operations <em>add()</em> and <em>size()</em> are <em>O(1)</em> on average.</p>
<p>However, <strong><em>HashSet</em> suffers from <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-frog-river-one">collisions</a>, so it has a log-linear <em>O(n log n)</em> worst-case time complexity for case where k is <em>O(n)</em>. </strong>If <em>k</em> is<em> O(1)</em>, the time complexity evaluates to <em>O(n), </em>which is same as that of  the array-based algorithm.</p>
<p>The space complexity is <em>O(n + k)</em>.</p>
<h2 id="bd-testing" data-id="testing">5. Testing</h2>
<div class="bd-anchor" id="testing"></div>
<h3 id="bd-1-array-based-solution-testing" data-id="1-array-based-solution-testing">5.1. Array-based Solution Testing</h3>
<div class="bd-anchor" id="1-array-based-solution-testing"></div>
<p>First, we test the array-based solution.</p>
<p>We create our socks array and pass it along with its length and the maximum color ID:</p>
<pre><code class="language-java">public void givenSockArray_whenUsingArray_thenReturnsCorrectPairCount() {
    SockMerchant merchant = new SockMerchant();
    int[] socks = {11, 22, 22, 11, 33, 3, 33, 111111, 33, 222222};
    int colorMax = 222223;
    int foundPairs = merchant.countPairsWithArray(socks.length, socks, colorMax);
    assertEquals(3, foundPairs);
}</code></pre>
<p>We expect the test to return 3 for success.</p>
<h3 id="bd-2-hashset-based-solution-testing" data-id="2-hashset-based-solution-testing">5.2. HashSet-based Solution Testing</h3>
<div class="bd-anchor" id="2-hashset-based-solution-testing"></div>
<p>Let&#8217;s test the HashSet-based solution:</p>
<pre><code class="language-java">public void givenSockArray_whenUsingSet_thenReturnsCorrectPairCount() {
    SockMerchant merchant = new SockMerchant();
    int[] socks = {11, 22, 22, 11, 33, 3, 33, 111111, 33, 222222};
    int foundPairs = merchant.countPairsWithSet(socks);
    assertEquals(3, actualPairs);
}</code></pre>
<p>As before, we expect the test to return 3 for success.</p>
<h2 id="bd-conclusion" data-id="conclusion">6. Conclusion</h2>
<div class="bd-anchor" id="conclusion"></div>
<p>In this article, we studied two solutions, based on two different <em>Java</em> data structures, for the Sock Merchant problem.</p>
<p>The array-based method is fast and memory-efficient when the color domain is small and the color IDs are contiguous. However, it wastes memory and computation time if the color IDs are sparse or <em>k</em> is exceedingly large.</p>
<p>On the other hand, the <em>HashSet</em> approach is more versatile since it can handle arbitrarily large integers and sparse datasets without allocating massive contiguous blocks of memory. Furthermore, we can adapt the <em>HashSet</em> logic to group custom objects or strings.</p>
<p>As always, the complete code examples are available <a href="https://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="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-sock-merchant-problem">How to Solve the Sock Merchant Problem in Java</a> first appeared on <a href="https://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/957603419/0/baeldung">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/957603419/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/957603419/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2024%2f11%2fAlgorithms-Featured-Image-01-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/957603419/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/957603419/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/957603419/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-sock-merchant-problem#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-sock-merchant-problem/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/~/957603419/0/baeldung~How-to-Solve-the-Sock-Merchant-Problem-in-Java/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<webfeeds:featuredImage>https://www.baeldung.com/wp-content/uploads/2024/11/Algorithms-Featured-Image-01-150x150.jpg</webfeeds:featuredImage></item>
<item>
<feedburner:origLink>https://www.baeldung.com/java-selenium-wait-complex-javascript</feedburner:origLink>
		<title>Waiting for Complex Page With JavaScript to Load in Selenium WebDriver</title>
		<link>https://feeds.feedblitz.com/~/957590264/0/baeldung~Waiting-for-Complex-Page-With-JavaScript-to-Load-in-Selenium-WebDriver</link>
					<comments>https://feeds.feedblitz.com/~/957590264/0/baeldung~Waiting-for-Complex-Page-With-JavaScript-to-Load-in-Selenium-WebDriver#respond</comments>
		
		<dc:creator><![CDATA[Ulisses Lima]]></dc:creator>
		<pubDate>Sun, 31 May 2026 17:27:48 +0000</pubDate>
				<category><![CDATA[Testing]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Selenium]]></category>
		<guid isPermaLink="false">https://www.baeldung.com/java-selenium-wait-complex-javascript</guid>
					<description><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/2024/11/featured-images-selenium-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 various strategies for waiting until a JavaScript-heavy page is fully loaded in Selenium WebDriver.</p>
The post <a rel="NOFOLLOW" href="https://feeds.feedblitz.com/~/957590264/0/baeldung~Waiting-for-Complex-Page-With-JavaScript-to-Load-in-Selenium-WebDriver">Waiting for Complex Page With JavaScript to Load in Selenium WebDriver</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/957590264/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/957590264/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2024%2f11%2ffeatured-images-selenium-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/957590264/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/957590264/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/957590264/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-selenium-wait-complex-javascript#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-selenium-wait-complex-javascript/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/featured-images-selenium-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/featured-images-selenium-1024x536.jpg 1024w, https://www.baeldung.com/wp-content/uploads/2024/11/featured-images-selenium-300x157.jpg 300w, https://www.baeldung.com/wp-content/uploads/2024/11/featured-images-selenium-768x402.jpg 768w, https://www.baeldung.com/wp-content/uploads/2024/11/featured-images-selenium-100x52.jpg 100w, https://www.baeldung.com/wp-content/uploads/2024/11/featured-images-selenium-600x314.jpg 600w, https://www.baeldung.com/wp-content/uploads/2024/11/featured-images-selenium.jpg 1200w" sizes="auto, (max-width: 580px) 100vw, 580px" /><h2 id="bd-introduction" data-id="introduction">1. Introduction</h2>
<div class="bd-anchor" id="introduction"></div>
<p>When testing applications with Selenium, waiting for a page to load completely is more complex when it comes to modern pages, as they rely heavily on JavaScript for rendering. These kinds of pages make asynchronous calls and manipulate the DOM after the initial HTML has loaded. Therefore, checking if it&#8217;s loaded isn&#8217;t sufficient to ensure the app is ready for interaction.</p>
<p>Introducing an arbitrary delay is a common but problematic choice. If the page loads faster than the delay, the test wastes time. Otherwise, if the page loads slower due to network conditions or server response time, the test may fail.</p>
<p>In this tutorial, we&#8217;ll explore different strategies for waiting until a JavaScript-heavy page is fully loaded in Selenium <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/selenium-webdriver-page-object"><em>WebDriver</em></a> without introducing arbitrary delays.</p>
<h2 id="bd-problem-and-setup" data-id="problem-and-setup">2. Problem and Setup</h2>
<div class="bd-anchor" id="problem-and-setup"></div>
<p>We&#8217;ll define a page as loaded when all asynchronous operations for the current view have completed. This includes HTTP requests, dynamic DOM updates, and framework-specific processing. Navigating to a new view is treated as a new page load that requires its own wait strategy.</p>
<p>Selenium provides two main wait strategies. With <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/selenium-implicit-explicit-wait#1-implicit-wait">implicit waits</a>, we set a global timeout for element lookups. On the other hand, with <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/selenium-implicit-explicit-wait#2-explicit-wait">explicit waits</a>, we wait for specific conditions using a <em>WebDriverWait</em> instance. We&#8217;ll only use explicit waits, which provide precise control over what conditions to check.</p>
<h3 id="bd-1-creating-a-helper-class" data-id="1-creating-a-helper-class">2.1. Creating a Helper Class</h3>
<div class="bd-anchor" id="1-creating-a-helper-class"></div>
<p><strong>Let&#8217;s create a helper class that encapsulates our waiting logic. It wraps a <em>WebDriverWait</em> instance and requires a <em>timeout</em> value so our tests don&#8217;t wait indefinitely in unexpected scenarios:</strong></p>
<pre><code class="language-java">public class PageLoadHelper {
    private final WebDriverWait wait;
    public PageLoadHelper(WebDriver driver, Duration timeout) {
        this.wait = new WebDriverWait(driver, timeout);
    }
    // ...
}</code></pre>
<p>We&#8217;ll add all the different wait strategies to this class, making them easy to reuse. <strong>We&#8217;ll only need the <em>until()</em> method from <em>WebDriverWait</em>, which polls the condition until it returns true or times out.</strong> This condition is written as a <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-8-lambda-expressions-tips">lambda</a> that takes the current driver:</p>
<pre><code class="language-java">public void waitUntil() { 
    wait.until(driver -&gt; { 
        JavascriptExecutor js = (JavascriptExecutor) driver; 
        return // condition...
    }); 
}</code></pre>
<p><strong>While we won&#8217;t need a specific driver implementation, the only requirement is that it implements the </strong><span style="margin: 0px;padding: 0px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.javadoc.io/doc/org.seleniumhq.selenium/selenium-api/4.38.0/org/openqa/selenium/JavascriptExecutor.html" target="_blank" rel="noopener"><strong>JavaScriptExecutor</strong></a><strong> interface</strong></span><strong>.</strong> We need this because the states we want to query are only accessible through the browser&#8217;s JavaScript runtime, not via the standard <em>WebDriver</em> API.</p>
<p>Also, since some of the checks rely on specific frameworks, most methods in this article start with checks such as <em>typeof someFrameworkObject === &#8216;undefined&#8217;</em>. If the framework isn&#8217;t there, the condition returns <em>true</em> immediately, making the method safe to call on any page and useful when chaining.</p>
<h2 id="bd-waiting-for-document-ready-state" data-id="waiting-for-document-ready-state">3. Waiting for Document Ready State</h2>
<div class="bd-anchor" id="waiting-for-document-ready-state"></div>
<p>The most fundamental check is inspecting the browser&#8217;s <em>document.readyState</em> property. <strong>This property becomes <em>complete</em> when the page and all its resources have finished loading.</strong> It&#8217;s the default behavior of <em>driver.get()</em>. It&#8217;s useful for SPA navigation, such as right after clicking a link that changes the view without a full page reload.</p>
<p>Let&#8217;s add a method to our <em>PageLoadHelper</em> that executes a script and waits until it returns the result we&#8217;re looking for:</p>
<pre><code class="language-java">public void waitForDocumentReady() {
    wait.until(driver -&gt; {
        JavascriptExecutor js = (JavascriptExecutor) driver;
        return js.executeScript("return document.readyState")
          .equals("complete");
    });
}</code></pre>
<p><strong>While this covers the initial HTML page load, it doesn&#8217;t apply to asynchronous JavaScript that runs after the DOM is ready.</strong></p>
<h2 id="bd-waiting-for-jquery-ajax-calls-to-complete" data-id="waiting-for-jquery-ajax-calls-to-complete">4. Waiting for jQuery AJAX Calls to Complete</h2>
<div class="bd-anchor" id="waiting-for-jquery-ajax-calls-to-complete"></div>
<p>Many apps still use jQuery for AJAX requests. It maintains an internal counter, <em>jQuery.active</em>, that tracks the number of pending requests. When this reaches zero, all requests have completed.</p>
<p>Let&#8217;s add a method that checks whether there are any pending requests:</p>
<pre><code class="language-java">public void waitForJQueryToFinish() {
    wait.until(driver -&gt; {
        JavascriptExecutor js = (JavascriptExecutor) driver;
        return (Boolean) js.executeScript(
          "return (typeof jQuery === 'undefined') || (jQuery.active === 0)");
    });
}</code></pre>
<p>It first checks whether jQuery is present on the page. If not, the condition returns true immediately.<strong> This type of guard is useful when building a universal test suite, and not all pages use jQuery. </strong></p>
<p>However, if an AJAX request hasn&#8217;t started yet when we call it, the condition sees <em>jQuery.active === 0</em> and returns before any request fires. So, let&#8217;s create another method that waits for a request to start:</p>
<pre><code class="language-java">public void waitForJQueryToStart() {
    wait.until(driver -&gt; {
        JavascriptExecutor js = (JavascriptExecutor) driver;
        return (Boolean) js.executeScript(
          "return (typeof jQuery === 'undefined') || (jQuery.active &gt; 0)");
    });
}</code></pre>
<p><strong>We can then chain these two to ensure that requests start before waiting for them to finish. </strong>But even with this approach, if all requests fire and complete before we have a chance to observe <em>jQuery.active </em>increasing, we&#8217;ll end up waiting until Selenium times out.</p>
<h2 id="bd-waiting-for-modern-angular-apps-to-stabilize" data-id="waiting-for-modern-angular-apps-to-stabilize">5. Waiting for Modern Angular Apps to Stabilize</h2>
<div class="bd-anchor" id="waiting-for-modern-angular-apps-to-stabilize"></div>
<p>Angular 2+ uses RxJS for HTTP calls, and it provides a <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://angular.dev/api/core/Testability">testability API</a> that allows us to check if the app is stable, meaning that it has completed all pending requests:</p>
<pre><code class="language-java">public Boolean waitForModernAngularAppStable() {
    return wait.until(driver -&gt; {
        JavascriptExecutor js = (JavascriptExecutor) driver;
        String script = """
          return (
            typeof getAllAngularTestabilities === 'undefined' 
            || getAllAngularTestabilities().every(t =&gt; t.isStable())
          )
          """;
        return (Boolean) js.executeScript(script);
    });
}</code></pre>
<p><strong>We check <span style="margin: 0px;padding: 0px">whether <em>getAllAngularTestabilities</em> is <em>undefined</em></span> to guard against future API changes.</strong></p>
<h2 id="bd-waiting-for-react-apps-to-be-ready" data-id="waiting-for-react-apps-to-be-ready">6. Waiting for React Apps to Be Ready</h2>
<div class="bd-anchor" id="waiting-for-react-apps-to-be-ready"></div>
<p>React apps don&#8217;t have a built-in JavaScript API we can use to test app readiness universally, so we have to handle it on a case-by-case basis. <strong>A common approach is to make an element visible only after we&#8217;ve finished making all the requests we need.</strong></p>
<p>Something as simple as a &#8220;done&#8221; flag that adds a CSS class to a button is enough:</p>
<pre><code class="language-xml">&lt;button id="doneButton" className={done ? 'visible' : ''}&gt;
    All Done
&lt;/button&gt;</code></pre>
<p><strong>Then, we can add an all-purpose method to wait for elements to be clicked:</strong></p>
<pre><code class="language-java">public void waitForElementToBeClickable(By locator) {
    wait.until(ExpectedConditions.elementToBeClickable(locator));
}</code></pre>
<p>Finally, we can test it by passing the ID of the element:</p>
<pre><code class="language-java">@Test
void whenWaitForElementClickable_thenClickable() {
    driver.get(PAGE_URL);
    pageLoadHelper.waitForElementToBeClickable(By.id("doneButton")); 
    
    assertTrue(driver.findElement(By.id("doneButton")).isDisplayed()); 
}</code></pre>
<p><strong>This approach isn&#8217;t limited to React and can be used with any page.</strong> Most importantly, the <em>done</em> flag must be set when the application is truly ready for interaction. If completing the initial set of requests triggers additional requests, the flag must account for the entire chain before being set to <em>true</em>.</p>
<h2 id="bd-injecting-a-custom-flag-in-the-window-object" data-id="injecting-a-custom-flag-in-the-window-object">7. Injecting a Custom Flag in the Window Object</h2>
<div class="bd-anchor" id="injecting-a-custom-flag-in-the-window-object"></div>
<p>In modern JavaScript apps, we usually use Promises to make requests, and we can use the &#8220;<em>Promise.all()</em>&#8221; function to wait for a set of promises to complete. Most importantly, if we don&#8217;t have access to a universal tool, we can always modify the <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.w3schools.com/js/js_window.asp">window</a> variable to include our own flags.</p>
<p><strong>So, if we know the slowest part of the app is completing a set of promises and we can&#8217;t reliably use the app before that, one alternative is creating a simple listener that adds a flag indicating when our app is ready:</strong></p>
<pre><code class="language-javascript">window.appReady = false;
// start promises ...
Promise.all(promises).then(() =&gt; {
    window.appReady = true;
});</code></pre>
<p><strong>It&#8217;s important to initialize the variable to <em>false</em> so we don&#8217;t get <em>undefined</em> when reading its value.</strong> We can then wait until this flag appears when testing the app with Selenium:</p>
<pre><code class="language-java">public void waitForJsAppReady() {
    wait.until(driver -&gt; {
        JavascriptExecutor js = (JavascriptExecutor) driver;
        return (Boolean) js.executeScript(
          """
          return (
            typeof window.appReady === 'undefined' 
            || window.appReady === true
          )
          """);
    });
}</code></pre>
<p>This will work for any app running in a modern browser.</p>
<h2 id="bd-patching-the-fetch-api" data-id="patching-the-fetch-api">8. Patching the Fetch API</h2>
<div class="bd-anchor" id="patching-the-fetch-api"></div>
<p>Another common approach <span style="margin: 0px;padding: 0px">in modern JavaScript apps is to use <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://developer.mozilla.org/en-US/docs/Web/API/Window/fetch" target="_blank" rel="noopener"><em>fetch</em></a>, which also doesn&#8217;t provide a standard way to count</span> pending requests. So, one option is to implement it on our own. We can do this by replacing the fetch implementation with a custom one that increments a global <em>fetchPending</em> counter and delegates the actual execution to the original implementation:</p>
<pre><code class="language-javascript">window.fetchPending = 0;
const originalFetch = window.fetch;
window.fetch = function(...args) {
    window.fetchPending++;
    return originalFetch.apply(this, args)
      .finally(() =&gt; window.fetchPending--);
};</code></pre>
<p><strong>This must be called before the requests we want to track are fired. Then, every request made with the <em>fetch</em> command becomes trackable (even on error, since we decrement it in a <em>finally</em> block).</strong> Finally, we can wait until <em>fetchPending</em> reaches zero, like in our <em>appReady</em> solution.</p>
<p>For requests that fire automatically on page load, the interception must happen before navigation. Selenium now supports this via the <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.selenium.dev/documentation/webdriver/bidi/cdp/">Chrome DevTools Protocol</a>, but that is beyond the scope of this article.</p>
<h2 id="bd-summary" data-id="summary">9. Summary</h2>
<div class="bd-anchor" id="summary"></div>
<p>The strategies we covered address different scenarios. Let&#8217;s see how they compare:</p>
<table class="table-styled">
<thead>
<tr>
<th>Approach</th>
<th>Best for</th>
<th>Limitation</th>
</tr>
</thead>
<tbody>
<tr>
<td>document.readyState</td>
<td>All pages; SPA navigation</td>
<td>Already the default for driver.get(); doesn&#8217;t cover post-load async ops</td>
</tr>
<tr>
<td>jQuery.active counter</td>
<td>Pages using jQuery</td>
<td>Race condition if requests haven&#8217;t started; chain with waitForJQueryToStart()</td>
</tr>
<tr>
<td>Angular testability API</td>
<td>Angular 2+ apps</td>
<td>May not work with all Angular configurations</td>
</tr>
<tr>
<td>ExpectedConditions.elementToBeClickable</td>
<td>Any page with a sentinel element</td>
<td>Only checks the DOM state, not pending requests</td>
</tr>
<tr>
<td>Window flag (window.appReady)</td>
<td>Any app with code-level control</td>
<td>Requires modifying the application under test</td>
</tr>
<tr>
<td>Fetch API interception</td>
<td>Apps using the Fetch API</td>
<td>Must intercept before requests fire; auto-load requests require CDP</td>
</tr>
</tbody>
</table>
<p><strong>In practice, combining strategies works best: start with <em>waitForDocumentReady()</em>, apply a framework-specific check, then confirm a meaningful element is interactable.</strong></p>
<h2 id="bd-10-conclusion" data-id="10-conclusion">10. Conclusion</h2>
<div class="bd-anchor" id="10-conclusion"></div>
<p>In this article, we explored several strategies for waiting until JavaScript-heavy pages fully load using Selenium. We started with the basic <em>document.readyState</em> check and covered Selenium&#8217;s built-in <em>WebDriverWait</em> for waiting on element states. We also extended our approach to handle jQuery AJAX calls, modern Angular applications, alternatives to React components, and pure JavaScript apps.</p>
<p>No single strategy covers all cases, and the right choice depends on the technologies the app uses and the level of control we have over its source code. Using a helper class like <em>PageLoadHelper</em> simplifies composing and reusing strategies across a test suite.</p>
<p>As always, the source code is available <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/eugenp/tutorials/tree/master/testing-modules/selenium-3">over on GitHub</a>.</p>The post <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-selenium-wait-complex-javascript">Waiting for Complex Page With JavaScript to Load in Selenium WebDriver</a> first appeared on <a href="https://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/957590264/0/baeldung">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/957590264/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/957590264/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2024%2f11%2ffeatured-images-selenium-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/957590264/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/957590264/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/957590264/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-selenium-wait-complex-javascript#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-selenium-wait-complex-javascript/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/~/957590264/0/baeldung~Waiting-for-Complex-Page-With-JavaScript-to-Load-in-Selenium-WebDriver/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<webfeeds:featuredImage>https://www.baeldung.com/wp-content/uploads/2024/11/featured-images-selenium-150x150.jpg</webfeeds:featuredImage></item>
<item>
<feedburner:origLink>https://www.baeldung.com/spring-ai-subagent-orchestration</feedburner:origLink>
		<title>Guide to Subagent Orchestration in Spring AI</title>
		<link>https://feeds.feedblitz.com/~/957590267/0/baeldung~Guide-to-Subagent-Orchestration-in-Spring-AI</link>
					<comments>https://feeds.feedblitz.com/~/957590267/0/baeldung~Guide-to-Subagent-Orchestration-in-Spring-AI#respond</comments>
		
		<dc:creator><![CDATA[Sagar Verma]]></dc:creator>
		<pubDate>Sun, 31 May 2026 17:19:02 +0000</pubDate>
				<category><![CDATA[Spring AI]]></category>
		<category><![CDATA[Spring AI ChatClient]]></category>
		<guid isPermaLink="false">https://www.baeldung.com/spring-ai-subagent-orchestration</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;" loading="lazy" /><p>Learn how to build a subagent orchestration system using Spring AI and Spring AI Community Agent Utils.</p>
The post <a rel="NOFOLLOW" href="https://feeds.feedblitz.com/~/957590267/0/baeldung~Guide-to-Subagent-Orchestration-in-Spring-AI">Guide to Subagent Orchestration in Spring AI</a> first appeared on <a rel="NOFOLLOW" href="https://www.baeldung.com">Baeldung</a>.<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/957590267/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/957590267/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/957590267/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/957590267/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/957590267/baeldung"><img height="20" src="https://assets.feedblitz.com/i/rss20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a rel="NOFOLLOW" title="View Comments" href="https://www.baeldung.com/spring-ai-subagent-orchestration#respond"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/comments20.png"></a>&#160;<a title="Follow Comments via RSS" href="https://www.baeldung.com/spring-ai-subagent-orchestration/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 data-section- data-start="165" data-end="178" id="bd-1f89aca" data-id="1f89aca">1. Overview</h2>
<div class="bd-anchor" id="1f89aca"></div>
<p>As AI systems grow more capable, a single “generalist” agent often becomes inefficient. It tries to handle everything in one context window, which leads to noisy prompts, slower responses, and degraded output quality. A better approach is to split responsibilities across specialized agents and let a central orchestrator coordinate them.</p>
<p><strong>This is exactly what <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://spring.io/blog/2026/01/27/spring-ai-agentic-patterns-4-task-subagents">Subagent Orchestration</a> enables in <span class="hover:entity-accent entity-underline inline cursor-pointer align-baseline"><span class="whitespace-normal">Spring AI</span></span>. Using the <em><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/spring-ai-community/spring-ai-agent-utils/blob/main/spring-ai-agent-utils/docs/TaskTools.md">Task</a></em><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/spring-ai-community/spring-ai-agent-utils/blob/main/spring-ai-agent-utils/docs/TaskTools.md"> tool</a> from the <em>spring-ai-agent-utils</em> library, we can build hierarchical agent systems where each subagent works in an isolated context and returns only essential results.</strong></p>
<p>In this tutorial, we&#8217;ll implement this pattern end-to-end using real APIs from the Spring ecosystem. We&#8217;ll learn how the orchestration works, how to configure subagents, and how to build a working system that dynamically delegates tasks.</p>
<h2 data-section- data-start="1058" data-end="1099" id="bd-rng8ig" data-id="rng8ig">2. Understanding Subagent Orchestration</h2>
<div class="bd-anchor" id="rng8ig"></div>
<p><strong>Subagent orchestration is a pattern where a primary AI agent delegates work to smaller, specialized agents</strong>. Each subagent is designed for a specific responsibility and operates in its own context window. This isolation ensures that prompts remain focused and prevents unnecessary information from polluting the reasoning process.</p>
<p><strong>Unlike traditional service orchestration, the delegation decision isn&#8217;t hardcoded. The main agent uses LLM to decide when a task should be delegated</strong>. This decision is based on natural language descriptions provided for each subagent, making the system flexible and adaptive. This approach improves separation of concerns, prompt clarity, maintainability, extensibility, and model specialization.</p>
<h3 id="bd-1-why-use-specialized-subagents" data-id="1-why-use-specialized-subagents">2.1. Why Use Specialized Subagents?</h3>
<div class="bd-anchor" id="1-why-use-specialized-subagents"></div>
<p>Specialized subagents help us create more modular AI systems. For example, in an AI travel assistant, one subagent can search flights, another can recommend hotels, and another can build personalized itineraries based on user preferences. This allows each subagent to focus on a specialized responsibility instead of relying on a single large prompt.</p>
<p>Each subagent receives a focused responsibility instead of competing for context inside a shared workflow. This pattern becomes especially useful in enterprise systems where AI applications continue to grow in complexity over time.</p>
<h3 id="bd-2-how-spring-ai-supports-orchestration" data-id="2-how-spring-ai-supports-orchestration">2.2. How Spring AI Supports Orchestration</h3>
<div class="bd-anchor" id="2-how-spring-ai-supports-orchestration"></div>
<p>Spring AI Community Agent Utils provides orchestration utilities through <em>TaskTool</em> and <em>ClaudeSubagentReferences</em>. These components help us register subagents, load subagent definitions dynamically, delegate tasks automatically, and orchestrate multiple AI workflows.</p>
<p>One of the most interesting aspects of this approach is that subagents can be defined in markdown files instead of Java classes.</p>
<h2 data-section- data-start="3384" data-end="3402" id="bd-1ibx8pa" data-id="1ibx8pa">3. Project Setup</h2>
<div class="bd-anchor" id="1ibx8pa"></div>
<p>Before implementing Subagent Orchestration, we’ll set up a simple <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/spring-boot">Spring Boot</a> application using <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://start.spring.io/" target="_blank" rel="noopener">Spring Initializr</a> with <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://mvnrepository.com/artifact/org.springframework.ai/spring-ai-openai-spring-boot-starter/">Spring AI starter OpenAI</a>, <em><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-test/">starter-test</a>,</em> and <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://mvnrepository.com/artifact/org.springaicommunity/spring-ai-agent-utils/">Spring AI Community Agent Utils</a>. We’ll first add the required dependencies and then configure the OpenAI model and markdown-based subagent definitions.</p>
<p>In this application, we&#8217;ll build an AI-powered orchestration system that delegates work to multiple specialized subagents. One subagent reviews the code quality of a Spring Boot application, while another generates concise technical documentation. A central orchestrator analyzes the user request and coordinates these subagents to produce a combined response.</p>
<h3 id="bd-1-adding-maven-dependencies" data-id="1-adding-maven-dependencies">3.1. Adding Maven Dependencies</h3>
<div class="bd-anchor" id="1-adding-maven-dependencies"></div>
<p>First, let&#8217;s configure the required dependencies:</p>
<pre><code class="language-java">&lt;dependencies&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
        &lt;artifactId&gt;spring-boot-starter-test&lt;/artifactId&gt;
        &lt;scope&gt;test&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;org.springframework.ai&lt;/groupId&gt;
        &lt;artifactId&gt;spring-ai-starter-model-openai&lt;/artifactId&gt;
        &lt;version&gt;2.0.0-M5&lt;/version&gt;
        &lt;scope&gt;compile&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;org.springaicommunity&lt;/groupId&gt;
        &lt;artifactId&gt;spring-ai-agent-utils&lt;/artifactId&gt;
        &lt;version&gt;0.4.2&lt;/version&gt;
    &lt;/dependency&gt;
&lt;/dependencies&gt;</code></pre>
<p>This configuration adds the core dependencies required for our application. These dependencies provide Spring Boot application support, OpenAI integration through Spring AI, orchestration utilities for subagents, and testing support. After adding the dependencies, we&#8217;ll configure the OpenAI API key.</p>
<h3 data-start="3917" data-end="4034" id="bd-2-configuring-openai-access" data-id="2-configuring-openai-access">3.2. Configuring OpenAI Access</h3>
<div class="bd-anchor" id="2-configuring-openai-access"></div>
<p>Next, we’ll configure the OpenAI API key, the default LLM model, and the location of the markdown-based subagent definitions inside <em data-start="760" data-end="784">application.properties</em>:</p>
<pre><code class="language-yaml">spring.ai.openai.api-key=${OPENAI_API_KEY}
spring.ai.openai.chat.options.model=gpt-4.1-mini
spring.application.name=spring-ai-subagent
agent.tasks.paths=classpath:/agents/*.md</code></pre>
<p>We should replace <em data-start="361" data-end="377">OPENAI_API_KEY</em> with a valid <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://platform.openai.com/settings/organization/api-keys">OpenAI API key</a> or expose it through an environment variable to avoid storing sensitive credentials directly in the codebase.</p>
<p>The <em data-start="520" data-end="539">agent.tasks.paths</em> property points to the markdown-based subagent definitions located under <em data-start="613" data-end="641">src/main/resources/agents/</em>. Spring AI uses these files to dynamically load and register specialized subagents during application startup.</p>
<h2 id="bd-creating-specialized-subagents" data-id="creating-specialized-subagents">4. Creating Specialized Subagents</h2>
<div class="bd-anchor" id="creating-specialized-subagents"></div>
<p>This project uses markdown files to define specialized subagents. Their locations are declared as classpath resources. This approach keeps agent behavior externalized and easy to maintain. First, we’ll create an <em>agents</em> directory under the path <em>src/main/resources/</em>.</p>
<h3 id="bd-1-creating-the-code-reviewer-subagent" data-id="1-creating-the-code-reviewer-subagent">4.1. Creating the Code Reviewer Subagent</h3>
<div class="bd-anchor" id="1-creating-the-code-reviewer-subagent"></div>
<p>Let’s create a subagent responsible for reviewing code quality. The Markdown body acts as the subagent’s system prompt and defines its specialized behavior.</p>
<p>We’ll add a <em>code-reviewer.md</em> file under path <em>src/main/resources/agents/ </em>with the following instructions:</p>
<pre><code class="language-yaml">---
name: code-reviewer
description: &gt;
  Expert code reviewer. Use proactively after writing or modifying code
  to surface quality, security, and readability issues.
tools: Read, Grep, Glob
disallowedTools: Edit, Write
model: sonnet
---
You are a senior code reviewer with expertise in software quality.
**When Invoked:**
1. Run `git diff` to identify recent changes
2. Inspect the modified files and surrounding context
3. Check for issues in the areas listed below
**Review Checklist:**
- Code clarity and readability
- Proper naming conventions
- Error handling and edge cases
- Security vulnerabilities
**Output:** Clear, actionable feedback organized by file, with line references.</code></pre>
<p>This subagent focuses only on code analysis responsibilities. Externalizing the behavior into markdown files makes it easier to evolve prompts without modifying Java classes.</p>
<h3 id="bd-2-creating-the-documentation-writer-subagent" data-id="2-creating-the-documentation-writer-subagent">4.2. Creating the Documentation Writer Subagent</h3>
<div class="bd-anchor" id="2-creating-the-documentation-writer-subagent"></div>
<p>Next, let’s create another subagent that specializes in technical documentation. We’ll add a <em>documentation-writer.md</em> file under <em>src/main/resources/agents/</em>and define the following instructions:</p>
<pre><code class="language-yaml">---
name: documentation-writer
description: &gt;
  Technical documentation specialist for architecture explanations,
  workflow summaries, and concise developer-facing docs.
model: default
---
You are a senior technical documentation specialist.
Your responsibilities:
- Generate concise technical documentation
- Explain Spring Boot and Java application architecture
- Summarize workflows clearly
- Produce developer-friendly explanations
- Keep documentation simple and technically accurate</code></pre>
<p>This subagent focuses entirely on generating developer documentation. Now we have two specialized subagents named <em>code-reviewer</em> and <em>documentation-writer</em>.</p>
<h2 id="bd-configuring-the-main-orchestrator-agent" data-id="configuring-the-main-orchestrator-agent">5. Configuring the Main Orchestrator Agent</h2>
<div class="bd-anchor" id="configuring-the-main-orchestrator-agent"></div>
<p><strong>The orchestrator is responsible for loading subagents, registering orchestration tools, and executing delegated workflows.</strong> This main agent is the entry point that a user interacts with directly. Its underlying large language model (LLM) has access to the <em>Tasktool</em>, which exposes a catalog of available subagents. When the main agent decides that a specialist better handles a portion of a user request, it invokes the <em>Tasktool</em>, passing in the subagent name and a task description.</p>
<h3 id="bd-1-configuring-subagent-references" data-id="1-configuring-subagent-references">5.1. Configuring Subagent References</h3>
<div class="bd-anchor" id="1-configuring-subagent-references"></div>
<p><em>Spring AI Community Agent Utils</em> provides <em>ClaudeSubagentReferences</em> to load markdown-based subagents. The following configuration dynamically loads subagents from the markdown resources directory:</p>
<pre><code class="language-java">@Configuration
public class AgentConfig {
    @Value("${agent.tasks.paths}")
    private List&lt;Resource&gt; agentPaths;
    @Bean
    @Primary
    public ChatClient orchestratorChatClient(ChatClient.Builder chatClientBuilder) {
        SubagentType claudeType = ClaudeSubagentType.builder()
          .chatClientBuilder("default", chatClientBuilder.clone())
          .build();
        ToolCallback taskTool = TaskTool.builder()
          .subagentReferences(ClaudeSubagentReferences.fromResources(agentPaths))
          .subagentTypes(claudeType)
          .build();
        return chatClientBuilder.clone()
          .defaultToolCallbacks(taskTool)
          .build();
    }
}</code></pre>
<p>The two key classes wire together are <em>TaskTool</em> (the tool that the orchestrator&#8217;s LLM calls) and <em>ClaudeSubagentType</em> (which tells the tool how to spawn a subagent and which <em>ChatClient.Builder</em> to use). Note this <em>.clone()</em> calls on <em>chatClientBuilder</em>.<strong> This is important because the orchestrator and each subagent need their own independent <em>ChatClient.Builder</em> instance so they do not share default options or system prompts.</strong></p>
<h3 id="bd-2-creating-the-orchestrator-service" data-id="2-creating-the-orchestrator-service">5.2. Creating the Orchestrator Service</h3>
<div class="bd-anchor" id="2-creating-the-orchestrator-service"></div>
<p>This service acts as the entry point for orchestrated AI requests. The main agent&#8217;s LLM automatically decides whether to delegate to a subagent based on the task descriptions in the Agent Registry:</p>
<pre><code class="language-yaml">@Service
public class OrchestratorService {
    private final ChatClient chatClient;
    public OrchestratorService(ChatClient chatClient) {
        this.chatClient = chatClient;
    }
    public String ask(String userMessage) {
        return chatClient.prompt(userMessage).call().content();
    }
}</code></pre>
<p>The service itself remains very small because the orchestration complexity is handled internally through Spring AI tools. <strong>Notice that there is no manual subagent invocation code here. The delegation happens transparently inside the LLM reasoning loop when the model selects the <em>Task</em> tool.</strong></p>
<h3 id="bd-3-execute-orchestrated-workflows" data-id="3-execute-orchestrated-workflows">5.3. Execute Orchestrated Workflows</h3>
<div class="bd-anchor" id="3-execute-orchestrated-workflows"></div>
<p>Now we&#8217;ll execute orchestrated workflows. The following method triggers multiple specialized subagents:</p>
<pre><code class="language-java">public class SpringAiSubagentApplication {
    private static final Logger logger = LoggerFactory.getLogger(SpringAiSubagentApplication.class);
    public static void main(String[] args) {
        SpringApplication.run(SpringAiSubagentApplication.class, args);
    }
    @Bean
    CommandLineRunner demo(OrchestratorService orchestratorService) {
        return args -&gt; {
            String response = orchestratorService.ask(
              """
              Perform the following tasks:
              - Review the code quality.
              - Generate concise technical documentation like user guide.
              """
            );
            logger.info("{}", response);
        };
    }
}</code></pre>
<p>This prompt allows the orchestrator to delegate responsibilities across multiple subagents. When we run the application, Spring AI loads the markdown-based subagents, routes the request through the orchestration layer, and generates a combined response from the specialized agents.</p>
<p>The following screenshot shows the output generated by the multi-subagent orchestration workflow:</p>
<a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/wp-content/uploads/2026/05/SpringAISubAgentOutput.png"><img decoding="async" class="aligncenter size-large wp-image-245173" src="https://www.baeldung.com/wp-content/uploads/2026/05/SpringAISubAgentOutput-1024x553.png" alt="Spring_AI_SubAgent_Output" /></a>
<p>From the generated response, we can clearly see how each subagent handles its own specialized responsibility. The <em data-start="1192" data-end="1207">code-reviewer</em> subagent focuses on analyzing code quality concerns, while the <em data-start="1289" data-end="1311">documentation-writer</em> subagent generates concise technical documentation. This separation of responsibilities is one of the main advantages of subagent orchestration.</p>
<h2 id="bd-testing-subagent-orchestration" data-id="testing-subagent-orchestration">6. Testing Subagent Orchestration</h2>
<div class="bd-anchor" id="testing-subagent-orchestration"></div>
<p>AI orchestration workflows should still be tested like any other application component. The application includes integration testing for orchestration behavior.</p>
<h3 id="bd-1-testing-subagent-loading" data-id="1-testing-subagent-loading">6.1. Testing Subagent Loading</h3>
<div class="bd-anchor" id="1-testing-subagent-loading"></div>
<p>The following test verifies that Spring AI can load subagent definitions correctly:</p>
<pre><code class="language-java">@Test
void givenSubagentDefinitions_whenLoadingSubagents_thenReferencesAreCreated() {
    var references = ClaudeSubagentReferences.fromResources(agentPaths);
    assertThat(references).isNotNull();
}</code></pre>
<p>This test ensures the orchestration layer can successfully load markdown-based subagents.</p>
<h3 id="bd-2-testing-orchestrated-responses" data-id="2-testing-orchestrated-responses">6.2. Testing Orchestrated Responses</h3>
<div class="bd-anchor" id="2-testing-orchestrated-responses"></div>
<p>Next, let’s verify that the orchestrator can execute requests successfully:</p>
<pre><code class="language-java">@Test
void givenPrompt_whenExecutingOrchestration_thenResponseIsGenerated() {
    List&lt;Resource&gt; agentResources = List.of(
      new ClassPathResource("agents/test-agent.md")
    );
    SubagentType claudeType = ClaudeSubagentType.builder()
      .chatClientBuilder("default", chatClientBuilder.clone())
      .build();
    ToolCallback taskTool = TaskTool.builder()
      .subagentReferences(ClaudeSubagentReferences.fromResources(agentResources))
      .subagentTypes(claudeType)
      .build();
    ChatClient chatClient = chatClientBuilder.clone()
      .defaultToolCallbacks(taskTool)
      .build();
    String result = chatClient.prompt("Explain how the authentication module works.")
      .call()
      .content();
    assertThat(result).isNotBlank();
    assertThat(result).contains("authentication");
}</code></pre>
<p>This integration test validates the orchestration flow. Here, the unit test should mock the model layer and verify the orchestration output. This test validates the service contract and keeps orchestration behavior verifiable without external API calls.</p>
<h2 id="bd-conclusion" data-id="conclusion">7. Conclusion</h2>
<div class="bd-anchor" id="conclusion"></div>
<p>In this article, we built a subagent orchestration system using Spring AI and Spring AI Community Agent Utils. We  created specialized subagents for code review and technical documentation, then orchestrated them through a centralized AI workflow. This approach helps keep AI systems modular, maintainable, and easier to evolve.</p>
<p>We also explored how Spring AI provides a clean and declarative way to build hierarchical multi-agent systems. By isolating each subagent within its own context window, we can reduce the context pollution that often impacts single-agent workflows. The Markdown-based configuration makes it straightforward to define and version subagents without introducing additional Java implementations. We also saw how <em data-start="765" data-end="775">TaskTool</em> acts as the bridge between the orchestrator and specialized subagents.</p>
<p>As AI applications continue to grow in complexity, subagent orchestration offers a practical way to distribute responsibilities among focused agents rather than relying on a single large prompt.</p>
<p>As always, the code for this example is available <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/eugenp/tutorials/tree/master/spring-ai-modules/spring-ai-subagent-orchestrator">over on GitHub</a>.</p>The post <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/spring-ai-subagent-orchestration">Guide to Subagent Orchestration in Spring AI</a> first appeared on <a href="https://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/957590267/0/baeldung">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/957590267/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/957590267/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/957590267/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/957590267/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/957590267/baeldung"><img height="20" src="https://assets.feedblitz.com/i/rss20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a rel="NOFOLLOW" title="View Comments" href="https://www.baeldung.com/spring-ai-subagent-orchestration#respond"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/comments20.png"></a>&#160;<a title="Follow Comments via RSS" href="https://www.baeldung.com/spring-ai-subagent-orchestration/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/~/957590267/0/baeldung~Guide-to-Subagent-Orchestration-in-Spring-AI/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/spring-ai-embed-mcp-server-html-ui</feedburner:origLink>
		<title>Embedding HTML UIs in MCP Servers With Spring AI</title>
		<link>https://feeds.feedblitz.com/~/957590270/0/baeldung~Embedding-HTML-UIs-in-MCP-Servers-With-Spring-AI</link>
					<comments>https://feeds.feedblitz.com/~/957590270/0/baeldung~Embedding-HTML-UIs-in-MCP-Servers-With-Spring-AI#respond</comments>
		
		<dc:creator><![CDATA[Emanuel Trandafir]]></dc:creator>
		<pubDate>Sun, 31 May 2026 17:16:19 +0000</pubDate>
				<category><![CDATA[Spring AI]]></category>
		<category><![CDATA[MCP]]></category>
		<category><![CDATA[Spring AI ChatClient]]></category>
		<guid isPermaLink="false">https://www.baeldung.com/spring-ai-embed-mcp-server-html-ui</guid>
					<description><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/2016/10/social-Java-On-Baeldung-2.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 build a Spring AI MCP server, connect it to Claude Desktop, and embed interactive HTML UIs directly inside AI chat conversations.</p>
The post <a rel="NOFOLLOW" href="https://feeds.feedblitz.com/~/957590270/0/baeldung~Embedding-HTML-UIs-in-MCP-Servers-With-Spring-AI">Embedding HTML UIs in MCP Servers With Spring AI</a> first appeared on <a rel="NOFOLLOW" href="https://www.baeldung.com">Baeldung</a>.<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/957590270/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/957590270/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2016%2f10%2fsocial-Java-On-Baeldung-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/957590270/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/957590270/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/957590270/baeldung"><img height="20" src="https://assets.feedblitz.com/i/rss20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a rel="NOFOLLOW" title="View Comments" href="https://www.baeldung.com/spring-ai-embed-mcp-server-html-ui#respond"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/comments20.png"></a>&#160;<a title="Follow Comments via RSS" href="https://www.baeldung.com/spring-ai-embed-mcp-server-html-ui/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-Java-On-Baeldung-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/2016/10/social-Java-On-Baeldung-2.jpg 952w, https://www.baeldung.com/wp-content/uploads/2016/10/social-Java-On-Baeldung-2-300x157.jpg 300w, https://www.baeldung.com/wp-content/uploads/2016/10/social-Java-On-Baeldung-2-768x402.jpg 768w" 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>MCP (Model Context Protocol) servers are the basis of modern AI handling and development. To that end, knowing how to configure one and integrate it into projects can be essential.</p>
<p>In this tutorial, <strong>we&#8217;ll learn how to build an MCP server with Spring AI and connect it to an AI harness such as Claude Desktop</strong>. To start, we create a simple <em>hello-world</em> tool, test it using the MCP Inspector, and then register it with Claude Desktop as a custom connector.</p>
<p>Once the basics are in place, we&#8217;ll take it one step further and expose a rich, interactive HTML UI — a fortune wheel that randomly picks today&#8217;s sport. In that implementation, we&#8217;ll see how Spring AI&#8217;s <em>@McpTool</em> and <em>@McpResource</em> annotations let the harness render the page inline in the chat and feed the result back into the conversation.</p>
<h2 id="bd-creating-an-mcp-server" data-id="creating-an-mcp-server">2. Creating an MCP Server</h2>
<div class="bd-anchor" id="creating-an-mcp-server"></div>
<p>The <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/spring-ai-model-context-protocol-mcp">Model Context Protocol (MCP)</a> provides a standardized way for AI assistants such as Claude Code or Claude Desktop to invoke some custom functionality whenever the model sees fit. <strong>An MCP server is the lightweight backend that exposes this functionality via <em>tools</em>, <em>resources</em>, and <em>prompts</em></strong>.</p>
<p>Let&#8217;s start by creating a simple <em>hello-world</em> MCP server. First, we add the <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://mvnrepository.com/artifact/org.springframework.ai/spring-ai-mcp-server-webmvc-spring-boot-starter"><em>spring-ai-starter-mcp-server-webmvc</em></a> dependency to the <em>pom.xml</em>:</p>
<pre><code class="language-xml">&lt;dependency&gt;
  &lt;groupId&gt;org.springframework.ai&lt;/groupId&gt;
  &lt;artifactId&gt;spring-ai-starter-mcp-server-webmvc&lt;/artifactId&gt;
&lt;/dependency&gt;</code></pre>
<p>Additionally, we use <em><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://mvnrepository.com/artifact/org.springframework.ai/spring-ai-bom">spring-ai-bom</a></em> for version management:</p>
<pre><code class="language-">&lt;dependencyManagement&gt;
  &lt;dependencies&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;org.springframework.ai&lt;/groupId&gt;
      &lt;artifactId&gt;spring-ai-bom&lt;/artifactId&gt;
      &lt;version&gt;2.0.0-M6&lt;/version&gt;
      &lt;type&gt;pom&lt;/type&gt;
      &lt;scope&gt;import&lt;/scope&gt;
    &lt;/dependency&gt;
  &lt;/dependencies&gt;
&lt;/dependencyManagement&gt;</code></pre>
<p>Then, let&#8217;s configure the server port and the MCP transport protocol that the server exposes. Spring AI supports three transport options:</p>
<ul>
<li><em><strong>stdio</strong></em> for local process-based communication</li>
<li><em><strong>sse</strong></em> for the legacy HTTP transport based on Server-Sent Events</li>
<li><em><strong>streamable</strong></em> for the newer Streamable HTTP transport that handles both requests and streamed responses over a single endpoint</li>
</ul>
<p>Here, we use the <em>streamable</em> protocol. So, let&#8217;s configure it in <em>application.properties:</em></p>
<pre><code class="language-properties">server.port=3001
spring.ai.mcp.server.protocol=STREAMABLE</code></pre>
<p>Finally, we add a <em>tool</em> that says <em>hello</em> from the server back to the user:</p>
<pre><code class="language-java">@SpringBootApplication
class McpUiApplication {
    public static void main(String[] args) {
        SpringApplication.run(McpUiApplication.class, args);
    }
    @McpTool(
        title = "Say Hello",
        name = "say-hello",
        description = "A simple tool that returns a greeting message."
    )
    String sayHello() {
        return "Hello from the MCP UI Application!";
    }
}</code></pre>
<p>As expected, this tool is exposed to the AI agent, and the greeting message is returned to the user whenever the model decides to invoke it.</p>
<h2 id="bd-testing-the-mcp-server" data-id="testing-the-mcp-server">3. Testing the MCP Server</h2>
<div class="bd-anchor" id="testing-the-mcp-server"></div>
<p>There are several ways to connect to and test an MCP server. Let&#8217;s try to use some of them to do that and trigger the <em>Say Hello</em> tool.</p>
<h3 id="bd-1-test-using-mcp-inspector" data-id="1-test-using-mcp-inspector">3.1. Test Using MCP Inspector</h3>
<div class="bd-anchor" id="1-test-using-mcp-inspector"></div>
<p><strong>One convenient option is the <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://modelcontextprotocol.io/docs/tools/inspector">MCP Inspector</a>, an interactive developer tool designed for testing and debugging MCP servers</strong>:</p>
<pre><code class="language-bash">npx @modelcontextprotocol/inspector</code></pre>
<p>This command starts a local proxy server along with a web-based UI that we can open in the browser to test the MCP. Using this interface, we can perform different actions:</p>
<ol>
<li>connect to an MCP server</li>
<li>see the <em>resources</em>, <em>prompts</em>, and <em>tools</em> it exposes</li>
<li>trigger tools</li>
</ol>
<p>The interface is fairly straightforward:</p>
<img loading="lazy" decoding="async" class="aligncenter wp-image-8975" src="https://www.baeldung.com/wp-content/uploads/2026/05/mcp_inspector.jpg" alt="MCP Inspector" width="1140" height="736" />
<p>As we can see, we are connected to the MCP server we created using Spring AI, and we successfully ran its <em>Say Hello</em> tool.</p>
<h3 id="bd-2-test-using-claude-desktop" data-id="2-test-using-claude-desktop">3.2. Test Using Claude Desktop</h3>
<div class="bd-anchor" id="2-test-using-claude-desktop"></div>
<p>Alternatively, we can use an AI harness to test the MCP server. After all,<strong> the end goal here is to use the MCP server from a desktop application such as Claude Desktop</strong>.</p>
<p>Firstly, we need to register it in the <em>claude_desktop_config.json</em> file, the location of which varies:</p>
<ul>
<li>on Windows, it&#8217;s <em>%APPDATA%\Claude\claude_desktop_config.json</em></li>
<li>on macOS, it&#8217;s <em>~/Library/Application Support/Claude/claude_desktop_config.json</em></li>
</ul>
<p>Claude Desktop natively supports only the <em>stdio</em> transport for local MCP servers, but the server speaks streamable <em>HTTP</em>. To bridge that gap, we use <em><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.npmjs.com/package/mcp-remote">mcp-remote</a></em> — a small <em>npm</em> utility that runs as a local <em>stdio</em> process and forwards every MCP message to a remote <em>HTTP</em> endpoint. Simply put, Claude Desktop talks to <em>mcp-remote</em> over standard input-output, and <em>mcp-remote</em> relays the traffic to the Spring AI server at <em>http://localhost:3001/mcp</em>:</p>
<pre><code class="language-json">"mcpServers": {
  "sport-spinner": {
    "command": "npx",
    "args": [
      "mcp-remote",
      "http://localhost:3001/mcp",
      "--transport",
      "http-only",
      "--allow-http"
    ]
  }
}</code></pre>
<p>As we can see, we also need to assign a name to the MCP application. Let&#8217;s call it <em>sport-spinner</em>, since we extend it to recommend a sport for the user to practice on any given day.</p>
<p>Finally, if we restart Claude Desktop, we should be able to see the MCP server as a custom connector:</p>
<img loading="lazy" decoding="async" class="aligncenter wp-image-8976" src="https://www.baeldung.com/wp-content/uploads/2026/05/claude-desktop-connector.png" alt="Enable connector" width="748" height="554" />
<p>Therefore, the model can now decide to invoke the tools exposed by the MCP server:</p>
<img loading="lazy" decoding="async" class="aligncenter wp-image-8977" src="https://www.baeldung.com/wp-content/uploads/2026/05/claude-desktop-sayhello.png" alt="Example of usage" width="745" height="372" />
<p><strong>Looks like we managed to connect to the MCP application and return a <em>String</em> that AI Harness can use or display to the user</strong>. Now, let&#8217;s upgrade the application to return HTML that can be rendered in Claude Desktop.</p>
<h2 id="bd-embedding-html" data-id="embedding-html">4. Embedding HTML</h2>
<div class="bd-anchor" id="embedding-html"></div>
<p>So far, the MCP server only returns plain text. However, modern AI harnesses such as Claude Desktop can also render rich, interactive UIs that the server exposes as HTML resources. <strong>We can achieve this by combining an <em>@McpTool</em> that triggers the UI with an <em>@McpResource</em> that serves the actual HTML</strong>.</p>
<p>Let&#8217;s enhance the <em>sport-spinner</em> to display a real fortune wheel that picks today&#8217;s sport. First, we add an HTML file under <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/eugenp/tutorials/tree/master/spring-ai-modules/spring-ai-mcp/src/main/resources/static/sport-spinner.html"><em>src/main/resources/static/sport-spinner.html</em></a>, containing the HTML, CSS, and JavaScript that animates the wheel.</p>
<h3 id="bd-1-exposing-the-html-as-an-mcp-resource" data-id="1-exposing-the-html-as-an-mcp-resource">4.1. Exposing the HTML as an MCP Resource</h3>
<div class="bd-anchor" id="1-exposing-the-html-as-an-mcp-resource"></div>
<p>Let&#8217;s create a new Spring bean that loads the HTML file and exposes it via the <em>@McpResource</em> annotation:</p>
<pre><code class="language-java">@Component
class SportSpinnerUI {
    @Value("classpath:/static/sport-spinner.html")
    private Resource sportSpinnerResource;
    @McpResource(
        name = "Sport Spinner App Resource",
        uri = "ui://sport/sport-spinner.html",
        mimeType = "text/html;profile=mcp-app",
        metaProvider = CspMetaProvider.class)
    public String getSportSpinnerResource() throws IOException {
        return sportSpinnerResource.getContentAsString(Charset.defaultCharset());
    }
}</code></pre>
<p>A few things worth highlighting here:</p>
<ul>
<li>the <em>uri</em> uniquely identifies the resource within the MCP server</li>
<li>the <em>mimeType</em> uses the <em>text/html;profile=mcp-app</em> profile &#8211; signaling to the client that this HTML should be rendered as an interactive MCP app rather than displayed as raw text</li>
<li>the <em>metaProvider</em> attaches additional metadata to the resource — in this case, a Content Security Policy that allow-lists <em>unpkg.com</em> so the page can load external scripts from that CDN</li>
</ul>
<p>Let&#8217;s have a look at the <em>CspMetaProvider</em>:</p>
<pre><code class="language-java">class CspMetaProvider implements MetaProvider {
    @Override
    public Map&lt;String, Object&gt; getMeta() {
        return Map.of("ui",
            Map.of("csp",
                Map.of("resourceDomains", List.of("https://unpkg.com"))));
    }
}</code></pre>
<p>At this point, we should be ready to connect the UI to the tool.</p>
<h3 id="bd-2-linking-the-tool-to-the-ui-resource" data-id="2-linking-the-tool-to-the-ui-resource">4.2. Linking the Tool to the UI Resource</h3>
<div class="bd-anchor" id="2-linking-the-tool-to-the-ui-resource"></div>
<p>Finally, let&#8217;s add an MCP tool that instructs the harness to open the wheel:</p>
<pre><code class="language-java">@McpTool(
    title = "Spin Sport Wheel",
    name = "spin-sport-wheel",
    description = "Opens a fortune wheel that spins and randomly picks today's sport.",
    metaProvider = SportSpinnerToolMetaProvider.class)
public String spinSportWheel() {
    return "Opening the sport spinner wheel.";
}</code></pre>
<p><strong>The key element here is <em>metaProvider</em>, which links this tool to the HTML resource we defined earlier</strong>:</p>
<pre><code class="language-java">class SportSpinnerToolMetaProvider implements MetaProvider {
    @Override
    public Map&lt;String, Object&gt; getMeta() {
        return Map.of("ui",
            Map.of("resourceUri", "ui://sport/sport-spinner.html"));
    }
}</code></pre>
<p>When the model invokes <em>spin-sport-wheel</em>, the harness reads this metadata, fetches the resource at <em>ui://sport/sport-spinner.html</em>, and renders it inline in the chat, giving the user a fully interactive wheel instead of a plain text reply.</p>
<p><strong>Let&#8217;s restart Claude Desktop and ask it what sport we should practice today</strong>:</p>
<img decoding="async" class="aligncenter size-full wp-image-8979" src="https://www.baeldung.com/wp-content/uploads/2026/05/claude-desktop-embedded-html.png" alt="Fortune Wheel spin UI" />
<p>As expected, <strong>the HTML from the Spring Boot application is now rendered directly inside the Claude Desktop chat</strong>. At this point, we can spin the wheel to let it pick today&#8217;s sport, with the result fed back into the conversation so the model can react to it.</p>
<h2 id="bd-conclusion" data-id="conclusion">5. Conclusion</h2>
<div class="bd-anchor" id="conclusion"></div>
<p>In this tutorial, we learned how to build an MCP server with Spring AI and connect it to an AI harness such as Claude Desktop.</p>
<p>Specifically, we started with a simple <em>hello-world</em> tool and tested it using the MCP Inspector and Claude Desktop. Then, we took it one step further by exposing a rich, interactive HTML UI through Spring AI&#8217;s <em>@McpTool</em> and <em>@McpResource</em> annotations. As a result, we made the harness render a fortune wheel inline in the chat and feed the result back into the conversation.</p>
<p>As always, the full source code is available <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/eugenp/tutorials/tree/master/spring-ai-modules/spring-ai-mcp">over on GitHub</a>.</p>The post <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/spring-ai-embed-mcp-server-html-ui">Embedding HTML UIs in MCP Servers With Spring AI</a> first appeared on <a href="https://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/957590270/0/baeldung">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/957590270/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/957590270/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2016%2f10%2fsocial-Java-On-Baeldung-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/957590270/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/957590270/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/957590270/baeldung"><img height="20" src="https://assets.feedblitz.com/i/rss20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a rel="NOFOLLOW" title="View Comments" href="https://www.baeldung.com/spring-ai-embed-mcp-server-html-ui#respond"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/comments20.png"></a>&#160;<a title="Follow Comments via RSS" href="https://www.baeldung.com/spring-ai-embed-mcp-server-html-ui/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/~/957590270/0/baeldung~Embedding-HTML-UIs-in-MCP-Servers-With-Spring-AI/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<webfeeds:featuredImage>https://www.baeldung.com/wp-content/uploads/2016/10/social-Java-On-Baeldung-2-150x150.jpg</webfeeds:featuredImage></item>
<item>
<feedburner:origLink>https://www.baeldung.com/java-weekly-648</feedburner:origLink>
		<title>Java Weekly, Issue 648</title>
		<link>https://feeds.feedblitz.com/~/957491033/0/baeldung~Java-Weekly-Issue</link>
					<comments>https://feeds.feedblitz.com/~/957491033/0/baeldung~Java-Weekly-Issue#respond</comments>
		
		<dc:creator><![CDATA[baeldung]]></dc:creator>
		<pubDate>Fri, 29 May 2026 17:00:42 +0000</pubDate>
				<category><![CDATA[Weekly Review]]></category>
		<category><![CDATA[no-ads]]></category>
		<category><![CDATA[no-after-post]]></category>
		<category><![CDATA[no-before-post]]></category>
		<category><![CDATA[no-optins]]></category>
		<guid isPermaLink="false">https://www.baeldung.com/?p=203862</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>Getting to value classes and mechanically enforced security in this era of AI. A solid week.</p>
The post <a rel="NOFOLLOW" href="https://feeds.feedblitz.com/~/957491033/0/baeldung~Java-Weekly-Issue">Java Weekly, Issue 648</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/957491033/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/957491033/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/957491033/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/957491033/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/957491033/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-648#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-648/feed"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/commentsrss20.png"></a>&#160;</div>]]>
</description>
										<content:encoded><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/2016/10/social-Weekly-Reviews-4.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="float: left; margin-right: 5px;" decoding="async" loading="lazy" srcset="https://www.baeldung.com/wp-content/uploads/2016/10/social-Weekly-Reviews-4.jpg 952w, https://www.baeldung.com/wp-content/uploads/2016/10/social-Weekly-Reviews-4-300x157.jpg 300w, https://www.baeldung.com/wp-content/uploads/2016/10/social-Weekly-Reviews-4-768x402.jpg 768w" sizes="auto, (max-width: 580px) 100vw, 580px" /><h2 style="text-align: left;" id="bd-spring-and-java" data-id="spring-and-java">1.<strong> Spring and Java</strong></h2>
<div class="bd-anchor" id="spring-and-java"></div>
<p><strong><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://cr.openjdk.org/~jrose/values/default-values.html">&gt;&gt; On Default Values for Primitive-Like Classes</a></strong> [<span style="color: #993300;">openjdk.org</span>]</p>
<p>One of the thorniest problems standing between us and value classes: what happens when a value object never gets explicitly initialized? A deep exploration of how primitive-like classes might nominate their own default values, and what that means across the language, the JVM, and the runtime. Good stuff for the weekend.</p>
<p><strong><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://martinfowler.com/articles/vibesec-reckoning.html">&gt;&gt; The VibeSec Reckoning</a></strong> [<span style="color: #993300;">martinfowler.com</span>]</p>
<p>As AI-assisted coding moves into the mainstream, prompting an LLM toward &#8220;secure&#8221; output isn&#8217;t, of course, enough. Security has to be structural and enforced mechanically in the harness.</p>
<h4><strong>Also worth reading:</strong></h4>
<ul>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://inside.java/2026/05/23/java-aot-in-production-at-netflix/" target="_blank" rel="noopener"><strong>Java AOT in Production at Netflix</strong></a> [<span style="color: #800000;">inside.java</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://foojay.io/today/a-new-generation-of-java-libraries-is-born-wasm-becomes-the-implementation-detail/" target="_blank" rel="noopener"><strong>A New Generation of Java Libraries Is Born: Wasm Becomes the Implementation Detail</strong></a> [<span style="color: #800000;">foojay.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://inside.java/2026/05/26/jep523-target-jdk27/" target="_blank" rel="noopener"><strong>JEP targeted to JDK 27: 523: Make G1 the Default Garbage Collector in All Environments</strong></a> [<span style="color: #800000;">inside.java</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://inside.java/2026/05/25/jep537-target-jdk27/" target="_blank" rel="noopener"><strong>JEP targeted to JDK 27: 537: Vector API (12th Incubator)</strong></a> [<span style="color: #800000;">inside.java</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://inside.java/2026/05/26/openjdk-ai-agents/" target="_blank" rel="noopener"><strong>Agentic AI Workflows for OpenJDK Development</strong></a> [<span style="color: #800000;">inside.java</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://quarkus.io/blog/introducing-voting-pattern/" target="_blank" rel="noopener"><strong>Parallel voting and adaptive model selection: smarter agentic AI on a budget</strong></a> [<span style="color: #800000;">quarkus.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://foojay.io/today/context-is-a-budget-eight-levers-and-three-workflow-patterns/" target="_blank" rel="noopener"><strong>Context Is a Budget &#8211; Eight levers and three workflow patterns</strong></a> [<span style="color: #800000;">foojay.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.infoq.com/news/2026/05/tamboui-java-tui/" target="_blank" rel="noopener"><strong>TamboUI Promises to Bring Better Capabilities to Build TUIs in Java</strong></a> [<span style="color: #800000;">infoq.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.infoq.com/articles/schema-proliferation-problem/" target="_blank" rel="noopener"><strong>The Schema Proliferation Problem in Kafka and Flink Pipelines: How to Solve It</strong></a> [<span style="color: #800000;">infoq.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://blog.jetbrains.com/kotlin/2026/05/security-support-policy-for-the-kotlin-standard-library/" target="_blank" rel="noopener"><strong>Introducing a Security Support Policy for the Kotlin Standard Library</strong></a> [<span style="color: #800000;">jetbrains.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://bell-sw.com/news/spring-developers-have-a-blindspot-when-it-comes-to-container-security/" target="_blank" rel="noopener"><strong>Spring Developers Have a Blindspot When It Comes to Container Security</strong></a> [<span style="color: #800000;">bell-sw.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://advancedweb.hu/nixos-first-impressions-writing-system-level-tests/" target="_blank" rel="noopener"><strong>NixOS first impressions: writing system-level tests</strong></a> [<span style="color: #800000;">advancedweb.hu</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://blog.frankel.ch/seasons-time-lapse/2/" target="_blank" rel="noopener"><strong>Seasons time-lapse &#8211; alignment</strong></a> [<span style="color: #800000;">frankel.ch</span>]</li>
</ul>
<h4><strong>Webinars and presentations:</strong></h4>
<ul>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://foojay.io/today/foojay-podcast-96/" target="_blank" rel="noopener"><strong>Foojay Podcast #96: Local AWS Development Without LocalStack: Meet Floci, the GraalVM-Powered Alternative</strong></a> [<span style="color: #800000;">foojay.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.infoq.com/podcasts/chasing-efficient-java-development/" target="_blank" rel="noopener"><strong>Podcast: Chasing Efficient Java Development: From 1BRC to Developing Hardwood AI Natively</strong></a> [<span style="color: #800000;">infoq.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://spring.io/blog/2026/05/21/a-bootiful-podcast-hadi-hariri" target="_blank" rel="noopener"><strong>A Bootiful Podcast: Hadi Hariri, Jetbrains legend</strong></a> [<span style="color: #800000;">spring.io</span>]</li>
</ul>
<h4><strong>Time to upgrade:</strong></h4>
<ul>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://in.relation.to/2026/05/26/orm-74/" target="_blank" rel="noopener"><strong>Hibernate 7.4.0.Final</strong></a> [<span style="color: #800000;">in.relation.to</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://in.relation.to/2026/05/27/hibernate-search-8-4-0-Final/" target="_blank" rel="noopener"><strong>Hibernate Search 8.4.0.Final is out</strong></a> [<span style="color: #800000;">in.relation.to</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.wildfly.org/news/2026/05/21/WildFly-40-is-released/" target="_blank" rel="noopener"><strong>WildFly 40 is released!</strong></a> [<span style="color: #800000;">wildfly.org</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://spring.io/blog/2026/05/23/spring-ai-1-0-8-1-1-7-2-0-0-M7-available-now" target="_blank" rel="noopener"><strong>Spring AI 1.0.8, 1.1.7, 2.0.0-M7 Available Now</strong></a> [<span style="color: #800000;">spring.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://blog.jetbrains.com/ai/2026/05/koog-1-0-is-out-stable-core-better-interop-and-multiplatform-observability/" target="_blank" rel="noopener"><strong>Koog 1.0 Is Out: Stable Core, Better Interop, and Multiplatform Observability</strong></a> [<span style="color: #800000;">jetbrains.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://blog.jetbrains.com/idea/2026/05/intellij-idea-2026-2-eap/" target="_blank" rel="noopener"><strong>IntelliJ IDEA 2026.2 EAP Is Open</strong></a> [<span style="color: #800000;">jetbrains.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/eclipse-vertx/vert.x/releases/tag/5.1.0" target="_blank" rel="noopener"><strong>Vert.x 5.1.0</strong></a> [<span style="color: #800000;">github.com/eclipse-vertx</span>]</li>
</ul>
<h2 style="text-align: left;" id="bd-pick-of-the-week" data-id="pick-of-the-week">2.<strong> Pick of the Week</strong></h2>
<div class="bd-anchor" id="pick-of-the-week"></div>
<p><strong><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://martinfowler.com/articles/break-monolith-into-microservices.html">&gt;&gt; How to break a Monolith into Microservices</a></strong> [<span style="color: #993300;">martinfowler.com</span>]</p>The post <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-weekly-648">Java Weekly, Issue 648</a> first appeared on <a href="https://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/957491033/0/baeldung">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/957491033/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/957491033/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/957491033/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/957491033/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/957491033/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-648#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-648/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/~/957491033/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/jdbc-connector-j-mysql-communications-link-failure</feedburner:origLink>
		<title>How to Fix the Communications link failure Error in Java Applications With MySQL</title>
		<link>https://feeds.feedblitz.com/~/957397595/0/baeldung~How-to-Fix-the-Communications-link-failure-Error-in-Java-Applications-With-MySQL</link>
					<comments>https://feeds.feedblitz.com/~/957397595/0/baeldung~How-to-Fix-the-Communications-link-failure-Error-in-Java-Applications-With-MySQL#respond</comments>
		
		<dc:creator><![CDATA[Hiks Gerganov]]></dc:creator>
		<pubDate>Thu, 28 May 2026 02:00:36 +0000</pubDate>
				<category><![CDATA[Persistence]]></category>
		<category><![CDATA[JDBC]]></category>
		<category><![CDATA[MySQL]]></category>
		<guid isPermaLink="false">https://www.baeldung.com/jdbc-connector-j-mysql-communications-link-failure</guid>
					<description><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/2024/11/Persistence-Featured-Image-02-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 troubleshoot the "Communications link failure" error in Java/MySQL applications, typically thrown as CommunicationsException.</p>
The post <a rel="NOFOLLOW" href="https://feeds.feedblitz.com/~/957397595/0/baeldung~How-to-Fix-the-Communications-link-failure-Error-in-Java-Applications-With-MySQL">How to Fix the <em>Communications link failure</em> Error in Java Applications With MySQL</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/957397595/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/957397595/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2024%2f11%2fPersistence-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/957397595/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/957397595/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/957397595/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/jdbc-connector-j-mysql-communications-link-failure#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/jdbc-connector-j-mysql-communications-link-failure/feed"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/commentsrss20.png"></a>&#160;</div>]]>
</description>
										<content:encoded><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/2024/11/Persistence-Featured-Image-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/Persistence-Featured-Image-02-1024x536.jpg 1024w, https://www.baeldung.com/wp-content/uploads/2024/11/Persistence-Featured-Image-02-300x157.jpg 300w, https://www.baeldung.com/wp-content/uploads/2024/11/Persistence-Featured-Image-02-768x402.jpg 768w, https://www.baeldung.com/wp-content/uploads/2024/11/Persistence-Featured-Image-02-100x52.jpg 100w, https://www.baeldung.com/wp-content/uploads/2024/11/Persistence-Featured-Image-02-600x314.jpg 600w, https://www.baeldung.com/wp-content/uploads/2024/11/Persistence-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>Since MySQL is one of the most common database management systems, we might need a way to establish a stable connection between <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-connect-mysql">MySQL and a Java application</a>. Usually, this happens via the MySQL Connector/J <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-jdbc">JDBC</a> driver. However, a common problem is the <em>Communications link failure</em> error, typically thrown as <em>CommunicationsException</em>. Although the error message may appear simple, the underlying causes can vary significantly.</p>
<p>In this tutorial, <strong>we explain how to fix the <em>Communications link failure</em> error in Java applications using MySQL</strong>. First, we explore what the exception means and when it appears. After that, we go over configuration issues, networking problems, MySQL settings, and other potential causes. Finally, we discuss different ways to diagnose the problem and work around or fix it.</p>
<p>Notably, we mainly refer to MySQL Connector/J <em>8.x</em> used with MySQL Server <em>5.7</em> and <em>8.x</em>. Since there are some differences between older Connector/J <em>5.1.x</em> versions and newer 8.x releases, we&#8217;ll mention them explicitly throughout the text when necessary.</p>
<h2 id="bd-understanding-the-error" data-id="understanding-the-error">2. Understanding the Error</h2>
<div class="bd-anchor" id="understanding-the-error"></div>
<p>Before attempting to fix the issue, let&#8217;s understand how and when the error appears.</p>
<h3 id="bd-1-communicationsexception" data-id="1-communicationsexception">2.1. <em>CommunicationsException</em></h3>
<div class="bd-anchor" id="1-communicationsexception"></div>
<p>Usually, the error happens in Java applications, causing a JDBC <em>CommunicationsEsception</em>:</p>
<pre><code class="language-java">com.mysql.jdbc.exceptions.jdbc4.CommunicationsException:
Communications link failure
The last packet sent successfully to the server was 0 milliseconds ago.
The driver has not received any packets from the server.</code></pre>
<p>Basically, <strong>the JDBC driver attempts to exchange data with the MySQL server, but no data goes through</strong>.</p>
<p>When it comes to Connector/J <em>5.1.x</em>, the exception commonly appears under the <em>com.mysql.jdbc.exceptions.jdbc4.CommunicationsException</em> package. However, Connector/J <em>8.x</em> changed the package to <em>com.mysql.cj.jdbc.exceptions.CommunicationsException</em>. Such changes aren&#8217;t unexpected, and future versions may continue the trend.</p>
<p>In practice, we often encounter this error in two scenarios:</p>
<ul>
<li>during the initial connection attempt</li>
<li>when executing queries on an already established connection</li>
</ul>
<p>Considering this, let&#8217;s inspect common causes.</p>
<h3 id="bd-2-common-causes" data-id="2-common-causes">2.2. Common Causes</h3>
<div class="bd-anchor" id="2-common-causes"></div>
<p>Although the error itself is generic, <strong>several underlying issues appear frequently in production systems</strong>:</p>
<ul>
<li>Our MySQL server isn&#8217;t running</li>
<li>JDBC connection URL contains incorrect hostname or port</li>
<li>DNS resolution fails for the configured host</li>
<li>MySQL isn&#8217;t listening for TCP/IP connections</li>
<li>firewall or proxy rules block database traffic</li>
<li>server closing idle connections</li>
<li>application exhausts available database connections</li>
<li>JDBC driver version incompatible with the server</li>
</ul>
<p>Since multiple factors can lead to the same exception, diagnosing the problem may require multiple steps.</p>
<h2 id="bd-verifying-basic-connectivity" data-id="verifying-basic-connectivity">3. Verifying Basic Connectivity</h2>
<div class="bd-anchor" id="verifying-basic-connectivity"></div>
<p>To begin with, let&#8217;s confirm that the application can reach the database server.</p>
<h3 id="bd-1-verify-mysql-server-is-running" data-id="1-verify-mysql-server-is-running">3.1. Verify MySQL Server Is Running</h3>
<div class="bd-anchor" id="1-verify-mysql-server-is-running"></div>
<p>Perhaps the most straightforward cause for the error is a non-running MySQL server instance. Naturally, <strong>if the service isn&#8217;t up, the JDBC driver can&#8217;t reach it</strong>.</p>
<p>Here, a simple restart can resolve the issue:</p>
<pre><code class="language-bash"># sudo service mysql restart</code></pre>
<p>After the server restarts, the application should be able to reconnect normally. Still, <strong>the problem can also occur due to intermittent restarts,</strong> in which case further debugging might be required.</p>
<h3 id="bd-2-check-jdbc-connection-url" data-id="2-check-jdbc-connection-url">3.2. Check JDBC Connection URL</h3>
<div class="bd-anchor" id="2-check-jdbc-connection-url"></div>
<p>The key parameters of the initial MySQL connection can cause communication failures.</p>
<p>Let&#8217;s analyze a typical MySQL JDBC connection string:</p>
<pre><code class="language-java">jdbc:mysql://localhost:3306/mydatabase</code></pre>
<p>When troubleshooting, we should verify the correctness of at least several parameters:</p>
<ul>
<li>hostname or IP address</li>
<li>port number (default: 3306)</li>
<li>database name</li>
<li>username and password</li>
</ul>
<p>Specifically, <strong>an incorrect port or hostname can prevent the application from connecting to the server entirely</strong>.</p>
<h3 id="bd-3-test-hostname-resolution" data-id="3-test-hostname-resolution">3.3. Test Hostname Resolution</h3>
<div class="bd-anchor" id="3-test-hostname-resolution"></div>
<p>As with any networking issue, the difference between a hostname and a host address is critical. Failure at name resolution is enough to block a connection. There are typically several possible reasons for this:</p>
<ul>
<li>bad operating system configuration</li>
<li>incorrect <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/linux/check-etc-hosts-file-entries">hosts file</a> entries</li>
<li>misconfigured DNS server</li>
<li>DNS server unaware of host</li>
<li>DNS server not responding</li>
</ul>
<p>Any of these factors can prevent the JDBC driver from reaching the server. To troubleshoot, we can try replacing a name like <em>localhost</em> or <em>MYSQL-1</em> with the explicit IP address, such as <em>127.0.0.1</em> or <em>192.168.6.66</em>.</p>
<p>If the connection works with an explicit IP address but not a hostname, DNS or hostname resolution issues are probably the culprit. In contrast, if the connection still fails even with the direct IP address, the root cause is more likely related to networking, firewall rules, incorrect ports, or the MySQL server configuration. Let&#8217;s look at each of these possibilities.</p>
<h2 id="bd-mysql-configuration-issues" data-id="mysql-configuration-issues">4. MySQL Configuration Issues</h2>
<div class="bd-anchor" id="mysql-configuration-issues"></div>
<p>If we can reach the actual hardware that hosts the server, but still experience issues, then MySQL might not be configured to accept network connections as expected. To diagnose this, we often check the options and values in the MySQL configuration file (<a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/linux/mysql-find-my-cnf-command-line"><em>my.cnf</em></a> or <em>my.ini</em>).</p>
<h3 id="bd-1-verify-the-bind-address-setting" data-id="1-verify-the-bind-address-setting">4.1. Verify the <em>bind-address</em> Setting</h3>
<div class="bd-anchor" id="1-verify-the-bind-address-setting"></div>
<p>One common MySQL option is <em>bind-address</em>.</p>
<p>Specifically, <strong>the value of <em>bind-address</em> determines the network interfaces that the server listens on</strong>:</p>
<pre><code class="language-ini">bind-address = 127.0.0.1</code></pre>
<p>In this case, we only expect connections from within <em>localhost</em>.</p>
<p>On the other hand, <strong>we can accept connections to any address or interface</strong>:</p>
<pre><code class="language-ini">bind-address = 0.0.0.0</code></pre>
<p>Checking whether <em>bind-address</em> is properly set with the expected value is critical for diagnosing connectivity issues.</p>
<h3 id="bd-2-disable-skip-networking" data-id="2-disable-skip-networking">4.2. Disable <em>skip-networking</em></h3>
<div class="bd-anchor" id="2-disable-skip-networking"></div>
<p>Some MySQL installations support the <em>skip-networking</em> configuration option, which disables TCP/IP connections entirely.</p>
<p>Thus, if the setting appears in the configuration file, we should comment it out:</p>
<pre><code class="language-ini"># skip-networking</code></pre>
<p>Although this is a rare cause, checking for such edge cases takes little time and can fix the issue. So, it&#8217;s worth exploring.</p>
<h3 id="bd-3-adjust-connection-timeout-settings" data-id="3-adjust-connection-timeout-settings">4.3. Adjust Connection Timeout Settings</h3>
<div class="bd-anchor" id="3-adjust-connection-timeout-settings"></div>
<p>To prevent resource waste, MySQL may close connections that remain idle for too long.</p>
<p>Several parameters control this behavior:</p>
<ul>
<li><em>wait_timeout</em>: maximum time to wait before closing an idle non-interactive connection</li>
<li><em>interactive_timeout</em>: maximum time to wait before closing an idle interactive connection (such as <em>mysql</em> CLI)</li>
<li><em>connect_timeout</em>: maximum time to wait for a client to complete the initial connection handshake</li>
</ul>
<p>As expected, increasing these values can reduce unexpected connection failures:</p>
<pre><code class="language-sql">wait_timeout = 28800
interactive_timeout = 28800</code></pre>
<p>In all cases, after changing the configuration, we should restart the MySQL service.</p>
<h2 id="bd-network-and-environment-issues" data-id="network-and-environment-issues">5. Network and Environment Issues</h2>
<div class="bd-anchor" id="network-and-environment-issues"></div>
<p>Even when MySQL is configured correctly, external factors may still prevent the application from connecting.</p>
<h3 id="bd-1-firewall-and-antivirus-or-proxy-restrictions" data-id="1-firewall-and-antivirus-or-proxy-restrictions">5.1. Firewall and Antivirus or Proxy Restrictions</h3>
<div class="bd-anchor" id="1-firewall-and-antivirus-or-proxy-restrictions"></div>
<p><strong>Network controls can block the traffic between the application and the MySQL server</strong>. For instance, a firewall rule, antivirus software, or a proxy can be the reason for connectivity issues.</p>
<p>To ensure the connection goes through, we can use tools such as <em>ping</em> or <em>telnet</em> for simple checks and <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/linux/nmap-command-examples"><em>nmap</em></a> for port testing.</p>
<p>Regardless of the network setup, we should ensure that port <em>3306</em> is open and accessible through the whole chain. Naturally, if MySQL is configured to listen on another port, we should verify connectivity against that specific port instead of <em>3306</em>.</p>
<h3 id="bd-2-ipv6-versus-ipv4-issues" data-id="2-ipv6-versus-ipv4-issues">5.2. IPv6 Versus IPv4 Issues</h3>
<div class="bd-anchor" id="2-ipv6-versus-ipv4-issues"></div>
<p>Some environments resolve names to IPv6 addresses, such as <em>::1</em> for <em>localhost</em> instead of its IPv4 equivalent <em>127.0.0.1</em>. However, <strong>if the Java application environment and the MySQL server don&#8217;t use the same IP version, we can experience connection failures</strong>.</p>
<p>Common solutions:</p>
<ol>
<li>use <em>127.0.0.1</em> instead of <em>localhost</em></li>
<li>start Java with the JVM option <em>-Djava.net.preferIPv4Stack=true</em></li>
</ol>
<p>This forces the application to prefer IPv4 networking.</p>
<h2 id="bd-application-level-causes" data-id="application-level-causes">6. Application-Level Causes</h2>
<div class="bd-anchor" id="application-level-causes"></div>
<p>The way that an application is implemented also affects the establishment and stability of connections.</p>
<h3 id="bd-1-stale-connections-in-connection-pools" data-id="1-stale-connections-in-connection-pools">6.1. Stale Connections in Connection Pools</h3>
<div class="bd-anchor" id="1-stale-connections-in-connection-pools"></div>
<p><strong>Connection pools with stale entries are a common culprit for problematic MySQL connectivity.</strong> When the application tries to execute a query over a connection that the server has already closed, the JDBC driver reports a communication failure.</p>
<p>Usually, the solution is to switch over to a modern connection pool:</p>
<ul>
<li>HikariCP</li>
<li>Apache DBCP</li>
<li>C3P0</li>
</ul>
<p>The reason is that these implementations validate connections before returning them to the application.</p>
<p>In practice, <strong>connection pools may require explicit configuration to validate or recycle stale connections.</strong> For example, HikariCP uses several settings:</p>
<ul>
<li><em>maxLifetime</em></li>
<li><em>idleTimeout</em></li>
<li><em>keepaliveTime</em></li>
</ul>
<p>Apache DBCP and C3P0 support validation queries and connection test options. The exact specifics are outside the scope of this text.</p>
<h3 id="bd-2-connection-pool-exhaustion" data-id="2-connection-pool-exhaustion">6.2. Connection Pool Exhaustion</h3>
<div class="bd-anchor" id="2-connection-pool-exhaustion"></div>
<p><strong>Connection limits may necessitate closing old connections before attempting new ones.</strong> Otherwise, the MySQL server may reject the connection attempt.</p>
<p>In particular, ensuring the JDBC resources are closed correctly is essential:</p>
<pre><code class="language-java">try (Connection conn = dataSource.getConnection()) {
    // execute queries
}</code></pre>
<p>Connection pools can also limit and recycle connections.</p>
<p>Even if the application closes all JDBC resources, the database server may still reject new connections. For example, MySQL may reach the <em>max_connections</em> limit or experience temporary overload conditions. In such cases, the application could receive different exceptions, including errors such as <em>Too many connections</em>, instead of a generic <em>CommunicationsException</em>.</p>
<p>Furthermore, the configured pool size matters significantly. If the connection pool allows more concurrent connections than MySQL accepts, server connections can be depleted. Therefore, <strong>there should be a proper balance between the pool connection size and <em>max_connections</em> in MySQL.</strong></p>
<h3 id="bd-3-update-the-jdbc-driver" data-id="3-update-the-jdbc-driver">6.3. Update the JDBC Driver</h3>
<div class="bd-anchor" id="3-update-the-jdbc-driver"></div>
<p><strong>Older versions of the MySQL Connector/J driver may not work reliably with newer database versions</strong>.</p>
<p>Updating the dependency often resolves compatibility problems:</p>
<pre><code class="language-xml">&lt;dependency&gt;
  &lt;groupId&gt;mysql&lt;/groupId&gt;
  &lt;artifactId&gt;mysql-connector-java&lt;/artifactId&gt;
  &lt;version&gt;8.0.33&lt;/version&gt;
&lt;/dependency&gt;</code></pre>
<p>For Connector/J <em>8.x</em>, the Maven artifact may also appear under the newer coordinates <em>com.mysql:mysql-connector-j</em>, depending on the project setup and repository metadata.</p>
<p>As with other areas of computing, keeping the driver up to date ensures compatibility with the MySQL protocol and improves connection stability.</p>
<h2 id="bd-summary" data-id="summary">7. Summary</h2>
<div class="bd-anchor" id="summary"></div>
<p>In this article, we explored how to diagnose and fix the <em>Communications link failure</em> error in Java applications using MySQL.</p>
<p>This error occurs when the JDBC driver is unable to communicate with the database server. Common causes include server downtime, incorrect connection configuration, MySQL network settings, firewall restrictions, IPv6 resolution problems, stale pooled connections, and connection exhaustion within the application.</p>
<p>Carefully verifying connectivity, reviewing MySQL configuration, using reliable connection pools, updating JDBC drivers, and examining diagnostic logs can significantly reduce communication failures in Java applications that rely on MySQL.</p>The post <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/jdbc-connector-j-mysql-communications-link-failure">How to Fix the <em>Communications link failure</em> Error in Java Applications With MySQL</a> first appeared on <a href="https://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/957397595/0/baeldung">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/957397595/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/957397595/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2024%2f11%2fPersistence-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/957397595/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/957397595/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/957397595/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/jdbc-connector-j-mysql-communications-link-failure#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/jdbc-connector-j-mysql-communications-link-failure/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/~/957397595/0/baeldung~How-to-Fix-the-Communications-link-failure-Error-in-Java-Applications-With-MySQL/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<webfeeds:featuredImage>https://www.baeldung.com/wp-content/uploads/2024/11/Persistence-Featured-Image-02-150x150.jpg</webfeeds:featuredImage></item>
<item>
<feedburner:origLink>https://www.baeldung.com/java-quantum-resistant-ml-kem-ml-dsa</feedburner:origLink>
		<title>Quantum-Resistant ML-KEM and ML-DSA in Java</title>
		<link>https://feeds.feedblitz.com/~/957346181/0/baeldung~QuantumResistant-MLKEM-and-MLDSA-in-Java</link>
					<comments>https://feeds.feedblitz.com/~/957346181/0/baeldung~QuantumResistant-MLKEM-and-MLDSA-in-Java#respond</comments>
		
		<dc:creator><![CDATA[Burak Gökmen]]></dc:creator>
		<pubDate>Wed, 27 May 2026 05:34:07 +0000</pubDate>
				<category><![CDATA[Security]]></category>
		<category><![CDATA[>= Java 24]]></category>
		<guid isPermaLink="false">https://www.baeldung.com/?p=203818</guid>
					<description><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-13-1024x536.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="max-width:100% !important;height:auto !important;float: left; margin-right: 5px;" loading="lazy" /><p>Learn how to use quantum-resistant ML-KEM and ML-DSA in Java to securely establish a shared secret key.</p>
The post <a rel="NOFOLLOW" href="https://feeds.feedblitz.com/~/957346181/0/baeldung~QuantumResistant-MLKEM-and-MLDSA-in-Java">Quantum-Resistant ML-KEM and ML-DSA 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/957346181/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/957346181/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2024%2f07%2fJava-Featured-13-1024x536.jpg"><img height="20" src="https://assets.feedblitz.com/i/pinterest20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Post to X.com" href="https://feeds.feedblitz.com/_/24/957346181/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/957346181/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/957346181/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-quantum-resistant-ml-kem-ml-dsa#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-quantum-resistant-ml-kem-ml-dsa/feed"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/commentsrss20.png"></a>&#160;</div>]]>
</description>
										<content:encoded><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-13-1024x536.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="float: left; margin-right: 5px;" decoding="async" loading="lazy" srcset="https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-13-1024x536.jpg 1024w, https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-13-300x157.jpg 300w, https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-13-768x402.jpg 768w, https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-13-100x52.jpg 100w, https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-13.jpg 1200w" sizes="auto, (max-width: 580px) 100vw, 580px" /><h2 id="bd-overview" data-id="overview">1. Overview</h2>
<div class="bd-anchor" id="overview"></div>
<p><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://nvlpubs.nist.gov/nistpubs/fips/nist.fips.203.pdf">ML-KEM</a> (Module-Lattice-Based Key Encapsulation Mechanism) is a post-quantum cryptographic key exchange algorithm that allows two parties to securely establish a shared secret key even against attacks from future quantum computers. <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://nvlpubs.nist.gov/nistpubs/fips/nist.fips.204.pdf">ML-DSA</a> (Module-Lattice-Based Digital Signature Algorithm), on the other hand, is a post-quantum digital signature algorithm that enables secure authentication and message integrity protection, resistant to attacks by quantum computers.</p>
<p>ML-KEM  and ML-DSA  weren’t part of the standard JDK (Java Development Kit) before Java 24. We had to use external libraries like <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-bouncy-castle">Bounty Castle</a> to perform cryptographic operations.</p>
<p>Both algorithms have been part of the native Java API since Java 24. The ML-KEM and ML-DSA implementations within the native Java API were proposed by <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://openjdk.org/jeps/496">JEP 496</a> and <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://openjdk.org/jeps/497">JEP 497</a>, respectively.</p>
<p>In this tutorial, we’ll discuss the usage of quantum-resistant ML-KEM and ML-DSA in Java.</p>
<h2 id="bd-quantum-resistant-ml-kem" data-id="quantum-resistant-ml-kem">2. Quantum-Resistant ML-KEM</h2>
<div class="bd-anchor" id="quantum-resistant-ml-kem"></div>
<p><strong>A <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/cs/symmetric-cryptography#2-key-encapsulation-mechanism">key encapsulation mechanism</a> allows two parties, i.e., a sender and a receiver, to securely exchange a shared secret key over an insecure network</strong>. The mechanism consists of the following steps:</p>
<ul>
<li>The receiver creates a public/private key pair</li>
<li>The sender creates an encrypted shared secret key using the public key</li>
<li>The receiver decrypts the encrypted shared secret key using the private key</li>
</ul>
<p>Consequently, both parties obtain the same secret key. This shared key can be used with symmetric-key algorithms such as AES (Advanced Encryption Standard) and Blowfish.</p>
<p><strong>ML-KEM is based on the M-LWE (Module Learning with Errors) problem, which is computationally hard</strong>. The hardness of the M-LWE problem further depends on the hardness of certain computational problems in module lattices. Therefore, ML-KEM is resistant to both classical and quantum attacks.</p>
<h3 id="bd-1-generating-a-key-pair" data-id="1-generating-a-key-pair">2.1. Generating a Key Pair</h3>
<div class="bd-anchor" id="1-generating-a-key-pair"></div>
<p>Let&#8217;s start by generating an ML-KEM key pair at the receiver side:</p>
<pre><code class="language-java">KeyPairGenerator kpg = KeyPairGenerator.getInstance("ML-KEM");
kpg.initialize(NamedParameterSpec.ML_KEM_768);
KeyPair receiverKeyPair = kpg.generateKeyPair();
PrivateKey privateKey = receiverKeyPair.getPrivate();
PublicKey publicKey = receiverKeyPair.getPublic();</code></pre>
<p>Firstly, we get a <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://docs.oracle.com/en/java/javase/24/docs/api/java.base/java/security/KeyPairGenerator.html"><em>KeyPairGenerator</em></a> object for the ML-KEM algorithm. Then, we choose <em>ML_KEM_768</em> to set the security strength of the keys we’ll generate. <strong>JEP 496 adds support for ML-KEM-512, ML-KEM-768, and ML-KEM-1024</strong>. Indeed, <em>ML_KEM_768</em> is the default option, i.e., if we don’t initialize the <em>KeyPairGenerator</em> object with the <em>initialize()</em> method, the security level will still be <em>ML_KEM_768</em>.</p>
<p>It’s also possible to pass the security strength directly to <em>getInstance()</em>. We don’t have to call the <em>initialize()</em> method in this case, either:</p>
<pre><code class="language-java">KeyPairGenerator kpg = KeyPairGenerator.getInstance("ML-KEM-768");
KeyPair receiverKeyPair = kpg.generateKeyPair();</code></pre>
<p><em>receiverKeyPair</em>, of type <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://docs.oracle.com/javase/8/docs/api/java/security/KeyPair.html"><em>KeyPair</em></a>, holds a public and private key. We can access these keys using the <em>getPublic()</em> and <em>getPrivate()</em> member methods, respectively. It’s safe for the receiver to share the public key with the sender, but the private key must be kept secret.</p>
<h3 id="bd-2-generating-and-encapsulating-a-secret-shared-key" data-id="2-generating-and-encapsulating-a-secret-shared-key">2.2. Generating and Encapsulating a Secret Shared Key</h3>
<div class="bd-anchor" id="2-generating-and-encapsulating-a-secret-shared-key"></div>
<p>Once the sender receives the receiver’s public key, it generates and encapsulates a shared secret key that will be used by both the sender and the receiver:</p>
<pre><code class="language-java">KEM senderKem = KEM.getInstance("ML-KEM");
KEM.Encapsulator encapsulator = senderKem.newEncapsulator(publicKey);
KEM.Encapsulated encapsulated = encapsulator.encapsulate();
SecretKey senderSharedSecret = encapsulated.key();
byte[] ciphertext = encapsulated.encapsulation();</code></pre>
<p><strong><em>senderSharedSecret</em></strong><strong> is the actual secret key used in communication</strong>. But the sender doesn’t send it directly to the receiver. It sends it encrypted by encapsulating it with the receiver’s public key. <strong><em>ciphertext</em> corresponds to the encrypted version of <em>senderSharedSecret</em></strong>.</p>
<h3 id="bd-3-decapsulating-the-secret-shared-key" data-id="3-decapsulating-the-secret-shared-key">2.3. Decapsulating the Secret Shared Key</h3>
<div class="bd-anchor" id="3-decapsulating-the-secret-shared-key"></div>
<p>After the receiver receives the encrypted secret key, it decapsulates the secret key using the private key:</p>
<pre><code class="language-java">KEM receiverKem = KEM.getInstance("ML-KEM");
KEM.Decapsulator decapsulator = receiverKem.newDecapsulator(privateKey);
SecretKey receiverSharedSecret = decapsulator.decapsulate(ciphertext);</code></pre>
<p>The actual secret key, <em>receiverSharedSecret</em>, is extracted by decapsulating the received <em>ciphertext</em>. Consequently, <strong>both sides obtain the same shared secret key for symmetric encryption and decryption</strong>. We can check that both parties use the same key as follows:</p>
<pre><code class="language-java">boolean match = Arrays.equals(senderSharedSecret.getEncoded(), receiverSharedSecret.getEncoded());</code></pre>
<p>The comparison returns <em>true</em>. Therefore, we achieve secure communication over insecure networks. Besides, the method is resistant to quantum attacks, unlike RSA or Diffie-Hellman.</p>
<h2 id="bd-quantum-resistant-ml-dsa" data-id="quantum-resistant-ml-dsa">3. Quantum-Resistant ML-DSA</h2>
<div class="bd-anchor" id="quantum-resistant-ml-dsa"></div>
<p>A <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/cs/introduction-to-cryptography#1-digital-signature">digital signature algorithm</a> is a cryptographic method that verifies the authenticity and integrity of digital messages or documents. The algorithm consists of the following steps:</p>
<ul>
<li>The signer (sender) creates a public/private key pair</li>
<li>The signer creates a signature using the message and the private key</li>
<li>The verifier (receiver) verifies the signature using the received message and the public key</li>
</ul>
<p><strong>Like ML-KEM, ML-DSA is based on the M-LWE problem and on another computationally hard problem, M-SIS (Module Short Integer Solution)</strong>. Therefore, ML-DSA is resistant to both classical and quantum attacks.</p>
<h3 id="bd-1-generating-a-key-pair-1" data-id="1-generating-a-key-pair-1">3.1. Generating a Key Pair</h3>
<div class="bd-anchor" id="1-generating-a-key-pair-1"></div>
<p>Let&#8217;s start by generating an ML-DSA key pair on the signer side:</p>
<pre><code class="language-java">KeyPairGenerator kpg = KeyPairGenerator.getInstance("ML-DSA");
kpg.initialize(NamedParameterSpec.ML_DSA_65);
KeyPair kp = kpg.generateKeyPair();
PrivateKey privateKey = kp.getPrivate();
PublicKey publicKey = kp.getPublic();</code></pre>
<p>Firstly, we get a <em>KeyPairGenerator</em> object for the ML-DSA algorithm. Then, we choose <em>ML_DSA_65</em> to set the security strength of the keys we’ll generate. Indeed, <em>ML_DSA_65</em> is the default option. <strong>JEP 497 adds support for ML-DSA-44, ML-DSA-65, and ML-DSA-87</strong>.</p>
<p>Like ML-KEM, it’s possible to pass the security strength directly to <em>getInstance()</em>.</p>
<h3 id="bd-2-signing" data-id="2-signing">3.2. Signing</h3>
<div class="bd-anchor" id="2-signing"></div>
<p>Then, we, the signer, sign the message to be sent using the private key:</p>
<pre><code class="language-java">Signature signature = Signature.getInstance("ML-DSA");
String message = "This is a test message signed";
byte[] messageBytes = message.getBytes();
signature.initSign(privateKey);
signature.update(messageBytes);
byte[] sigBytes = signature.sign();</code></pre>
<p>Firstly, we get a <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://docs.oracle.com/javase/8/docs/api/java/security/Signature.html"><em>Signature</em></a> object that implements the ML-DSA algorithm. Then, we initialize this object for signing using the <em>initSign()</em> method. We pass the private key to this method. Then, we feed the message to the <em>Signature</em> object using the <em>update()</em> method. Finally, <strong>we create the digital signature using the <em>Signature</em> object’s <em>sign()</em> method</strong>.</p>
<h3 id="bd-3-verification" data-id="3-verification">3.3. Verification</h3>
<div class="bd-anchor" id="3-verification"></div>
<p>Then, having received the message and the signature, we, the verifier, verify the signature using the public key:</p>
<pre><code class="language-java">signature.initVerify(publicKey);
signature.update(messageBytes);
boolean isValid = signature.verify(sigBytes);</code></pre>
<p>This time, we initialize the <em>Signature</em> object for verification using the <em>initVerify()</em> method. Then we feed the message received from the signer to the <em>Signature</em> object using <em>update()</em>. Finally, <strong>we verify the signature using the <em>Signature</em> object’s <em>verify()</em> method</strong>. It returns <em>true</em>. Successful validation means that the signature was created using the corresponding private key.</p>
<h2 id="bd-conclusion" data-id="conclusion">4. Conclusion</h2>
<div class="bd-anchor" id="conclusion"></div>
<p>In this article, we discussed the usage of quantum-resistant ML-KEM and ML-DSA in Java. Firstly, we learned that these algorithms weren’t available in the standard JDK before Java 24.</p>
<p>Then, we saw the usage of the algorithms in Java. We simulated the secret key exchange between a receiver and a sender using ML-KEM. Similarly, we simulated message signing and signature verification between two parties using ML-DSA. As we saw in the examples, Java 24 provided ML-KEM implementations of the <em>KeyPairGenerator</em> and <em>KEM</em> classes, and ML-DSA implementations of the <em>KeyPairGenerator</em> and <em>Signature</em> classes.</p>
<p>As usual, the complete source code for the examples is available <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/eugenp/tutorials/tree/master/core-java-modules/core-java-24/">over on GitHub</a>.</p>The post <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-quantum-resistant-ml-kem-ml-dsa">Quantum-Resistant ML-KEM and ML-DSA in Java</a> first appeared on <a href="https://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/957346181/0/baeldung">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/957346181/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/957346181/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2024%2f07%2fJava-Featured-13-1024x536.jpg"><img height="20" src="https://assets.feedblitz.com/i/pinterest20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Post to X.com" href="https://feeds.feedblitz.com/_/24/957346181/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/957346181/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/957346181/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-quantum-resistant-ml-kem-ml-dsa#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-quantum-resistant-ml-kem-ml-dsa/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/~/957346181/0/baeldung~QuantumResistant-MLKEM-and-MLDSA-in-Java/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<webfeeds:featuredImage>https://www.baeldung.com/wp-content/uploads/2024/07/Java-Featured-13-150x150.jpg</webfeeds:featuredImage></item>
<item>
<feedburner:origLink>https://www.baeldung.com/java-http-basic-authentication-httpservletrequest</feedburner:origLink>
		<title>Getting HTTP Basic Authentication from HttpServletRequest</title>
		<link>https://feeds.feedblitz.com/~/957111833/0/baeldung~Getting-HTTP-Basic-Authentication-from-HttpServletRequest</link>
					<comments>https://feeds.feedblitz.com/~/957111833/0/baeldung~Getting-HTTP-Basic-Authentication-from-HttpServletRequest#respond</comments>
		
		<dc:creator><![CDATA[Hamid Reza Sharifi]]></dc:creator>
		<pubDate>Sat, 23 May 2026 23:11:28 +0000</pubDate>
				<category><![CDATA[Security]]></category>
		<category><![CDATA[Authentication]]></category>
		<guid isPermaLink="false">https://www.baeldung.com/?p=203787</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 the HTTP Basic Authentication works and how to extract credentials from a HTTP request in a Spring-based application.</p>
The post <a rel="NOFOLLOW" href="https://feeds.feedblitz.com/~/957111833/0/baeldung~Getting-HTTP-Basic-Authentication-from-HttpServletRequest">Getting HTTP Basic Authentication from HttpServletRequest</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/957111833/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/957111833/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/957111833/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/957111833/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/957111833/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-http-basic-authentication-httpservletrequest#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-http-basic-authentication-httpservletrequest/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><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/cs/digest-vs-basic-authentication#introduction-to-basic-authentication">Basic Authentication</a> is the most common security mechanism for HTTP services. Its popularity stems from simplicity and ease of implementation. In this tutorial, we’ll explore how HTTP Basic Authentication works and how to extract credentials, specifically the password, from an incoming HTTP request in a Spring-based application.</p>
<h2 id="bd-http-basic-authentication" data-id="http-basic-authentication">2. HTTP Basic Authentication</h2><div class="bd-anchor" id="http-basic-authentication"></div>
<p>HTTP Basic Authentication is a simple authentication scheme where the client sends credentials in the HTTP request header. <strong>The client sends the request with the credentials included in the <em>Authorization</em> header, and the server then validates them</strong>. The header format is:</p>
<pre><code class="language-plaintext">Authorization: Basic &lt;base64(username:password)&gt;</code></pre>
<p>The username and password are combined into a single string separated by a colon. This string is then encoded using <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-base64-encode-and-decode">Base64</a>. For example, if the username is <em>admin</em> and the password is <em>secret</em>, the combined string is <em>admin:secret</em>. The Base64 encoded version of this string is <em>YWRtaW46c2VjcmV0</em>. The final HTTP header looks like this:</p>
<pre><code class="language-plaintext">Authorization: Basic YWRtaW46c2VjcmV0</code></pre>
<p><strong>It’s important to note that Base64 is encoding, not encryption</strong>. It is easily reversible, which is why HTTPS is strictly required when using Basic Authentication.</p>
<h2 id="bd-maven-dependency" data-id="maven-dependency">3. Maven Dependency</h2><div class="bd-anchor" id="maven-dependency"></div>
<p>Let’s start by importing the <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-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-retrieving-credentials-from-the-authorization-header" data-id="retrieving-credentials-from-the-authorization-header">4. Retrieving Credentials from the Authorization Header</h2><div class="bd-anchor" id="retrieving-credentials-from-the-authorization-header"></div>
<p>In this section, we describe the step-by-step process of retrieving the raw username and password from the incoming HTTP request.</p>
<h3 id="bd-1-manual-extraction-from-the-http-request" data-id="1-manual-extraction-from-the-http-request">4.1. Manual Extraction from the HTTP Request</h3><div class="bd-anchor" id="1-manual-extraction-from-the-http-request"></div>
<p><strong>The most direct way to get the password is to read the <em>Authorization</em> header directly from the <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-servlet-request-set-parameter#1-httpservletrequest"><em>HttpServletRequest</em></a> and decode it</strong>. Let’s create a <em>BasicAuthExtractor</em> class and a utility method to do this:</p>
<pre><code class="language-java">public class BasicAuthExtractor {
    public static String[] extractCredentials(String authHeader) {
        if (authHeader != null &amp;&amp; authHeader.startsWith("Basic ")) {
            String base64Credentials = authHeader.substring("Basic ".length()).trim();
            byte[] credDecoded = Base64.getDecoder().decode(base64Credentials);
            String credentials = new String(credDecoded, StandardCharsets.UTF_8);
            final String[] values = credentials.split(":", 2);
            if (values.length == 2) {
                return values;
            }
        }
        return null;
    }
}</code></pre>
<p>The <em>extractCredentials()</em> method first checks whether the <em>Authorization</em> header exists. It also verifies that the header starts with the &#8220;<em>Basic</em> &#8221; prefix. Next, it removes the prefix from the header value. Then, it decodes the remaining Base64-encoded string using <em>Base64.getDecoder()</em>. After decoding, the bytes are converted into a UTF-8 string. The resulting string should follow the <em>username:password</em> format. Finally, the method splits the string on the first colon. It returns a two-element array containing the username and password. If the header is invalid or incorrectly formatted, the method returns <em>null</em>. We can easily use the <em>extractCredentials()</em> method inside a <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/spring-controllers"><em>RestController</em></a>:</p>
<pre><code class="language-java">@GetMapping("/extract")
public ResponseEntity&lt;String&gt; extract(@RequestHeader("Authorization") String authHeader) {
    String[] credentials = BasicAuthExtractor.extractCredentials(authHeader);
    if (credentials != null) {
        String username = credentials[0];
        String password = credentials[1];
        return ResponseEntity.ok("Extracted Username: " + username +
          " Extracted Password: " + password);
    }
    return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
}</code></pre>
<p>We use the <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/spring-rest-http-headers"><em>@RequestHeader</em></a> annotation for getting the <em>Authorization</em> header value from the incoming request.</p>
<h3 id="bd-2-custom-servlet-filter" data-id="2-custom-servlet-filter">4.2. Custom Servlet Filter</h3><div class="bd-anchor" id="2-custom-servlet-filter"></div>
<p><strong>Another way is to create a custom <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/spring-boot-add-filter">Filter</a> that reads the header, extracts the password, and stores it in a request attribute for later use</strong>. Let&#8217;s create an <em>AuthFilter</em> class to do this:</p>
<pre><code class="language-java">@Component
public class AuthFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
        FilterChain filterChain) throws ServletException, IOException {
        String authHeader = request.getHeader("Authorization");
        String[] credentials = BasicAuthExtractor.extractCredentials(authHeader);
        if (credentials != null) {
            request.setAttribute("rawPassword", credentials[1]);
        }
        filterChain.doFilter(request, response);
    }
}</code></pre>
<p>This filter intercepts every incoming HTTP request and reads the <em>Authorization</em> header. Then, it extracts the password using the <em>extractCredentials()</em> method and stores it as a request attribute before continuing the filter chain. Later, in our service or controller, we can retrieve it safely:</p>
<pre><code class="language-java">String rawPassword = (String) request.getAttribute("rawPassword");</code></pre>
<h2 id="bd-testing-the-basicauthextractor" data-id="testing-the-basicauthextractor">5. Testing the BasicAuthExtractor</h2><div class="bd-anchor" id="testing-the-basicauthextractor"></div>
<p>Let’s start by testing the core extraction logic. First, we need to ensure it correctly handles a valid Basic Authentication header and returns the expected credentials array:</p>
<pre><code class="language-java">@Test
void givenValidHeader_whenExtract_thenReturnCredentialsArray() {
    // Given
    String header = encodeCredentials("admin", "secret");
    // When
    String[] credentials = BasicAuthExtractor.extractCredentials(header);
    // Then
    assertThat(credentials).isNotNull();
    assertThat(credentials).hasSize(2);
    assertThat(credentials[0]).isEqualTo("admin");
    assertThat(credentials[1]).isEqualTo("secret");
}</code></pre>
<p>To keep our tests clean and readable, we utilize a helper method that handles the Base64 encoding and header formatting for us:</p>
<pre><code class="language-java">private String encodeCredentials(String username, String password) {
    String credentials = username + ":" + password;
    return "Basic " + Base64.getEncoder().encodeToString(credentials.getBytes());
}</code></pre>
<p>Additionally, we need to verify that the method safely returns <em>null</em> for invalid headers, such as those missing the <em>Basic</em> prefix or using a different authentication scheme:</p>
<pre><code class="language-java">@Test
void givenMissingBasicPrefix_whenExtract_thenReturnNull() {
    // Given
    String header = "Bearer some-token";
    // When
    String[] credentials = BasicAuthExtractor.extractCredentials(header);
    // Then
    assertThat(credentials).isNull();
}</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 how HTTP Basic Authentication encodes credentials and how to decode them manually using Java’s Base64 utility. We also explored how to capture the raw password using a custom filter. While extracting passwords is sometimes necessary for legacy integrations, it should be avoided whenever possible due to the inherent security risks. As always, the source code is available <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/eugenp/tutorials/tree/master/spring-boot-modules/spring-boot-basic-customization-3">over on GitHub</a>.</p>The post <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-http-basic-authentication-httpservletrequest">Getting HTTP Basic Authentication from HttpServletRequest</a> first appeared on <a href="https://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/957111833/0/baeldung">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/957111833/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/957111833/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/957111833/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/957111833/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/957111833/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-http-basic-authentication-httpservletrequest#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-http-basic-authentication-httpservletrequest/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/~/957111833/0/baeldung~Getting-HTTP-Basic-Authentication-from-HttpServletRequest/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-weekly-647</feedburner:origLink>
		<title>Java Weekly, Issue 647</title>
		<link>https://feeds.feedblitz.com/~/956980241/0/baeldung~Java-Weekly-Issue</link>
					<comments>https://feeds.feedblitz.com/~/956980241/0/baeldung~Java-Weekly-Issue#respond</comments>
		
		<dc:creator><![CDATA[baeldung]]></dc:creator>
		<pubDate>Fri, 22 May 2026 13:41:58 +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=203802</guid>
					<description><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/2016/10/social-Weekly-Reviews-4.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="max-width:100% !important;height:auto !important;float: left; margin-right: 5px;" loading="lazy" /><p>A look at the last few Java releases and feedback loops for agents. A solid week.</p>
The post <a rel="NOFOLLOW" href="https://feeds.feedblitz.com/~/956980241/0/baeldung~Java-Weekly-Issue">Java Weekly, Issue 647</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/956980241/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/956980241/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/956980241/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/956980241/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/956980241/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-647#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-647/feed"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/commentsrss20.png"></a>&#160;</div>]]>
</description>
										<content:encoded><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/2016/10/social-Weekly-Reviews-4.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="float: left; margin-right: 5px;" decoding="async" loading="lazy" srcset="https://www.baeldung.com/wp-content/uploads/2016/10/social-Weekly-Reviews-4.jpg 952w, https://www.baeldung.com/wp-content/uploads/2016/10/social-Weekly-Reviews-4-300x157.jpg 300w, https://www.baeldung.com/wp-content/uploads/2016/10/social-Weekly-Reviews-4-768x402.jpg 768w" sizes="auto, (max-width: 580px) 100vw, 580px" /><h2 style="text-align: left;" id="bd-spring-and-java" data-id="spring-and-java">1.<strong> Spring and Java</strong></h2>
<div class="bd-anchor" id="spring-and-java"></div>
<p><strong><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://inside.java/2026/05/19/javaone-better-jdk26/">&gt;&gt; Java 26: Better Language, Better APIs, Better Runtime</a></strong> [<span style="color: #993300;">inside.java</span>]</p>
<p>Nicolai walks through the Java platform&#8217;s recent evolution, from JDK 21 through 25 and into JDK 26. Good way to catch up.</p>
<h4><strong>Also worth reading:</strong></h4>
<ul>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://inside.java/2026/05/18/javaone-caching-agentic-ai/" target="_blank" rel="noopener"><strong>Caching for Agentic Java Systems: Internal, Distributed, and Semantic</strong></a> [<span style="color: #800000;">inside.java</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://foojay.io/today/dont-panic-the-thymeleaf-template-injection-that-only-hurts-if-you-let-it-cve-2026-40478/" target="_blank" rel="noopener"><strong>Don&#8217;t Panic: The Thymeleaf Template Injection That Only Hurts If You Let It (CVE-2026-40478)</strong></a> [<span style="color: #800000;">foojay.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://foojay.io/today/from-zero-really-zero-to-opentelemetry/" target="_blank" rel="noopener"><strong>From Zero (Really Zero) to OpenTelemetry</strong></a> [<span style="color: #800000;">foojay.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://blog.jetbrains.com/kotlin/2026/05/built-for-productivity-what-the-data-shows-about-kotlin/" target="_blank" rel="noopener"><strong>Built for Productivity: What the Data Finally Shows About Kotlin</strong></a> [<span style="color: #800000;">jetbrains.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://foojay.io/today/all-azul-zulu-container-images-explained-ca-sa-and-chainguard/" target="_blank" rel="noopener"><strong>All Azul Zulu Container Images Explained: CA, SA, and Chainguard</strong></a> [<span style="color: #800000;">foojay.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://foojay.io/today/boxlang-ai-series-complete-guide-to-building-ai-agents/" target="_blank" rel="noopener"><strong>BoxLang AI Series: Complete Guide to Building AI Agents</strong></a> [<span style="color: #800000;">foojay.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://inside.java/2026/05/20/quality-heads-up/" target="_blank" rel="noopener"><strong>Quality Outreach Heads-up &#8211; JDK 27: Numeric Fields in JSON Thread Dumps</strong></a> [<span style="color: #800000;">inside.java</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://inside.java/2026/05/17/jep531-target-jdk27/" target="_blank" rel="noopener"><strong>JEP targeted to JDK 27: 531: Lazy Constants (3rd Preview)</strong></a> [<span style="color: #800000;">inside.java</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://inside.java/2026/05/17/quality-heads-up/" target="_blank" rel="noopener"><strong>Quality Outreach Heads-up &#8211; JDK 27: Post-Quantum Hybrid Key Exchange for TLS 1.3</strong></a> [<span style="color: #800000;">inside.java</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://inside.java/2026/05/16/javaone-jcmd-jvm-analysis/" target="_blank" rel="noopener"><strong>Post-Mortem JVM Crash Analysis with jcmd</strong></a> [<span style="color: #800000;">inside.java</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://inside.java/2026/05/15/quality-heads-up/" target="_blank" rel="noopener"><strong>Quality Outreach Heads-up &#8211; JDK 26: Warnings About Final Field Mutation</strong></a> [<span style="color: #800000;">inside.java</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.petrikainulainen.net/programming/unit-testing/getting-started-with-mockk-the-setup/" target="_blank" rel="noopener"><strong>Getting Started With MockK: The Setup</strong></a> [<span style="color: #800000;">petrikainulainen.net</span>]</li>
</ul>
<h4><strong>Webinars and presentations:</strong></h4>
<ul>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://spring.io/blog/2026/05/19/spring-office-hours-podcast-S5E16" target="_blank" rel="noopener"><strong>Spring Office Hours Podcast: S5E16 &#8211; May Release Train Shift &amp; What&#8217;s Coming in Spring Boot 4.1</strong></a> [<span style="color: #800000;">spring.io</span>]</li>
</ul>
<h4><strong>Time to upgrade:</strong></h4>
<ul>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://foojay.io/today/glassfish-8-0-2-released/" target="_blank" rel="noopener"><strong>GlassFish 8.0.2 Released: With important security fixes, other improvements, and commercial support</strong></a> [<span style="color: #800000;">foojay.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://foojay.io/today/boxlang-v1-13-0-compatibility-concurrency-and-formatter-maturity/" target="_blank" rel="noopener"><strong>BoxLang v1.13.0: Compatibility, Concurrency, and Formatter Maturity</strong></a> [<span style="color: #800000;">foojay.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://blog.jetbrains.com/idea/2026/05/intellij-idea-2026-1-2/" target="_blank" rel="noopener"><strong>IntelliJ IDEA 2026.1.2 Is Out!</strong></a> [<span style="color: #800000;">jetbrains.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://blog.jetbrains.com/kotlin/2026/05/compose-multiplatform-1-11-0/" target="_blank" rel="noopener"><strong>Compose Multiplatform 1.11.0 Is Now Available</strong></a> [<span style="color: #800000;">jetbrains.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/quarkusio/quarkus/releases/tag/3.36.0" target="_blank" rel="noopener"><strong>Quarkus 3.36.0</strong></a>, <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/quarkusio/quarkus/releases/tag/3.35.4" target="_blank" rel="noopener"><strong>Quarkus 3.35.4</strong></a>, <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/quarkusio/quarkus/releases/tag/3.33.2" target="_blank" rel="noopener"><strong>Quarkus 3.33.2</strong></a>, and <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/quarkusio/quarkus/releases/tag/3.27.4" target="_blank" rel="noopener"><strong>Quarkus 3.27.4</strong></a> [<span style="color: #800000;">github.com/quarkusio</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/Netflix/zuul/releases/tag/v3.6.8" target="_blank" rel="noopener"><strong>Zuul v3.6.8</strong></a>, <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/Netflix/zuul/releases/tag/v3.6.7" target="_blank" rel="noopener"><strong>Zuul v3.6.7</strong></a>, <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/Netflix/zuul/releases/tag/v3.6.6" target="_blank" rel="noopener"><strong>Zuul v3.6.6</strong></a>, and <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/Netflix/zuul/releases/tag/v3.6.5" target="_blank" rel="noopener"><strong>Zuul v3.6.5</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="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://martinfowler.com/articles/sensors-for-coding-agents.html">&gt;&gt; Maintainability sensors for coding agents</a></strong> [<span style="color: #993300;">martinfowler.com</span>]</p>
<p>A practical look at keeping AI-assisted codebases maintainable, using &#8220;sensors&#8221; such as linting, dependency rules, coupling data, and modularity reviews to give coding agents fast feedback. Good stuff.</p>
<h4><strong>Also worth reading:</strong></h4>
<ul>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://blog.scottlogic.com/2026/05/14/the-human-bottleneck.html" target="_blank" rel="noopener"><strong>The Human Bottleneck</strong></a> [<span style="color: #800000;">scottlogic.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://netflixtechblog.medium.com/the-evolution-of-cassandra-data-movement-at-netflix-6e13329c80a1" target="_blank" rel="noopener"><strong>The Evolution of Cassandra Data Movement at Netflix</strong></a> [<span style="color: #800000;">netflixtechblog.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://blog.frankel.ch/seasons-time-lapse/1/" target="_blank" rel="noopener"><strong>Seasons time-lapse &#8211; the foundations</strong></a> [<span style="color: #800000;">frankel.ch</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://martinfowler.com/bliki/InterrogatoryLLM.html" target="_blank" rel="noopener"><strong>Interrogatory LLM</strong></a> [<span style="color: #800000;">martinfowler.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://blog.scottlogic.com/2026/05/18/talking-about-tech.html" target="_blank" rel="noopener"><strong>Finding Your Voice: A Guide to Technical Communication</strong></a> [<span style="color: #800000;">scottlogic.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://blog.scottlogic.com/2026/05/13/alternative-coding-agents-pi.html" target="_blank" rel="noopener"><strong>Alternative Coding Agents: Pi</strong></a> [<span style="color: #800000;">scottlogic.com</span>]</li>
</ul>
<h2 style="text-align: left;" id="bd-pick-of-the-week" data-id="pick-of-the-week">3.<strong> Pick of the Week</strong></h2>
<div class="bd-anchor" id="pick-of-the-week"></div>
<p><strong><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://markmanson.net/the-backwards-law">&gt;&gt; The Backwards Law—Why the Best Things in Life Must Be Let Go</a></strong> [<span style="color: #993300;">markmanson.net</span>]</p>The post <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-weekly-647">Java Weekly, Issue 647</a> first appeared on <a href="https://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/956980241/0/baeldung">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/956980241/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/956980241/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/956980241/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/956980241/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/956980241/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-647#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-647/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/~/956980241/0/baeldung~Java-Weekly-Issue/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<webfeeds:featuredImage>https://www.baeldung.com/wp-content/uploads/2016/10/social-Weekly-Reviews-4-150x150.jpg</webfeeds:featuredImage></item>
<item>
<feedburner:origLink>https://www.baeldung.com/java-weekly-646</feedburner:origLink>
		<title>Java Weekly, Issue 646</title>
		<link>https://feeds.feedblitz.com/~/956081237/0/baeldung~Java-Weekly-Issue</link>
					<comments>https://feeds.feedblitz.com/~/956081237/0/baeldung~Java-Weekly-Issue#respond</comments>
		
		<dc:creator><![CDATA[baeldung]]></dc:creator>
		<pubDate>Fri, 15 May 2026 12:51:12 +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=203778</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>Thinking about code in the age of AI and a deep loop at ArchRules and ArchUnit at scale. A good week.</p>
The post <a rel="NOFOLLOW" href="https://feeds.feedblitz.com/~/956081237/0/baeldung~Java-Weekly-Issue">Java Weekly, Issue 646</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/956081237/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/956081237/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/956081237/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/956081237/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/956081237/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-646#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-646/feed"><img height="20" style="border:0;margin:0;padding:0;" src="https://assets.feedblitz.com/i/commentsrss20.png"></a>&#160;</div>]]>
</description>
										<content:encoded><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/2016/10/social-Weekly-Reviews-4.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="float: left; margin-right: 5px;" decoding="async" loading="lazy" srcset="https://www.baeldung.com/wp-content/uploads/2016/10/social-Weekly-Reviews-4.jpg 952w, https://www.baeldung.com/wp-content/uploads/2016/10/social-Weekly-Reviews-4-300x157.jpg 300w, https://www.baeldung.com/wp-content/uploads/2016/10/social-Weekly-Reviews-4-768x402.jpg 768w" sizes="auto, (max-width: 580px) 100vw, 580px" /><h2 style="text-align: left;" id="bd-spring-and-java" data-id="spring-and-java">1.<strong> Spring and Java</strong></h2>
<div class="bd-anchor" id="spring-and-java"></div>
<p><strong><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://netflixtechblog.com/scaling-archunit-with-nebula-archrules-b4642c464c5a?source=rss-c3aeaf49d8a4------2">&gt;&gt; Scaling ArchUnit with Nebula ArchRules</a></strong> [<span style="color: #993300;">netflixtechblog.com</span>]</p>
<p>Netflix shares how its JVM Ecosystem team scales architecture rules across thousands of Java repositories with Nebula ArchRules and ArchUnit. A strong practical read on build-time feedback, technical debt visibility, and turning architecture guidance into enforceable, fleet-wide checks.</p>
<h4><strong>Also worth reading:</strong></h4>
<ul>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://inside.java/2026/05/12/javaone-post-native-interop/" target="_blank" rel="noopener"><strong>Native Interoperability with JDK 25 and the FFM API</strong></a> [<span style="color: #800000;">inside.java</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://blog.frankel.ch/tokensparsamkeit-coding-assistants/" target="_blank" rel="noopener"><strong>Tokensparsamkeit for coding assistants</strong></a> [<span style="color: #800000;">frankel.ch</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://foojay.io/today/java-is-not-the-dark-side-why-learning-java-is-easier-than-you-think/" target="_blank" rel="noopener"><strong>Java is Not the Dark Side: Why Learning Java is Easier Than You Think</strong></a> [<span style="color: #800000;">foojay.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://foojay.io/today/liquid-glass-material-3-and-a-lot-of-plumbing/" target="_blank" rel="noopener"><strong>Liquid Glass, Material 3, And A Lot Of Plumbing</strong></a> [<span style="color: #800000;">foojay.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://foojay.io/today/using-the-azul-zulu-docker-official-images-from-simple-pull-to-lean-container/" target="_blank" rel="noopener"><strong>Using the Azul Zulu Docker Official Images: From Simple Pull to Lean Container</strong></a> [<span style="color: #800000;">foojay.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://foojay.io/today/boxlang-ai-deep-dive-part-7-of-7-mcp-the-protocol-that-connects-everything/" target="_blank" rel="noopener"><strong>BoxLang AI Deep Dive &#8211; Part 7 of 7: MCP &#8211; The Protocol That Connects Everything</strong></a> [<span style="color: #800000;">foojay.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.infoq.com/news/2026/05/jep-533-jdk-27/" target="_blank" rel="noopener"><strong>JEP 533 Tightens Exception Handling in Java&#8217;s Structured Concurrency for JDK 27</strong></a> [<span style="color: #800000;">infoq.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://inside.java/2026/05/13/quality-heads-up/" target="_blank" rel="noopener"><strong>Quality Outreach Heads-up &#8211; JDK 27: Removal of Deprecated Java Launcher Options</strong></a> [<span style="color: #800000;">inside.java</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://inside.java/2026/05/11/jep533-target-jdk27/" target="_blank" rel="noopener"><strong>JEP targeted to JDK 27: 533: Structured Concurrency (7th Preview)</strong></a> [<span style="color: #800000;">inside.java</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://inside.java/2026/05/08/jep532-target-jdk27/" target="_blank" rel="noopener"><strong>JEP targeted to JDK 27: 532: Primitive Types in Patterns, instanceof, and switch (5th Preview)</strong></a> [<span style="color: #800000;">inside.java</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://blogs.oracle.com/java/release-of-the-new-java-card-development-kit-version-26-0" target="_blank" rel="noopener"><strong>Release of the new Java Card Development Kit version 26.0</strong></a> [<span style="color: #800000;">oracle.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://blogs.oracle.com/java/how-preview-features-support-java-card-evolution" target="_blank" rel="noopener"><strong>How Preview Features Support Java Card Evolution</strong></a> [<span style="color: #800000;">oracle.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.wildfly.org/news/2026/05/12/Next-Gen-Management-Console-for-WildFly/" target="_blank" rel="noopener"><strong>Next-Gen Management Console for WildFly</strong></a> [<span style="color: #800000;">wildfly.org</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://blog.jooq.org/simplifying-anti-join-with-jooq-syntax/" target="_blank" rel="noopener"><strong>Simplifying ANTI JOIN with jOOQ Syntax</strong></a> [<span style="color: #800000;">jooq.org</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://advancedweb.hu/designing-safer-listitems-and-getitem-permissions/" target="_blank" rel="noopener"><strong>Designing safer listItems and getItem permissions</strong></a> [<span style="color: #800000;">advancedweb.hu</span>]</li>
</ul>
<h4><strong>Webinars and presentations:</strong></h4>
<ul>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://foojay.io/today/foojay-podcast-95/" target="_blank" rel="noopener"><strong>Foojay Podcast #95: Is Your Java App Actually Secure, Or Does It Just Look That Way?</strong></a> [<span style="color: #800000;">foojay.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.infoq.com/podcasts/java-ee-quarkus-llm/" target="_blank" rel="noopener"><strong>Podcast: From Java EE to Quarkus and LLMs: Adam Bien&#8217;s Playbook for Boring, Future-Proof Systems</strong></a> [<span style="color: #800000;">infoq.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://inside.java/2026/05/14/newscast-112/" target="_blank" rel="noopener"><strong>Java Gets Post-Quantum TLS &#8211; Inside Java Newscast #112</strong></a> [<span style="color: #800000;">inside.java</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://spring.io/blog/2026/05/14/a-bootiful-podcast-daniel-adib-saikali" target="_blank" rel="noopener"><strong>A Bootiful Podcast: the legendary Adib Saikali</strong></a> [<span style="color: #800000;">spring.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://spring.io/blog/2026/05/07/a-bootiful-podcast-daniel-garnier-moiroux" target="_blank" rel="noopener"><strong>A Bootiful Podcast: Daniel Garnier-Moiroux on his new book &#8216;Testing Spring Boot Applications&#8217;</strong></a> [<span style="color: #800000;">spring.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://spring.io/blog/2026/05/11/spring-office-hours-podcast-S5E15" target="_blank" rel="noopener"><strong>Spring Office Hours Podcast: S5E15 &#8211; Upgrading Spring and OSS Security</strong></a> [<span style="color: #800000;">spring.io</span>]</li>
</ul>
<h4><strong>Time to upgrade:</strong></h4>
<ul>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://foojay.io/today/the-12-labours-of-primefaces-15-0-15-release/" target="_blank" rel="noopener"><strong>THE 12 LABOURS OF PRIMEFACES 15.0.15 #release</strong></a> [<span style="color: #800000;">foojay.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://in.relation.to/2026/05/11/hibernate-search-8-4-0-CR1/" target="_blank" rel="noopener"><strong>Hibernate Search 8.4.0.CR1 is out</strong></a> [<span style="color: #800000;">in.relation.to</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://spring.io/blog/2026/05/08/spring-ai-1-0-7-1-1-6-2-0-0-M6-available-now" target="_blank" rel="noopener"><strong>Spring AI 1.0.7, 1.1.6, 2.0.0-M6 available now</strong></a> [<span style="color: #800000;">spring.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://quarkus.io/blog/quarkus-3-35-3-released/" target="_blank" rel="noopener"><strong>Quarkus 3.35.3 &#8211; Maintenance release</strong></a> [<span style="color: #800000;">quarkus.io</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/apache/maven/releases/tag/maven-3.9.16" target="_blank" rel="noopener"><strong>Maven 3.9.16</strong></a> [<span style="color: #800000;">github.com/apache</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/elastic/elasticsearch/releases/tag/v9.4.1" target="_blank" rel="noopener"><strong>Elasticsearch 9.4.1</strong></a> [<span style="color: #800000;">github.com/elastic</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/Netflix/zuul/releases/tag/v3.6.4" target="_blank" rel="noopener"><strong>Zuul 3.6.4</strong></a> [<span style="color: #800000;">github.com/Netflix</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/micronaut-projects/micronaut-core/releases/tag/v5.0.0" target="_blank" rel="noopener"><strong>Micronaut Core 5.0.0</strong></a> [<span style="color: #800000;">github.com/micronaut-projects</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/payara/Payara/releases/tag/payara-server-7.2026.5" target="_blank" rel="noopener"><strong>Payara Platform Community 7.2026.5</strong></a> [<span style="color: #800000;">github.com/payara</span>]</li>
</ul>
<h2 style="text-align: left;" id="bd-technical-amp-musings" data-id="technical-amp-musings">2.<strong> Technical &amp; Musings</strong></h2>
<div class="bd-anchor" id="technical-amp-musings"></div>
<p><strong><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://martinfowler.com/articles/what-is-code.html">&gt;&gt; What is Code</a></strong> [<span style="color: #993300;">martinfowler.com</span>]</p>
<p>A thoughtful piece for anyone thinking about what software development means as AI changes how code is written and maintained. A weekend read.</p>
<h4><strong>Also worth reading:</strong></h4>
<ul>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://lucumr.pocoo.org/2026/5/8/local-models/" target="_blank" rel="noopener"><strong>Pushing Local Models With Focus And Polish</strong></a> [<span style="color: #800000;">lucumr.pocoo.org</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://netflixtechblog.medium.com/data-projects-managing-data-assets-at-netflix-scale-7ca25888591e?source=rss-c3aeaf49d8a4------2" target="_blank" rel="noopener"><strong>Data Projects: Managing Data Assets at Netflix Scale</strong></a> [<span style="color: #800000;">netflixtechblog.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://mnot.net/blog/2026/feed-survey" target="_blank" rel="noopener"><strong>Web Feeds in 2026: A Survey</strong></a> [<span style="color: #800000;">mnot.net</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://blog.scottlogic.com/2026/05/12/data-engineering-on-a-budget.html" target="_blank" rel="noopener"><strong>Data Engineering on a Budget</strong></a> [<span style="color: #800000;">scottlogic.com</span>]</li>
<li><strong>&gt;&gt;</strong> <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://event-driven.io/en/should_we_trust_domain_experts/" target="_blank" rel="noopener"><strong>Don&#8217;t overestimate domain knowledge</strong></a> [<span style="color: #800000;">event-driven.io</span>]</li>
</ul>
<h2 style="text-align: left;" id="bd-pick-of-the-week" data-id="pick-of-the-week">3.<strong> Pick of the Week</strong></h2>
<div class="bd-anchor" id="pick-of-the-week"></div>
<p><strong><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://wasp.sh/blog/2026/05/13/new-language-for-web-dev-was-a-mistake">&gt;&gt; 5 Years and $5M Later: Inventing a New Programming Language for Web Development Was a Mistake</a></strong> [<span style="color: #800000;">wasp.sh</span>]</p>The post <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-weekly-646">Java Weekly, Issue 646</a> first appeared on <a href="https://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/956081237/0/baeldung">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/956081237/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/956081237/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/956081237/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/956081237/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/956081237/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-646#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-646/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/~/956081237/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/selenium-webdrivermanager</feedburner:origLink>
		<title>Introduction to WebDriverManager</title>
		<link>https://feeds.feedblitz.com/~/956008835/0/baeldung~Introduction-to-WebDriverManager</link>
					<comments>https://feeds.feedblitz.com/~/956008835/0/baeldung~Introduction-to-WebDriverManager#respond</comments>
		
		<dc:creator><![CDATA[Sidrah Abdullah]]></dc:creator>
		<pubDate>Fri, 15 May 2026 01:11:19 +0000</pubDate>
				<category><![CDATA[Testing]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[JUnit]]></category>
		<category><![CDATA[Selenium]]></category>
		<guid isPermaLink="false">https://www.baeldung.com/selenium-webdrivermanager</guid>
					<description><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/2017/08/Java-on-Baeldung-2.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="max-width:100% !important;height:auto !important;float: left; margin-right: 5px;" loading="lazy" /><p>Learn about <em>WevDriverManager</em> in Java, how to set it up, along with different applications and modes of operation.</p>
The post <a rel="NOFOLLOW" href="https://feeds.feedblitz.com/~/956008835/0/baeldung~Introduction-to-WebDriverManager">Introduction to <em>WebDriverManager</em></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/956008835/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/956008835/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2017%2f08%2fJava-on-Baeldung-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/956008835/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/956008835/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/956008835/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/selenium-webdrivermanager#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/selenium-webdrivermanager/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/Java-on-Baeldung-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/Java-on-Baeldung-2.jpg 952w, https://www.baeldung.com/wp-content/uploads/2017/08/Java-on-Baeldung-2-300x157.jpg 300w, https://www.baeldung.com/wp-content/uploads/2017/08/Java-on-Baeldung-2-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>The purpose of web automation in Java is simple. In essence, the idea is to open a browser and interact with a web page. However, an immediate challenge appears from the browser itself, namely, the binary compatibility. To elaborate, each browser requires a corresponding driver binary, and that binary must match the installed browser version. Even a small mismatch leads to runtime errors. <em>WebDriverManager</em> in Java addresses this issue by automating driver management in Java-based <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-selenium-with-junit-and-testng" target="_blank" rel="noopener">Selenium</a> projects.</p>
<p>In this tutorial, <strong>we&#8217;ll introduce <em>WebDriverManager</em></strong>. First, we&#8217;ll explore the purpose and need for this driver. Subsequently, we&#8217;ll look at how to include <em>WebDriverManager</em> in the code. Lastly, we&#8217;ll discuss integrating <em>WebDriverManager</em> with different libraries.</p>
<h2 id="bd-what-is-webdrivermanager" data-id="what-is-webdrivermanager">2. What Is <em>WebDriverManager</em>?</h2>
<div class="bd-anchor" id="what-is-webdrivermanager"></div>
<p><strong><em>WebDriverManager</em> is a Java library that automatically resolves, downloads, and configures browser drivers required by Selenium</strong>. Instead of manually managing binaries and system properties, the library handles these steps programmatically. It determines which browser version is installed, finds the correct driver version, downloads it if necessary, and configures the system so Selenium can use it.</p>
<p>Notably, Selenium includes a built-in tool called Selenium Manager, which also automates driver management. Selenium Manager removes the need to manually download browser drivers. However, <em>WebDriverManager</em> is an enhanced alternative with additional features, such as driver caching control, support for Dockerized browsers, and flexibility in complex environments.</p>
<p>A traditional Selenium setup requires explicitly specifying the driver path in the code. For instance, for a Chrome browser, we set the driver using <em>setProperty</em>:</p>
<pre><code class="language-java">System.setProperty("webdriver.chrome.driver", "/path/to/chromedriver");
WebDriver driver = new ChromeDriver();</code></pre>
<p>This approach works initially but doesn&#8217;t scale well. <strong>Every time the browser updates, the corresponding driver should also be updated manually</strong>. In shared environments such as <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/junit-5" target="_blank" rel="noopener">CI/CD</a> pipelines or team projects, maintaining consistent driver versions becomes difficult. Moreover, hardcoded paths make the code less portable across systems.</p>
<p>In addition, <em>WebDriverManager</em> removes this burden by handling driver resolution dynamically. It also caches downloaded drivers locally, so repeated executions don&#8217;t trigger unnecessary downloads. As a result, test execution becomes both faster and more reliable.</p>
<p>To use <em>WebDriverManager</em>, we should include it as a dependency in the <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/java-xml" target="_blank" rel="noopener">XML</a> file.</p>
<p>For <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/spring-with-maven#maven" target="_blank" rel="noopener">Maven</a>, we use the <em>&lt;dependency&gt;</em> tag:</p>
<pre><code class="language-xml">&lt;dependency&gt;
    &lt;groupId&gt;io.github.bonigarcia&lt;/groupId&gt;
    &lt;artifactId&gt;webdrivermanager&lt;/artifactId&gt;
    &lt;version&gt;6.3.3&lt;/version&gt;
    &lt;scope&gt;test&lt;/scope&gt;
&lt;/dependency&gt;</code></pre>
<p>For Gradle, we use dependencies:</p>
<pre><code class="language-xml">dependencies {
    testImplementation("io.github.bonigarcia:webdrivermanager:6.3.3")
}</code></pre>
<p>This ensures the library is available during test execution without affecting production builds.</p>
<h2 id="bd-using-webdrivermanager" data-id="using-webdrivermanager">3. Using <em>WebDriverManager</em></h2>
<div class="bd-anchor" id="using-webdrivermanager"></div>
<p>In this example, we look at a basic way to use <em>WebDriverManager</em> for a simple call:</p>
<pre><code class="language-java">import io.github.bonigarcia.wdm.WebDriverManager;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
public class SimpleWebDriver {
     public static void main(String[] args) {
          WebDriverManager.chromedriver().setup();
          WebDriver driver = new ChromeDriver();
          driver.get("https://google.com");
          driver.quit();
}
}</code></pre>
<p>In the example above, <em>WebDriverManager.chromedriver()</em> creates a manager instance specifically for Chrome. This instance hides all logic required to handle <em>ChromeDriver</em> binaries.</p>
<p>To explain the code further, <strong>calling <em>.setup()</em> triggers the resolution process</strong>:</p>
<ol>
<li style="list-style-type: none">
<ol>
<li>Inspect the system to detect the installed Chrome version.</li>
<li>Determine the compatible driver version.</li>
<li>Download the correct driver version if not already cached.</li>
<li>Set the appropriate system property <em>webdriver.chrome.driver</em>.</li>
</ol>
</li>
</ol>
<p>Because of this, the subsequent line of <em>ChromeDriver()</em> works without any manual configuration.</p>
<p>In addition, <em>driver.get()</em> opens the desired URL, and <em>driver.quit()</em> closes the browser and releases resources.</p>
<h2 id="bd-using-webdrivermanager-with-different-libraries" data-id="using-webdrivermanager-with-different-libraries">4. Using <em>WebDriverManager</em> With Different Libraries</h2>
<div class="bd-anchor" id="using-webdrivermanager-with-different-libraries"></div>
<p>In this section, we explore how <em>WebDriverManager</em> integrates with <em>JUnit</em> for structured test execution and how it supports multiple browsers through a consistent interface. Furthermore, we also explore how it extends into more advanced use cases such as generic driver instantiation and browser detection.</p>
<h3 id="bd-1-usingwebdrivermanager-with-junit" data-id="1-usingwebdrivermanager-with-junit">4.1. Using <em>WebDriverManager</em> With JUnit</h3>
<div class="bd-anchor" id="1-usingwebdrivermanager-with-junit"></div>
<p>In professional test environments, <strong>it&#8217;s considered best practice to perform setup operations once per test class rather than repeating them before every individual test</strong>. <em>WebDriverManager</em> fits into this pattern when combined with <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/junit-5" target="_blank" rel="noopener">JUnit</a> 5&#8217;s <em>@BeforeAll</em> annotation:</p>
<pre><code class="language-java">import io.github.bonigarcia.wdm.WebDriverManager;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
public class GoogleTest {
    @BeforeAll
    static void setupClass() {
        WebDriverManager.chromedriver().setup();
    }
    @Test
    void testGoogle() {
        WebDriver driver = new ChromeDriver();
        driver.get("https://www.google.com");
        driver.quit();
    }
}</code></pre>
<p>The <em>@BeforeAll</em> annotation guarantees that the <em>setupClass()</em> method is executed exactly once before any test methods in the class run. By calling <em>WebDriverManager.chromedriver().setup()</em> at this stage, the framework downloads and configures the correct ChromeDriver binary ahead of time, so that later tests don&#8217;t need to repeat this process. This avoids redundant driver resolution for each test case. Once the setup is complete, each individual test method can focus on browser interactions, navigating to a URL, and quitting the driver.</p>
<h3 id="bd-2-working-with-multiple-browsers" data-id="2-working-with-multiple-browsers">4.2. Working With Multiple Browsers</h3>
<div class="bd-anchor" id="2-working-with-multiple-browsers"></div>
<p>One of the strengths of <em>WebDriverManager</em> is its ability to manage drivers for multiple browsers using the same consistent pattern. Rather than writing separate setup logic for each browser, the library provides dedicated manager methods that follow an identical structure regardless of which browser is being targeted:</p>
<pre><code class="language-java">// Firefox
WebDriverManager.firefoxdriver().setup();
WebDriver driver = new org.openqa.selenium.firefox.FirefoxDriver();
// Microsoft Edge
WebDriverManager.edgedriver().setup();
WebDriver driver = new org.openqa.selenium.edge.EdgeDriver();</code></pre>
<p>Each method returns a browser-specific manager object that handles the resolution and configuration of the appropriate driver binary for that browser.</p>
<h3 id="bd-3generic-manager-usage" data-id="3generic-manager-usage">4.3. Generic Manager Usage</h3>
<div class="bd-anchor" id="3generic-manager-usage"></div>
<p>One of the scenarios for generic manager usage is when we don&#8217;t know the type of target browser at compile time.</p>
<p>For example, <strong>when the browser type is passed as a runtime parameter, or it is read from a configuration file, we use <em>WebDriverManager</em> to determine the appropriate manager dynamically</strong>:</p>
<pre><code class="language-java">import io.github.bonigarcia.wdm.WebDriverManager;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
public class GenericExample {
    public static void main(String[] args) {
        WebDriverManager.getInstance(ChromeDriver.class).setup();
        WebDriver driver = new ChromeDriver();
        driver.get("https://example.com");
        driver.quit();
    }
}</code></pre>
<p>In the code above, the <em>getInstance(ChromeDriver.class)</em> call accepts a driver class as its argument and uses it to identify and return the correct manager at runtime. This means the same line of code can resolve the manager for any supported browser simply by swapping out the class reference. In practice, this is useful in parameterized or data-driven test frameworks where the browser type is injected from an external source.</p>
<h2 id="bd-conclusion" data-id="conclusion">5. Conclusion</h2>
<div class="bd-anchor" id="conclusion"></div>
<p>In this article, <strong>we began with a basic introduction to <em>WebDriverManager</em></strong>. We also discussed how to use this driver for Selenium automation. Lastly, we explored how to use this driver with various libraries.</p>
<p>To conclude, <em>WebDriverManager</em> simplifies Selenium automation by eliminating manual driver management. Instead of handling downloads, version compatibility, and configuration, projects can rely on a single method call to perform all setup tasks. This assists in maintaining a clean code, fewer runtime errors, and improved maintainability.</p>
<p>The source code is available <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://github.com/eugenp/tutorials/tree/master/testing-modules/selenium-3" target="_blank" rel="noopener">over on GitHub</a>.</p>The post <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/~https://www.baeldung.com/selenium-webdrivermanager">Introduction to <em>WebDriverManager</em></a> first appeared on <a href="https://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/956008835/0/baeldung">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/956008835/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/956008835/baeldung,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2f2017%2f08%2fJava-on-Baeldung-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/956008835/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/956008835/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/956008835/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/selenium-webdrivermanager#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/selenium-webdrivermanager/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/~/956008835/0/baeldung~Introduction-to-WebDriverManager/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<webfeeds:featuredImage>https://www.baeldung.com/wp-content/uploads/2017/08/Java-on-Baeldung-2-150x150.jpg</webfeeds:featuredImage></item>
</channel></rss>

