<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jonathan Vila</title>
    <description>The latest articles on DEV Community by Jonathan Vila (@jonathanvila).</description>
    <link>https://dev.to/jonathanvila</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F988929%2F5fec304e-5e7c-4ce2-9b2f-eceea9ca2f66.png</url>
      <title>DEV Community: Jonathan Vila</title>
      <link>https://dev.to/jonathanvila</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jonathanvila"/>
    <language>en</language>
    <item>
      <title>7 habits of Highly Effective Java Coding</title>
      <dc:creator>Jonathan Vila</dc:creator>
      <pubDate>Tue, 23 Sep 2025 17:16:04 +0000</pubDate>
      <link>https://dev.to/jonathanvila/7-habits-of-highly-effective-java-coding-4jdg</link>
      <guid>https://dev.to/jonathanvila/7-habits-of-highly-effective-java-coding-4jdg</guid>
      <description>&lt;h3&gt;
  
  
  &lt;strong&gt;From AI User to AI Pro&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Let's be real, AI coding tools are everywhere now. 🤖 They're no longer some shiny new toy—they're a part of our daily grind as developers, just like our morning coffee. ☕&lt;br&gt;
For us Java devs, whether we're wrestling with a giant legacy app or juggling a bunch of microservices, these tools look like a huge win for getting stuff done faster. 🚀&lt;br&gt;
But here's the catch: just coding faster isn't the whole story. If you're not careful, it can actually lead to bigger problems down the road. 🤔&lt;br&gt;
The real goal is to learn how to work with the AI to write code that's actually good—solid, secure, and won't give the next person on your team a headache or your company a serious problem.&lt;br&gt;
This means we have to level up from being copy-paste machines and become smart developers who really know how to handle these powerful tools. 💪&lt;/p&gt;

&lt;p&gt;So, I’m sharing 7 key habits that will help you do just that. This isn't just about speed; it's about getting way better at the job you love: 💡&lt;/p&gt;

&lt;p&gt;1. The Golden Rule: Take Pride and Ownership in Your Craft 🥇&lt;br&gt;
2. Feed the Beast: Your Project's Context is its Fuel ⛽&lt;br&gt;
3. Dodge the "Ball of Mud": Keep Your Code Maintainable 🧠&lt;br&gt;
4. Clean Your Room: No Stray Code or Sketchy Dependencies 🧹&lt;br&gt;
5. Trust but review: Analyze the AI, the Code, and the Supply Chain 🕵️‍♀️&lt;br&gt;
6. Beyond Coverage: Mandate Meaningful Tests ✅&lt;br&gt;
7. The Human Gateway: A Code Review for What AI Can't See 🧠&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;1. The Golden Rule: Take Pride and Ownership in Your Craft 🥇&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The first and most important habit isn't about blame; it's about &lt;strong&gt;pride and ownership&lt;/strong&gt;. As developers, we are modern-day craftspeople. There's a deep, intrinsic satisfaction that comes from delivering high-quality, elegant, and robust code. This sense of pride is the foundation of a successful career and a healthy team dynamic. It’s what transforms a difficult pull request conversation into a collaborative design session and what turns the daily task of writing code into an opportunity for learning and mastery.&lt;/p&gt;

&lt;p&gt;AI coding assistants are powerful new tools in our workshop, but like any power tool, they can be used to create beautiful work or to make a mess quickly. &lt;strong&gt;Blindly accepting AI-generated code is the fastest way to erode that professional pride&lt;/strong&gt;. When you let unvetted code into your codebase, you're not just introducing potential bugs; you're forfeiting a chance to learn, to improve, and to stand behind your work with &lt;strong&gt;confidence&lt;/strong&gt;. The rule isn't "you will be blamed"; it's "your name is on it, so make it something to be proud of."&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;From Painful PRs to Productive Conversations&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;We've all been in pull request (PR) reviews that feel like a slog. The comments are a long list of stylistic nits, potential null pointer exceptions, and questions like, "What is this part even supposed to do?". This often happens when code is rushed or not fully understood.&lt;/p&gt;

&lt;p&gt;Now, imagine a PR where the code has high quality, the logic is clear, and the implementation is robust, and obviously &lt;strong&gt;you completely understand the code inside the PR&lt;/strong&gt;. The conversation instantly elevates. Instead of nitpicking syntax, the team discusses architectural choices, business logic, and potential feature enhancements. This is where real collaboration happens.&lt;/p&gt;

&lt;p&gt;By using AI as a starting point and then meticulously refining the output, you ensure your PRs fall into the second category. You are demonstrating to your team that you've done the hard work of thinking, not just the easy work of prompting. &lt;strong&gt;You own the solution&lt;/strong&gt;, and the resulting discussion respects that ownership.&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;Technical Example: The AI's Brittle &lt;code&gt;CompletableFuture&lt;/code&gt; vs. The Crafted Resilient Solution&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Consider a common scenario in a microservices architecture: you need to build a user's dashboard by aggregating data from three different services concurrently. You ask an AI: &lt;em&gt;&lt;code&gt;“// Java: using CompletableFuture, concurrently fetch a user's details, their 5 most recent orders, and their product review count. Combine them into a single DTO and handle errors."&lt;/code&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The AI, aiming for a direct solution, might produce something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// AI-Generated First Draft - Brittle and Naive&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;UserDashboardDTO&lt;/span&gt; &lt;span class="nf"&gt;getDashboard&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Fire off all requests in parallel&lt;/span&gt;
    &lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;userFuture&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;supplyAsync&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;userService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Order&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ordersFuture&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;supplyAsync&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;orderService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getRecentForUser&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;reviewsFuture&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;supplyAsync&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;reviewService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;countByUser&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;

    &lt;span class="c1"&gt;// Wait for all of them to complete&lt;/span&gt;
    &lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;allOf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userFuture&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ordersFuture&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reviewsFuture&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// The first major flaw&lt;/span&gt;

    &lt;span class="c1"&gt;// If we get here, all services succeeded.&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;UserDashboardDTO&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userFuture&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;ordersFuture&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;reviewsFuture&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// The second flaw&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code is a hidden landmine in a distributed system. 💣&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Brittle Failure Mode:&lt;/strong&gt; &lt;code&gt;CompletableFuture.allOf(...).join()&lt;/code&gt; creates an "all-or-nothing" scenario. If just one of the services (e.g., &lt;code&gt;reviewService&lt;/code&gt;) times out or throws an error, the &lt;code&gt;join()&lt;/code&gt; call will throw an exception, and the entire operation fails. The user gets an error page instead of seeing their user details and orders, which were fetched successfully.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No Timeouts:&lt;/strong&gt; There are no timeouts defined. If &lt;code&gt;orderService&lt;/code&gt; is slow, this thread will hang indefinitely, consuming resources on your server.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inefficient Composition:&lt;/strong&gt; Calling &lt;code&gt;.get()&lt;/code&gt; after the &lt;code&gt;join()&lt;/code&gt; can re-throw exceptions and is less elegant than a proper composition chain.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A developer who &lt;strong&gt;takes pride in their craft&lt;/strong&gt; recognizes that in a microservices world, partial communications and network failure is not rare. They refactor the code for &lt;strong&gt;resilience and graceful degradation&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Human-Crafted, Professional Solution - Resilient and Robust&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;UserDashboardDTO&lt;/span&gt; &lt;span class="nf"&gt;getDashboard&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;ExecutorService&lt;/span&gt; &lt;span class="n"&gt;customExecutor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Executors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newVirtualThreadPerTaskExecutor&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Each future is now a self-contained, resilient unit of work.&lt;/span&gt;
    &lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;userFuture&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;supplyAsync&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;userService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="n"&gt;customExecutor&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;orTimeout&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;TimeUnit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SECONDS&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Set a reasonable timeout&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;exceptionally&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ex&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;GuestUser&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// On error, return a default/guest user&lt;/span&gt;

    &lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Order&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ordersFuture&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;supplyAsync&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;orderService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getRecentForUser&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="n"&gt;customExecutor&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;orTimeout&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;TimeUnit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SECONDS&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;exceptionally&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ex&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// On error, return an empty list&lt;/span&gt;

    &lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;reviewsFuture&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;supplyAsync&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;reviewService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;countByUser&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="n"&gt;customExecutor&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;orTimeout&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;TimeUnit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SECONDS&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;exceptionally&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ex&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// On error, return zero&lt;/span&gt;

    &lt;span class="c1"&gt;// Combine the results of the now-safe futures&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;CompletableFuture&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;allOf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userFuture&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ordersFuture&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reviewsFuture&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;thenApply&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;UserDashboardDTO&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;userFuture&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
            &lt;span class="n"&gt;ordersFuture&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
            &lt;span class="n"&gt;reviewsFuture&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;)).&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This professional solution is vastly superior. It handles failures gracefully within each asynchronous call using &lt;code&gt;.exceptionally()&lt;/code&gt;, allowing the dashboard to render with partial data. It enforces timeouts with &lt;code&gt;.orTimeout()&lt;/code&gt; to protect system resources. By explaining these choices in the PR—discussing the principles of resilient design and fault tolerance—&lt;strong&gt;YOU&lt;/strong&gt; demonstrate deep expertise that goes far beyond simply making the code "work." This is how you build a reputation for excellence and drive your career forward.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;2. Feed the Beast: Your Project's Context is its Fuel ⛽&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;AI coding assistants are incredibly powerful, but they aren't mind readers. They operate on a simple principle: garbage in, garbage out. If you give them a vague, one-line request, you'll get back a generic, probably useless, chunk of code. The secret to getting amazing results is to "feed the beast" with as much high-quality context as you possibly can.&lt;/p&gt;

&lt;p&gt;Think of it like briefing a new developer on your team. You wouldn't just say, "Hey, go build the shipping cost feature." You'd give them the Jira ticket, point them to the requirements, explain the existing data models, and show them the acceptance criteria. You need to do the exact same thing for your AI partner.&lt;/p&gt;

&lt;p&gt;This means going way beyond in-code comments. Give it the issue link, paste in the user story, and provide the Gherkin &lt;code&gt;feature&lt;/code&gt; file if you have one. The more details you provide about the "what" and "why," the better the AI will be at generating the "how."&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Technical Example: The Vague Wish vs. The Detailed Brief&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Imagine you're tasked with implementing a dynamic shipping cost calculation based on a complex set of business rules.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Vague Wish (and its useless result):&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You start with a lazy prompt, giving the AI almost nothing to work with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// TODO: Implement the shipping cost logic&lt;/span&gt;
&lt;span class="c1"&gt;// A vague prompt to the AI:&lt;/span&gt;
&lt;span class="c1"&gt;// "Java method to calculate shipping cost for an order" &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The AI, having no context, will produce a generic, over-simplified method that is completely wrong for your application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// AI's Generic (and wrong) Response:&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="nf"&gt;calculateShippingCost&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// A complete guess based on common, simple examples.&lt;/span&gt;
    &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;baseRate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"5.00"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;weightCharge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getWeightInKg&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;multiply&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"1.50"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;baseRate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;weightCharge&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code is a waste of time. It doesn't know about your business rules, your customer types, or your data structures. Now, let's try again by giving the AI a proper brief.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Detailed Brief (and its awesome result):&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This time, you treat the prompt like a mini-spec document, packing it with context right from your project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="cm"&gt;/*
 * Feature: JIRA-451 - Calculate Dynamic Shipping Cost
 * * User Story: As a user, I want to see an accurate shipping cost at checkout
 * based on my membership status, location, and the items in my cart.
 *
 * Acceptance Criteria (from feature file):
 * - Prime members in the US get free shipping.
 * - Non-Prime US orders have a $5 flat fee.
 * - International orders have a 15% surcharge on the subtotal.
 * - Any order containing a 'HEAVY_GOODS' item has an additional $25 fee.
 *
 * Relevant Data Classes:
 * class User { boolean isPrimeMember(); Address getAddress(); }
 * class Order { List&amp;lt;LineItem&amp;gt; getItems(); BigDecimal getSubtotal(); }
 * class LineItem { Product getProduct(); }
 * class Product { ProductCategory getCategory(); } // enum ProductCategory { STANDARD, HEAVY_GOODS }
 *
 * AI Prompt:
 * "Using the context and data classes above, write a Java method `calculateShipping`
 * that takes a User and an Order and returns the final shipping cost as a BigDecimal."
 */&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this rich context, the AI can now generate something incredibly useful and specific to your actual codebase:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// AI's Context-Aware (and useful) Response:&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="nf"&gt;calculateShipping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Rule 1: Prime members in the US&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isPrimeMember&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="s"&gt;"US"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAddress&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getCountryCode&lt;/span&gt;&lt;span class="o"&gt;()))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ZERO&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;shippingCost&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Rule 2 &amp;amp; 3: US vs. International&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"US"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAddress&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getCountryCode&lt;/span&gt;&lt;span class="o"&gt;()))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;shippingCost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"5.00"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Flat fee for non-prime US&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// 15% surcharge for international&lt;/span&gt;
        &lt;span class="n"&gt;shippingCost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getSubtotal&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;multiply&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"0.15"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Rule 4: Surcharge for heavy goods&lt;/span&gt;
    &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;hasHeavyGoods&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getItems&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;anyMatch&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getProduct&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getCategory&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nc"&gt;ProductCategory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;HEAVY_GOODS&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hasHeavyGoods&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;shippingCost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;shippingCost&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"25.00"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;shippingCost&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look at that difference! ✨ The second version is almost production-ready. It correctly implements the complex business logic because you gave the AI a map of your world. You spent an extra minute providing context and saved yourself thirty minutes of writing boilerplate and fixing the AI's guesses. That's a massive win.&lt;/p&gt;

&lt;p&gt;Furthermore, this idea of creating rich context is expanding beyond just code and tickets. A whole ecosystem of specialized AI tools is emerging to help create and understand high-level documentation, which then becomes another powerful source of context. &lt;/p&gt;

&lt;p&gt;MCP Servers can help to expand the capabilities of our AI Agents. Directories like &lt;a href="http://mcp.so" rel="noopener noreferrer"&gt;mcp.so&lt;/a&gt; are great places to discover these. For instance, you can use a tool to connect to Jira to get information about the issues for a given feature, or even Google Docs to get formal and extended requirements definitions. &lt;/p&gt;

&lt;p&gt;This information then serves as excellent context for your primary coding assistant, helping it understand the system's architecture when you ask it to write related code. This creates a virtuous cycle: you use AI to generate clear documentation, which in turn helps your coding AI generate better code.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;3. Dodge the "Ball of Mud": Keep Your Code Maintainable 🧠&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;"Keep it simple" is easy advice to give, but in the real world of enterprise Java, it’s not so simple, is it? A 20-line method might be simple, but if you have a hundred of them in a tangled mess, you've created a classic "Big Ball of Mud" architecture. 👎&lt;/p&gt;

&lt;p&gt;The real goal isn't just simplicity; it's &lt;strong&gt;maintainability&lt;/strong&gt;. We want to write code that our future selves (and our teammates) can read, debug, and extend without wanting to tear their hair out.&lt;/p&gt;

&lt;p&gt;AI assistants, for all their power, don't have a great sense of long-term consequences. They are fantastic at solving the immediate problem you give them, but they're not thinking about your architectural goals. They can, and will, generate overly clever, complex, or just plain weird code if you let them. Our job is to be the architect, not just the bricklayer, and guide the AI toward solutions that are easy to live with.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Technical Example: The "Clever" Stream vs. The Debuggable Loop&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;The Java Stream API is incredibly powerful, but it's also one of the easiest ways to write code that's "write-only." An AI, trained on millions of examples of functional programming, can get a little &lt;em&gt;too&lt;/em&gt; excited about streams.&lt;/p&gt;

&lt;p&gt;Imagine you need to process a list of new user signups. For each user, you need to check if they are eligible for a promo, send them a welcome email, and add them to a database, but only if they've verified their email.&lt;/p&gt;

&lt;p&gt;You ask your AI: &lt;em&gt;"// Java: using a stream, process this list of signups. Filter for verified users, check promo eligibility, send a welcome email, and save to the database. Return a list of the users who were successfully saved."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The AI might produce this "clever" one-liner:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// AI's "Clever" (but unmaintainable) Solution&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;processSignups&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SignUp&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;signups&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;signups&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;filter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;SignUp:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;isVerified&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Filter for verified users&lt;/span&gt;
                  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;peek&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;signup&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// DANGER: Side effects inside a stream!&lt;/span&gt;
                      &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;eligible&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;promoService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEligible&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;signup&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getEmail&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
                      &lt;span class="n"&gt;emailService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sendWelcomeEmail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;signup&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getEmail&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;eligible&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                  &lt;span class="o"&gt;})&lt;/span&gt;
                  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;convertAndSaveUser&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// This method handles the DB interaction&lt;/span&gt;
                  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;collect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Collectors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toList&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="nf"&gt;convertAndSaveUser&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SignUp&lt;/span&gt; &lt;span class="n"&gt;signup&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;signup&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;signup&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getEmail&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;userRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code is a maintenance nightmare. 😵&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Debugging Hell:&lt;/strong&gt; How do you debug this? If &lt;code&gt;sendWelcomeEmail&lt;/code&gt; throws an exception for one user, the whole stream fails. You can't easily put a breakpoint inside the &lt;code&gt;peek&lt;/code&gt; to inspect the state for a single user without getting swamped.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hidden Side Effects:&lt;/strong&gt; The &lt;code&gt;peek&lt;/code&gt; operation is performing major side effects (sending an email!). This violates the functional principles that make streams great and makes the code incredibly hard to reason about.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Poor Readability:&lt;/strong&gt; To understand the logic, you have to mentally unpack this dense chain of operations. It's not immediately obvious what's happening.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A developer focused on &lt;strong&gt;maintainability&lt;/strong&gt; would see this and immediately refactor it into something more "boring," but infinitely more professional: a simple loop.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Human-Crafted, Maintainable Solution&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;processSignups&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SignUp&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;signups&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;successfullyProcessedUsers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// A simple, "boring" loop is easy to read, easy to debug.&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SignUp&lt;/span&gt; &lt;span class="n"&gt;signup&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;signups&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;signup&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isVerified&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Skip unverified users&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Each step is clear and explicit.&lt;/span&gt;
            &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;eligible&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;promoService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEligible&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;signup&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getEmail&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
            &lt;span class="n"&gt;emailService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sendWelcomeEmail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;signup&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getEmail&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;eligible&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

            &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="n"&gt;userToSave&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;signup&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;signup&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getEmail&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
            &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="n"&gt;savedUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;userRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userToSave&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;successfullyProcessedUsers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedUser&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;EmailException&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;DataAccessException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// We can handle errors for a single user without crashing the whole batch.&lt;/span&gt;
            &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to process signup for email: {}"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;signup&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getEmail&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;successfullyProcessedUsers&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This version is superior in every practical way. It's easy to read, you can stick a breakpoint anywhere you want, and the &lt;code&gt;try-catch&lt;/code&gt; block provides robust, granular error handling. This same principle applies at a higher level. Resist the urge to let an AI push you toward an overly complex design like microservices when a well-structured monolith or a Hexagonal Architecture would be far more maintainable for your team's size and scope. Use AI as a tool, but you are the architect. Choose boring, maintainable solutions. Your future self will thank you. 🙏&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;4. Clean Your Room: No Stray Code or Sketchy Dependencies 🧹&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Think of your AI assistant as a super-enthusiastic and brilliant, but slightly messy, collaborator. In its rush to build something cool, it might leave some tools out, grab a sketchy-looking part from a random website, or leave unused scraps of code lying on the floor.&lt;/p&gt;

&lt;p&gt;Our job is to be the diligent cleaner who tidies up afterward. "Stray code" isn't just about unused imports or dead methods; it's about ensuring every single line in our project, including our build files, is there for a reason and comes from a trusted source.&lt;/p&gt;

&lt;p&gt;Failing to do this isn't just sloppy—it can be a massive security risk. Modern software development is built on a mountain of dependencies, and AI can inadvertently lead us to pull a malicious one right into our project.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Technical Example: The AI's "Helpful" but Malicious Dependency&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;This is one of the most subtle and dangerous ways an AI can cause trouble. Let's say you need to add a feature to process and manipulate some complex XML files. You're not sure which library is best.&lt;/p&gt;

&lt;p&gt;You ask your AI: &lt;em&gt;"// I need to parse a complex XML file in Java. Suggest a good library and give me the Maven dependency for it."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The AI, having been trained on a vast amount of public code, including forum posts and GitHub issues with typos, might suggest this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.apache.commons&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;commons-text-utils&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt; 
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.10.0&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You, the busy developer, glance at it. "org.apache.commons" looks legit, the name seems right, and you paste it into your &lt;code&gt;pom.xml&lt;/code&gt;. &lt;strong&gt;You've just potentially opened the door to a typosquatting or dependency confusion attack.&lt;/strong&gt; 💀&lt;/p&gt;

&lt;p&gt;A threat actor could have published a malicious library to Maven Central under that slightly incorrect name (&lt;code&gt;commons-text-utils&lt;/code&gt; instead of the real &lt;code&gt;commons-text&lt;/code&gt;). Your build system would happily download it, and suddenly you have malware executing with full permissions inside your build environment or even in your production application.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;only&lt;/strong&gt; safe habit is to &lt;strong&gt;never, ever trust a dependency string from an AI&lt;/strong&gt;. Always do the 30-second check:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open your web browser.
&lt;/li&gt;
&lt;li&gt;Go to Maven Central (&lt;code&gt;search.maven.org&lt;/code&gt;) or the library's official GitHub page.
&lt;/li&gt;
&lt;li&gt;Search for the library and copy the &lt;strong&gt;official, verified&lt;/strong&gt; dependency snippet.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;What About Dead Code?&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;On a less dramatic but still important note, AIs often leave behind digital clutter. It might generate three helper methods but only end up using one in its final answer.&lt;/p&gt;

&lt;p&gt;In Java, this isn't always a critical failure. An unused import is harmless. But an unused dependency in your &lt;code&gt;pom.xml&lt;/code&gt;? That still gets bundled into your final JAR/WAR, bloating your application size. Worse, if you're using a framework like Spring with broad component scanning, a class from an "unused" dependency on the classpath could be auto-detected and wired into your application, causing truly baffling behavior.&lt;/p&gt;

&lt;p&gt;The habit here is simple hygiene. Before you commit, run your IDE's code cleanup tools. Remove unused imports, variables, and methods. Use static analysis to flag unused dependencies. It's the digital equivalent of sweeping the workshop floor before you lock up for the night. It keeps your project lean, clean, and predictable. ✨&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;5. Trust but review: Analyze the AI, the Code, and the Supply Chain 🕵️‍♀️&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Working with an AI is like getting advice from a brilliant expert who sometimes hallucinates. This is the core of my article "&lt;a href="https://dev.to/jonathanvila/ai-gives-you-not-developer-productivity-toolkit-1n9d"&gt;AI gives you TIME not CONFIDENCE&lt;/a&gt;.". The AI gives you a head start, but it doesn't give you a guarantee. To turn that AI-generated time into a reliable product, you have to practice healthy skepticism and analyze &lt;em&gt;everything&lt;/em&gt;. This habit goes deeper than just checking the generated code; it involves scrutinizing the entire development ecosystem.&lt;/p&gt;

&lt;p&gt;We must analyze three distinct areas:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The AI System Itself&lt;/strong&gt;: Its limitations, its biases, and its security posture.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Generated Code&lt;/strong&gt;: Its correctness, its security, and its adherence to modern practices.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Software Supply Chain&lt;/strong&gt;: The third-party dependencies the AI suggests.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;First, Analyze Your AI System&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Before you even write a prompt, remember that the AI is not an oracle. It's a tool with known limitations.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Is Your Prompt Safe?&lt;/strong&gt; 🔐 When you paste a chunk of your company's proprietary code into a free, public AI website, where does it go? You could be unintentionally leaking trade secrets. The habit is to &lt;strong&gt;use enterprise-grade, secure tools&lt;/strong&gt; (like GitHub Copilot for Business or self-hosted options) that guarantee your code stays private.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Is your AI architecture secure?&lt;/strong&gt; 👮When you use Agents and MCP servers, are you sure what they do? Have you checked their source code to know where your information goes?&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Second, Analyze the Generated Code: Accuracy, Bugs, Security and Outdated Knowledge&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This is where the rubber meets the road. Recent research confirms that while AI boosts speed, it comes with significant risks to quality and security.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;The Sobering Reality of AI Accuracy&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Don't fall for the marketing hype. A &lt;a href="https://www.sonarsource.com/resources/the-coding-personalities-of-leading-llms/" rel="noopener noreferrer"&gt;report from Sonar analysing top notch LLM models&lt;/a&gt;, revealed that although they produce a lot of good code, they have different levels of accuracy in their responses and are still incorporating issues and vulnerabilities. This means you must assume that any code generated by an AI is likely to be flawed in some way.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Security Vulnerabilities and Outdated Java Knowledge&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;LLMs can directly introduce vulnerabilities into the code they generate because their training data might contain insecure patterns, or they might make logical errors during generation that result in security flaws. For example, an LLM might generate SQL code without proper input sanitization or hardcoding secrets, leading to SQL injection vulnerabilities or credentials leak.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// DON'T PASTE THIS! ❌ It contains proprietary logic and sensitive keys.&lt;/span&gt;
&lt;span class="c1"&gt;// "Refactor this method to be more efficient"&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;processTransaction&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Transaction&lt;/span&gt; &lt;span class="n"&gt;tx&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ProjectTitan"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getProjectCode&lt;/span&gt;&lt;span class="o"&gt;()))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;apiKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"d3b07384d113edec49eaa6238ad5ff00"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Hardcoded secret!&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ProprietaryBillingClient&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;apiKey&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;charge&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAmount&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;tx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getUserId&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// ... more confidential logic&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also an AI model might have a knowledge cutoff of early 2023. It knows nothing about the latest features in Java 21+. It will generate correct, but clunky and outdated code.&lt;/p&gt;

&lt;p&gt;For example, you ask it to process different shapes. It might generate this pre-Java 21 code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// AI's Outdated (pre-Java 21) solution&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="nf"&gt;getArea&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Shape&lt;/span&gt; &lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;Circle&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Circle&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Circle&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PI&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;radius&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;radius&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;Square&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Square&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Square&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;side&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;side&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A modern Java developer would immediately refactor this to a much cleaner and safer &lt;code&gt;switch&lt;/code&gt; expression with type patterns:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// The Modern Java 21+ Solution&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="nf"&gt;getArea&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Shape&lt;/span&gt; &lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;switch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nc"&gt;Circle&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PI&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;radius&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;radius&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nc"&gt;Square&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;side&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;side&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;};&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  &lt;strong&gt;Third, Analyze the Dependencies (The Software Supply Chain)&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This is where things get really serious. An AI might suggest a cool, niche library to solve your problem. Here's your analysis checklist before you ever add it to your &lt;code&gt;pom.xml&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Is it Well-Maintained?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You ask an AI for a CSV parsing library. It might suggest a once-popular but now-abandoned option , like &lt;a href="http://net.sf" rel="noopener noreferrer"&gt;*&lt;code&gt;net.sf&lt;/code&gt;&lt;/a&gt;&lt;code&gt;.supercsv:super-csv&lt;/code&gt;* discontinued in 2015. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Is it Properly Licensed?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Accidentally using the wrong license can create a legal nightmare for your company. An AI won't warn you if a library is AGPL-licensed.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Threat&lt;/strong&gt;: An AI suggests a library for charting. You add it to your &lt;code&gt;pom.xml&lt;/code&gt;, not realizing it has a restrictive license that could force you to open-source your proprietary product.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Habit&lt;/strong&gt;: You &lt;strong&gt;must&lt;/strong&gt; check the license. Use automated tools like the &lt;strong&gt;SonarQube&lt;/strong&gt; or  &lt;strong&gt;OWASP Dependency-Check plugin&lt;/strong&gt; for Maven/Gradle, among others, which can automatically scan your dependencies and flag license conflicts based on policies you define.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3. Are There Known Vulnerabilities?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Even if a library is well-maintained and properly licensed, older versions (or even the latest) might have publicly reported security vulnerabilities.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Threat&lt;/strong&gt;: An AI suggests &lt;code&gt;jackson-databind&lt;/code&gt; version 2.9.0. You add it, unaware that this version has a critical deserialization vulnerability (CVE-2017-7525) that attackers could exploit to execute arbitrary code.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Habit&lt;/strong&gt;: This is the most crucial check. You &lt;strong&gt;must&lt;/strong&gt; scan your dependencies for known vulnerabilities. Tools like SonarQube*&lt;em&gt;,&lt;/em&gt;*  integrate with your build process and continuously monitor your dependencies against public vulnerability databases (like the National Vulnerability Database - NVD) to alert you of potential issues. Regularly updating your dependencies is also key.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Analyzing your dependencies is a non-negotiable part of a professional developer's job. The AI is just a recommender; you are the gatekeeper. ✅&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;6. Beyond Coverage: Mandate &lt;em&gt;Meaningful&lt;/em&gt; Tests ✅&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;For years, we've been told to chase the holy grail of 100% code coverage. But as you astutely noted, that's often a vanity metric. A suite of heavily mocked unit tests that covers every line of code can still completely miss the point. The real goal of testing isn't to cover code; it's to &lt;strong&gt;build confidence&lt;/strong&gt; that your software correctly solves a real-world business problem.&lt;/p&gt;

&lt;p&gt;AI is a game-changer for testing, but it can also lead you down the wrong path if you're not careful. It's brilliant at generating boilerplate, but it has no understanding of your business intent. The modern testing habit is to use AI as a tireless assistant for the simple stuff, freeing up your valuable brainpower to design the high-level tests that truly matter.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;AI for the Easy Stuff: Boilerplate Unit Tests&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Let's be clear: AI is fantastic at generating simple unit tests for pure functions or utility classes. You can point it at a class and say, &lt;em&gt;"Generate JUnit 5 tests for this,"&lt;/em&gt; and it will save you a ton of tedious work.&lt;/p&gt;

&lt;p&gt;But here's the trap we discussed in the last habit: if the AI wrote the buggy code, it will happily write a test that confirms the bug, giving you a beautiful "green" test suite that is actively lying to you.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// AI wrote this buggy method...&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;truncate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// BUG: Off-by-one error. Should be &amp;lt;= length&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;substring&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"..."&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// ...and the AI will gladly write a test that confirms the bug.&lt;/span&gt;
&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;testTruncation&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;truncate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hello world"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// DANGER: The AI asserts the incorrect result it expects.&lt;/span&gt;
    &lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hell..."&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// This passes! 😱&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The habit:&lt;/strong&gt; Use AI for boilerplate, but you, the human, must write the critical assertions based on the &lt;em&gt;requirements&lt;/em&gt;, not based on the code's current behavior.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;The Human's Job: Integration Tests That Build Real Confidence&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;True confidence comes from watching your code interact with real infrastructure. This is where you should focus your energy. Stop over-mocking and start writing real integration tests.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Wrong Way (Useless Mocking):&lt;/strong&gt; Many developers test their service layer by mocking the database repository. This is a low-value test.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// This test proves almost nothing.&lt;/span&gt;
&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;testUserServiceWithMock&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// 1. Setup the mock&lt;/span&gt;
    &lt;span class="nc"&gt;UserRepository&lt;/span&gt; &lt;span class="n"&gt;mockRepo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mock&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;UserRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;when&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mockRepo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findByStatus&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ACTIVE"&lt;/span&gt;&lt;span class="o"&gt;)).&lt;/span&gt;&lt;span class="na"&gt;thenReturn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Jon"&lt;/span&gt;&lt;span class="o"&gt;)));&lt;/span&gt;

    &lt;span class="c1"&gt;// 2. Call the service&lt;/span&gt;
    &lt;span class="nc"&gt;UserService&lt;/span&gt; &lt;span class="n"&gt;userService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;UserService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mockRepo&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;activeUsers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;userService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findActiveUsers&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// 3. Assert&lt;/span&gt;
    &lt;span class="c1"&gt;// This only checks if your service called the mock. It tells you NOTHING&lt;/span&gt;
    &lt;span class="c1"&gt;// about whether your actual @Query works, if your DB schema is correct,&lt;/span&gt;
    &lt;span class="c1"&gt;// or if transactions behave as expected.&lt;/span&gt;
    &lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;activeUsers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="n"&gt;verify&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mockRepo&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;findByStatus&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ACTIVE"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The Right Way (Real Confidence with Testcontainers):&lt;/strong&gt; A professional Java developer uses tools like &lt;strong&gt;Testcontainers&lt;/strong&gt; to spin up a &lt;em&gt;real&lt;/em&gt; database for the test.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// This test builds REAL confidence.&lt;/span&gt;
&lt;span class="nd"&gt;@SpringBootTest&lt;/span&gt;
&lt;span class="nd"&gt;@Testcontainers&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserServiceIntegrationTest&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Container&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;PostgreSQLContainer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;postgres&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PostgreSQLContainer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;"postgres:15-alpine"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Spring Boot will automatically configure the app to use this database.&lt;/span&gt;
    &lt;span class="nd"&gt;@DynamicPropertySource&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;configure&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;DynamicPropertyRegistry&lt;/span&gt; &lt;span class="n"&gt;registry&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;registry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"spring.datasource.url"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;postgres:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;getJdbcUrl&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;registry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"spring.datasource.username"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;postgres:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;getUsername&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;registry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"spring.datasource.password"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;postgres:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;getPassword&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Autowired&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;UserService&lt;/span&gt; &lt;span class="n"&gt;userService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Autowired&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;UserRepository&lt;/span&gt; &lt;span class="n"&gt;userRepository&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;findsOnlyActiveUsersFromRealDatabase&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// 1. Setup REAL data in a REAL database&lt;/span&gt;
        &lt;span class="n"&gt;userRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Jon"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"ACTIVE"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
        &lt;span class="n"&gt;userRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Jane"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"INACTIVE"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;

        &lt;span class="c1"&gt;// 2. Call the service&lt;/span&gt;
        &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;activeUsers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;userService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findActiveUsers&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// 3. Assert&lt;/span&gt;
        &lt;span class="c1"&gt;// This test proves your @Query, schema, and service logic all work together.&lt;/span&gt;
        &lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;activeUsers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Jon"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;activeUsers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;The Ultimate Collaboration: AI-Powered Acceptance Tests&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Here's where it all comes together. Your Product Owner or a domain expert writes the requirements in a plain-text Gherkin file. This file becomes the ultimate source of context.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gherkin &lt;code&gt;login.feature&lt;/code&gt; file (written by a human):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Feature: User Login

  Scenario: Successful login with valid credentials
    Given I am on the login page
    When I enter &lt;span class="s2"&gt;"jon.doe"&lt;/span&gt; as my username
    And I enter &lt;span class="s2"&gt;"a-valid-password"&lt;/span&gt; as my password
    And I click the login button
    Then I should be redirected to my dashboard page
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, you use this as context for your AI. &lt;strong&gt;The habit:&lt;/strong&gt; Ask the AI to be a translator. &lt;em&gt;"Given this Gherkin feature, generate the boilerplate Java step definitions for Cucumber."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI-Generated Java "Glue Code" (a huge time-saver):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// AI generates this skeleton code for you instantly.&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LoginSteps&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Given&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"I am on the login page"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;i_am_on_the_login_page&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// TODO: Implement browser navigation logic here&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;cucumber&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;java&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PendingException&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="nd"&gt;@When&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"I enter {string} as my username"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;i_enter_as_my_username&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// TODO: Implement selenium/playwright logic here&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;cucumber&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;java&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PendingException&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// ... and so on for the rest of the steps.&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The AI handles the tedious mapping, and you focus on implementing the meaningful automation logic. You're not just testing code anymore; you're verifying business requirements directly. And if you want to be extra sure your tests are good, look into &lt;strong&gt;mutation testing&lt;/strong&gt; (e.g., with Pitest) to see if your test suite can actually catch bugs.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;7. The Human Gateway: A Code Review for What AI Can't See 🧠&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Let's get one thing straight: automated code reviewers and SAST tools are fantastic. They are tireless defenders against simple bugs, style violations, and common security flaws. Let the machines handle that stuff. That is their job now.&lt;/p&gt;

&lt;p&gt;Modern platforms like SonarQube, with its "&lt;a href="https://www.sonarsource.com/blog/ai-code-assurance-sonar/" rel="noopener noreferrer"&gt;AI Code Assurance&lt;/a&gt;" feature, are evolving to specifically address code generated by AI. They can help maintain quality and consistency, acting as the first line of defense even for machine-generated code, ensuring that the human reviewer's focus remains on higher-order concerns.&lt;/p&gt;

&lt;p&gt;This frees up human code reviews to be what they were always meant to be: a high-level conversation about the &lt;em&gt;thinking&lt;/em&gt; behind the code. The Pull Request (PR) is no longer a gate for catching typos; it's a forum for sharing knowledge, questioning assumptions, and ensuring the solution truly aligns with the business domain and our long-term architectural vision.&lt;/p&gt;

&lt;p&gt;Your role as a reviewer has been upgraded. You are no longer a human linter; you are a design partner and a knowledge steward.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Focus on What Only a Human Can Judge&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;When you open a PR in this new world, you can skip the stuff an automated tool can find. Instead, you focus your valuable brainpower on these questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Does it actually solve the business problem?&lt;/strong&gt; 🧠 An AI doesn't understand the nuances of your company's new return policy or the legal requirements of a GDPR data request. Does the code &lt;em&gt;really&lt;/em&gt; do what the JIRA ticket asked for, including the unwritten assumptions?
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Is this a maintainable design?&lt;/strong&gt; 🏗️ The code might work today, but will a junior developer understand it in six months? Is this a quick fix that adds to our technical debt, or a solid, long-term solution that fits our architecture (e.g., Hexagonal, DDD)?
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What are the hidden edge cases?&lt;/strong&gt; ⛈️ Based on your experience, what could go wrong? What happens if a downstream API times out? What if the input list is empty? What if a user's name contains weird characters? Humans are great at this kind of "what-if" analysis.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Is it a good opportunity to mentor?&lt;/strong&gt; 🌱 A PR is one of the best places to share knowledge. It's a chance to explain a design pattern, suggest a better way to handle an error, or introduce a teammate to a more modern library or language feature.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Example: A Conversation, Not a Judgment&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Imagine a developer used an AI to implement a caching layer for a frequently called service. The code is clean and the automated checks all pass. ✅&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The old way of reviewing&lt;/strong&gt; might be a simple "LGTM" (Looks Good To Me).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The new way of reviewing&lt;/strong&gt; is a collaborative conversation that shares knowledge and improves the design.&lt;/p&gt;

&lt;p&gt;Here's the code snippet in the PR:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// service/ProductService.java&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.google.common.cache.Cache&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.google.common.cache.CacheBuilder&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@Service&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProductService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// An in-memory cache for product details&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Cache&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Long&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ProductDetails&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;productCache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CacheBuilder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newBuilder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;maximumSize&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;expireAfterWrite&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;TimeUnit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;MINUTES&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ProductDetails&lt;/span&gt; &lt;span class="nf"&gt;getProductDetails&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;productId&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// AI correctly implemented the cache-aside pattern&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;productCache&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;productId&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findDetailsById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;productId&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And here's the &lt;strong&gt;human-centric review&lt;/strong&gt; in the PR comments:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Senior Dev:&lt;/strong&gt; "Hey, great job getting the caching logic in here! The AI did a nice job with the Guava cache implementation. It's super clean. 👍"&lt;/p&gt;

&lt;p&gt;"I have one architectural question for us to think about. This is an in-memory cache, which is perfect for a single instance. What do you think will happen when we deploy this to our production environment, which runs 3 instances of this service for high availability?"&lt;/p&gt;

&lt;p&gt;"The risk is that the caches could get out of sync. An admin might update a product's details, and that request might hit instance A, updating its cache. But instances B and C would still be serving the old, stale data for up to 10 minutes."&lt;/p&gt;

&lt;p&gt;"This might be a good opportunity for us to introduce a distributed cache like &lt;strong&gt;Redis&lt;/strong&gt;. It would solve the consistency problem and give us a centralized place to manage our caching strategy. It's a bigger change, but it would make our system much more robust. What are your thoughts on that approach? No pressure to do it in this PR, but let's discuss it. 🤔"&lt;/p&gt;

&lt;p&gt;This review accomplishes everything a human review should. It validates the work, shares deep knowledge about distributed systems, prevents a future production issue, and does it all in a collaborative, respectful way. This is a conversation AI can't have. This is where we, the humans, provide the real value.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Conclusion: Your AI Co-Pilot Needs a Safety Net 🚀&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The age of AI-assisted development isn't about replacing developers; it's about upgrading them. &lt;/p&gt;

&lt;p&gt;The seven habits we've explored are a roadmap for moving beyond being a simple "user" of AI to becoming a skilled craftsperson who wields it with intention and wisdom. It’s about taking pride in your work, providing deep context, demanding maintainability, practicing good hygiene, scrutinizing everything, writing tests that matter, and keeping the human element at the heart of your reviews.&lt;/p&gt;

&lt;p&gt;Cultivating these habits is a conscious effort, but you don't have to do it alone. While you focus on high-level design and business logic, you need a safety net to catch the subtle mistakes, security vulnerabilities, and bad practices that AI can introduce into your code. This is where having an automated code quality and security toolset becomes non-negotiable.&lt;/p&gt;

&lt;p&gt;That's why you should check out the Sonar solution. By &lt;a href="https://www.sonarsource.com/products/sonarlint/ide-login/" rel="noopener noreferrer"&gt;adding&lt;/a&gt; &lt;strong&gt;SonarQube&lt;/strong&gt; IDE extension(IntelliJ, VS Code, etc.), you get real-time feedback on the code as it's generated, catching bugs and vulnerabilities before they're even committed. Then, by &lt;a href="https://www.sonarsource.com/products/sonarcloud/signup-free/" rel="noopener noreferrer"&gt;connecting&lt;/a&gt; it to &lt;strong&gt;SonarQube Cloud&lt;/strong&gt;, your entire team gets a shared understanding of the project's health, ensuring that what you ship is not just functional, but truly with high quality and security. Think of it as the perfect third partner in your development process: your skill, the AI's speed, and Sonar's safety.&lt;/p&gt;

</description>
      <category>codequality</category>
      <category>ai</category>
      <category>java</category>
      <category>programming</category>
    </item>
    <item>
      <title>Building a Secure Fortress within AI: A Developer's Guide to Full-Stack Security 🏰</title>
      <dc:creator>Jonathan Vila</dc:creator>
      <pubDate>Wed, 17 Sep 2025 16:40:39 +0000</pubDate>
      <link>https://dev.to/jonathanvila/building-a-secure-fortress-within-ai-a-developers-guide-to-full-stack-security-2nep</link>
      <guid>https://dev.to/jonathanvila/building-a-secure-fortress-within-ai-a-developers-guide-to-full-stack-security-2nep</guid>
      <description>&lt;p&gt;Hey developers! 👋 Do you ever feel like you're constantly rushing to build new features, fix bugs, and keep up with the latest tech? That's a lot, right? And now, powerful tools like Generative AI are here to help us accelerate even more. But this new age of development brings a unique set of challenges, especially for security.&lt;/p&gt;

&lt;p&gt;With all this pressure to move fast, security can feel like the first thing to get pushed aside. But what if it didn't have to be a chore? This article is about making security a natural, easy part of your daily coding—an automated safety net that ensures everything you build, whether by hand or with AI, is secure from the start. Let's make security a superpower we all have! 💪&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;What we'll cover&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The rise of AI code generation:&lt;/strong&gt; How AI tools are changing development and why this makes security analysis more important than ever.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SAST (Static Application Security Testing):&lt;/strong&gt; Finding security bugs in your own code before it even runs.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Advanced SAST:&lt;/strong&gt; Discovering hidden vulnerabilities that result due to interaction of first-party code with third-party open source libraries.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secrets detection:&lt;/strong&gt; Keeping sensitive keys and passwords out of your source code.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IaC (Infrastructure as Code) analysis:&lt;/strong&gt; Checking your configuration files for issues.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SCA (Software Composition Analysis):&lt;/strong&gt; Managing risks in your open source dependencies.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1. Why security matters: Lessons from the real world&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;We all know the pressure: "Get it done yesterday!" In this race, security often gets pushed to the side. But here's the thing: finding a security problem when your application is already in production is like trying to fix a leaky roof during a storm. It's expensive, stressful, and usually a mess. 😱&lt;/p&gt;

&lt;p&gt;This is why we talk about "Shift-Left" security. It just means finding and fixing issues &lt;em&gt;early&lt;/em&gt; in the development process. The cost of not shifting left can be enormous, as some of the biggest names in tech have learned the hard way.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Apache Struts vulnerability (2017)&lt;/strong&gt; One of the most damaging breaches in history was caused by a vulnerability in a third-party framework (Apache Struts). This is a classic, painful lesson in the importance of &lt;strong&gt;Software Composition Analysis (SCA)&lt;/strong&gt;, which we'll cover in &lt;strong&gt;Section 4&lt;/strong&gt;. (&lt;a href="https://www.ftc.gov/enforcement/cases-proceedings/refunds/equifax-data-breach-settlement" rel="noopener noreferrer"&gt;Read more about the breach&lt;/a&gt;). &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The Log4Shell vulnerability (2021):&lt;/strong&gt; This zero-day vulnerability in a popular Java logging library, Log4j, sent shockwaves through the tech world. It perfectly illustrates how a single flaw in an open-source dependency can have a global impact, reinforcing the need for both &lt;strong&gt;SCA&lt;/strong&gt; and &lt;strong&gt;advanced SAST&lt;/strong&gt;. (&lt;a href="https://en.wikipedia.org/wiki/Log4Shell" rel="noopener noreferrer"&gt;Read more about Log4Shell&lt;/a&gt;).  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Missconfigured IaC (2019):&lt;/strong&gt; This breach, which exposed the data of over 100 million customers, was a result of a misconfigured web application firewall. This highlights why &lt;strong&gt;Infrastructure as Code (IaC) Analysis&lt;/strong&gt; is no longer optional. (&lt;a href="https://dl.acm.org/doi/10.1145/3546068" rel="noopener noreferrer"&gt;Read more about the incident&lt;/a&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These aren't just stories; they are cautionary tales that show how the small details in our code and configurations can have massive consequences.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;2. A new challenge: The age of AI-generated code 🤖&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;There's a new player in our daily workflow: Generative AI. Tools like GitHub Copilot are incredible productivity boosters, helping us write boilerplate, solve complex problems, and learn new patterns. But with great power comes great responsibility. The code generated by these AI assistants is not perfect. In fact, it's trained on massive datasets of public code—which includes both good and bad patterns.&lt;/p&gt;

&lt;p&gt;This means AI can, and often does, generate code that contains subtle security vulnerabilities or introduces technical debt. Research supports this: a study led by Stanford University found that developers who used AI assistants were significantly more likely to produce insecure code. &lt;/p&gt;

&lt;p&gt;Another analysis of popular  LLMs used by AI code generation, done by Sonar, found that more than &lt;strong&gt;60% of the security issues of AI-generated code suggestions were Blockers&lt;/strong&gt; (&lt;a href="https://www.sonarsource.com/the-coding-personalities-of-leading-llms/" rel="noopener noreferrer"&gt;Read the full report here&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;This doesn't mean we should stop using AI. It means that as we accelerate code production, having a robust, automated security safety net is more critical than ever. The tools and techniques we're about to discuss act as that essential quality gate, ensuring the code—whether written by a human or an AI—is secure before it reaches production.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;3. Securing our code: The core foundation 🕵️‍♀️&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Let's start with the code in our project, regardless of who (or what) wrote it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SAST (Static Application Security Testing):&lt;/strong&gt; Think of SAST as your vigilant code reviewer. It scans your source code for common vulnerabilities like SQL Injection. For example, a SAST tool would immediately flag this Python code because it uses an f-string to build a query, which is unsafe.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# 👎 BAD - Vulnerable to SQL Injection
&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;username&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SELECT * FROM users WHERE username = &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'"&lt;/span&gt; &lt;span class="c1"&gt;# Unsafe!
&lt;/span&gt;&lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;The fix is to use parameterized queries, which separate the command from the data.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# 👍 GOOD - Safe from SQL Injection
&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SELECT * FROM users WHERE username = %s&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Taint analysis &amp;amp; advanced  SAST:&lt;/strong&gt; Taint Analysis is a smart type of SAST that tracks dangerous user input. &lt;strong&gt;Advanced  SAST&lt;/strong&gt; takes this a step further. Traditional SAST often treats third-party libraries like a "black box." It sees your code call a library function, but it doesn't look &lt;em&gt;inside&lt;/em&gt; that function to see what happens next. Advanced SAST is dependency aware SAST that analyzes the interaction &lt;em&gt;between&lt;/em&gt; your code and your dependencies, finding hidden flaws.
Consider this JavaScript example using the &lt;code&gt;fs-extra&lt;/code&gt; library:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// User input from a request, e.g., "../../../etc/passwd"&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/readfile&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;targetDirectory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/data/app/resources/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userFilename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;targetDirectory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userFilename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;encoding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;utf8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;r&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;An advanced SAST analysis knows that the &lt;code&gt;readFileSync&lt;/code&gt; function can create directories, leading to a Path Traversal vulnerability. It finds security issues or vulnerabilities that are hidden deep inside your opensource dependencies. 🔴➡️📦➡️🛡️
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secrets detection:&lt;/strong&gt; We've all been there, right? You're rushing, and suddenly, an API key ends up committed to your Git repository. 🤦‍♂️ Secrets detection tools scan your code for these slip-ups. A tool would immediately flag a hardcoded secret like this:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// 👎 BAD - Hardcoded secret&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;super-secret-key-123456789-abcdefg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Leaked key!&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Infrastructure as Code (IaC) analysis:&lt;/strong&gt; As we saw with the Capital One case, misconfigurations can be disastrous. IaC analysis scans configuration files for these issues. For example, this &lt;code&gt;Dockerfile&lt;/code&gt; has two common security flaws:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# 👎 BAD - Insecure Dockerfile
FROM ubuntu:latest
USER root      # 1. Running as the root user is risky
EXPOSE 22     # 2. Exposing the SSH port is dangerous
COPY . /app
CMD ["run_app"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;4. Securing our dependencies: The software supply chain 🌍&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;As the Equifax and Log4Shell incidents proved, our applications are only as secure as the open-source libraries they are built on. This is where Software Composition Analysis (SCA) comes in. SCA tools analyze your dependency files (like &lt;code&gt;package.json&lt;/code&gt; or &lt;code&gt;pom.xml&lt;/code&gt;) to give you a clear picture of your supply chain risk.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Vulnerability (CVE) detection:&lt;/strong&gt; The most obvious task of SCA is to check your libraries against a database of known vulnerabilities (CVEs). An SCA tool would scan the &lt;code&gt;pom.xml&lt;/code&gt; below and immediately flag &lt;code&gt;jackson-databind&lt;/code&gt; because version &lt;code&gt;2.9.8&lt;/code&gt; has multiple critical remote code execution vulnerabilities. 🚨
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;dependencies&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-boot-starter-web&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;2.5.4&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;com.fasterxml.jackson.core&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;jackson-databind&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;2.9.8&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt; 
    &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependencies&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;This instant feedback allows you to patch the vulnerability by upgrading the dependency version, long before it becomes a problem in production.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why License checks are critical:&lt;/strong&gt; "Open source" doesn't mean "no rules." Accidentally using a library with the wrong license can create huge legal and intellectual property risks for your company. An SCA tool analyzes all direct and transitive dependencies and reports on their licenses, comparing them against your policies. The output might look something like this:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;--- License Check Report ---&lt;/span&gt;
&lt;span class="n"&gt;Policy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Forbid&lt;/span&gt; &lt;span class="s1"&gt;'copyleft'&lt;/span&gt; &lt;span class="n"&gt;licenses&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GPL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AGPL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;INFO&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;spring&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;boot&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;starter&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;web&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;jar&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Apache&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;OK&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;INFO&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;jackson&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;databind&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;jar&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Apache&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;OK&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;VIOLATION&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;gpl&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;library&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;jar&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GPL&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;FORBIDDEN&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;This automated check is essential for avoiding "copyleft" licenses like the GPL that could legally obligate you to make your own proprietary source code public.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SBOM: Your application's essential "Ingredients List":&lt;/strong&gt; A Software Bill of Materials (SBOM) is a formal, machine-readable inventory of every component in your application. An SBOM tool reads your &lt;code&gt;pom.xml&lt;/code&gt;, resolves the entire dependency tree, and generates this list. Here is a small, simplified example of what part of an SBOM file (in CycloneDX format) looks like:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"bomFormat"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CycloneDX"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"specVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"metadata"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"component"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"application"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"my-cool-app"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"components"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"library"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"jackson-databind"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2.9.8"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"purl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.9.8"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;hundreds&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;other&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;dependencies&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;would&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;be&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;listed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;here&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;This inventory is critical for vulnerability management and is quickly becoming a &lt;strong&gt;legal requirement&lt;/strong&gt;. The &lt;strong&gt;U.S. government's Executive Order 14028&lt;/strong&gt; and the &lt;strong&gt;European Union's Cyber Resilience Act (CRA)&lt;/strong&gt; are making SBOMs mandatory for selling software in major markets.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;5. The challenge: Avoiding "Tool Sprawl" 🧩&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;So, we have all these important security checks. The obvious first step might be to grab a separate open-source or commercial tool for each job: one for SAST, another for SCA, a third for secrets, and so on. But this approach, known as "tool sprawl," quickly creates a new set of problems that hurt developer productivity.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Unaggregated reports and alert fatigue:&lt;/strong&gt; You get SAST alerts in your CI/CD logs, SCA vulnerability reports in your email, and IaC issues on another dashboard. The data is scattered everywhere. It's impossible to get a single, clear picture of your application's security posture, and developers become overwhelmed by alerts from too many sources.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lack of integration and context:&lt;/strong&gt; These separate tools don't talk to each other. A vulnerability in your code (found by SAST) might be exploitable only because of a specific library version (flagged by SCA). Without an integrated view, you lose this critical context, making it harder to prioritize and fix the most important issues first.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;High maintenance overhead:&lt;/strong&gt; If you're managing these tools on-premise, each one is a new application to maintain. Every tool needs its own deployment, configuration, user management, and regular updates. Your teams can end up spending more time managing the security tools than actually using them to fix security issues.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This "tool sprawl" creates noise, friction, and ultimately slows development down. The ideal solution is a single, integrated platform that unifies all these capabilities.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;6. A practical solution &amp;amp; your next step 🚀&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;So, how can you get that integrated, clear, and actionable view of your application's security? This is where a powerful tool like &lt;strong&gt;SonarQube Cloud&lt;/strong&gt; comes in, especially with the latest addition of the &lt;a href="https://www.sonarsource.com/blog/sonarqube-advanced-security-now-available/" rel="noopener noreferrer"&gt;Advanced Security&lt;/a&gt; (available as a subscription) feature including all the points touched previously. It's built specifically to solve the "tool sprawl" problem by showing you how all these concepts come together in a real-world workflow.&lt;/p&gt;

&lt;p&gt;Here’s a glimpse of how SonarQube Cloud brings all the capabilities we've discussed to life:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A unified view of your project's health:&lt;/strong&gt; Instead of scattered reports, you get a single dashboard that gives you a clear overview of your project's health. It combines code quality metrics, security vulnerabilities from your code, and risks from your dependencies all in one place. This immediately tells you if your project is ready for release or needs attention.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn9dziel76pbitzz39spc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn9dziel76pbitzz39spc.png" alt=" " width="800" height="430"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;[Screenshot 1a: The main SonarQube dashboard showing a project's overall quality gate status, with clear metrics for vulnerabilities, bugs, and security hotspots.]&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fumcvyzvrdc5l7b78gx7u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fumcvyzvrdc5l7b78gx7u.png" alt=" " width="800" height="608"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;[Screenshot 1b: The SonarQube Security report showing a project's overall security issues grouped by Category and showing the CVE associated.]&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Actionable advanced  SAST findings:&lt;/strong&gt; When a vulnerability is found in your code, you get more than just a line number. The tool explains &lt;em&gt;why&lt;/em&gt; it's a vulnerability, shows the full data flow for complex taint analysis issues, and provides rich examples and guidance on how to fix it properly. This turns a simple finding into a learning opportunity.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0aaw1052g5txu0yatq5u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0aaw1052g5txu0yatq5u.png" alt=" " width="800" height="498"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;[Screenshot 2: A detailed SonarQube issue view, showing the highlighted vulnerable code, a clear explanation of the risk (e.g., SQL Injection), and the full taint analysis path from source to sink.]&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Clear SCA and supply chain insights:&lt;/strong&gt; You can see a clear, prioritized list of all your third-party dependencies with any detected CVEs and License violations. The interface shows you the severity of the vulnerability and whether a safe, upgraded version is available, making it easy to manage risks like Log4Shell.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxnp0cbdnyi6fxplv5lyx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxnp0cbdnyi6fxplv5lyx.png" alt=" " width="800" height="536"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;[Screenshot 3a: The SonarQube SCA view listing vulnerable dependencies, their CVEs, severity levels, and available upgrade versions.]&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3ntoq81nmdljz7sxmw65.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3ntoq81nmdljz7sxmw65.png" alt=" " width="800" height="463"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;[Screenshot 3b: The SonarQube CVE view showing the different library versions partially or completely fixing the vulnerability.]&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6lzzyxfo3bziafwpa6wf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6lzzyxfo3bziafwpa6wf.png" alt=" " width="800" height="520"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;[Screenshot 3c: The SonarQube Dependency Risks view showing the licensing issues we suffer with the current dependencies]&lt;/em&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Integrated secrets and IaC analysis:&lt;/strong&gt; Hardcoded secrets and IaC misconfigurations aren't treated as separate, isolated problems. They are flagged and reported right alongside your other code issues, directly within your pull request or branch analysis. This ensures these critical issues are never missed before they reach production.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuy4ceuttlevs671ni14c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuy4ceuttlevs671ni14c.png" alt=" " width="800" height="325"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;[Screenshot 4: A SonarQube issue view showing a newly introduced container image without version or tag in a Dockerfile]&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;By presenting all these issues directly in your CI/CD pipeline, SonarQube Cloud makes security a natural part of the development workflow. It helps you fix issues early, before they even get merged, and reduces the noise so you can focus on building great, secure software.&lt;/p&gt;

&lt;p&gt;The best way to truly understand the power of this integrated approach is to see it work on your own code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://sonarcloud.io/login" rel="noopener noreferrer"&gt;&lt;strong&gt;SonarQube Cloud&lt;/strong&gt;&lt;/a&gt; is free for open-source projects, and for private projects under 50K lines of code. It's super easy to set up with your existing GitHub, GitLab, Bitbucket, or Azure DevOps repository. You can get your first analysis in minutes!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>security</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Want to use Java 22, 23 and 24 features safely ? This article will give you tips and checks that will help you on the way.</title>
      <dc:creator>Jonathan Vila</dc:creator>
      <pubDate>Fri, 11 Jul 2025 17:16:30 +0000</pubDate>
      <link>https://dev.to/jonathanvila/want-to-use-java-22-23-and-24-features-safely-this-article-will-give-you-tips-and-checks-that-1bmg</link>
      <guid>https://dev.to/jonathanvila/want-to-use-java-22-23-and-24-features-safely-this-article-will-give-you-tips-and-checks-that-1bmg</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/jonathanvila/java-22-to-24-level-up-your-java-code-by-embracing-new-features-safely-2oin" class="crayons-story__hidden-navigation-link"&gt;Java 22 to 24: Level up your Java Code by embracing new features safely&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/jonathanvila" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F988929%2F5fec304e-5e7c-4ce2-9b2f-eceea9ca2f66.png" alt="jonathanvila profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/jonathanvila" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Jonathan Vila
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Jonathan Vila
                
              
              &lt;div id="story-author-preview-content-2678577" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/jonathanvila" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F988929%2F5fec304e-5e7c-4ce2-9b2f-eceea9ca2f66.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Jonathan Vila&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/jonathanvila/java-22-to-24-level-up-your-java-code-by-embracing-new-features-safely-2oin" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Jul 11 '25&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/jonathanvila/java-22-to-24-level-up-your-java-code-by-embracing-new-features-safely-2oin" id="article-link-2678577"&gt;
          Java 22 to 24: Level up your Java Code by embracing new features safely
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/programming"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;programming&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/java"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;java&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/codequality"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;codequality&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/jonathanvila/java-22-to-24-level-up-your-java-code-by-embracing-new-features-safely-2oin" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;1&lt;span class="hidden s:inline"&gt; reaction&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/jonathanvila/java-22-to-24-level-up-your-java-code-by-embracing-new-features-safely-2oin#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              &lt;span class="hidden s:inline"&gt;Add Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            15 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>programming</category>
      <category>java</category>
      <category>codequality</category>
    </item>
    <item>
      <title>Java 22 to 24: Level up your Java Code by embracing new features safely</title>
      <dc:creator>Jonathan Vila</dc:creator>
      <pubDate>Fri, 11 Jul 2025 17:13:47 +0000</pubDate>
      <link>https://dev.to/jonathanvila/java-22-to-24-level-up-your-java-code-by-embracing-new-features-safely-2oin</link>
      <guid>https://dev.to/jonathanvila/java-22-to-24-level-up-your-java-code-by-embracing-new-features-safely-2oin</guid>
      <description>&lt;p&gt;Java introduces several new language features in the 22 to 24 versions which collectively simplify code, enhance documentation, and provide powerful tools for bytecode manipulation and advanced stream processing. This article shows you how to leverage these new features  with simple examples. &lt;/p&gt;

&lt;p&gt;Understanding these new features in Java is crucial for writing updated, efficient, and high quality code. To assist developers in adopting these changes correctly, SonarQube has introduced &lt;a href="https://rules.sonarsource.com/java/tag/java22" rel="noopener noreferrer"&gt;several new rules&lt;/a&gt; designed to check for the proper usage of unnamed variables and patterns, javadoc and markdown, Class-file new API and Stream gatherers, ensuring your code adheres to best practices and avoids common pitfalls.&lt;/p&gt;

&lt;p&gt;We’ll cover several new Java features, with new rules in SonarQube: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Java 22 : Unnamed variables
&lt;/li&gt;
&lt;li&gt;Java 23 : JavaDoc and Markdown
&lt;/li&gt;
&lt;li&gt;Java 24 : Class-File API and Stream Gatherers&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Java 22: Unnamed variables and patterns
&lt;/h1&gt;

&lt;p&gt;A significant and welcome addition in Java 22 is the finalization of unnamed variables and patterns, officially detailed in &lt;a href="https://openjdk.java.net/jeps/456" rel="noopener noreferrer"&gt;JEP 456&lt;/a&gt;. This feature enhances code clarity by allowing developers to use an underscore (&lt;code&gt;_&lt;/code&gt;) for variables and patterns that are intentionally left unused. &lt;/p&gt;

&lt;p&gt;This elegantly addresses common scenarios where a variable is required by syntax but has no relevance to the business logic, such as a caught exception object that is never inspected or a loop variable in an enhanced for-loop where only the iteration count matters. &lt;/p&gt;

&lt;p&gt;By replacing these placeholder names with a simple underscore, developers can reduce code clutter, eliminate "unused variable" warnings, and more clearly express their intent. This ultimately leads to higher-quality,more maintainable Java code.&lt;/p&gt;

&lt;p&gt;SonarQube introduces a suite of new rules to ensure proper adoption of Java 22's unnamed variables and patterns. These rules — including &lt;a href="https://rules.sonarsource.com/java/RSPEC-7466/" rel="noopener noreferrer"&gt;S7466&lt;/a&gt;, &lt;a href="https://rules.sonarsource.com/java/RSPEC-7467" rel="noopener noreferrer"&gt;S7467&lt;/a&gt;, and &lt;a href="https://rules.sonarsource.com/java/RSPEC-7475" rel="noopener noreferrer"&gt;S7475&lt;/a&gt; — guide developers in leveraging this feature for more maintainable code. Adhering to these guidelines enables teams to significantly improve code clarity and address redundant warnings.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Rule S7466: Unnamed variable declarations should use the &lt;code&gt;var&lt;/code&gt; identifier&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;When declaring an unnamed variable, the type declaration often becomes redundant. The primary purpose of an unnamed variable is to signal that it won't be used, making its specific type less critical. Using &lt;code&gt;var&lt;/code&gt; in this context enhances conciseness and maintains focus on the intent: to intentionally ignore the variable.&lt;/p&gt;

&lt;p&gt;Let's look at an example. When iterating over a collection where only the number of iterations matters, the element itself is not used.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Noncompliant Code Example:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;myList&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// "element" is unused&lt;/span&gt;
    &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="o"&gt;++;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Java 22, you can use an unnamed variable. However, explicitly declaring the type is unnecessary.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Noncompliant Code Example:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;myList&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// The type "String" is redundant&lt;/span&gt;
    &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="o"&gt;++;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is where rule S7466 comes in, suggesting a cleaner, more concise approach.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Compliant Solution:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;myList&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="o"&gt;++;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By using &lt;code&gt;var&lt;/code&gt;, the code becomes less verbose and the intent remains clear.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Rule S7467: Unused exception parameters should use the unnamed variable pattern&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;A common scenario in Java is catching an exception where the exception object itself is not needed. Previously, developers would have to declare the exception variable, even if it was never referenced, leading to "unused variable" warnings from static analysis tools. Java 22's unnamed variables provide a perfect solution for this.&lt;/p&gt;

&lt;p&gt;Consider a &lt;code&gt;try-catch&lt;/code&gt; block where the simple fact that an exception was caught is enough, and its details are irrelevant.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Noncompliant Code Example:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// some operation that might throw an exception&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;NumberFormatException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// "e" is unused&lt;/span&gt;
    &lt;span class="c1"&gt;// log that the format was invalid&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While functional, the declaration of &lt;code&gt;e&lt;/code&gt; is noise. Using an unnamed variable is a better approach, and this is what SonarQube now recommends.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Compliant Solution:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// some operation that might throw an exception&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;NumberFormatException&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// log that the format was invalid&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This compliant solution is cleaner and explicitly communicates that the exception object itself is not important for the handling logic.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Rule S7475: Types of unused record components should be removed from pattern matching&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Record patterns, a powerful feature for deconstructing record instances, are also enhanced by unnamed patterns. When pattern matching against a record, you might only be interested in a subset of its components. With unnamed patterns, you can ignore the components you don't need.&lt;/p&gt;

&lt;p&gt;When an entire record component is unused in a pattern match, specifying its type is superfluous. Rule S7475 encourages the removal of these unnecessary type declarations, leading to more readable and less cluttered code.&lt;/p&gt;

&lt;p&gt;Imagine you have a &lt;code&gt;ColoredPoint&lt;/code&gt; record and you only need the &lt;code&gt;Point&lt;/code&gt; component in your logic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Noncompliant Code Example:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nf"&gt;ColoredPoint&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Point&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Color&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// "c" is unused&lt;/span&gt;
    &lt;span class="c1"&gt;// logic that only uses p&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Java 22, you can use an unnamed pattern for the &lt;code&gt;Color&lt;/code&gt; component. However, including the type is not necessary if the component is completely ignored.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Noncompliant Code Example:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nf"&gt;ColoredPoint&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Point&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Color&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// The type "Color" is redundant&lt;/span&gt;
    &lt;span class="c1"&gt;// logic that only uses p&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The most concise and readable version, as enforced by SonarQube, omits the type for the unused component entirely.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Compliant Solution:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nf"&gt;ColoredPoint&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Point&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// logic that only uses p&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach makes the code more focused on the relevant data, improving maintainability.&lt;/p&gt;

&lt;h1&gt;
  
  
  Java 23: JavaDoc and Markdown
&lt;/h1&gt;

&lt;p&gt;Java 23 introduces an enhancement to JavaDoc, allowing comments that begin with three slashes &lt;code&gt;///\&lt;/code&gt; to be interpreted as JavaDoc comments using Markdown syntax. This subtle yet significant change aims to simplify the process of writing rich and readable documentation directly within the code. By leveraging Markdown, developers can more easily format their JavaDoc comments with features like bold text, italics, lists, and code blocks, without needing to learn specific JavaDoc HTML tags, officially detailed in &lt;a href="https://openjdk.org/jeps/445" rel="noopener noreferrer"&gt;JEP 445&lt;/a&gt;. This streamlines the documentation process, making it more intuitive and encouraging the creation of better-formatted and more accessible API documentation. &lt;/p&gt;

&lt;p&gt;SonarQube has introduced new rules to assist developers in adopting Java 23's Javadoc and Markdown enhancements. These rules — including &lt;a href="https://rules.sonarsource.com/java/RSPEC-7476" rel="noopener noreferrer"&gt;S7476&lt;/a&gt; and &lt;a href="https://rules.sonarsource.com/java/RSPEC-7474" rel="noopener noreferrer"&gt;S7474&lt;/a&gt; — ensure that documentation is consistently formatted, easy to read, and free from common migration pitfalls. By leveraging these rules, developers can seamlessly integrate Markdown into their Javadoc comments to improve clarity and maintainability, ensuring that the old code is completely aligned with the new features.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Rule S7476: Comments should not start with more than two slashes&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;With Java 23, comments starting with &lt;code&gt;///&lt;/code&gt; are now officially interpreted as Javadoc comments that use Markdown syntax. Before, they were simply ignored by the Javadoc tool and treated as regular implementation comments. This change means that existing comments in your codebase could unintentionally become part of your public API documentation after migrating to Java 23. This can lead to confusing or unprofessional-looking documentation and increases the effort required for migration. This new rule helps you find these cases in advance so they can be corrected.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Noncompliant Code Example:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Calculator&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

  &lt;span class="c1"&gt;/////////////////////////////////////////////&lt;/span&gt;
  &lt;span class="c1"&gt;// A section for advanced math operations. //&lt;/span&gt;
  &lt;span class="c1"&gt;// These are experimental.                 //&lt;/span&gt;
  &lt;span class="c1"&gt;/////////////////////////////////////////////&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;/// This is a super important implementation note for the add method.&lt;/span&gt;
    &lt;span class="c1"&gt;/// It should not be in the final Javadoc.&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the example above, both the decorative block comment and the &lt;code&gt;///&lt;/code&gt; comment would be incorrectly processed as Javadoc in Java 23. &lt;strong&gt;Compliant Solution:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Calculator&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

  &lt;span class="c1"&gt;// A section for advanced math operations.&lt;/span&gt;
  &lt;span class="c1"&gt;// These are experimental.&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// This is a super important implementation note for the add method.&lt;/span&gt;
    &lt;span class="c1"&gt;// It should not be in the final Javadoc.&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The compliant solution is to ensure regular comments use the standard &lt;code&gt;//&lt;/code&gt; syntax.
&lt;/h3&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Rule S7474: Markdown, HTML and Javadoc tags should not be mixed&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Java 23's introduction of Markdown in Javadoc comments is a significant step towards cleaner, more readable documentation. To maintain consistency, it's best to fully embrace Markdown syntax and avoid mixing it with legacy HTML tags (like &lt;code&gt;&amp;lt;b&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;code&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;li&amp;gt;&lt;/code&gt;) or old Javadoc block tags (like &lt;code&gt;{@code}&lt;/code&gt; or &lt;code&gt;{@link}&lt;/code&gt;). Mixing these styles can lead to inconsistent rendering across different tools and makes the raw documentation harder to read. This rule encourages developers to use the modern, more concise Markdown syntax wherever possible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Noncompliant Code Example:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;///&lt;/span&gt;
&lt;span class="c1"&gt;/// A utility class for &amp;lt;b&amp;gt;String&amp;lt;/b&amp;gt; operations.&lt;/span&gt;
&lt;span class="c1"&gt;/// &amp;lt;p&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;/// Use this class to perform common manipulations. For more details,&lt;/span&gt;
&lt;span class="c1"&gt;/// see {@link java.lang.String}.&lt;/span&gt;
&lt;span class="c1"&gt;/// You can also use {@code new StringManipulator()}.&lt;/span&gt;
&lt;span class="c1"&gt;///&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;StringManipulator&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This Javadoc mixes bold HTML tags with Javadoc's &lt;code&gt;{@link}&lt;/code&gt; and &lt;code&gt;{@code}&lt;/code&gt; tags. The clean, modern approach is to use Markdown for all formatting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Compliant Solution:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;///&lt;/span&gt;
&lt;span class="c1"&gt;/// A utility class for **String** operations.&lt;/span&gt;
&lt;span class="c1"&gt;///&lt;/span&gt;
&lt;span class="c1"&gt;/// Use this class to perform common manipulations. For more details,&lt;/span&gt;
&lt;span class="c1"&gt;/// see [String].&lt;/span&gt;
&lt;span class="c1"&gt;/// You can also use `new StringManipulator()`.&lt;/span&gt;
&lt;span class="c1"&gt;///&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;StringManipulator&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By adopting a consistent Markdown style, your documentation becomes cleaner, easier to write, and future-proof.&lt;/p&gt;

&lt;h1&gt;
  
  
  Java 24 : Class-File API
&lt;/h1&gt;

&lt;p&gt;Java 24 introduces the Class-File API (&lt;a href="https://openjdk.org/jeps/457" rel="noopener noreferrer"&gt;JEP 457&lt;/a&gt;), a significant enhancement for parsing, generating, and transforming Java class files. This API provides a programmatic way to work with class files at a low level, offering more flexibility and control than existing bytecode manipulation libraries. It's particularly beneficial for tools that perform static analysis, bytecode instrumentation, or code generation, enabling them to operate directly on the structured representation of class files. By standardizing this access, the Class-File API simplifies development for such tools and ensures greater compatibility across different Java versions.&lt;/p&gt;

&lt;p&gt;SonarQube provides a new set of rules to help developers effectively utilize the Class-File API. These rules — including &lt;a href="https://rules.sonarsource.com/java/RSPEC-7479" rel="noopener noreferrer"&gt;S7479&lt;/a&gt;, &lt;a href="https://rules.sonarsource.com/java/RSPEC-7477" rel="noopener noreferrer"&gt;S7477&lt;/a&gt;, and &lt;a href="https://rules.sonarsource.com/java/RSPEC-7478" rel="noopener noreferrer"&gt;S7478&lt;/a&gt; — are designed to ensure that you use the API efficiently and correctly, leading to more concise, readable, and maintainable bytecode generation and transformation code. Adhering to these guidelines helps developers avoid common pitfalls and leverage the full potential of Java 24's Class-File API.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Rule S7479: &lt;code&gt;withMethodBody&lt;/code&gt; should be used to define methods with a body&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The new Class-File API (&lt;a href="https://openjdk.org/jeps/484" rel="noopener noreferrer"&gt;JEP 484&lt;/a&gt;) provides a standardized and flexible way to programmatically generate and modify Java class files. When building a class, the &lt;code&gt;ClassBuilder&lt;/code&gt; API offers two similar methods for adding a method: &lt;code&gt;withMethod&lt;/code&gt; and &lt;code&gt;withMethodBody&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;While both can achieve the same result, &lt;code&gt;withMethod&lt;/code&gt; is a general-purpose tool that requires an extra step to define the method's code via a nested &lt;code&gt;methodBuilder&lt;/code&gt;. For the common case of defining a non-abstract method with a body, the &lt;code&gt;withMethodBody&lt;/code&gt; method is a more direct and efficient choice. It reduces boilerplate code, lowers cognitive complexity by removing a layer of nesting, and ultimately improves the maintainability of your class-generation code.&lt;/p&gt;

&lt;p&gt;This rule encourages replacing &lt;code&gt;withMethod&lt;/code&gt; with its more concise counterpart, &lt;code&gt;withMethodBody&lt;/code&gt;, whenever you are defining a method that has a concrete implementation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Noncompliant Code Example:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;ClassBuilder&lt;/span&gt; &lt;span class="nf"&gt;addMethod&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ClassBuilder&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withMethod&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"foo"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MTD_void&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;ACC_PUBLIC&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="no"&gt;ACC_STATIC&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;methodBuilder&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// Noncompliant&lt;/span&gt;
            &lt;span class="n"&gt;methodBuilder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withCode&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;codeBuilder&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
                &lt;span class="n"&gt;codeBuilder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getstatic&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ClassDesc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"java.lang.System"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="s"&gt;"out"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ClassDesc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"java.io.PrintStream"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
                    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ldc&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello World"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;invokevirtual&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ClassDesc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"java.io.PrintStream"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="s"&gt;"println"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MTD_void&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;return_&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;});&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code uses &lt;code&gt;withMethod&lt;/code&gt;, which introduces a &lt;code&gt;methodBuilder&lt;/code&gt;. This then requires a call to &lt;code&gt;withCode&lt;/code&gt; and an additional nested lambda (&lt;code&gt;codeBuilder -&amp;gt; ...&lt;/code&gt;) just to define the method's body, making the code unnecessarily verbose.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Compliant Solution:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;ClassBuilder&lt;/span&gt; &lt;span class="nf"&gt;addMethod&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ClassBuilder&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withMethodBody&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"foo"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MTD_void&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;ACC_PUBLIC&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="no"&gt;ACC_STATIC&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;codeBuilder&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="n"&gt;codeBuilder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getstatic&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ClassDesc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"java.lang.System"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="s"&gt;"out"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ClassDesc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"java.io.PrintStream"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ldc&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello World"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;invokevirtual&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ClassDesc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"java.io.PrintStream"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="s"&gt;"println"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MTD_void&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;return_&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The compliant solution uses &lt;code&gt;withMethodBody&lt;/code&gt;, which directly accepts the code-building lambda. This removes the intermediate &lt;code&gt;methodBuilder&lt;/code&gt;, resulting in flatter, more readable, and more maintainable code that clearly expresses the intent of defining a method and its body in a single, streamlined operation.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Rule S7477: The simpler &lt;code&gt;transformClass&lt;/code&gt; overload should be used when the class name is unchanged&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The Class-File API, introduced in Java via &lt;a href="https://openjdk.org/jeps/484" rel="noopener noreferrer"&gt;JEP 484&lt;/a&gt;, provides powerful methods for transforming class files. Among these is the &lt;code&gt;transformClass&lt;/code&gt; method, which comes in several overloaded versions to handle different use cases.&lt;/p&gt;

&lt;p&gt;A common scenario is transforming a class without changing its name. For this specific situation, the API provides a concise two-argument version of &lt;code&gt;transformClass&lt;/code&gt;. Using the more complex, three-argument overload and manually passing the original class name is unnecessary.&lt;/p&gt;

&lt;p&gt;This rule encourages using the simplest possible API to make code shorter, clearer, and less prone to error. By choosing the correct &lt;code&gt;transformClass&lt;/code&gt; overload, you explicitly signal that the class is not being renamed, which improves the overall readability and maintainability of the code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Noncompliant Code Example:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;transformClassFile&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Path&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;IOException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;ClassFile&lt;/span&gt; &lt;span class="n"&gt;classFile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ClassFile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="nc"&gt;ClassModel&lt;/span&gt; &lt;span class="n"&gt;classModel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;classFile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;newBytes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;classFile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;transformClass&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;classModel&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;classModel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;thisClass&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;asSymbol&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="c1"&gt;// Noncompliant: This argument is redundant&lt;/span&gt;
      &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;classBuilder&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;classElement&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(!(&lt;/span&gt;&lt;span class="n"&gt;classElement&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;MethodModel&lt;/span&gt; &lt;span class="n"&gt;methodModel&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
            &lt;span class="n"&gt;methodModel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;methodName&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;stringValue&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;startsWith&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"debug"&lt;/span&gt;&lt;span class="o"&gt;)))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;classBuilder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;classElement&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;});&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, the class name is explicitly passed to &lt;code&gt;transformClass&lt;/code&gt;, even though it remains unchanged. This adds unnecessary code and can make the transformation's intent harder to grasp at a glance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Compliant Solution:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;transformClassFile&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Path&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;IOException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;ClassFile&lt;/span&gt; &lt;span class="n"&gt;classFile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ClassFile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="nc"&gt;ClassModel&lt;/span&gt; &lt;span class="n"&gt;classModel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;classFile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;newBytes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;classFile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;transformClass&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;classModel&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
      &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;classBuilder&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;classElement&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(!(&lt;/span&gt;&lt;span class="n"&gt;classElement&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;MethodModel&lt;/span&gt; &lt;span class="n"&gt;methodModel&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
            &lt;span class="n"&gt;methodModel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;methodName&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;stringValue&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;startsWith&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"debug"&lt;/span&gt;&lt;span class="o"&gt;)))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;classBuilder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;classElement&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;});&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The compliant solution uses the simpler, two-argument overload of &lt;code&gt;transformClass&lt;/code&gt;. By removing the redundant class name parameter, the code becomes more direct and effectively communicates that the transformation modifies the class in place without renaming it.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Rule S7478: &lt;code&gt;transformClass&lt;/code&gt; should be used to modify existing classes&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The Class-File API (&lt;a href="https://openjdk.org/jeps/484" rel="noopener noreferrer"&gt;JEP 484&lt;/a&gt;) provides developers with two primary methods for generating class files: &lt;code&gt;build&lt;/code&gt; and &lt;code&gt;transformClass&lt;/code&gt;. While &lt;code&gt;build&lt;/code&gt; is a general-purpose tool for creating a class from scratch, &lt;code&gt;transformClass&lt;/code&gt; is specifically designed for the common task of modifying an existing class.&lt;/p&gt;

&lt;p&gt;A frequent pattern in bytecode manipulation is to parse a class, iterate through its elements (like methods or fields), and write a new version with some elements removed or altered. Implementing this pattern with &lt;code&gt;build&lt;/code&gt; requires manually iterating over the original class's elements and adding them one by one to a new &lt;code&gt;ClassBuilder&lt;/code&gt;. This approach is verbose and full of boilerplate code that obscures the core transformation logic.&lt;/p&gt;

&lt;p&gt;This rule encourages using the &lt;code&gt;transformClass&lt;/code&gt; method for such tasks. It abstracts away the manual iteration, leading to code that is more declarative, easier to read, and clearly expresses the intent of transforming an existing class model.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Noncompliant Code Example:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;transformClassFile&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Path&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;IOException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;ClassFile&lt;/span&gt; &lt;span class="n"&gt;classFile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ClassFile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
  &lt;span class="nc"&gt;ClassModel&lt;/span&gt; &lt;span class="n"&gt;classModel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;classFile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;newBytes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;classFile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt; &lt;span class="c1"&gt;// Noncompliant&lt;/span&gt;
    &lt;span class="n"&gt;classModel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;thisClass&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;asSymbol&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;classBuilder&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Manual iteration over class elements is boilerplate&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ClassElement&lt;/span&gt; &lt;span class="n"&gt;classElement&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;classModel&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(!(&lt;/span&gt;&lt;span class="n"&gt;classElement&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;MethodModel&lt;/span&gt; &lt;span class="n"&gt;methodModel&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
              &lt;span class="n"&gt;methodModel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;methodName&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;stringValue&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;startsWith&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"debug"&lt;/span&gt;&lt;span class="o"&gt;)))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;classBuilder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;classElement&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

          &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;});&lt;/span&gt;
  &lt;span class="nc"&gt;Files&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;write&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;newBytes&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code manually rebuilds the class using &lt;code&gt;build&lt;/code&gt;, requiring an explicit loop to copy over the elements that are being kept. This boilerplate distracts from the actual goal: filtering out debug methods.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Compliant Solution:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;transformClassFile&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Path&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;IOException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;ClassFile&lt;/span&gt; &lt;span class="n"&gt;classFile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ClassFile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
  &lt;span class="nc"&gt;ClassModel&lt;/span&gt; &lt;span class="n"&gt;classModel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;classFile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;newBytes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;classFile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;transformClass&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;classModel&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;classBuilder&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;classElement&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// The transform is applied to each element, no manual loop needed&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(!(&lt;/span&gt;&lt;span class="n"&gt;classElement&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;MethodModel&lt;/span&gt; &lt;span class="n"&gt;methodModel&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
            &lt;span class="n"&gt;methodModel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;methodName&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;stringValue&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;startsWith&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"debug"&lt;/span&gt;&lt;span class="o"&gt;)))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
          &lt;span class="n"&gt;classBuilder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;classElement&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;});&lt;/span&gt;
  &lt;span class="nc"&gt;Files&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;write&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;newBytes&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The compliant solution uses &lt;code&gt;transformClass&lt;/code&gt;, which handles the iteration implicitly. The provided lambda is applied to each &lt;code&gt;ClassElement&lt;/code&gt;, allowing the developer to focus solely on the transformation logic. The resulting code is more concise, readable, and less error-prone.&lt;/p&gt;

&lt;h1&gt;
  
  
  Java 24: Stream Gatherers
&lt;/h1&gt;

&lt;p&gt;Java 24 also introduces Stream Gatherers (&lt;a href="https://openjdk.org/jeps/461" rel="noopener noreferrer"&gt;JEP 461&lt;/a&gt;), a new feature designed to enhance the Stream API by allowing for custom intermediate stream operations. Unlike existing &lt;code&gt;map\&lt;/code&gt;, &lt;code&gt;filter\&lt;/code&gt;, or &lt;code&gt;reduce\&lt;/code&gt; operations, Gatherers enable more complex, stateful, and flexible transformations of stream elements. This allows developers to implement operations like grouping, windowing, or de-duplication directly within the stream pipeline, leading to more expressive, efficient, and readable code for advanced data processing scenarios.&lt;/p&gt;

&lt;p&gt;SonarQube continues its commitment to code quality by introducing new rules specifically for Java 24's Stream Gatherers. These rules — including &lt;a href="https://github.com/SonarSource/rspec/blob/master/rules/S7481/java/rule.adoc" rel="noopener noreferrer"&gt;S7481&lt;/a&gt; , &lt;a href="https://github.com/SonarSource/rspec/blob/master/rules/S7482/java/rule.adoc" rel="noopener noreferrer"&gt;S7482&lt;/a&gt; and &lt;a href="https://github.com/SonarSource/rspec/blob/master/rules/S7629/java/rule.adoc" rel="noopener noreferrer"&gt;S7629&lt;/a&gt; — are designed to guide developers in effectively leveraging this powerful new Stream API feature. They ensure that your custom intermediate stream operations are implemented efficiently and clearly, promoting best practices and helping to avoid common pitfalls associated with stateful and stateless gatherers, leading to more robust and readable stream pipelines.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Rule S7481: Sequential gatherers should use &lt;code&gt;Gatherer.ofSequential&lt;/code&gt;&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The introduction of Stream Gatherers (&lt;a href="https://openjdk.org/jeps/461" rel="noopener noreferrer"&gt;JEP 461&lt;/a&gt;) in Java provides a powerful way to create custom intermediate operations in stream pipelines. When creating a gatherer, the API offers two main factories: &lt;code&gt;Gatherer.of(...)&lt;/code&gt; for gatherers that can be used in both sequential and parallel streams, and &lt;code&gt;Gatherer.ofSequential(...)&lt;/code&gt; for those designed exclusively for sequential processing.&lt;/p&gt;

&lt;p&gt;A common pattern for a sequential-only gatherer is to provide a combiner function—the third argument in &lt;code&gt;Gatherer.of(...)&lt;/code&gt;—that simply throws an exception, as it's never expected to be called. This, however, is a signal that the gatherer is not truly parallel-capable.&lt;/p&gt;

&lt;p&gt;This rule helps improve code clarity by guiding you to use the more specific &lt;code&gt;Gatherer.ofSequential(...)&lt;/code&gt; factory in these cases. Doing so makes the intended processing model explicit, removes the need for a dummy or throwing combiner, and makes the code cleaner and easier to understand.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Noncompliant Code Example:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;diffWithFirstPositive&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;Gatherer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;AtomicInteger&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;gatherer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Gatherer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AtomicInteger&lt;/span&gt;&lt;span class="o"&gt;(-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
    &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;downstream&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
      &lt;span class="o"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;downstream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;},&lt;/span&gt;
    &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// The combiner is never meant to be called&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;IllegalStateException&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;},&lt;/span&gt;
    &lt;span class="nc"&gt;Gatherer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;defaultFinisher&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;gather&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gatherer&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;toList&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this code, the presence of a combiner that unconditionally throws an &lt;code&gt;IllegalStateException&lt;/code&gt; is a clear indicator that the gatherer cannot function in a parallel stream.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Compliant Solution:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;diffWithFirstPositive&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;Gatherer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;AtomicInteger&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;gatherer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Gatherer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofSequential&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AtomicInteger&lt;/span&gt;&lt;span class="o"&gt;(-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
    &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;downstream&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
      &lt;span class="o"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;downstream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;},&lt;/span&gt;
    &lt;span class="nc"&gt;Gatherer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;defaultFinisher&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;gather&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gatherer&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;toList&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By switching to &lt;code&gt;Gatherer.ofSequential&lt;/code&gt;, the code becomes more obvious about its intent. It clearly communicates that the operation is sequential-only and eliminates the unnecessary and misleading throwing combiner, resulting in a cleaner implementation.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Rule S7482: Stateless gatherers should be created without a null initializer&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Stream Gatherers can be either stateful—maintaining a state across elements—or stateless, processing each element independently. For stateless gatherers, there is no need to initialize a state object. The &lt;code&gt;java.util.stream.Gatherer&lt;/code&gt; API reflects this distinction by providing overloaded factory methods, including versions that do not take an &lt;code&gt;initializer&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;When creating a stateless gatherer, it is a common mistake to use a factory method that requires an initializer and simply provide a dummy one, such as &lt;code&gt;() -&amp;gt; null&lt;/code&gt;. This practice, while functional, makes the code less clear and fails to communicate the gatherer's stateless nature effectively.&lt;/p&gt;

&lt;p&gt;This rule encourages the use of the correct factory method for stateless gatherers. By choosing the factory that omits the initializer, you make the stateless design explicit and your code more concise and readable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Noncompliant Code Example:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;Gatherer&lt;/span&gt; &lt;span class="nf"&gt;inRange&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Gatherer&lt;/span&gt;&lt;span class="o"&gt;.&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Void&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ofSequential&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Noncompliant: unnecessary initializer for a stateless gatherer&lt;/span&gt;
      &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;downstream&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;downstream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;downstream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isRejecting&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
      &lt;span class="o"&gt;},&lt;/span&gt;
      &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;downstream&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;downstream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="o"&gt;(-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, the &lt;code&gt;() -&amp;gt; null&lt;/code&gt; initializer serves no purpose other than to satisfy the signature of the factory method. This adds unnecessary boilerplate and obscures the fact that the operation does not depend on a state.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Compliant Solution:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nc"&gt;Gatherer&lt;/span&gt; &lt;span class="nf"&gt;inRange&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Gatherer&lt;/span&gt;&lt;span class="o"&gt;.&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ofSequential&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;downstream&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;downstream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;downstream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isRejecting&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
      &lt;span class="o"&gt;},&lt;/span&gt;
      &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;downstream&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;downstream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="o"&gt;(-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The compliant solution uses the appropriate &lt;code&gt;Gatherer.ofSequential&lt;/code&gt; overload that does not require an initializer. This removes the redundant code and clearly signals to anyone reading it that the gatherer is stateless by design.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Rule S7629: When a defaultFinisher is passed to a Gatherer factory, use the overload that does not take a finisher&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;java.util.stream.Gatherer&lt;/code&gt; API, used for creating custom stream operations, provides overloaded factory methods like &lt;code&gt;of(...)&lt;/code&gt; and &lt;code&gt;ofSequential(...)&lt;/code&gt;. Some of these overloads accept a &lt;code&gt;finisher&lt;/code&gt; function to perform a final action after all elements have been processed.&lt;/p&gt;

&lt;p&gt;However, the API also provides a &lt;code&gt;Gatherer.defaultFinisher()&lt;/code&gt;, which does nothing. Passing this default finisher to a factory method is redundant and adds unnecessary boilerplate to the code. Using the simpler overload of the factory method that does not take a finisher at all achieves the same result while more clearly communicating that no special finishing action is needed.&lt;/p&gt;

&lt;p&gt;This rule helps you write more concise code by flagging the unnecessary use of &lt;code&gt;Gatherer.defaultFinisher()&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Noncompliant Code Example :&lt;/strong&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Gatherer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;AtomicInteger&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;gatherer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Gatherer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofSequential&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
  &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AtomicInteger&lt;/span&gt;&lt;span class="o"&gt;(-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
  &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;downstream&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;downstream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
  &lt;span class="o"&gt;},&lt;/span&gt;
  &lt;span class="nc"&gt;Gatherer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;defaultFinisher&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// Noncompliant: this finisher is useless&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this code, &lt;code&gt;Gatherer.defaultFinisher()&lt;/code&gt; is explicitly passed, making the code more verbose than necessary for no additional benefit.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Compliant Solution :&lt;/strong&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Gatherer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;AtomicInteger&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;gatherer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Gatherer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofSequential&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
  &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;AtomicInteger&lt;/span&gt;&lt;span class="o"&gt;(-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
  &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;downstream&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;downstream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
  &lt;span class="o"&gt;});&lt;/span&gt; &lt;span class="c1"&gt;// Compliant&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The compliant solution removes the default finisher and calls the simpler overload of &lt;code&gt;Gatherer.ofSequential&lt;/code&gt;. The functionality is identical, but the code intent—that no special finisher is required—is perfectly clear.&lt;/p&gt;

&lt;h1&gt;
  
  
  Java and SonarQube
&lt;/h1&gt;

&lt;p&gt;By embracing the new features in Java 22, 23, and 24—such as unnamed variables and patterns, Markdown in Javadoc, the Class-File API, and Stream Gatherers—developers can write more efficient, and more maintainable code resulting in a higher-quality code. However, staying abreast of these evolving language enhancements and consistently applying best practices can be challenging. &lt;/p&gt;

&lt;p&gt;This is where tools like &lt;a href="https://www.sonarsource.com/products/sonarqube/" rel="noopener noreferrer"&gt;SonarQube&lt;/a&gt;, become invaluable. They provide automated checks that help ensure your code not only leverages these modern features correctly but also adheres to high-quality standards, ultimately improving code clarity and overall project quality.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>java</category>
      <category>codequality</category>
    </item>
    <item>
      <title>Diving Deep into SonarQube's AI CodeFix: A Hands-On Experiment with Eclipse JKube</title>
      <dc:creator>Jonathan Vila</dc:creator>
      <pubDate>Wed, 04 Jun 2025 20:27:17 +0000</pubDate>
      <link>https://dev.to/jonathanvila/diving-deep-into-sonarqubes-ai-codefix-a-hands-on-experiment-with-eclipse-jkube-150d</link>
      <guid>https://dev.to/jonathanvila/diving-deep-into-sonarqubes-ai-codefix-a-hands-on-experiment-with-eclipse-jkube-150d</guid>
      <description>&lt;p&gt;SonarQube has long been a staple in a Java developer's toolkit for maintaining code quality. With the introduction of its AI CodeFix feature, SonarQube promises to take automated code remediation to the next level. This article explores a practical experiment conducted using &lt;a href="https://www.sonarsource.com/solutions/ai/ai-codefix/" rel="noopener noreferrer"&gt;SonarQube's AI CodeFix&lt;/a&gt; on the open-source Java project, &lt;a href="https://github.com/eclipse-jkube/jkube" rel="noopener noreferrer"&gt;Eclipse JKube&lt;/a&gt;. We'll delve into the setup, the process, the successes, and the challenges encountered, offering insights for Java developers looking to leverage this cutting-edge technology.&lt;/p&gt;




&lt;h2&gt;
  
  
  AI impact in the development lifecycle
&lt;/h2&gt;

&lt;p&gt;AI code generation offers accelerated development by automating repetitive tasks and suggesting solutions with access to a long list of sources. This, combined with the deterministic analysis executed by SonarQube, produces a powerful solution that will boost the development experience.&lt;/p&gt;

&lt;p&gt;You have to keep in mind, especially when using AI generated code, that critical oversight, thorough review, and continued skill development are essential. Treating AI as a helpful tool rather than a complete replacement ensures that developers leverage its power effectively while maintaining control and understanding of their codebase.&lt;br&gt;&lt;br&gt;
AI has a huge potential in enhancing developer productivity and improving code quality. The experiment with JKube highlighted that while it's not a silver bullet, it's a powerful assistant for specific types of code cleanup. &lt;/p&gt;

&lt;h2&gt;
  
  
  What is SonarQube offering here to help?
&lt;/h2&gt;

&lt;p&gt;SonarQube, the code quality guardian tool you’ve been using to ensure your project quality and security, has an advanced feature called AI CodeFix. This feature leverages artificial intelligence to automatically suggest fixes for detected code issues, moving beyond simple static analysis and offering practical remediation suggestions.&lt;/p&gt;

&lt;p&gt;AI CodeFix aims to streamline the process of code maintenance and quality improvement by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Identifying Code Issues:&lt;/strong&gt; SonarQube performs in-depth code analysis to pinpoint various issues, ranging from stylistic inconsistencies to potential bugs and vulnerabilities.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generating AI-Driven Suggestions:&lt;/strong&gt; When a code issue is identified, AI CodeFix attempts to generate a specific code change that would resolve the problem. These suggestions are based on patterns learned from vast amounts of code and best practices.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Providing Contextual Solutions:&lt;/strong&gt; The AI-generated fixes are designed to be contextually relevant, taking into account the surrounding code and the nature of the issue.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Facilitating Quicker Resolutions:&lt;/strong&gt; By providing direct fix suggestions, AI CodeFix can significantly reduce the time developers spend manually debugging and correcting issues, allowing them to focus more on feature development.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enhancing Learning:&lt;/strong&gt; Developers can learn from the AI suggestions, gaining insights into better coding practices and common pitfalls to avoid.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In essence, SonarQube AI CodeFix acts as an intelligent assistant, proactively identifying and suggesting remedies for code quality issues, thus contributing to cleaner, more reliable code.&lt;/p&gt;

&lt;p&gt;These modifications play a significant role in maintaining code integrity. Let's explore the impact of these specific fixes on the overall project health and efficiency.&lt;/p&gt;

&lt;p&gt;From the SonarQube issue description page, for certain rules, you see the “Generate AI Fix” button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff7lrxo92c5ife95oaa7p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff7lrxo92c5ife95oaa7p.png" alt="Image description" width="800" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And clicking on it, SonarQube will produce the fix for that particular issue.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fukhcvf26x92zt8us3bbt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fukhcvf26x92zt8us3bbt.png" alt="Image description" width="800" height="310"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Clicking on “View fix in IDE” will open your current local IDE on the file with the changes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4rfzelielbr5gkplhdtw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4rfzelielbr5gkplhdtw.png" alt="Image description" width="800" height="751"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;AI CodeFix delivers valuable results for a selected subset of rules, confirmed through testing. These targeted rules undergo verification to ensure performance enhancements. Focusing on this checked subgroup optimizes the utility of the AI tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  Eclipse JKube: An Overview
&lt;/h2&gt;

&lt;p&gt;Eclipse JKube is an open source collection of plugins and tools for Kubernetes and OpenShift that simplify the process of building and deploying Java applications to containerized environments. It aims to provide a streamlined, developer-friendly experience, reducing the complexity of working with Kubernetes and OpenShift directly.&lt;/p&gt;

&lt;p&gt;It simplifies and streamlines the process of building container images (using Docker, JIB, or S2I strategies) and deploying Java applications to Kubernetes and OpenShift. Users appreciate its "zero-configuration" capability for quick starts, while also offering flexible XML and external template configurations for more complex needs. JKube effectively bridges the gap between Java applications and cloud-native environments.&lt;/p&gt;

&lt;p&gt;The Eclipse JKube project itself maintains a rich repository of quickstart projects. These demonstrate how to use JKube with various Java frameworks and technologies, including: Spring Boot, Quarkus, Micronaut, Vert.x, Open Liberty, Apache Camel, Apache Karaf among others, and companies like Red Hat are heavily using it and contributing to it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Features and Objectives of JKube
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Simplified Kubernetes Development:&lt;/strong&gt; JKube simplifies the process of creating Kubernetes manifests, building container images, and deploying applications. Developers can focus more on writing code and less on configuration details.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Maven and Gradle Integration:&lt;/strong&gt; It integrates seamlessly with popular build tools like Maven and Gradle, allowing developers to manage their Kubernetes deployments as part of their existing build processes.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OpenShift Support:&lt;/strong&gt; In addition to Kubernetes, JKube also supports OpenShift, Red Hat's enterprise Kubernetes platform, making it versatile for different environments.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero Configuration Defaults:&lt;/strong&gt; JKube provides sensible default configurations that work for many common Java application scenarios, minimizing the need for manual configuration.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hot Reloading and Debugging:&lt;/strong&gt; It supports features like hot reloading, which allows developers to see changes in their application without restarting the entire container, and remote debugging for troubleshooting.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resource Generation:&lt;/strong&gt; JKube automatically generates Kubernetes resource descriptors from project metadata, reducing the amount of YAML configuration required.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extensibility:&lt;/strong&gt; The plugin is designed to be extensible, allowing developers to customize or add new features as needed.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How JKube Works
&lt;/h3&gt;

&lt;p&gt;JKube uses a combination of build tool plugins and libraries to achieve its goals. When a project is built with JKube, it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Analyzes Project Metadata:&lt;/strong&gt; JKube inspects the project's POM file (for Maven) or build.gradle (for Gradle) to gather information about the application, such as dependencies, ports, and environment variables.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generates Kubernetes Manifests:&lt;/strong&gt; Based on the project metadata, JKube automatically generates the necessary Kubernetes resource descriptors (YAML files) for deploying the application.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Builds Container Images:&lt;/strong&gt; It handles the process of building container images (Docker or Podman) that package the application and its dependencies.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deploys to Kubernetes/OpenShift:&lt;/strong&gt; JKube can directly deploy the built image to a Kubernetes or OpenShift cluster, simplifying the deployment workflow.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Benefits of Using JKube
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Increased Developer Productivity:&lt;/strong&gt; By automating much of the Kubernetes and OpenShift interaction, JKube allows developers to spend more time coding and less time managing infrastructure.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reduced Configuration Overhead:&lt;/strong&gt; JKube's zero-configuration defaults and automatic resource generation reduce the complexity of configuring deployments.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consistent Deployments:&lt;/strong&gt; JKube ensures consistent deployments across different environments by using the same build process and metadata.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Faster Iteration:&lt;/strong&gt; Features like hot reloading and remote debugging speed up the development cycle and make it easier to troubleshoot issues.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simplified CI/CD Integration:&lt;/strong&gt; JKube can be easily integrated into Continuous Integration/Continuous Deployment (CI/CD) pipelines, automating the deployment process further.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  AI CodeFix in Action: A Module-by-Module Breakdown
&lt;/h2&gt;

&lt;p&gt;The experiment focused on targeting specific modules within JKube: openshift-maven-plugin, kubernetes-maven-plugin, and gradle-plugin. The general workflow for each issue involved navigating to it in the SonarQube server, clicking the "CodeFix" button to see the suggestion, and then attempting to view it in the IDE, accept the changes, commit and create the Pull Request.&lt;/p&gt;

&lt;p&gt;These are some of the issues detected during the process with their explanation and the specific changes implemented:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Openshift-maven-plugin&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Issue Remove the declaration of thrown exception 'java.io.IOException', as it cannot be thrown from method's body (&lt;a href="https://rules.sonarsource.com/java/RSPEC-1130/" rel="noopener noreferrer"&gt;S1130&lt;/a&gt;)

&lt;ul&gt;
&lt;li&gt;Superfluous exceptions within throws clauses have negative effects on the readability and maintainability of the code. An exception in a throws clause is superfluous if it is:
&lt;/li&gt;
&lt;li&gt;listed multiple times
&lt;/li&gt;
&lt;li&gt;a subclass of another listed exception
&lt;/li&gt;
&lt;li&gt;not actually thrown by any execution path of the method&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fta35gx8q0qpypgn0ia9w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fta35gx8q0qpypgn0ia9w.png" alt="Image description" width="800" height="179"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Kubernetes-maven-plugin&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Issue Rename "remoteDevelopmentService" which hides the field declared at line 39.(&lt;a href="https://rules.sonarsource.com/java/RSPEC-1117" rel="noopener noreferrer"&gt;S1117&lt;/a&gt;)

&lt;ul&gt;
&lt;li&gt;Shadowing occurs when a local variable has the same name as a variable or a field in an outer scope.
&lt;/li&gt;
&lt;li&gt;This can lead to three main problems:
&lt;/li&gt;
&lt;li&gt;Confusion: The same name can refer to different variables in different parts of the scope, making the code hard to read and understand.
&lt;/li&gt;
&lt;li&gt;Unintended Behavior: You might accidentally use the wrong variable, leading to hard-to-detect bugs.
&lt;/li&gt;
&lt;li&gt;Maintenance Issues: If the inner variable is removed or renamed, the code’s behavior might change unexpectedly because the outer variable is now being used.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuy4s6sn04wffrcoudq3o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuy4s6sn04wffrcoudq3o.png" alt="Image description" width="800" height="194"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Issue Use a primitive boolean expression here (&lt;a href="https://rules.sonarsource.com/java/RSPEC-5411" rel="noopener noreferrer"&gt;S5411&lt;/a&gt;)

&lt;ul&gt;
&lt;li&gt;When boxed type java.lang.Boolean is used as an expression to determine the control flow (as described in &lt;a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-4.html#jls-4.2.5" rel="noopener noreferrer"&gt;Java Language Specification §4.2.5 The boolean Type and boolean Values&lt;/a&gt;) it will throw a NullPointerException if the value is null (as defined in &lt;a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.8" rel="noopener noreferrer"&gt;Java Language Specification §5.1.8 Unboxing Conversion&lt;/a&gt;).
&lt;/li&gt;
&lt;li&gt;It is safer to avoid such conversion altogether and handle the &lt;code&gt;null&lt;/code&gt; value explicitly. &lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbknine7c0eca06sl8yy2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbknine7c0eca06sl8yy2.png" alt="Image description" width="800" height="209"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Gradle-plugin&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This module saw more consistent success:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Issue Define a constant instead of duplicating this literal "jkube" 5 times (&lt;a href="https://rules.sonarsource.com/java/RSPEC-1192/" rel="noopener noreferrer"&gt;S1192&lt;/a&gt;)

&lt;ul&gt;
&lt;li&gt;Duplicated string literals (more than 5 times) make the process of refactoring complex and error-prone, as any change would need to be propagated on all occurrences.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk51331epkk8v82g6ntuq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk51331epkk8v82g6ntuq.png" alt="Image description" width="800" height="394"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Issue Replace this lambda with method reference 'task::mustRunAfter' (&lt;a href="https://rules.sonarsource.com/java/RSPEC-1612/" rel="noopener noreferrer"&gt;S1612&lt;/a&gt;)

&lt;ul&gt;
&lt;li&gt;Method or constructor references are more readable than lambda expressions in many situations, and may therefore be preferred.
&lt;/li&gt;
&lt;li&gt;However, method references are sometimes less concise than lambdas. In such cases, it might be preferable to keep the lambda expression for better readability. Therefore, this rule only raises issues on lambda expressions where the replacement method reference is shorter &lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5p77yb4keo1zv3lfzwlf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5p77yb4keo1zv3lfzwlf.png" alt="Image description" width="800" height="167"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h1&gt;
  
  
  Key Takeaways for Java Developers
&lt;/h1&gt;

&lt;p&gt;SonarQube's AI CodeFix is a promising feature that can undoubtedly speed up the process of addressing certain types of code quality issues. &lt;/p&gt;

&lt;p&gt;For now, Java developers can benefit from using AI as a helpful co-pilot, always keeping a discerning eye on the suggestions before committing them to the codebase.&lt;/p&gt;

&lt;p&gt;Based on this experiment:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Trust but Verify: While AI can provide valuable suggestions, developers must meticulously review each proposed change. Automatic application without review can lead to compilation errors or introduce unintended behavior.
&lt;/li&gt;
&lt;li&gt;Best for Boilerplate: The feature seems most reliable for common, boilerplate-style fixes like removing unused code, simple refactorings, and enforcing consistent style.
&lt;/li&gt;
&lt;li&gt;Complex Logic is Still Human Domain: For more complex issues, especially those described in TODO comments requiring new logic or significant code modification, the developer is the important part. AI definitely help the developer to focus on important tasks.
&lt;/li&gt;
&lt;li&gt;Iterative Improvement: AI technology is rapidly evolving. The issues and limitations observed in this experiment might be addressed in future versions of SonarQube.
&lt;/li&gt;
&lt;li&gt;Tooling Limitations: The lack of bulk fixing and refined filtering options for AI-ready fixes can slow down the process if a project has many issues. The API approach for automation also hit a snag.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>codequality</category>
    </item>
    <item>
      <title>➡️ AI gives you ✅ 𝐓𝐈𝐌𝐄 not ❌𝐂𝐎𝐍𝐅𝐈𝐃𝐄𝐍𝐂𝐄 : Developer productivity toolkit</title>
      <dc:creator>Jonathan Vila</dc:creator>
      <pubDate>Fri, 23 May 2025 12:52:04 +0000</pubDate>
      <link>https://dev.to/jonathanvila/ai-gives-you-not-developer-productivity-toolkit-1n9d</link>
      <guid>https://dev.to/jonathanvila/ai-gives-you-not-developer-productivity-toolkit-1n9d</guid>
      <description>&lt;p&gt;Let's be real – keeping up with the pace of software development today is intense. New frameworks pop up and the push for faster, better, &lt;em&gt;and&lt;/em&gt; more secure code never stops. &lt;/p&gt;

&lt;p&gt;This article is all about cutting through the buzz and looking at how AI-powered tools can actually help you, the Java developer, day-to-day. We'll dive into specific ways AI can help you through the whole SDLC:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Understanding Complex Tasks&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accelerating Code Creation&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Streamlining Cloud Deployment&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Creating Effective Tests&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Increasing Code Quality and Security&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Improving Code Review&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Using AI to Understand Complex Tasks
&lt;/h1&gt;

&lt;p&gt;Okay, first up: wrapping your head around the job at hand. You know those moments where you need to implement a feature based on requirements that feel a bit… fuzzy. Traditionally, this means lots of reading, maybe drawing diagrams, and asking clarifying questions.&lt;/p&gt;

&lt;p&gt;Here's where AI can lend a hand. Think of tools like &lt;code&gt;GitHub Copilot, Windsurf and Cursor ,&lt;/code&gt;among others, as smart summarizers and brainstorming partners.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Digest Docs:&lt;/strong&gt; Feed the AI that long requirements doc and ask it to summarize the key points related to a specific feature.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clarify Ambiguity:&lt;/strong&gt; Try phrasing a requirement as a question to the AI. "Explain the user session timeout logic described here "
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Break It Down:&lt;/strong&gt; Feeling overwhelmed by a big task? Describe the goal to the AI and ask it to suggest potential steps or components.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Connect it to your code base&lt;/strong&gt;: Feed your code base to the AI assistant , link the requirements doc and ask the AI where you should put the new code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Getting Specific with Github issues and Your Code:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now, what about pointing the AI at a specific issue ticket and your actual codebase to figure out &lt;em&gt;where&lt;/em&gt; to start coding? This is getting more powerful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;IDE Integrations are Key:&lt;/strong&gt; Tools like &lt;code&gt;GitHub Copilot&lt;/code&gt; operate right within your IDE. You can copy the core description from your &lt;code&gt;Jira&lt;/code&gt; ticket into the chat panel and ask something like: &lt;em&gt;"Based on this ticket #1, what services might I need to modify?"&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Codebase-Aware AI :&lt;/strong&gt; Some newer tools like &lt;code&gt;Cursor&lt;/code&gt; can actually index your entire codebase. This allows for more powerful queries. You &lt;em&gt;might&lt;/em&gt; be able to ask: &lt;em&gt;"Where in our codebase is the logic related to 'JIRA-456' located?"&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI Tool integration&lt;/strong&gt;: MCP servers (more details below) connect your AI assistant directly to servers in order to add capabilities to the Agent. In this case it’s the Github API that will give read or write information regarding the current repository issues. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As an example, you can use Github Code Spaces &lt;a href="https://github.blog/changelog/2025-04-11-vscode-copilot-agent-mode-in-codespaces/" rel="noopener noreferrer"&gt;with Copilot Agent Mode&lt;/a&gt; , and it will give us an explanation of the ticket and the changes to do. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxwmiiobapci559gq7ddv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxwmiiobapci559gq7ddv.png" alt="Image description" width="782" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important Caveats:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Security First:&lt;/strong&gt; Be &lt;em&gt;very&lt;/em&gt; careful about pasting internal code or sensitive information into public AI tools.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It's a Guide, Not a Guru:&lt;/strong&gt; Treat the AI's output as educated guesses. It's a starting point to accelerate your own investigation. You still need your developer brain to validate its reasoning. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Using AI this way is about accelerating the initial investigation phase. It helps you form a hypothesis about &lt;em&gt;where&lt;/em&gt; to look and &lt;em&gt;what&lt;/em&gt; might be involved so you can jump into the interesting design and coding parts sooner.&lt;/p&gt;

&lt;h1&gt;
  
  
  Accelerating Code Creation
&lt;/h1&gt;

&lt;p&gt;Okay, let's talk about actually producing Java code. This is where tools like &lt;code&gt;GitHub Copilot&lt;/code&gt; in &lt;code&gt;VS Code&lt;/code&gt; really shine. Think of them as having a pair programmer who types &lt;em&gt;really&lt;/em&gt; fast and knows a ton of standard library calls, common patterns and the company's codebase.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Killing Boilerplate:&lt;/strong&gt; We all know Java can be a bit verbose sometimes. Need to write constructors, accessors, &lt;code&gt;equals()&lt;/code&gt;, &lt;code&gt;hashCode()&lt;/code&gt; for a POJO? These tools can generate them based on the fields you've declared.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generating Snippets and Methods:&lt;/strong&gt; Write a clear method signature and the AI will generate a surprisingly decent implementation. You can use different methods to generate code:.

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Inline chats&lt;/strong&gt;  Ask the assistant to generate &lt;code&gt;“Java method to fetch data from API endpoint XYZ and parse the JSON response”&lt;/code&gt; and wait a bit. The AI might suggest the entire method body using &lt;code&gt;HttpClient&lt;/code&gt; or &lt;code&gt;RestTemplate&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1oou6ymc7jo5n6egojjf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1oou6ymc7jo5n6egojjf.png" alt="Image description" width="780" height="453"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ghost text&lt;/strong&gt;:  Start typing a typical Spring Boot controller method like &lt;code&gt;@GetMapping("/products/{id}") public ResponseEntity&amp;lt;Product&amp;gt; getProductById&lt;/code&gt; ... The AI will likely suggest the code to call a service and return the response.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;How Context Improves Suggestions:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;These tools use the &lt;strong&gt;context of your project&lt;/strong&gt; to tailor suggestions. But how do they get this context?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Primarily Your Open Files:&lt;/strong&gt; The AI heavily analyzes the code in the file(s) you currently have open in your editor.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chat &amp;amp; Explicit Prompts:&lt;/strong&gt; Mentioning specific class/method names from your project or pasting relevant snippets guides the AI. For example: &lt;em&gt;"Using our &lt;code&gt;CustomerService&lt;/code&gt; class, generate the boilerplate code for a new method &lt;code&gt;findCustomerByEmail(String email)&lt;/code&gt; that calls the &lt;code&gt;customerRepository&lt;/code&gt;."&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Codebase Awareness:&lt;/strong&gt; Specialized tools using Agents can be set up to index your entire codebase. This allows for much deeper context, potentially leading to suggestions that understand your project's specific patterns even if the relevant files aren't currently open.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy0zb3f80h0vgnr5vf9vz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy0zb3f80h0vgnr5vf9vz.png" alt="Image description" width="291" height="383"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;List of context elements to add in a chat&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Context Matters:&lt;/strong&gt; This context is crucial. It means the AI is more likely to suggest code that: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Calls your existing helper functions or service methods.
&lt;/li&gt;
&lt;li&gt;Follows the coding style and patterns already present in the file.
&lt;/li&gt;
&lt;li&gt;Uses the correct versions of libraries already defined in your project dependencies.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The result?&lt;/strong&gt; Code suggestions feel less generic and much more like they actually &lt;em&gt;belong&lt;/em&gt; in your specific project. &lt;/p&gt;

&lt;p&gt;Using the right context also helps on two important points : &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Learning New Libraries:&lt;/strong&gt; Trying out a new Java library or framework feature? You can often just write a comment describing what you want to achieve ("// Use Apache Commons CSV to write records to a file") and let the AI generate a starting example, often using the context of your existing code style.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Quick Mockups:&lt;/strong&gt; Need a quick data transformation or a utility function? Describe it in a comment or start typing, and let the AI fill it in, leveraging context for better results.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;For Experienced Devs:&lt;/strong&gt; Look, this isn't about the AI writing your core, complex business logic. You're still the architect and the problem solver. AI can handle some of the work by leveraging your codebase context, it frees you up to focus on the harder, more valuable parts of the system.&lt;/p&gt;

&lt;p&gt;It takes a little getting used to, and you absolutely &lt;strong&gt;&lt;em&gt;must&lt;/em&gt;&lt;/strong&gt; review the generated code (even context-aware AI isn't perfect!).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Integrating Specialized Agents and Reasoning in Agentic IDEs:&lt;/strong&gt; Agentic IDEs can significantly enhance code generation by employing various specialized agents, each tailored for specific tasks like API interaction, database querying, or UI component creation. Moreover, these IDEs can provide detailed reasoning behind the generated code, outlining the steps taken improving developer understanding and trust in the AI's output.&lt;/p&gt;

&lt;p&gt;In tools like &lt;em&gt;&lt;code&gt;VS Code with Github Copilot&lt;/code&gt;&lt;/em&gt; or &lt;em&gt;&lt;code&gt;Cursor&lt;/code&gt;&lt;/em&gt;, we can even tailor the behaviour of the agents when they generate code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd16gjevpo423gmqu7ra7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd16gjevpo423gmqu7ra7.png" alt="Image description" width="754" height="424"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here we can specify to use the latest Java 24 features, or a specific version of Quarkus, or even which front end frameworks to use, among other particularities of your code. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Advanced tip :&lt;/strong&gt; ask the assistant to create an instructions file based on your current code base structure as the template for all future projects.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MCP servers to the rescue:&lt;/strong&gt; &lt;a href="https://modelcontextprotocol.io/introduction" rel="noopener noreferrer"&gt;MCP&lt;/a&gt; servers greatly enhance code generation and understanding by facilitating connections to specialized tools, expanding knowledge beyond typical Large Language Model (LLM) training data. Several IDEs like &lt;em&gt;&lt;code&gt;Windsurf, Cursor or VS Code with Copilot&lt;/code&gt;&lt;/em&gt; support this technology, enabling developers to leverage MCP-driven AI within their coding environment.&lt;br&gt;&lt;br&gt;
For instance, using an MCP server connected to a database tool, the assistant can generate CRUD (Create, Read, Update, Delete) operations tailored to each table in a database, incorporating specific data types, relationships, and constraints. &lt;/p&gt;

&lt;p&gt;There are several places where we can get MCP servers for specific tasks and with a very easy installation process : &lt;a href="https://mcpservers.org/" rel="noopener noreferrer"&gt;https://mcpservers.org/&lt;/a&gt; , &lt;a href="https://mcpmarket.com/" rel="noopener noreferrer"&gt;https://mcpmarket.com/&lt;/a&gt;, &lt;a href="https://mcp.so/" rel="noopener noreferrer"&gt;https://mcp.so/&lt;/a&gt; , etc.&lt;/p&gt;

&lt;p&gt;This is an example of installation of a Docker MCP server implementing the GitHub tools, that will allow our assistant to connect to our GitHub repository and get issues, branches, PRs, etc.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft61rxfndt7g65xyyk6ob.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft61rxfndt7g65xyyk6ob.png" alt="Image description" width="403" height="292"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These MCP servers expose tools to be used by the agent. In this case the Github MCP Server share 36 tools :   &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj1khjqdbiw4benug1ae0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj1khjqdbiw4benug1ae0.png" alt="Image description" width="521" height="286"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Streamlining Cloud Deployment
&lt;/h1&gt;

&lt;p&gt;Okay, so your Java code is looking good. Now, how about actually shipping it? Getting applications deployed to the cloud involves writing a &lt;em&gt;lot&lt;/em&gt; of configuration – Dockerfiles to containerize your app, Kubernetes YAML for orchestration, and CI/CD pipeline definitions (&lt;code&gt;GitHub Actions&lt;/code&gt;, &lt;code&gt;GitLab CI&lt;/code&gt;, etc.).&lt;/p&gt;

&lt;p&gt;This is another area where AI assistants can save you significant time and effort, acting as configuration generators.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Generating Dockerfiles:&lt;/strong&gt; Need to containerize your Spring Boot or Quarkus app? Instead of starting from scratch, ask your AI assistant: &lt;em&gt;"Generate a multi-stage Dockerfile for a Java 21 Maven project that builds the JAR and runs it using an OpenJDK JRE slim image."&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scaffolding Kubernetes Manifests:&lt;/strong&gt; Get a head start by asking: &lt;em&gt;"Create a Kubernetes Deployment YAML for an app named 'order-service', using image 'my-repo/order-service:v1', with 3 replicas and exposing container port 8080."&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Infrastructure as Code (IaC) Templates:&lt;/strong&gt; Need a basic Terraform configuration? Describe what you need: &lt;em&gt;"Write a simple Terraform configuration (HCL) to create an AWS S3 bucket named 'my-app-data-bucket' with versioning enabled."&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CI/CD Pipeline Starters:&lt;/strong&gt; Setting up a build and test pipeline? Ask: &lt;em&gt;"Generate a basic GitHub Actions workflow file that checks out code, sets up Java 21, builds with Maven, and runs unit tests."&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Debugging Config Errors:&lt;/strong&gt; Pasting a cryptic error message from &lt;code&gt;kubectl&lt;/code&gt; into an AI chat and asking &lt;em&gt;"What does this error mean and how can I fix it?"&lt;/em&gt; can point you in the right direction faster than searching online.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Agentic MCP AI is your friend:&lt;/strong&gt; Getting the logs or the configuration for running apps in your cluster can be crucial to produce more aligned code. For instance, getting the CRDs in your cluster can help you create a better Kubernetes operator that reacts to changes on them. &lt;/p&gt;

&lt;p&gt;You can rely on the multiple MCP servers with your Agentic AI assistant to consider that information when you are chatting with it. &lt;a href="https://github.com/manusa/kubernetes-mcp-server" rel="noopener noreferrer"&gt;Kubernetes MCP server&lt;/a&gt; is a clear example of this and it gives you 15 tools to interact with your K8s cluster.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffesa1qjyfk42sibu1u7r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffesa1qjyfk42sibu1u7r.png" alt="Image description" width="778" height="611"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;VS Code with Github Copilot using Kubernetes MCP to interact with a local cluster&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Java Context Matters:&lt;/strong&gt; When generating configs for Java apps, you can get specific. Ask for Dockerfiles that set appropriate &lt;code&gt;JAVA_OPTS&lt;/code&gt; environment variables for JVM memory limits (&lt;code&gt;-Xms&lt;/code&gt;, &lt;code&gt;-Xmx&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;⚠️ Hold Up! Review Carefully! ⚠️&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Just like with generated code, &lt;strong&gt;AI-generated configuration files are starting points, NOT final products.&lt;/strong&gt; You absolutely need to review them carefully:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Security is Paramount:&lt;/strong&gt; This is critical. AI might generate insecure configurations – hardcoded secrets, overly permissive IAM roles or network policies (like &lt;code&gt;0.0.0.0/0&lt;/code&gt;). &lt;strong&gt;Security configurations MUST be reviewed by someone knowledgeable.&lt;/strong&gt; Don't assume the AI got it right.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check for Best Practices:&lt;/strong&gt; Does the generated config follow current best practices for the specific cloud provider or tool? AI knowledge might be outdated or too generic.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Understand, Don't Just Copy:&lt;/strong&gt; Make sure you understand what the configuration actually &lt;em&gt;does&lt;/em&gt; before applying it. You're still responsible for the infrastructure and deployment.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test Thoroughly:&lt;/strong&gt; Deploy to a non-production environment first and test rigorously.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Reinforce with IaC Static Analysis:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Beyond manual review, remember that specialized &lt;strong&gt;static analysis tools can also help validate your Infrastructure as Code (IaC) files.&lt;/strong&gt; Tools like &lt;code&gt;SonarQube&lt;/code&gt; (which supports Terraform, Kubernetes YAML, Dockerfiles, etc.), are designed specifically to scan these configuration files. They check for: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Common security misconfigurations
&lt;/li&gt;
&lt;li&gt;Adherence to cloud provider best practices
&lt;/li&gt;
&lt;li&gt;Potential syntax errors or logical issues
&lt;/li&gt;
&lt;li&gt;Secrets misusage&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Integrating these IaC scanners into your CI/CD pipeline adds an essential automated check. It complements manual reviews and helps catch issues in both human-written &lt;em&gt;and&lt;/em&gt; AI-generated configurations &lt;em&gt;before&lt;/em&gt; they potentially impact your deployed environment.&lt;/p&gt;

&lt;h1&gt;
  
  
  Creating Effective Tests
&lt;/h1&gt;

&lt;p&gt;Ah, testing. We all know it's crucial for catching regressions, ensuring correctness, and enabling confident refactoring. But it can also be time-consuming. Good news! AI can lend a hand here, helping you generate tests faster.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Generating Unit Test Scaffolding:&lt;/strong&gt; You can ask to generate tests to your AI assistant on a Java class or method. The AI will attempt to create a test class (e.g., using JUnit 5) with basic test methods covering the public methods of your source class.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Suggesting Test Cases:&lt;/strong&gt; You can use AI chat features to brainstorm. Paste your method's code and ask: &lt;em&gt;"What are some important edge cases I should test for this Java method?"&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Creating Mock Objects:&lt;/strong&gt; Setting up mocks can be tedious. AI assistants can often generate the necessary &lt;code&gt;@Mock&lt;/code&gt; annotations, injection points (&lt;code&gt;@InjectMocks&lt;/code&gt;), and &lt;code&gt;when(...).thenReturn(...)&lt;/code&gt; statements based on how your class interacts with its dependencies. For example: &lt;em&gt;"Generate a JUnit test for this &lt;code&gt;OrderService&lt;/code&gt; method, mocking the &lt;code&gt;ProductRepository&lt;/code&gt;"&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Copilot chat asking it to generate the test methods&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvhr6k7k2vst9u1cxqlnm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvhr6k7k2vst9u1cxqlnm.png" alt="Image description" width="757" height="311"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Tests generated by Copilot for this method&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffypfw3639irjd6a4ceun.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffypfw3639irjd6a4ceun.png" alt="Image description" width="580" height="357"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;⚠️ HUGE WARNING: Review Generated Tests Like Crazy! ⚠️&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is possibly even more critical than reviewing generated application code: &lt;strong&gt;AI-generated tests MUST be thoroughly reviewed and often significantly refined.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Common AI test generations :&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AI Doesn't Understand Intent:&lt;/strong&gt; AI tests the code &lt;em&gt;as it's written&lt;/em&gt;. It doesn't know the &lt;em&gt;business requirements&lt;/em&gt; or the &lt;em&gt;intended behavior&lt;/em&gt;. If your code has a bug, the AI might happily generate a test that confirms the buggy behavior!. In this case it doesn’t make any sense to have a total tax of -1000 , and AI has tested that the test is really verifying what the code is doing, including the bug.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx1b191ybskalf6niaerx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx1b191ybskalf6niaerx.png" alt="Image description" width="577" height="171"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Trivial and Meaningless Tests:&lt;/strong&gt; AI often generates tests for simple getters/setters or very basic logic that might not provide much value. It might miss the truly complex or critical paths.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Incorrect Assertions:&lt;/strong&gt; The assertions generated might be wrong, incomplete, or nonsensical. Don't assume they are correct.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Poor Quality:&lt;/strong&gt; Generated tests might not follow best practices for naming, structure, or readability, making them hard to maintain.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Over-reliance on Mocking:&lt;/strong&gt; AI might excessively mock things, leading to brittle tests that don't actually verify useful interactions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;How to Use AI for Testing Effectively:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Use it as a Starting Point:&lt;/strong&gt; Let AI generate the boilerplate structure, basic happy-path tests, and mock setups.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Focus Your Effort:&lt;/strong&gt; Use the time saved to focus on writing tests for the complex logic, critical business rules and tricky edge cases – the areas where human understanding is essential.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Critically Review &amp;amp; Refine:&lt;/strong&gt; Read every generated test. Does it make sense? Is it testing something important? Is the assertion correct? Is it readable?
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don't Chase Coverage Blindly:&lt;/strong&gt; AI can quickly increase test coverage numbers, but coverage isn't the same as quality. A few meaningful tests are better than hundreds of trivial ones.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Provide the right context:&lt;/strong&gt; including functional testing information, or feature requirements will help AI assistants to tailor the test to what it’s supposed to be tested and not what it is written in the code. In this case we are asking to create the tests but considering the requirements specified in a github issue.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh0r1h1w4wg7usbkpwqji.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh0r1h1w4wg7usbkpwqji.png" alt="Image description" width="693" height="552"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flb3lnc9f7bshzjxtajpi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flb3lnc9f7bshzjxtajpi.png" alt="Image description" width="672" height="298"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Don't Forget Static Analysis for Test Code:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One more point on test quality: don't forget that &lt;strong&gt;static analysis tools can also help here!&lt;/strong&gt; Tools like &lt;code&gt;SonarQube&lt;/code&gt;, &lt;code&gt;Checkstyle&lt;/code&gt;, and &lt;code&gt;PMD&lt;/code&gt; often include specific rule sets designed to analyze your &lt;em&gt;test&lt;/em&gt; code, not just your production code. They can check for: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Common testing anti-patterns.
&lt;/li&gt;
&lt;li&gt;Adherence to JUnit/testing framework best practices .
&lt;/li&gt;
&lt;li&gt;Potential bugs in tests .
&lt;/li&gt;
&lt;li&gt;Unused test code or helper methods.
&lt;/li&gt;
&lt;li&gt;Consistency in naming conventions for test classes and methods.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Running these analyzers on your test suites is another good practice, especially when incorporating AI-generated tests. &lt;/p&gt;

&lt;h1&gt;
  
  
  Improving Code Reviews
&lt;/h1&gt;

&lt;p&gt;Alright, let's talk about pull requests (PRs) and code reviews. They're super important for team health and code quality, but they can also be time-consuming and sometimes frustrating. Understand a massive PR, catching subtle issues and providing constructive feedback. And if you're the author, waiting for reviews and addressing comments takes time too. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How AI Helps Reviewers:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Quick Summaries:&lt;/strong&gt; Tools like &lt;code&gt;GitHub Copilot&lt;/code&gt; can automatically generate summaries of the changes in a PR. This helps reviewers quickly grasp the purpose and scope of the changes before diving into the code details.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxwvjw8eqlk26i4lx5su6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxwvjw8eqlk26i4lx5su6.png" alt="Image description" width="767" height="430"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;They can even interact with the PR using extensions in order to provide functionalities that are out of the scope of the LLM like creating Mermaid diagrams for the classes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Automated First Pass (via CI/CD):&lt;/strong&gt; Remember those static analysis (SAST) and IaC scanning tools we discussed? Integrating them into your CI/CD pipeline to run automatically on PRs is a huge win. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;How AI Helps Authors:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pre-Submission Polish:&lt;/strong&gt; Authors can use AI coding assistants (&lt;code&gt;Copilot Chat&lt;/code&gt;, &lt;code&gt;IntelliJ AI Assistant&lt;/code&gt;) in their IDE to refine, and improve their code &lt;em&gt;before&lt;/em&gt; even creating the PR. Asking "Can this code be simplified?" can catch issues early.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Implementing Feedback:&lt;/strong&gt; If a reviewer asks for a specific change, an author could potentially ask their AI assistant for suggestions on how to implement that feedback efficiently and correctly.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generating Related Artifacts:&lt;/strong&gt; AI can help generate or update comments (like Javadoc for changed methods) or even draft basic documentation snippets related to the code changes, making the PR more complete.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;⚠️ AI Assists, It Doesn't Replace Human Review! ⚠️&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is crucial: &lt;strong&gt;AI is a code review &lt;em&gt;assistant&lt;/em&gt;, not a replacement for human reviewers.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Context is King:&lt;/strong&gt; AI often lacks the deep understanding of the project's history, overall architecture, business requirements, and long-term goals that experienced human reviewers bring. Add the proper context for each prompt. You can even guide AI answers with the Personal instructions directly in the Github Pull Request page.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F24d93kyk1yodjq1jyvie.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F24d93kyk1yodjq1jyvie.png" alt="Image description" width="423" height="347"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Design &amp;amp; Logic Still Need Humans:&lt;/strong&gt; AI is generally poor at evaluating the &lt;em&gt;appropriateness&lt;/em&gt; of a design choice or the correctness of complex business logic. That requires human critical thinking.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Knowledge Sharing:&lt;/strong&gt; Code reviews are vital for team learning and knowledge sharing – something AI assistance doesn't replace.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Evaluate AI Output:&lt;/strong&gt; Reviewers need to critically assess any summaries or issues flagged by AI. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Think of AI in code review as handling the first-pass checks, summarizing changes, and assisting with implementation details. This frees up valuable human reviewer time to focus on the deeper aspects of code quality, design, and correctness.&lt;/p&gt;

&lt;h1&gt;
  
  
  Increasing Code Quality and Security
&lt;/h1&gt;

&lt;p&gt;Writing high-quality, secure Java code is crucial, going beyond just making things work. It's vital to understand AI limitations, especially regarding reliability. Let's explore how AI can help refine code and how traditional tools remain essential for verification.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Using AI for Code Refinement and Understanding:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Where AI &lt;em&gt;can&lt;/em&gt; be a valuable assistant is in helping &lt;em&gt;you&lt;/em&gt;, the developer, understand and improve code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Untangling Complexity:&lt;/strong&gt; Use AI chat assistants to explain complex Java code sections.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Refactoring Collaboration:&lt;/strong&gt; Ask the AI for suggestions on refactoring specific methods for better readability, simplification, or to apply certain patterns (&lt;code&gt;"Refactor this using Java Streams"&lt;/code&gt; or &lt;code&gt;"How can I simplify this nested logic?"&lt;/code&gt;). Treat these suggestions as ideas to be critically evaluated and adapted by you.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Learning Best Practices:&lt;/strong&gt; Use AI to ask questions about secure coding practices (&lt;code&gt;"What are common pitfalls with Java serialization?"&lt;/code&gt;) . &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;⚠️ THE GIANT RED FLAG: AI IS NOT RELIABLE FOR ISSUE DETECTION ⚠️&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9y1fj6ey71lony7m4yg2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9y1fj6ey71lony7m4yg2.png" alt="Image description" width="523" height="374"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dl.acm.org/doi/pdf/10.1145/3558489.3559072" rel="noopener noreferrer"&gt;https://dl.acm.org/doi/pdf/10.1145/3558489.3559072&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, regarding finding bugs and security vulnerabilities: &lt;strong&gt;relying on AI for direct issue detection is highly risky due to its fundamental lack of correctness and predictability guarantees.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Why the Risk? AI Makes Mistakes:&lt;/strong&gt; AI models can hallucinate findings, generate numerous false positives, miss critical vulnerabilities, or provide incomplete/incorrect security advice. They operate on patterns, not deterministic analysis. Therefore, &lt;strong&gt;AI is NOT a substitute for proper analysis tools.&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The Solution: Deterministic Static Analysis (SAST)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Because AI cannot be trusted for reliable issue detection, you &lt;strong&gt;must&lt;/strong&gt; use dedicated Static Application Security Testing (SAST) tools. These are the right tools for the job:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tools:&lt;/strong&gt; &lt;code&gt;SonarQube&lt;/code&gt;, &lt;code&gt;Checkstyle&lt;/code&gt;, &lt;code&gt;PMD&lt;/code&gt;, etc.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why They Work:&lt;/strong&gt; SAST tools operate by applying defined, verifiable rulesets and analysis techniques in a deterministic way.
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Best practices:&lt;/strong&gt;   &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use tooling as soon as possible in your SDLC. Incorporate these SAST tools in the IDE to analyze the quality of your code at the same time you are introducing new changes.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7j0nqcmad39jj7wc3umu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7j0nqcmad39jj7wc3umu.png" alt="Image description" width="587" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;SonarQube IDE view with an issue and its explanation&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Connect your CI/CD pipeline with a Quality Gate tool in order to ensure no bad code is going to be merged to your main branch.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhvfup7i13i8gfv4jxz0t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhvfup7i13i8gfv4jxz0t.png" alt="Image description" width="674" height="345"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use Quality Gate messages in your Pull Requests through PR decoration.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6tlhpzwolf8lmsa54n40.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6tlhpzwolf8lmsa54n40.png" alt="Image description" width="350" height="385"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Essential Supporting Pillars: Testing and Reviews using Human skills&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Alongside reliable SAST, robust engineering practices remain critical:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Rigorous Testing (TDD!):&lt;/strong&gt; Test-Driven Development provides concrete proof that your code meets requirements and handles various scenarios correctly.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Human Code Reviews:&lt;/strong&gt; Critical examination by experienced peers is essential to catch logical flaws, architectural issues, and subtle security concerns that automated tools (whether AI-based or traditional) might miss.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pair Programming:&lt;/strong&gt; This practice inherently includes collaborative review and discussion, promoting higher quality code, especially when integrating any new tool or technique like AI assistance.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;In Summary:&lt;/strong&gt; Leverage AI assistants carefully for tasks where they excel – helping you understand, refactor, and learn. But for the critical task of identifying bugs and security vulnerabilities, &lt;strong&gt;trust deterministic SAST tools.&lt;/strong&gt; Combine this with rigorous testing and thorough code reviews to build truly high-quality, secure Java applications.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;So, what's the bottom line here? Is AI going to take over Java development? Not anytime soon. But is it becoming a genuinely useful, practical tool that can make our lives as developers easier and more productive? Absolutely.&lt;/p&gt;

&lt;p&gt;The real takeaway is to think of these AI tools not as replacements, but as &lt;strong&gt;powerful assistants&lt;/strong&gt; or &lt;strong&gt;co-pilots&lt;/strong&gt;. By offloading some of that work to AI, you get more time and energy to focus on the truly challenging and rewarding parts of software development.&lt;/p&gt;

&lt;p&gt;But (and it's a big but!), remember those warnings we sprinkled throughout. AI isn't magic, and it's certainly not infallible. &lt;strong&gt;Critical thinking, thorough review, rigorous testing, deterministic static analysis, and collaborative code reviews are more important than ever.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;And remember : &lt;strong&gt;➡️ 𝑨𝑰 gives you ✅ 𝐓𝐈𝐌𝐄 not ❌𝐂𝐎𝐍𝐅𝐈𝐃𝐄𝐍𝐂𝐄&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>AI Test Generation: A Dev's Guide Without Shooting Yourself in the Foot</title>
      <dc:creator>Jonathan Vila</dc:creator>
      <pubDate>Mon, 28 Apr 2025 10:05:21 +0000</pubDate>
      <link>https://dev.to/jonathanvila/ai-test-generation-a-devs-guide-without-shooting-yourself-in-the-foot-4afb</link>
      <guid>https://dev.to/jonathanvila/ai-test-generation-a-devs-guide-without-shooting-yourself-in-the-foot-4afb</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;So, AI Can Write Tests Now? Cool, But...&lt;/strong&gt;🤔
&lt;/h2&gt;

&lt;p&gt;AI assisted coding tools are everywhere now, helping with autocomplete, suggesting fixes, and sometimes writing surprisingly large blocks of code. A hot topic 🚀 is using generative AI to generate tests automatically – unit, integration, e2e, etc. The idea's definitely appealing. Who wouldn't want an AI to help crank out tests, bump up those coverage numbers, and maybe save us from some of the testing grind? It sounds like a fast track to better feedback and tackling that mountain of untested code.&lt;/p&gt;

&lt;p&gt;But, hang on a sec. Like any tool, especially one this complex, artificial intelligence is not a silver bullet. Just grabbing AI driven tests and calling it a day is risky. You might &lt;em&gt;think&lt;/em&gt; your code's solid because the test count is high, but the tests themselves might be junk. These AI language models learn from tons of code online and in repos – and let's face it, a lot of that code isn't exactly high quality nor correct code.&lt;/p&gt;

&lt;p&gt;This article is for devs 👉 figuring out how to actually &lt;em&gt;use&lt;/em&gt; these AI tools without creating a mess and produce high quality software. We'll touch on the good stuff but focus on the traps 🪤: the tests might be flat-out &lt;em&gt;wrong&lt;/em&gt;, or they might just "prove" that your buggy code works exactly like the buggy mess it is, instead of checking if it meets user needs. We'll also bring in static analysis with &lt;a href="https://www.sonarsource.com/products/sonarqube/downloads/" rel="noopener noreferrer"&gt;SonarQube&lt;/a&gt;, using its big list of Java test rules [&lt;a href="https://rules.sonarsource.com/java/tag/tests/" rel="noopener noreferrer"&gt;https://rules.sonarsource.com/java/tag/tests/&lt;/a&gt;] to show concrete examples of what can go wrong and what to watch for. The point isn't to ditch AI, but to use it intelligently, so you don't trade real quality for fake coverage.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;How AI Learns to Code (And Why That's a Problem for Tests)&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;To understand why AI tests can be uncertain, it helps to know how these code-generating AIs learn. Most are Large Language Models (LLMs) trained on absolutely massive datasets. These datasets contain billions of lines of code from GitHub, Stack Overflow, open-source projects, maybe your own company's code. The AI digests all this and learns patterns: common code structures, how people usually use certain APIs, popular libraries, coding styles. It gets really good at predicting the next bit of code in a sequence, leading it to write stuff that often &lt;em&gt;looks&lt;/em&gt; right.&lt;/p&gt;

&lt;p&gt;But that's the catch. The training data is just… code. All kinds of code. Including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Plain old &lt;strong&gt;bugs&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;Nasty &lt;strong&gt;security holes&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;Weird &lt;strong&gt;anti-patterns&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Outdated code&lt;/strong&gt; using old libraries, patterns or approaches.
&lt;/li&gt;
&lt;li&gt;Code that &lt;strong&gt;ignores&lt;/strong&gt; &lt;strong&gt;style guides&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;Code with &lt;strong&gt;zero useful&lt;/strong&gt; &lt;strong&gt;comments&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The AI doesn't &lt;em&gt;understand&lt;/em&gt; good code from bad code. It just mimics the patterns it saw. If buggy code patterns were common in its training data, it'll happily reproduce them. It's the classic "garbage in, garbage out" deal.&lt;/p&gt;

&lt;p&gt;So when you ask this AI to write tests, problems pop up:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The Tests Have Bugs:&lt;/strong&gt; The generated test code itself might be flawed, misuse resources, have race conditions – just like buggy tests humans write.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Tests Verify Bugs:&lt;/strong&gt; This is the really sneaky one. The AI looks at your &lt;em&gt;current&lt;/em&gt; code, sees how it works (even the buggy parts), and writes a test to confirm &lt;em&gt;that&lt;/em&gt; behavior. It doesn't know what the code &lt;em&gt;should&lt;/em&gt; do from requirements; it just tests what the code &lt;em&gt;does&lt;/em&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Think of learning English only by reading internet comments. You'd get good at slang and common mistakes, but you wouldn't be able to write clean technical docs. An AI testing tool trained on a huge, messy pile of code is similar – good at mimicry, not guaranteed to be correct or follow best practices in software development.&lt;/p&gt;

&lt;p&gt;AI powered tests can be inaccurate and may only validate existing code, not the intended behavior. Let’s see some of the main problems you can encounter by generating the tests with AI.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Problem #1: AI Tests Might Just Be Wrong&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Yeah, AI can generate code that uses &lt;a class="mentioned-user" href="https://dev.to/test"&gt;@test&lt;/a&gt; and compiles. It will save a lot of manual effort on time consuming test case generation. But is it &lt;em&gt;correct&lt;/em&gt;? Often, it might not be. When you're reviewing AI-generated tests, watch out for:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Looks Right, Works Wrong:&lt;/strong&gt; AI usually nails the syntax. But code that compiles doesn't mean the test logic is sound or it tests anything useful.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Incomplete Tests&lt;/strong&gt;: Super common. The AI sets things up, calls the method, and... forgets the important part.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No Asserts&lt;/strong&gt;: A test without asserts is pointless. AI often forgets to actually check the result.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Weak Asserts&lt;/strong&gt;: An assertNotNull(result) is better than nothing, but doesn't prove the result is correct. Also assertTrue(true) is useless.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Happy Path Only&lt;/strong&gt;: AI often tests the simple case. What about nulls, errors, edge conditions? AI might miss these unless you specifically tell it to check them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Weird or Irrelevant Tests:&lt;/strong&gt; AI can "hallucinate" and generate tests for things that don't make sense for your app, or test trivial details instead of important behavior.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sneaky Logic Bugs&lt;/strong&gt;: These look okay at first glance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bad Setup&lt;/strong&gt;: Mocking things wrong, starting the test in an invalid state.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bad Asserts&lt;/strong&gt;: Using the wrong comparison, expecting the wrong result, off-by-one errors.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Flaky Tests&lt;/strong&gt;: Tests involving threads or async code are hard. AI might generate tests that sometimes pass, sometimes fail due to timing issues.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Missing the Big Picture:&lt;/strong&gt; Good tests often need domain knowledge. AI usually doesn't have deep context about &lt;em&gt;your specific app&lt;/em&gt; unless you give it lots of info. It might test a method fine in isolation but miss its system-wide impact.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dynamic Stuff &amp;amp; Async:&lt;/strong&gt; Testing tricky things like UIs, message queues, or async operations? AI often struggles to generate reliable tests for these without a lot of help or manual fixes.&lt;/p&gt;

&lt;p&gt;Here’s a quick example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// AI might generate something like this:&lt;/span&gt;
&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;testProcessItem&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;ItemProcessor&lt;/span&gt; &lt;span class="n"&gt;processor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ItemProcessor&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="cm"&gt;/* dependencies */&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="nc"&gt;Item&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getTestItem&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Maybe AI doesn't know mocking is needed here&lt;/span&gt;
    &lt;span class="c1"&gt;// MockItemRepository mockRepo = mock(ItemRepository.class);&lt;/span&gt;
    &lt;span class="c1"&gt;// when(mockRepo.save(any(Item.class))).thenReturn(item);&lt;/span&gt;
    &lt;span class="c1"&gt;// processor.setRepository(mockRepo);&lt;/span&gt;

    &lt;span class="n"&gt;processor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;process&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Problem: No assertion! Does 'process' do anything? Is item saved?&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looks like a test, runs, but proves nothing. And it will be GREEN !! . &lt;em&gt;You gotta check.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Problem #2: Testing the Code You Have, Not the Code You Need (Verification vs. Validation Trap)&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This is the deeper problem. Even if an AI test is technically correct &lt;em&gt;for the current code&lt;/em&gt;, it might be testing the wrong thing if the code itself is buggy. It's about &lt;strong&gt;Verification vs. Validation&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Verification:&lt;/strong&gt; "Are we building the product right?" Does the code do what the current implementation says it does? &lt;strong&gt;AI is okay at this&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validation:&lt;/strong&gt; "Are we building the right product?" Does the code actually meet the user's &lt;em&gt;real&lt;/em&gt; needs? Does it solve the problem correctly? &lt;strong&gt;AI struggles here.&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your calculateTax method has a bug and returns negative tax for some inputs, an AI looking at the code might generate a test asserting that calculateTax(badInput) &lt;em&gt;should&lt;/em&gt; return that negative number. It &lt;em&gt;verifies&lt;/em&gt; the bug.&lt;/p&gt;

&lt;p&gt;Here is a simple example of this buggy method and its AI generated test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="nf"&gt;calculateTax&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;income&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;grossTax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;income&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;multiply&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;TAX_RATE&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

   &lt;span class="c1"&gt;// *** THE BUG IS HERE ***&lt;/span&gt;
   &lt;span class="c1"&gt;// Simple subtraction without checking if the result is negative.&lt;/span&gt;
   &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;netTax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;grossTax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;subtract&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;STANDARD_DEDUCTION&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

   &lt;span class="c1"&gt;// Rounding for standard currency format (e.g., 2 decimal places)&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;netTax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setScale&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;RoundingMode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;HALF_UP&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="nd"&gt;@DisplayName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Test calculateTax: Should return expected negative tax for low income due to BUG"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;calculateTax_whenIncomeIsLow_shouldReturnNegativeTax_dueToBug&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;lowIncome&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"10000.00"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// Expected calculation: (10000 * 0.15) - 5000 = 1500 - 5000 = -3500&lt;/span&gt;
  &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;expectedNegativeTax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"-3500.00"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;actualTax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;calculator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;calculateTax&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lowIncome&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// We are specifically asserting that the bug produces this negative result.&lt;/span&gt;
  &lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expectedNegativeTax&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;actualTax&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                &lt;span class="s"&gt;"BUG CONFIRMATION: calculateTax should return -3500.00 for 10000.00 income"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Code is the Source:&lt;/strong&gt; The AI learns from the code you give it.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No Requirements Mind-Reading:&lt;/strong&gt; Without clear, up-to-date requirements, AI doesn't know what the code &lt;em&gt;should&lt;/em&gt; do.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It Matches Patterns:&lt;/strong&gt; It sees input -&amp;gt; process -&amp;gt; output in your code and writes a test for &lt;em&gt;that specific pattern&lt;/em&gt;, bug or not.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let’s see which are the challenges with the validation trap and recommendations to avoid them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The False Confidence Problem:&lt;/strong&gt; This is bad. A test passing &lt;em&gt;because&lt;/em&gt; of a bug makes everything look green, but the bug is still there, now with a test "protecting" it. Fix the bug later, and the AI's test fails, confusing everyone.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ignoring Requirements Changes:&lt;/strong&gt; Requirements evolve. Code written last month might be wrong now. AI testing the &lt;em&gt;code&lt;/em&gt; won't know that. It just keeps confirming the potentially outdated behavior.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Analogy:&lt;/strong&gt; Like spell-checking a document but not fact-checking it. Verification passes, validation fails.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can AI Test Requirements Directly?&lt;/strong&gt; Some tools try. You feed them requirements (like Gherkin specs), and they generate tests \cite{aws, visuresolutions, thoughtworks}. Better, but still needs perfect, up-to-date requirements and the AI can still misinterpret them. Many simple AI tools just look at the code.&lt;/p&gt;

&lt;p&gt;Consider this buggy code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Buggy Implementation&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;formatUsername&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;trim&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"guest"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Should maybe throw exception?&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// Bug: Doesn't handle names with spaces well&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toLowerCase&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// AI-Generated Test (Based on Buggy Code)&lt;/span&gt;
&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;whenNameHasSpace_shouldReturnLowerCase&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// Validates bug!&lt;/span&gt;
    &lt;span class="nc"&gt;UserFormatter&lt;/span&gt; &lt;span class="n"&gt;formatter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;UserFormatter&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;formatter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;formatUsername&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Test User"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// AI sees the code returns "test user", so it asserts that.&lt;/span&gt;
    &lt;span class="c1"&gt;// Requirement might be to remove spaces or throw error.&lt;/span&gt;
    &lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"test user"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This test passes but locks in the bad behavior of allowing spaces. You, the dev, need to check if the test matches the &lt;em&gt;requirement&lt;/em&gt;, not just the buggy code.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;So? What to Do? Don't Use AI for Generating Tests? Nah, Rely on Your AI Test Quality Guardian&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Given that AI tests can be wonky, using static analysis tools is pretty much essential. These tools automatically scan your code (including tests) against a huge rulebook, finding potential bugs, security issues, and just plain confusing code. When AI is potentially adding lots of code fast, you need this automated check.&lt;/p&gt;

&lt;p&gt;Some of these tools even promote AI Code assurance, to keep AI-generated code in check, sometimes with even stricter rules. Makes sense – treat AI code with the same (or more) skepticism as human code.&lt;/p&gt;

&lt;p&gt;One of these tools is SonarQube, which has 47 specific rules just for Java tests [&lt;a href="https://rules.sonarsource.com/java/tag/tests/" rel="noopener noreferrer"&gt;https://rules.sonarsource.com/java/tag/tests/&lt;/a&gt;]. Let's break down the kinds of issues it catches, with quick examples showing how AI might mess up.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Assertions - Did You Actually Check Anything?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Purpose:&lt;/strong&gt; Ensure tests make meaningful checks. It can be easy to forget assertions and the test will pass making it difficult to spot.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Example (&lt;a href="https://rules.sonarsource.com/java/RSPEC-2699/" rel="noopener noreferrer"&gt;Rule S2699&lt;/a&gt;):&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Noncompliant code&lt;/span&gt;
&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;testAddItem&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Cart&lt;/span&gt; &lt;span class="n"&gt;cart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Cart&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="nc"&gt;Item&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Item&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Thing"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;cart&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// Forgot to assert!&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Compliant code&lt;/span&gt;
&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;testAddItem&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Cart&lt;/span&gt; &lt;span class="n"&gt;cart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Cart&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="nc"&gt;Item&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Item&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Thing"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;cart&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cart&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getItemCount&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// Added assertion&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AI Trap:&lt;/strong&gt; AI might just call the method and forget the assert.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. Test Structure, Setup, Teardown - Getting the Basics Right&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Purpose:&lt;/strong&gt; Enforce standard test structure conventions needed by frameworks like JUnit.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Example (&lt;a href="https://rules.sonarsource.com/java/RSPEC-5786/" rel="noopener noreferrer"&gt;Rule S5786&lt;/a&gt;):&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Noncompliant code (JUnit 5)&lt;/span&gt;
&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;myPrivateTest&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// Test methods shouldn't be private&lt;/span&gt;
    &lt;span class="n"&gt;assertTrue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Compliant code (JUnit 5)&lt;/span&gt;
&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;myVisibleTest&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// Default visibility is fine, or public&lt;/span&gt;
    &lt;span class="n"&gt;assertTrue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AI Trap:&lt;/strong&gt; Generating methods with wrong visibility (private, static) or return types.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3. Naming Conventions - Can Anyone Understand This?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Purpose:&lt;/strong&gt; Make tests readable and understandable from their names. The BDD convention is widely adopted, but there are &lt;a href="https://dzone.com/articles/7-popular-unit-test-naming" rel="noopener noreferrer"&gt;others&lt;/a&gt;.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Example (&lt;a href="https://rules.sonarsource.com/java/RSPEC-3577/" rel="noopener noreferrer"&gt;Rule S3577&lt;/a&gt;):&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Noncompliant code&lt;/span&gt;
&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;test1&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ... complex setup and assert ...&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Compliant code&lt;/span&gt;
&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;shouldThrowIllegalArgumentException_WhenInputIsNull&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ... clear test logic for null input ...&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AI Trap:&lt;/strong&gt; Using generic names like testMethod1 or test_feature_abc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;4. Using Test Frameworks Correctly - JUnit/TestNG Gotchas&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Purpose:&lt;/strong&gt; Ensure proper use of framework features and APIs. Test frameworks provide specific ways of handling different use cases. In this particular case, exceptions.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Example (&lt;a href="https://rules.sonarsource.com/java/RSPEC-5776/" rel="noopener noreferrer"&gt;Rule S5776&lt;/a&gt;):&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Noncompliant code (JUnit 5) - Old way to check exceptions&lt;/span&gt;
&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;testDivisionByZero_OldWay&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Calculator&lt;/span&gt; &lt;span class="n"&gt;calc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Calculator&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;calc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;divide&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;fail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Should have thrown ArithmeticException"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ArithmeticException&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Expected exception caught, test passes implicitly&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Compliant code (JUnit 5) - Using assertThrows&lt;/span&gt;
&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;testDivisionByZero_NewWay&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Calculator&lt;/span&gt; &lt;span class="n"&gt;calc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Calculator&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;assertThrows&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ArithmeticException&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;calc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;divide&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;});&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AI Trap:&lt;/strong&gt; Using outdated patterns (like the try/catch/fail for exceptions) or mixing framework versions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;5. Performance and Resource Usage - Don't Slow Down the Build&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Purpose:&lt;/strong&gt; Avoid bad practices like printing to console or leaking resources in tests. It is not easily configurable, can mess with build tools and it’s a sync process that will slow down the build.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Example (&lt;a href="https://rules.sonarsource.com/java/RSPEC-106/" rel="noopener noreferrer"&gt;Rule S106&lt;/a&gt;):&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Noncompliant code&lt;/span&gt;
&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;testSomethingComplex&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ... logic ...&lt;/span&gt;
    &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Debug: Intermediate value = "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Avoid this&lt;/span&gt;
    &lt;span class="c1"&gt;// ... asserts ...&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Compliant code&lt;/span&gt;
&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;testSomethingComplex&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ... logic ...&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;debug&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Debug: Intermediate value = "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// ... asserts ...&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AI Trap:&lt;/strong&gt; Leaving System.out.println calls used during generation/debugging.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;6. Mocking Frameworks - Using Mocks Correctly&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Purpose:&lt;/strong&gt; Guide correct usage of mocking frameworks like Mockito, specially on the setup phase. If not done correctly can lead to unexpected issues.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Example (&lt;a href="https://rules.sonarsource.com/java/RSPEC-5979" rel="noopener noreferrer"&gt;Rule S5979&lt;/a&gt;):&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Noncompliant code (Potential Issue: Forgetting to mock)@Testvoid testServiceUsingRepository() {&lt;/span&gt;
    &lt;span class="c1"&gt;// Missing mock setup for repository dependency&lt;/span&gt;
    &lt;span class="nc"&gt;MyRepository&lt;/span&gt; &lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// = mock(MyRepository.class);&lt;/span&gt;
    &lt;span class="nc"&gt;MyService&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MyService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Might throw NPE if repo is null&lt;/span&gt;
    &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;doWork&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="c1"&gt;// Assertions might fail unpredictably&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Compliant code (Basic Mocking)&lt;/span&gt;
&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;testServiceUsingRepository&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;MyRepository&lt;/span&gt; &lt;span class="n"&gt;repo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mock&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MyRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Mock dependency&lt;/span&gt;
    &lt;span class="n"&gt;when&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getData&lt;/span&gt;&lt;span class="o"&gt;()).&lt;/span&gt;&lt;span class="na"&gt;thenReturn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"mock data"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Stub method call&lt;/span&gt;
    &lt;span class="nc"&gt;MyService&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MyService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;doWork&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;verify&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;getData&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Verify interaction&lt;/span&gt;
    &lt;span class="c1"&gt;// Add assertions based on service logic&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AI Trap:&lt;/strong&gt; Generating incomplete mock setups or incorrect verification logic.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;7. Exception Handling - Be Specific&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Purpose:&lt;/strong&gt; Ensure tests checking for exceptions look for the &lt;em&gt;specific&lt;/em&gt; expected exception. Generic exceptions can swallow several different use cases, and the code should catch those exceptions types that can handle.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Example (&lt;a href="https://rules.sonarsource.com/java/RSPEC-112" rel="noopener noreferrer"&gt;Rule S112&lt;/a&gt;):&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Noncompliant code&lt;/span&gt;
&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;testInvalidInput&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Processor&lt;/span&gt; &lt;span class="n"&gt;processor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Processor&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="c1"&gt;// This is too broad, might catch unexpected runtime exceptions&lt;/span&gt;
    &lt;span class="n"&gt;assertThrows&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Exception&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;processor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;process&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;});&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Compliant code&lt;/span&gt;
&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;testInvalidInput&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Processor&lt;/span&gt; &lt;span class="n"&gt;processor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Processor&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="c1"&gt;// Be specific about the expected exception&lt;/span&gt;
    &lt;span class="n"&gt;assertThrows&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;IllegalArgumentException&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;processor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;process&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;});&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AI Trap:&lt;/strong&gt; Using generic Exception when a more specific one is appropriate.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Seeing these examples shows how easy it is for generated code (and human code!) to violate basic testing hygiene. SonarQube acts as your automated checklist for this stuff.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;How to Use AI Test Tools Without Getting Burned&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;So, how do you actually use these tools without causing chaos?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Human Review is Mandatory (Really!):&lt;/strong&gt; Never skip this. Check if the test makes sense, if the asserts are good, if it tests the &lt;em&gt;requirement&lt;/em&gt;, if it covers edge cases, and if your static analysis guardian is happy.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use Static Analysis Everywhere:&lt;/strong&gt; Put a linter in your IDE. Put it in your CI pipeline. Fail the build if quality drops. Make it non-negotiable.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Let AI Do the Easy Stuff:&lt;/strong&gt; Don't expect miracles. Use AI for:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Boilerplate:&lt;/strong&gt; Test methods, basic setup/teardown.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simple Mocking:&lt;/strong&gt; Basic when/thenReturn.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test Variations:&lt;/strong&gt; Generating different inputs for a test &lt;em&gt;you&lt;/em&gt; already wrote and trust.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Give Better Instructions:&lt;/strong&gt; Garbage prompts = garbage tests.

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Add Context:&lt;/strong&gt; Give it docs, requirements snippets, good examples.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Be Specific:&lt;/strong&gt; Tell it &lt;em&gt;exactly&lt;/em&gt; what to test, what to mock, what to assert.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Iterate:&lt;/strong&gt; Treat the AI output as a first draft. Review, fix, improve.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Learn the Tools:&lt;/strong&gt; Figure out how &lt;em&gt;your&lt;/em&gt; specific AI tool works best. Practice prompting. Learn to spot its common mistakes quickly.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Start Small:&lt;/strong&gt; Try it on a safe project first. See if it &lt;em&gt;really&lt;/em&gt; saves time after you account for fixing its output.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Wrapping Up&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;AI test generation? It's here and it can write test code fast, which is cool. But don't just trust it blindly. AI often gets things wrong, misses assertions, or writes tests that just confirm your bugs are still there.&lt;/p&gt;

&lt;p&gt;Think of AI as a helper, not &lt;strong&gt;&lt;em&gt;the&lt;/em&gt;&lt;/strong&gt; expert 🧙. Let it write first drafts or boring bits. But &lt;em&gt;you&lt;/em&gt; need to review everything. Does it test the actual requirement? Is the logic sound? Use static analysis to automatically check for common mistakes in your pipeline. Keep your brain engaged, and you can probably get some real speed benefits from AI without sacrificing quality.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>testing</category>
      <category>ai</category>
      <category>java</category>
    </item>
    <item>
      <title>TDD &amp; Human created tests are dead: Long live AIDD</title>
      <dc:creator>Jonathan Vila</dc:creator>
      <pubDate>Wed, 26 Feb 2025 10:40:27 +0000</pubDate>
      <link>https://dev.to/jonathanvila/tdd-human-created-tests-are-dead-long-live-aidd-2jhl</link>
      <guid>https://dev.to/jonathanvila/tdd-human-created-tests-are-dead-long-live-aidd-2jhl</guid>
      <description>&lt;p&gt;Software testing has traditionally been a human-centric task. Quality Assurance (QA) engineers meticulously craft test cases, execute them, and analyze the results. Developers, in the classic approach, generate the tests to check their code, or in a more advanced and mature approach, they start by creating the tests and evolve the code from there (TDD).&lt;/p&gt;

&lt;p&gt;This process, while effective, is time-consuming and prone to human error. However, the advent of artificial intelligence (AI) is poised to revolutionize this landscape.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Rise of AI in Software Development
&lt;/h2&gt;

&lt;p&gt;AI is already making significant inroads into software development. As highlighted in the article "&lt;a href="https://dev.to/jonathanvila/code-reviews-with-ai-a-developer-guide-3fam"&gt;Code Reviews with AI: a Developer Guide&lt;/a&gt;" AI-powered tools assist with code generation, review, and optimization. This integration of AI is not limited to development; it's also transforming the testing phase.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI-Generated Test Cases: A New Paradigm
&lt;/h2&gt;

&lt;p&gt;A thought-provoking idea is emerging: AI will generate test cases directly from Jira tickets and specifications documentation considering the current code. This concept challenges the traditional notion that test creation is a solely human task or that AI can assist in test generation by just looking at the code to test. &lt;/p&gt;

&lt;p&gt;AI, with its ability to analyze requirements and specifications, can potentially generate comprehensive and relevant test cases, reducing the manual effort involved.&lt;/p&gt;

&lt;p&gt;However, there's a potential for low-quality tests that merely test the code generated (sometimes by AI) and do not consider the human definition of the task and use cases to test.&lt;/p&gt;

&lt;h2&gt;
  
  
  Continuous Testing with AI
&lt;/h2&gt;

&lt;p&gt;Furthermore, AI can enable continuous testing throughout the development process. As code is written and modified, AI can automatically generate and execute tests, providing real-time feedback on code accuracy. This "shift-left" approach to testing can identify defects early, reducing the cost and effort of fixing them later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Challenging the Status Quo
&lt;/h2&gt;

&lt;p&gt;This AI-driven testing approach challenges established practices like Test-Driven Development (&lt;strong&gt;TDD&lt;/strong&gt;), where tests are written before the code. &lt;strong&gt;TDD&lt;/strong&gt; ensures that the application code is constantly tested, and only the code needed is created.&lt;/p&gt;

&lt;p&gt;Code generated with &lt;strong&gt;AI&lt;/strong&gt; can also be guided by requirements and specifications, with application code focused on meeting those requirements and tests generated automatically to validate the code against those specifications.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GenAI&lt;/strong&gt; tools can utilize internal company data as contextual input. Agents and supporting tooling are employed to ingest, parse, and understand a variety of data sources, including &lt;strong&gt;Jira&lt;/strong&gt; tickets, &lt;strong&gt;Google Docs&lt;/strong&gt;, and &lt;strong&gt;Slack&lt;/strong&gt; conversations, among others. This enables the &lt;strong&gt;AI&lt;/strong&gt; to construct a comprehensive operational context.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/modelcontextprotocol" rel="noopener noreferrer"&gt;AI MCP provides a standardized protocol&lt;/a&gt; that facilitates agent-to-connector communication. This allows agents to query and retrieve information from &lt;a href="https://github.com/modelcontextprotocol/servers" rel="noopener noreferrer"&gt;diverse data sources&lt;/a&gt;, effectively building contextual awareness. Additionally, the protocol supports data transformation, ensuring that retrieved information is formatted for optimal consumption by the GenAI system.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4jqr7ltqqjldshetcdap.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4jqr7ltqqjldshetcdap.png" alt="Image description" width="800" height="422"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;List of MCP Servers and Cursor IDE using MCP server&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefits of AI-Driven Testing
&lt;/h2&gt;

&lt;p&gt;The potential benefits of AI-driven testing are substantial:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Increased Efficiency&lt;/strong&gt;: AI can generate tests faster than humans, accelerating the testing process.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Improved Test Coverage&lt;/strong&gt;: AI can analyze code and requirements to identify potential test scenarios that humans might miss, leading to better test coverage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reduced Human Error&lt;/strong&gt;: AI can eliminate errors that humans might introduce during test creation and execution.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Faster Feedback&lt;/strong&gt;: AI-powered continuous testing provides real-time feedback, enabling developers to address issues quickly.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  But, Is it really as good as it seems?
&lt;/h2&gt;

&lt;p&gt;While &lt;strong&gt;AI-driven development&lt;/strong&gt; holds immense promise, it also presents challenges. Ensuring the accuracy and reliability of AI-generated test cases is crucial. Additionally, the role of QA engineers will need to evolve, focusing on overseeing AI-driven testing processes and interpreting results.&lt;/p&gt;

&lt;p&gt;AI is undoubtedly beneficial and is getting better and better. Still, to have the perfect solution, human intervention is required to sign off that the produced artifact meets the company and quality standards. This human intervention can be helped by &lt;strong&gt;tools that will analyze the code&lt;/strong&gt; produced and check for code quality by detecting any maintainability issues, security hotspots, and vulnerabilities. It’s crucial to have a good analyzer tool in our Swiss knife.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;AI is set to reshape software testing, much like it's transforming other aspects of software development. The idea of AI-generated test cases and continuous testing represents a significant shift in how we approach quality assurance. &lt;br&gt;
Embracing this AI-driven future with the help of static analysis tools will be key to delivering high-quality software efficiently and effectively.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>tdd</category>
      <category>test</category>
      <category>programming</category>
    </item>
    <item>
      <title>Code Reviews with AI: a Developer Guide</title>
      <dc:creator>Jonathan Vila</dc:creator>
      <pubDate>Tue, 18 Feb 2025 18:08:17 +0000</pubDate>
      <link>https://dev.to/jonathanvila/code-reviews-with-ai-a-developer-guide-3fam</link>
      <guid>https://dev.to/jonathanvila/code-reviews-with-ai-a-developer-guide-3fam</guid>
      <description>&lt;p&gt;Code reviews are a cornerstone of software development. They're where we share knowledge, catch bugs early, and ensure our code meets the highest standards. &lt;/p&gt;

&lt;p&gt;But let's be honest... &lt;/p&gt;

&lt;p&gt;Traditional code reviews can be time-consuming and tedious and sometimes even miss subtle yet critical issues. Enter the age of AI-powered code review, a game-changer that addresses these challenges and elevates code quality to new heights. &lt;/p&gt;

&lt;p&gt;This article dives into the common pitfalls of code reviews and explores how AI tools can revolutionize each phase of the development lifecycle.&lt;br&gt;&lt;br&gt;
I will discuss the use and impact of AI on the different phases of the SDLC from the 2 main perspectives of the developer and the reviewer. I will also talk specifically about the use of AI in the Code Review and how to implement it productively. I will provide examples of tools used in the different phases: &lt;a href="https://github.com/features/copilot" rel="noopener noreferrer"&gt;Github Copilot&lt;/a&gt;, &lt;a href="https://www.sonarsource.com" rel="noopener noreferrer"&gt;SonarQube&lt;/a&gt;, &lt;a href="https://www.qodo.ai/products/qodo-gen/" rel="noopener noreferrer"&gt;Qodo&lt;/a&gt;, and &lt;a href="https://www.jetbrains.com/es-es/idea/" rel="noopener noreferrer"&gt;IntelliJ&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Code generated by AI code assistants
&lt;/h2&gt;

&lt;p&gt;AI-powered generative code assistants take the power of AI even further by automatically generating code based on your inputs. This can dramatically reduce the time and effort required to write code, especially for repetitive or boilerplate tasks.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe9vrkg0g1bvt44ta8uqo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe9vrkg0g1bvt44ta8uqo.png" alt="Image description" width="302" height="133"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Generative code assistants can also help you explore different design options and identify potential problems before you start coding. By leveraging these tools, you can focus on the creative and strategic aspects of software development, while the AI handles the tedious and mechanical tasks. &lt;/p&gt;

&lt;p&gt;AI adoption &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9eeleowba6m6fzxh00o1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9eeleowba6m6fzxh00o1.png" alt="Image description" width="474" height="264"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There’s a long list of AI code assistants providing different features, with different ranking rates considering 5 different categorizations: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2yrk2ycgk1jpl68874ae.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2yrk2ycgk1jpl68874ae.png" alt="Image description" width="774" height="308"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://research.aimultiple.com/ai-coding-benchmark/" rel="noopener noreferrer"&gt;https://research.aimultiple.com/ai-coding-benchmark/&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;While these tools are powerful and feature-rich, they rely on models hosted somewhere and there is a price involved in some of the features. &lt;/p&gt;

&lt;p&gt;The local free open-source approach ....&lt;/p&gt;

&lt;p&gt;Other completely open-source options are also available. This option involves hosting the model to generate code locally or in your network. There are tons of free and open-source models that you can use, and you can only serve those models by installing the free tool Ollama on a machine in your network or locally. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frdd5jkpaeqq6av617m0q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frdd5jkpaeqq6av617m0q.png" alt="Image description" width="645" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feg0hnl2g99ry4nwfrvwv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feg0hnl2g99ry4nwfrvwv.png" alt="Image description" width="777" height="473"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I’ve tried with the IntelliJ plugin “&lt;a href="https://plugins.jetbrains.com/plugin/22707-continue/reviews" rel="noopener noreferrer"&gt;Continue&lt;/a&gt;”, &lt;a href="https://ollama.com/" rel="noopener noreferrer"&gt;Ollama&lt;/a&gt;, and the models “codellama” and ”deepseek-coder” and the experience was not bad at all. With this solution also you are sure your code, and &lt;a href="https://github.com/ollama/ollama/blob/main/docs/faq.md#does-ollama-send-my-prompts-and-answers-back-to-ollamacom" rel="noopener noreferrer"&gt;your prompts are not going anywhere out of your domains&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;But, every magic comes with a price. &lt;/p&gt;

&lt;p&gt;While generative AI holds immense promise, it is not without its pitfalls. One major concern is the potential for introducing bugs and vulnerabilities into code. AI models are trained on vast amounts of data, and if this data contains errors or malicious code, the generated code may inherit these flaws.  &lt;/p&gt;

&lt;p&gt;AI-generated code correctness &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8q4kodirhxscuyxj7rrd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8q4kodirhxscuyxj7rrd.png" alt="Image description" width="533" height="283"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Additionally, generative AI systems may not fully understand the context or intent of the code they generate, leading to nonsensical or even harmful output. Furthermore, there is a risk that generative AI could not use the full code base context in order to generate the most aligned code with our current content. It is crucial for developers to carefully review and test code generated by AI and to employ robust security measures to mitigate these risks. &lt;/p&gt;

&lt;p&gt;With this panorama, it’s clear that using AI to generate code will impact positively the speed, but also negatively in the full SDLC and more importantly in the code review process. &lt;/p&gt;

&lt;p&gt;Let’s focus on the traditional code review process and its pain points. &lt;/p&gt;
&lt;h2&gt;
  
  
  The Traditional Code Review Struggle: Familiar Pain Points
&lt;/h2&gt;

&lt;p&gt;We've all been there. Traditional code reviews, while valuable, often suffer from: &lt;br&gt;
●  &lt;strong&gt;Time Consumption&lt;/strong&gt;: Manually reviewing every line of code is a significant time investment, especially for large projects. &lt;br&gt;
●  &lt;strong&gt;Subjectivity&lt;/strong&gt;: "Good code" can be subjective, leading to inconsistencies in feedback and potential disagreements. &lt;br&gt;
●  &lt;strong&gt;Missed Issues&lt;/strong&gt;: Even the most experienced human reviewers can miss subtle bugs, security vulnerabilities, or performance bottlenecks. We’ve seen from above how code assistants can &lt;br&gt;
impact here. &lt;br&gt;
●  &lt;strong&gt;Focus on Style&lt;/strong&gt;: Too much emphasis on minor stylistic issues can distract from more critical problems. &lt;br&gt;
●  &lt;strong&gt;Lack of Context&lt;/strong&gt;: Reviewers may lack the full context of the code changes, making it harder to provide effective feedback. &lt;br&gt;
●  &lt;strong&gt;High Cognitive Load&lt;/strong&gt;: Reviewing large pull requests with hundreds of lines of code can overwhelm even the most experienced developers. &lt;br&gt;
●  &lt;strong&gt;Delayed Feedback&lt;/strong&gt;: Waiting for a code review can slow the development pipeline, impacting delivery timelines. &lt;br&gt;
●  &lt;strong&gt;Team friction&lt;/strong&gt;: Code reviews can lead to team friction when simple issues are overlooked due to a lack of context, when subjective feedback occurs, or when poor feature testing occurs, potentially escalating into disagreements. &lt;/p&gt;
&lt;h2&gt;
  
  
  AI to the Rescue: Enhancing Code Reviews
&lt;/h2&gt;

&lt;p&gt;AI-powered tools are transforming code reviews by automating tedious tasks, providing objective feedback, and uncovering hidden issues. Let's explore how these tools can assist throughout the development lifecycle: &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Development Phase (IDE Integration)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We’ve seen that several code assistant plugins and IDEs can help us generate code. Several benchmarks (&lt;a href="https://aider.chat/docs/leaderboards/" rel="noopener noreferrer"&gt;huggingface&lt;/a&gt;, &lt;a href="https://www.prollm.ai/leaderboard/stack-eval?type=conceptual,debugging,implementation,optimization&amp;amp;level=advanced,beginner,intermediate&amp;amp;tag=assembly,bash/shell,c,c%23,c%2B%2B,clojure,dart,delphi,elixir,go,haskell,java,javascript,kotlin,objective-c,perl,php,python,r,ruby,rust,scala,sql,swift,typescript,vba" rel="noopener noreferrer"&gt;stackeval&lt;/a&gt;, &lt;a href="https://huggingface.co/spaces/mike-ravkine/can-ai-code-results" rel="noopener noreferrer"&gt;Mike Ravkine’s&lt;/a&gt;) could help us choose the model to use in those assistants. &lt;/p&gt;

&lt;p&gt;So, we have the proper tools for auto-completion and code generation, but what about verifying that the code generated does not introduce issues, vulnerabilities, or solutions that are not well suited for the language version of the code base context? &lt;/p&gt;

&lt;p&gt;For this task, there are static analyzers in the form of IDE linters, like SonarQube for IDE, that will provide instant feedback as you write code, or CI/CD code analyzers, like SonarQube Server/Cloud, which will do a full analysis of your code and prevent or allow it to be merged.&lt;/p&gt;

&lt;p&gt;Imagine catching potential bugs and best practices before they even make it to a code review. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F74qlnrbowbyj92k3iwsu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F74qlnrbowbyj92k3iwsu.png" alt="Image description" width="777" height="219"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuuqq7d2rylzfx49t6xe8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuuqq7d2rylzfx49t6xe8.png" alt="Image description" width="782" height="191"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These linters use static analysis, and different functions, to detect code smells, bugs, and security vulnerabilities directly in your IDE, empowering you to write cleaner and safer code from &lt;br&gt;
the start. &lt;/p&gt;

&lt;p&gt;However, this includes not only bugs and vulnerabilities but &lt;strong&gt;also best practices for using certain frameworks or language versions&lt;/strong&gt;. AI code assistants sometimes are not well aware of the language version that you are using (e.g., Java 21) in your codebase, and the solutions they suggest do not consider the latest improvements in the language, just simply the most used approaches.&lt;/p&gt;

&lt;p&gt;In this case, GitHub Copilot didn’t suggest an approach using a feature introduced 7 years ago. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsfmsfajraaskhs529t4b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsfmsfajraaskhs529t4b.png" alt="Image description" width="776" height="101"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Generated by Github Copilot&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="nf"&gt;calculateAverage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Collection&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; 
   &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; 
   &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; 
       &lt;span class="n"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; 
   &lt;span class="o"&gt;}&lt;/span&gt; 
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; 
&lt;span class="o"&gt;}&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Manual approach considering Java's new Teeing collector, introduced in Java 12, using the consisted and language level approach to iterate collections and lazily compute values from it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="nf"&gt;calculateAverageManual&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Collection&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; 
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;collect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt; 
&lt;span class="nc"&gt;Collectors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;teeing&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt; 
             &lt;span class="nc"&gt;Collectors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;summingDouble&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; 
             &lt;span class="nc"&gt;Collectors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;counting&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; 
             &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sum&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; 
&lt;span class="o"&gt;);&lt;/span&gt; 
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or even not using the latest new features of a language. In this case, Virtual Threads were introduced in Java 21, a year and a half ago. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe2cdrdg8sadnh9dadgbl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe2cdrdg8sadnh9dadgbl.png" alt="Image description" width="772" height="71"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Code generated by Github Copilot, using platform threads&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; 
   &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="no"&gt;URI&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"http://localhost:4000"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;toURL&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; 
   &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpURLConnection&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;openConnection&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; 
   &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setRequestMethod&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GET"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; 
   &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;responseCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getResponseCode&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; 
&lt;span class="o"&gt;}).&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Manual approach using Virtual Threads, being able to create thousands of threads that will &lt;a href="https://blog.behzadian.info/2024-05-03/Java-Thread-Performance-vs.-Virtual-Threads" rel="noopener noreferrer"&gt;increase the performance dramatically in blocking operations&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofVirtual&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; 
   &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="no"&gt;URI&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"http://localhost:4000"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;toURL&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; 
   &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;HttpURLConnection&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;openConnection&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; 
   &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setRequestMethod&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GET"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; 
   &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;responseCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getResponseCode&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; 
&lt;span class="o"&gt;}).&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Luckily these linters will also warn us about the lack of best practices usage while we code and during the CI full analysis. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ficzv32sihtsevac0av9c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ficzv32sihtsevac0av9c.png" alt="Image description" width="782" height="282"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A particular benefit of some linters over others (like SonarQube IDE) is that they can analyze multiple types of files at the same time in the same project. This is not only restricted to programming languages like Java, Python, JScript, Kotlin, etc. but also to Cloud deployment files like Docker, Kubernetes, Ansible, Terraform, CloudFormation, etc., and even Secrets vulnerabilities.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Test generation Phase&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;AI can analyze current code, try to understand its purpose, and generate test methods that will potentially generate the test code, ensuring high coverage. This helps to ensure that your code is thoroughly tested before it is released. &lt;/p&gt;

&lt;p&gt;In this area, we can find tools like Qodo Gen, among others, that specialize in test generation. &lt;/p&gt;

&lt;p&gt;I’ve installed it in my IntelliJ IDE and tried it with my AI project. The result is impressive, considering several test use cases in the happy path or edge cases. As with most code assistants, we can select which remote-hosted model we want to use.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxp2q0rp6ggm3m2qimv9e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxp2q0rp6ggm3m2qimv9e.png" alt="Image description" width="330" height="413"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Tools like Qodo will take a class method and create its tests. We will have a dashboard to see the tests and executions, and also a plan for the test generation in the Qodo plugin :  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4rthxjobjagon0djfr70.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4rthxjobjagon0djfr70.png" alt="Image description" width="800" height="612"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Pull Request creation&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;The process of creating a Pull Request is also important in order to give the proper context and details to those who will review it.&lt;/p&gt;

&lt;p&gt;A typical workflow would usually imply: &lt;/p&gt;

&lt;p&gt;●  Follow the initial process of joining/sign-in a team &lt;br&gt;
●  Read the &lt;a href="https://eclipse.dev/jkube/contributing/" rel="noopener noreferrer"&gt;contribution guidelines&lt;/a&gt; &lt;br&gt;
●  Do the commits &lt;a href="https://www.conventionalcommits.org/en/v1.0.0/" rel="noopener noreferrer"&gt;following a convention&lt;/a&gt; &lt;br&gt;
●  Sign all the commits (please!) &lt;br&gt;
●  Create a draft pull request with a good and complete description (sometimes following a template e.g. &lt;a href="https://github.com/eclipse-jkube/jkube/blob/master/.github/pull_request_template.md" rel="noopener noreferrer"&gt;JKube project&lt;/a&gt;) &lt;br&gt;
●  Wait for all the checks to pass &lt;br&gt;
●  Change the PR status to ready to review.  &lt;/p&gt;

&lt;p&gt;Several guides (&lt;a href="https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;, &lt;a href="https://www.pullrequest.com/blog/writing-a-great-pull-request-description/" rel="noopener noreferrer"&gt;pull request&lt;/a&gt;) can help you write good descriptions, but we can leverage AI for this. One of the tools we can use for this is Github Copilot, which analyzes the code in the PR to provide a more detailed description. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4itg64llbnym02iolrlj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4itg64llbnym02iolrlj.png" alt="Image description" width="800" height="386"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In these two images, we see how we can ask Github Copilot to generate a summary for the PR. &lt;/p&gt;

&lt;p&gt;We can also expand this with all the details we think can add more context and value and help reviewers in their tasks. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Pre-Code Review (Automated Analysis)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Static analyzers (like SonarQube) perform in-depth static analysis on your codebase, identifying issues that might be missed by human reviewers. This goes beyond style checks and delves into:&lt;/p&gt;

&lt;p&gt;●  &lt;strong&gt;Bug Detection&lt;/strong&gt;: Identifying potential NullPointerExceptions, logic errors, and other bugs. &lt;br&gt;
●  &lt;strong&gt;Security Vulnerabilities&lt;/strong&gt;: Detecting potential injection attacks, cross-site scripting (XSS) vulnerabilities, and other security risks. &lt;br&gt;
●  &lt;strong&gt;Code Smells&lt;/strong&gt;: Highlighting code that is difficult to read, maintain, or understand. For example, overly complex methods or duplicated code. &lt;br&gt;
●  &lt;strong&gt;Code Coverage&lt;/strong&gt;: Measuring the percentage of code covered by unit tests, helping to ensure comprehensive testing. &lt;/p&gt;

&lt;p&gt;These analyzers present these issues clearly and actionably, prioritizing them based on severity. &lt;/p&gt;

&lt;p&gt;This allows developers to focus on the most critical problems first, making the review process more efficient and effective. &lt;br&gt;
Connecting this step with the previous PR workflow, the tools we connect to our repository can help us to check for all the scenarios that can make our code fail, before anyone invests time in reviewing it, to just focus on working changes that need experienced review. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpzok2w9t2i1jfgu23i9q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpzok2w9t2i1jfgu23i9q.png" alt="Image description" width="800" height="796"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Pull Request changes explanation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now it’s the turn of the reviewers. They should start by reading the ticket that defines the PR's goal. After that, a careful review of the checks' status will give us an idea of whether the changes are okay to be merged.&lt;/p&gt;

&lt;p&gt;For this, we can use several tools. I’ve tried &lt;a href="https://docs.github.com/en/copilot/using-github-copilot/copilot-chat/asking-github-copilot-questions-in-github#asking-copilot-chat-questions-about-specific-pieces-of-code" rel="noopener noreferrer"&gt;Github Copilot&lt;/a&gt; and &lt;a href="https://github.com/qodo-ai/pr-agent?tab=readme-ov-file#try-it-now" rel="noopener noreferrer"&gt;Qodo PR-Agent&lt;/a&gt; (you can find a comparison &lt;a href="https://dev.to/danielrendox/ai-powered-pull-requests-codiumai-vs-github-copilot-35d0"&gt;here&lt;/a&gt;) : &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu4zonrisjz2uyrqlao5g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu4zonrisjz2uyrqlao5g.png" alt="Image description" width="800" height="519"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While Copilot has an explanation feature per changed file, Qodo can create a description for the entire PR. This will help the reviewers understand the details applied to files and focus on those that require more attention. It’s important to reduce the time a PR needs to be merged, and definitely, the usage of AI tools can help us with that. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Changes suggestion&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In some PRs, reviewers make suggestions to improve or fix parts of the document. This is a crucial point that, if not done correctly, can add anxiety and friction among team members. &lt;/p&gt;

&lt;p&gt;There are some guidelines in order to have safe and productive communication between the author and reviewers.  &lt;/p&gt;

&lt;p&gt;Some AI tools, like Qodo PR-Agent, can also implement the improvements and changes suggested by the AI agent directly from the PR review to the code. &lt;/p&gt;

&lt;p&gt;Like all the changes, they need to be analyzed and checked with tools like SonarQube. If there are any issues, these tools will fail, preventing those changes from being merged into the main branch.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F44xvo4z9i73fhk40zrsp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F44xvo4z9i73fhk40zrsp.png" alt="Image description" width="800" height="580"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Addressing the Challenges with AI&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;Here's how AI tackles the traditional code review challenges:&lt;/p&gt;

&lt;p&gt;●  &lt;strong&gt;Reduced Time&lt;/strong&gt;: Automation frees up developers to focus on more complex and creative tasks. Also helps reduce the cognitive load for the review process needed to understand the scope of all the changes. &lt;br&gt;
●  &lt;strong&gt;Increased Objectivity&lt;/strong&gt;: Static analysis provides objective, consistent, and deterministic feedback based on predefined rules and best practices. &lt;br&gt;
●  &lt;strong&gt;Focus on Critical Issues&lt;/strong&gt;: Prioritization helps reviewers focus on the most important problems. &lt;br&gt;
●  &lt;strong&gt;Enhanced Context&lt;/strong&gt;: AI can read the changes and generate meaningful PR descriptions&lt;br&gt;
along with detailed explanations of the changes for the reviewers. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;AI is not replacing human reviewers; it's empowering them. By automating tedious tasks and providing valuable insights, AI tools will improve the speed and comprehension of the generated code. &lt;/p&gt;

&lt;p&gt;Tools like static analyzers will automatically check code compliance and guarantee code quality throughout the SDLC, allowing developers to focus on what they do best: designing, building, and innovating. &lt;/p&gt;

&lt;p&gt;By leveraging AI-powered tools, we can shift our focus from simply finding bugs to building &lt;strong&gt;high-quality, maintainable, and secure software&lt;/strong&gt;.  &lt;/p&gt;

</description>
      <category>programming</category>
      <category>ai</category>
      <category>codequality</category>
      <category>security</category>
    </item>
    <item>
      <title>Code Quality in the Cloud</title>
      <dc:creator>Jonathan Vila</dc:creator>
      <pubDate>Fri, 20 Dec 2024 08:41:26 +0000</pubDate>
      <link>https://dev.to/jonathanvila/code-quality-in-the-cloud-58a3</link>
      <guid>https://dev.to/jonathanvila/code-quality-in-the-cloud-58a3</guid>
      <description>&lt;p&gt;Infrastructure as Code (IaC) has transformed how you deploy and manage cloud infrastructure. Tools like &lt;strong&gt;Azure Resource Manager, AWS CloudFormation, Docker, Kubernetes, Ansible, and Terraform&lt;/strong&gt; have made deploying infrastructure faster and more scalable. However, they’ve also introduced a new set of security challenges. &lt;/p&gt;

&lt;p&gt;In recent years, there have been numerous security incidents caused by IaC misconfigurations. These include:  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Open Ports and Weak Security Groups&lt;/strong&gt;: Exposing cloud resources to the public internet.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hardcoded Secrets&lt;/strong&gt;: Credentials, API keys, or sensitive data embedded in code.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Overly Permissive Policies&lt;/strong&gt;: Granting unnecessary privileges to users or services.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Missing Resource Limits&lt;/strong&gt;: Allowing unrestricted use of cloud resources, leading to potential outages or abuse.
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The consequences of these issues can be severe, from data breaches to financial loss and reputational damage. Moreover when &lt;strong&gt;Code GenAI&lt;/strong&gt; is used in order to produce those artifacts. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code GenAI&lt;/strong&gt; is a great help to start code artifacts and produce boilerplate code, but &lt;a href="https://docs.google.com/presentation/d/10LT7F94HLwZgP-_3dbW38ZP6zrZTaTbr1OjGllQAxfA/edit#slide=id.g2c974d6bd0f_0_9" rel="noopener noreferrer"&gt;it also needs to be reviewed&lt;/a&gt; to avoid the introduction of unexpected issues and vulnerabilities.&lt;/p&gt;

&lt;p&gt;Fortunately, there are tools that can help identify critical vulnerabilities early in development. &lt;/p&gt;

&lt;p&gt;From the &lt;strong&gt;SonarQube Cloud&lt;/strong&gt; telemetry, I've gathered the most hit issues regarding &lt;strong&gt;IaC&lt;/strong&gt;, with more than 6 million hits in total across all projects analyzed.&lt;/p&gt;

&lt;p&gt;In this article, I focus on &lt;strong&gt;Azure, CloudFormation, Docker, Kubernetes, Ansible and Terraform&lt;/strong&gt; as examples of &lt;strong&gt;IaC&lt;/strong&gt; issues. I highlight each critical issue, its risks, and how to fix it.&lt;/p&gt;

&lt;p&gt;As a &lt;strong&gt;bonus chapter&lt;/strong&gt;, you can see the result of an experiment with &lt;strong&gt;Code GenAI&lt;/strong&gt; using different providers to generate Kubernetes artifacts and check if they are as clean and secure as we expect.&lt;/p&gt;

&lt;p&gt;Let's start with a list of examples of all the &lt;strong&gt;IaC&lt;/strong&gt; artifacts covered in this article (&lt;strong&gt;and supported by &lt;a href="//rules.sonarsource.com"&gt;SonarQube&lt;/a&gt;&lt;/strong&gt;).&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Azure Resource Manager&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Restrict Public Access to Resources&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;: Allowing unrestricted public access to Azure resources (e.g., Blob Storage) exposes them to unauthorized users.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Solution&lt;/strong&gt;: Using &lt;code&gt;publicNetworkAccess&lt;/code&gt; to control access to resources.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Microsoft.Web/sites"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"apiVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2020-12-01"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"example-site"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nl"&gt;"siteConfig"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"publicNetworkAccess"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Disabled"&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  &lt;strong&gt;AWS CloudFormation&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1. Ensure S3 Buckets Are Private&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;: Publicly accessible S3 buckets can lead to data leaks.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Solution&lt;/strong&gt;: Set the bucket's &lt;code&gt;AccessControl&lt;/code&gt; to &lt;code&gt;Private&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;MyBucket&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::S3::Bucket&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;AccessControl&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Private&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  &lt;strong&gt;2. Apply Least Privilege to IAM Roles&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;: Granting broad permissions creates unnecessary security risks.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Solution&lt;/strong&gt;: Limit actions and resources to only what’s required.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# Update Lambda code&lt;/span&gt;
  &lt;span class="na"&gt;lambdaUpdatePolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::IAM::ManagedPolicy&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;ManagedPolicyName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lambdaUpdatePolicy&lt;/span&gt;
      &lt;span class="na"&gt;PolicyDocument&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2012-10-17"&lt;/span&gt;
        &lt;span class="na"&gt;Statement&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Allow&lt;/span&gt;
            &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;lambda:UpdateFunctionCode&lt;/span&gt;
            &lt;span class="na"&gt;Resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;arn:aws:lambda:us-east-2:123456789012:function:my-function:1"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  &lt;strong&gt;Docker&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Avoid Running Containers as Root&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;: Running containers as &lt;code&gt;root&lt;/code&gt; increases the risk of privilege escalation.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Solution&lt;/strong&gt;: Create and use a non-root user in your Dockerfile.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; alpine&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;addgroup &lt;span class="nt"&gt;-S&lt;/span&gt; nonroot &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; adduser &lt;span class="nt"&gt;-S&lt;/span&gt; nonroot &lt;span class="nt"&gt;-G&lt;/span&gt; nonroot

&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; nonroot&lt;/span&gt;

&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; ["id"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  &lt;strong&gt;Kubernetes&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1. Don’t Run Privileged Pods&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;: Running containers in privileged mode can reduce the resilience of a cluster in the event of a security incident because it weakens the isolation between hosts and containers.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Solution&lt;/strong&gt;: Disable privileged mode in your pod specification.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Pod&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;example&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;web&lt;/span&gt;
      &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
      &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;web&lt;/span&gt;
          &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
          &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TCP&lt;/span&gt;
      &lt;span class="na"&gt;securityContext&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;privileged&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  &lt;strong&gt;2. Define Resource Requests and Limits&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;: Allowing pods to use unlimited resources can destabilize the cluster.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Solution&lt;/strong&gt;: Specify resource requests and limits for containers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Pod&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;resource-limited-pod&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;app&lt;/span&gt;
      &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;myapp:latest&lt;/span&gt;
      &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;256Mi"&lt;/span&gt;
          &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.5"&lt;/span&gt;
        &lt;span class="na"&gt;limits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;512Mi"&lt;/span&gt;
          &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  &lt;strong&gt;3. Specific version tag for image should be used&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;: When a container image is not tagged with a specific version, it is referred to as latest. This means that every time the image is built, deployed, or run, it will always use the latest version of the image.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Solution&lt;/strong&gt;: To avoid these issues, it is recommended to use specific version tags for container images.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Pod&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;example&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
      &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx:1.14.2&lt;/span&gt; 

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
      &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx@sha256:b0ad43f7ee5edbc0effbc14645ae7055e21bc1973aee5150745632a24a752661&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  &lt;strong&gt;Terraform&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Allowing public network access to cloud resources is security-sensitive&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;: Enabling public network access to cloud resources can affect an organization’s ability to protect its data or internal operations from data theft or disruption.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Solution&lt;/strong&gt;: Use private networks and VPC peering or other secure communication tunnels to communicate with other cloud components.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"google_compute_instance"&lt;/span&gt; &lt;span class="s2"&gt;"example"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;network_interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;network&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;google_compute_network&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vpc_network_example&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  &lt;strong&gt;Ansible&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1. Server certificates should be verified&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; This vulnerability makes it possible for encrypted communication to be intercepted.&lt;br&gt;
&lt;strong&gt;Solution:&lt;/strong&gt; Ensure playbooks do not bypass certificate validation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Example playbook&lt;/span&gt;
  &lt;span class="na"&gt;hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;server&lt;/span&gt;
  &lt;span class="na"&gt;tasks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Retrieve a web page&lt;/span&gt;
      &lt;span class="na"&gt;ansible.builtin.uri&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://www.example.com&lt;/span&gt;
        &lt;span class="na"&gt;validate_certs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="na"&gt;return_content&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;2. Loose POSIX permissions&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; Files with overly permissive POSIX permissions (e.g., 777) grant unnecessary read, write, or execute access to unauthorized users. &lt;br&gt;
&lt;strong&gt;Solution:&lt;/strong&gt; Ensure playbooks explicitly set restrictive permissions on sensitive files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;My deployment&lt;/span&gt;
  &lt;span class="na"&gt;hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;all&lt;/span&gt;
  &lt;span class="na"&gt;tasks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Create /etc/demo with permissions&lt;/span&gt;
      &lt;span class="na"&gt;ansible.builtin.file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/etc/demo&lt;/span&gt;
        &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;directory&lt;/span&gt;
        &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;0770'&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Copy demo3.conf and set symbolic permissions&lt;/span&gt;
      &lt;span class="na"&gt;ansible.builtin.copy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/files/demo.conf&lt;/span&gt;
        &lt;span class="na"&gt;dest&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/etc/demo/demo.conf&lt;/span&gt;
        &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;g=r,u+w,o='&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  &lt;strong&gt;Secrets management&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Keys and passwords being disclosed&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; Secret leaks often occur when sensitive authentication data is stored with an application's source code. This is one example (OVH keys, the most hit issue) but the issue extends to several platforms.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;props&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ovh-key"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"EXEgWIz07P0HYwtQDs7cNIqCiQaWSuHF"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;props&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ovh-key"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getenv&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"OVH_KEY"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  &lt;strong&gt;Experimenting with Code GenAI and IaC&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;In order to see how accurate is Code GenAI for IaC artifacts, I've done an experiment with an AI application made in Java using Qarkus. You can find the source code &lt;a href="https://github.com/jonathanvila/pingpong-ai" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Using my IDE I've asked two different code assistants to produce the Kubernetes Deployment yaml file to deploy the application.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frk44i1zms5ik4n8hktk2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frk44i1zms5ik4n8hktk2.png" alt="Prompt" width="360" height="75"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I've used Github Copilot and Amazon Q as code assistants.&lt;br&gt;
Let's see the results.&lt;/p&gt;

&lt;h3&gt;
  
  
  Github Copilot
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pingpong-ai-deployment&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pingpong-ai&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pingpong-ai&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pingpong-ai&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pingpong-ai-container&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;your-docker-repo/pingpong-ai:latest&lt;/span&gt;
          &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
          &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;QUARKUS_PROFILE&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;prod&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;JAVA_OPTS&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-Dquarkus.http.host=0.0.0.0"&lt;/span&gt;
          &lt;span class="na"&gt;volumeMounts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;config-volume&lt;/span&gt;
              &lt;span class="na"&gt;mountPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/deployments/config&lt;/span&gt;
      &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;config-volume&lt;/span&gt;
          &lt;span class="na"&gt;configMap&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pingpong-ai-config&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pingpong-ai-service&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pingpong-ai&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TCP&lt;/span&gt;
      &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
      &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;LoadBalancer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It has been smart enough to generate a Service and a volume. But, not all is shiny. SonarQube for IDE has detected 6 issues :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fevmhgxlob9ji958q48df.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fevmhgxlob9ji958q48df.png" alt="Issues in the Github Copilot artifact" width="720" height="191"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Amazon Q
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-application&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-application&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;  &lt;span class="c1"&gt;# Number of pod replicas you want to run&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-application&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-application&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-application&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;your-registry/your-image:tag&lt;/span&gt;  &lt;span class="c1"&gt;# Replace with your image&lt;/span&gt;
          &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;  &lt;span class="c1"&gt;# Replace with your application port&lt;/span&gt;
          &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;200m"&lt;/span&gt;
              &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;256Mi"&lt;/span&gt;
            &lt;span class="na"&gt;limits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;500m"&lt;/span&gt;
              &lt;span class="na"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;512Mi"&lt;/span&gt;
          &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ENVIRONMENT&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;production"&lt;/span&gt;
          &lt;span class="c1"&gt;# Add any environment variables your application needs&lt;/span&gt;
          &lt;span class="na"&gt;livenessProbe&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;httpGet&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/health&lt;/span&gt;  &lt;span class="c1"&gt;# Replace with your health check endpoint&lt;/span&gt;
              &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
            &lt;span class="na"&gt;initialDelaySeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;30&lt;/span&gt;
            &lt;span class="na"&gt;periodSeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
          &lt;span class="na"&gt;readinessProbe&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;httpGet&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/health&lt;/span&gt;  &lt;span class="c1"&gt;# Replace with your health check endpoint&lt;/span&gt;
              &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
            &lt;span class="na"&gt;initialDelaySeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
            &lt;span class="na"&gt;periodSeconds&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This output is way cleaner and of higher quality than the previous one, and SonarQube for IDE has detected only 2 issues. However, it doesn't provide a Service or a volume for configuration files.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsw0j3hulyzvgaln9qupf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsw0j3hulyzvgaln9qupf.png" alt="Issues in the Amazon Q artifact" width="720" height="115"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In both cases, it's been fast and without the problem of typing errors (wrong attribute name, wrong number of spaces, tabs, etc..)., but as with any code generated by AI, it needed a review phase to detect issues that are not always obvious in order to submit good-quality code to our repository and lead to smooth Pull Request reviews.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;IaC enables teams to automate and scale infrastructure efficiently, but with great power comes great responsibility. Misconfigurations, hardcoded secrets, and overly permissive access controls are common mistakes that can lead to serious security vulnerabilities.  &lt;/p&gt;

&lt;p&gt;By following best practices and leveraging tools like &lt;a href="https://www.sonarsource.com/" rel="noopener noreferrer"&gt;SonarQube&lt;/a&gt;, developers can identify and resolve critical security issues early in the development process.  &lt;/p&gt;

&lt;p&gt;More than just security, &lt;strong&gt;maintaining code quality in IaC is essential&lt;/strong&gt;. Well-structured, maintainable IaC ensures teams can quickly adapt to new requirements and maintain a robust, secure infrastructure. &lt;/p&gt;

&lt;p&gt;Combining high-quality code with automated tooling is the key to avoiding costly security mishaps. SonarQube has rules to check all these issues in &lt;a href="https://rules.sonarsource.com/azureresourcemanager/" rel="noopener noreferrer"&gt;Azure Resource Manager&lt;/a&gt;, &lt;a href="https://rules.sonarsource.com/docker/" rel="noopener noreferrer"&gt;Docker&lt;/a&gt;, &lt;a href="https://rules.sonarsource.com/kubernetes/" rel="noopener noreferrer"&gt;Kubernetes&lt;/a&gt;, &lt;a href="https://rules.sonarsource.com/cloudformation/" rel="noopener noreferrer"&gt;CloudFormation&lt;/a&gt;, &lt;a href="https://rules.sonarsource.com/terraform/" rel="noopener noreferrer"&gt;Terraform&lt;/a&gt;, &lt;a href="https://rules.sonarsource.com/ansible/" rel="noopener noreferrer"&gt;Ansible&lt;/a&gt; and &lt;a href="https://rules.sonarsource.com/secrets" rel="noopener noreferrer"&gt;Secrets&lt;/a&gt; in general.&lt;/p&gt;

</description>
      <category>cloudcomputing</category>
      <category>terraform</category>
      <category>kubernetes</category>
      <category>security</category>
    </item>
    <item>
      <title>Building local LLM AI-Powered Applications with Quarkus, Ollama and Testcontainers</title>
      <dc:creator>Jonathan Vila</dc:creator>
      <pubDate>Tue, 10 Dec 2024 15:39:54 +0000</pubDate>
      <link>https://dev.to/jonathanvila/building-local-llm-ai-powered-applications-with-quarkus-ollama-and-testcontainers-10ed</link>
      <guid>https://dev.to/jonathanvila/building-local-llm-ai-powered-applications-with-quarkus-ollama-and-testcontainers-10ed</guid>
      <description>&lt;p&gt;Traditionally, many AI-powered applications rely on cloud-based APIs or centralized services for model hosting and execution. While this approach has its advantages, such as scalability and ease of use, it also introduces challenges around latency, data privacy, and dependency on third-party providers.&lt;/p&gt;

&lt;p&gt;This is where local AI models shine. By running models directly within your application's infrastructure, you gain greater control over performance, data security, and deployment flexibility. However, building such systems requires the right tools and frameworks to bridge the gap between traditional software development and AI model integration.&lt;/p&gt;

&lt;p&gt;In this article, we explore how to combine Quarkus, a modern Java framework optimized for cloud-native applications, with Ollama, a platform for running AI models locally. We’ll also demonstrate how tools like Testcontainers and Quarkus Dev Services simplify development and testing workflows. Using the PingPong-AI project as a practical example, you'll learn how to build and test AI-driven applications that harness the power of local models.&lt;/p&gt;

&lt;p&gt;The PingPong-AI project demonstrates a simple implementation of AI-powered functionality using Quarkus as the backend framework and Ollama for handling AI models. Let’s break down the architecture and walk through key components of the code.&lt;/p&gt;




&lt;h2&gt;
  
  
  Project Overview
&lt;/h2&gt;

&lt;p&gt;In PingPong-AI, Ollama is used to simulate a simple conversation model where a curious service generates questions around a topic and a wise service responds with informated answers, that will generate more questions on the curious service.&lt;/p&gt;

&lt;p&gt;The project integrates Quarkus with Ollama to create an AI model-driven application. It leverages Quarkus's lightweight and fast development model to serve as a backend for invoking and managing AI interactions. Here's an overview of what we'll cover:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Integrating Quarkus with Ollama&lt;/li&gt;
&lt;li&gt;Using Testcontainers for Integration Testing&lt;/li&gt;
&lt;li&gt;Leveraging Quarkus Dev Services for Simplified Development&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  1. Integrating Quarkus with Ollama
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why Ollama?
&lt;/h3&gt;

&lt;p&gt;Ollama simplifies the deployment and use of AI models in applications. It provides a runtime for AI model execution and can be easily integrated into existing applications. &lt;/p&gt;

&lt;h3&gt;
  
  
  Quarkus and Ollama Integration
&lt;/h3&gt;

&lt;p&gt;The integration with Quarkus is handled using REST endpoints to interact with Ollama. The Quarkus application serves as the middleware to process client requests and communicate with the Ollama runtime.&lt;/p&gt;

&lt;p&gt;Here’s a snippet from &lt;code&gt;PingPongResource.java&lt;/code&gt;, which defines the REST endpoint for the PingPong interaction:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Path&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/chat"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CuriousChatResource&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Inject&lt;/span&gt;
    &lt;span class="nc"&gt;CuriousService&lt;/span&gt; &lt;span class="n"&gt;curiousService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Inject&lt;/span&gt;
    &lt;span class="nc"&gt;WiseService&lt;/span&gt; &lt;span class="n"&gt;wiseService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

   &lt;span class="nd"&gt;@POST&lt;/span&gt;
    &lt;span class="nd"&gt;@Produces&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MediaType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;TEXT_PLAIN&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nd"&gt;@Consumes&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MediaType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;TEXT_PLAIN&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nd"&gt;@Path&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/{numberOfQuestions}"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;chat&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@PathParam&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"numberOfQuestions"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;numberOfQuestions&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;topic&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;StringBuilder&lt;/span&gt; &lt;span class="n"&gt;sb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;StringBuilder&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;sb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;append&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&amp;gt; Topic: "&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;append&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;topic&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;append&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"\n"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numberOfQuestions&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;question&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;curiousService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;chat&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;topic&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;sb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;append&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&amp;gt; Question: "&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;append&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;question&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;append&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"\n"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;topic&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;wiseService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;chat&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;question&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;sb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;append&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&amp;gt; Answer: "&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;append&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;topic&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;append&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"\n"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;sb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;CuriousChatResource&lt;/code&gt; handles client POST requests.&lt;/li&gt;
&lt;li&gt;The injected &lt;code&gt;CuriousService&lt;/code&gt; and &lt;code&gt;WiseService&lt;/code&gt; interface with the Ollama runtime to process the message.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These Ollama services are responsible for calling the Ollama runtime. Here's a snippet from &lt;code&gt;CuriousService.java&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@RegisterAiService&lt;/span&gt;
&lt;span class="nd"&gt;@SystemMessage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"You are a curious person that creates a short question for every message you receive."&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;CuriousService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;chat&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@UserMessage&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can even use different models for each service, specifying the configuration property that identifies the model. This example comes from &lt;code&gt;CuriousService.java&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@RegisterAiService&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;modelName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"curiousModel"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we identify the model in &lt;code&gt;application.properties&lt;/code&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;quarkus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;langchain4j&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ollama&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;wiseModel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;chat&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;tinydolphin&lt;/span&gt;
&lt;span class="n"&gt;quarkus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;langchain4j&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ollama&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;curiousModel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;chat&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;tinyllama&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  2. Using Testcontainers for Integration Testing
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why Testcontainers?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Testcontainers&lt;/strong&gt; is a Java library for running lightweight, disposable containers during tests. In PingPong-AI, Testcontainers are used to set up an environment with an Ollama runtime for integration testing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example: Setting up a Testcontainer for Ollama
&lt;/h3&gt;

&lt;p&gt;The test class demonstrates how to configure and use Testcontainers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@QuarkusTest&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CuriousChatResourceTest&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Inject&lt;/span&gt;
    &lt;span class="nc"&gt;CuriousService&lt;/span&gt; &lt;span class="n"&gt;curiousService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Inject&lt;/span&gt;
    &lt;span class="nc"&gt;WiseService&lt;/span&gt; &lt;span class="n"&gt;wiseService&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="nd"&gt;@ActivateRequestContext&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;testFXMainControllerInteraction&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

        &lt;span class="c1"&gt;// Perform interaction and assertions&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;curiousAnswer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;curiousService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;chat&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Barcelona"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;wiseService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;chat&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;curiousAnswer&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="nc"&gt;Log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;infof&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Wise service response: %s"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// Using llama2 model we can check if the response contains 'Barcelona', but not&lt;/span&gt;
        &lt;span class="c1"&gt;// with tinyllama&lt;/span&gt;
        &lt;span class="n"&gt;assertFalse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="s"&gt;"Response should not be empty"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="nd"&gt;@ActivateRequestContext&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;testChatEndpoint&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;given&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Barcelona"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;contentType&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ContentType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;TEXT&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;post&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/chat/3"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;then&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;statusCode&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;contentType&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ContentType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;TEXT&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;not&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;empty&lt;/span&gt;&lt;span class="o"&gt;()))&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hamcrest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Matchers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stringContainsInOrder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Question:"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Answer:"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Question:"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Answer:"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Question:"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Answer:"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;

    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Key Points:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;@QuarkusTest&lt;/code&gt; annotation allows Quarkus to run the application in a test-friendly mode.&lt;/li&gt;
&lt;li&gt;Quarkus finds a service (Ollama) for which it needs an instance and it will spin up a container for that.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  3. Leveraging Quarkus Dev Services for Ollama
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What Are Quarkus Dev Services?
&lt;/h3&gt;

&lt;p&gt;Quarkus Dev Services simplifies the setup of required services during development. For this project, Quarkus Dev Services can spin up an Ollama runtime container automatically.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuring Dev Services
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;application.properties&lt;/code&gt; file includes configurations for enabling Dev Services:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;quarkus.langchain4j.ollama.chat-model.model-id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;tinyllama&lt;/span&gt;
&lt;span class="py"&gt;quarkus.langchain4j.ollama.devservices.model&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;tinyllama&lt;/span&gt;
&lt;span class="py"&gt;quarkus.langchain4j.log-requests&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With these configurations, Quarkus Dev Services automatically starts an Ollama container when the application is run in development mode or in test, removing the need for manual setup.&lt;/p&gt;

&lt;h3&gt;
  
  
  Development Workflow
&lt;/h3&gt;

&lt;p&gt;You can launch the application in development mode using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./mvnw quarkus:dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Starts the Quarkus application.&lt;/li&gt;
&lt;li&gt;Automatically sets up an Ollama runtime container.&lt;/li&gt;
&lt;li&gt;Enables hot-reloading for rapid development.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The PingPong-AI project demonstrates a seamless integration of Quarkus with Ollama, making it easy to build AI-powered applications. By leveraging Testcontainers and Quarkus Dev Services, developers can efficiently test and develop their applications in a containerized and automated environment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Takeaways:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Quarkus provides a lightweight framework for building and deploying Java applications.&lt;/li&gt;
&lt;li&gt;Ollama simplifies AI model integration with backend systems.&lt;/li&gt;
&lt;li&gt;Testcontainers and Dev Services streamline the testing and development workflows.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To explore this project further, check out the &lt;a href="https://github.com/jonathanvila/pingpong-ai" rel="noopener noreferrer"&gt;PingPong-AI GitHub repository&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>java</category>
      <category>ai</category>
      <category>test</category>
      <category>programming</category>
    </item>
    <item>
      <title>Building an AI Fix SonarQube Dashboard with Vaadin and Spring Boot</title>
      <dc:creator>Jonathan Vila</dc:creator>
      <pubDate>Mon, 02 Dec 2024 14:35:19 +0000</pubDate>
      <link>https://dev.to/jonathanvila/building-an-ai-fix-sonarqube-dashboard-with-vaadin-and-spring-boot-1ln9</link>
      <guid>https://dev.to/jonathanvila/building-an-ai-fix-sonarqube-dashboard-with-vaadin-and-spring-boot-1ln9</guid>
      <description>&lt;p&gt;SonarQube provides developers with static code analysis capabilities, allowing teams to identify and resolve code quality issues. It also includes an AI Fix feature that helps developers fix specific issues using the full power of AI. &lt;/p&gt;

&lt;p&gt;The project &lt;a href="https://github.com/jonathanvila/sonarqube-bulk-ai-fix" rel="noopener noreferrer"&gt;sonarqube-bulk-ai-fix&lt;/a&gt; shows how to focus only on those issues with AI fixes as an example of how to easily connect to SonarQube Server API and show the fixes in SonarQube IDE. &lt;/p&gt;

&lt;p&gt;In this article, we’ll explore how the project leverages the SonarQube API alongside &lt;strong&gt;Vaadin&lt;/strong&gt; and &lt;strong&gt;Spring Boot&lt;/strong&gt; to create an intuitive dashboard for AI fixing code issues.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why SonarQube API?
&lt;/h2&gt;

&lt;p&gt;SonarQube’s API provides extensive capabilities to interact with its core features programmatically, enabling:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fetching project and issue data&lt;/li&gt;
&lt;li&gt;Managing quality gates and rules&lt;/li&gt;
&lt;li&gt;Integrating with CI/CD pipelines&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This project highlights the use of the API to identify issues and seamlessly process AI fixes. Let's examine the technical components.&lt;/p&gt;




&lt;h2&gt;
  
  
  Overview of the Architecture
&lt;/h2&gt;

&lt;p&gt;The project architecture integrates:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Spring Boot&lt;/strong&gt;: Acts as the backend to manage business logic and handle API interactions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vaadin&lt;/strong&gt;: Provides a modern, web-based UI for the dashboard.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SonarQube API&lt;/strong&gt;: Fetches project issues and applies fixes programmatically.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;SonarQube Server / SonarQube Cloud instance running with AI CodeFix feature enabled (&amp;gt; 10.7)&lt;/li&gt;
&lt;li&gt;IDE running (VSCode, IntelliJ)&lt;/li&gt;
&lt;li&gt;Container runtime (Podman, Docker)&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Running SonarQube Server
&lt;/h2&gt;

&lt;p&gt;If you don't have access to a SonarQube Cloud instance with CodeFix feature enabled, you can try this example locally. To do that,&lt;a href="https://www.sonarsource.com/plans-and-pricing/enterprise/" rel="noopener noreferrer"&gt;request&lt;/a&gt; an Enterprise free trial license.&lt;/p&gt;

&lt;p&gt;The next step is to create a docker-compose file to have persistence in our analysis, otherwise, it would use a memory database, and every time you run the container, it will be empty.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;version: "3"

services:
  sonarqube:
    image: sonarqube:enterprise
    depends_on:
      - db
    environment:
      SONAR_JDBC_URL: jdbc:postgresql://db:5432/sonar
      SONAR_JDBC_USERNAME: sonar
      SONAR_JDBC_PASSWORD: sonar
    volumes:
      - sonarqube_data:/opt/sonarqube/data
      - sonarqube_extensions:/opt/sonarqube/extensions
      - sonarqube_logs:/opt/sonarqube/logs
      - ~/cacerts:/opt/java/openjdk/lib/security/cacerts
    ports:
      - "9000:9000"
  db:
    image: postgres:latest
    environment:
      POSTGRES_USER: sonar
      POSTGRES_PASSWORD: sonar
    volumes:
      - postgresql:/var/lib/postgresql
      - postgresql_data:/var/lib/postgresql/data

volumes:
  sonarqube_data:
  sonarqube_extensions:
  sonarqube_logs:
  postgresql:
  postgresql_data:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And finally, run SonarQube with this command :&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker-compose -f ./docker-compose-sonarqube-postgre.yaml up&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;After a few seconds, you can open our browser on &lt;code&gt;localhost:9000&lt;/code&gt; and specify the new password (the default is admin/admin). &lt;br&gt;
Now you should paste the contents of the trial license file we received and Voila!&lt;/p&gt;
&lt;h2&gt;
  
  
  Analysing our first project
&lt;/h2&gt;

&lt;p&gt;In order to test the connection with real data, you would need to incorporate a project analysis in the SonarQube dashboard. To do this for a given Java project simply run this command in the project folder (considering it's a Maven Java application):&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;mvn clean verify sonar:sonar -Dsonar.projectKey=sample -Dsonar.host.url=http://localhost:9000 -Dsonar.login=admin -Dsonar.password={replace with your pass}&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flhhnvb9pkot1tagtc4f3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flhhnvb9pkot1tagtc4f3.png" alt="Image description" width="800" height="506"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Using the SonarQube API
&lt;/h2&gt;

&lt;p&gt;The first step is connecting to the SonarQube API to retrieve and manipulate issue data. In the project, a &lt;code&gt;SonarQubeClient&lt;/code&gt; class encapsulates this functionality. &lt;br&gt;
There are some API calls supported by the &lt;a href="https://github.com/SonarSource/sonarqube/tree/master/sonar-ws" rel="noopener noreferrer"&gt;Sonar SDK&lt;/a&gt;, and others that are direct calls using HttpClient.&lt;/p&gt;

&lt;p&gt;To find out which API endpoints and types are supported, go to &lt;a href="http://localhost:9000/web_api" rel="noopener noreferrer"&gt;Web API&lt;/a&gt; and &lt;a href="http://localhost:9000/web_api_v2" rel="noopener noreferrer"&gt;Web API v2&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Sonar API Client in Spring Boot
&lt;/h3&gt;

&lt;p&gt;You can use the &lt;code&gt;sonar-ws&lt;/code&gt; SDK to connect to SonarQube and get the issues for a given filter.&lt;br&gt;
We need to use pagination, as it's only returning 100 elements per query.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;SearchWsResponse&lt;/span&gt; &lt;span class="nf"&gt;getListOfIssues&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;pageSize&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Call the SonarQube API to get the issues&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;httpConnector&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;HttpConnector&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newBuilder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sonarqubeUrl&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;credentials&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sonarqubeUser&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sonarqubePassword&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;wsClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;WsClientFactories&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getDefault&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;newClient&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;httpConnector&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;issueRequest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SearchRequest&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;issueRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setProjects&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Collections&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;singletonList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;severity&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;issueRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setSeverities&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;severity&lt;/span&gt;&lt;span class="o"&gt;()));&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;issueRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setP&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;issueRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setPs&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pageSize&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wsClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;issues&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;search&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;issueRequest&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To check if an issue has an AI Code Fix, you need to make a direct call using the HttpRequest object because the SDK doesn't yet cover this call.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// check if the issue has code fix suggestions&lt;/span&gt;
&lt;span class="nc"&gt;HttpRequest&lt;/span&gt; &lt;span class="n"&gt;requestCheckIfIssueHasCodeFix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;HttpRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newBuilder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;URI&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;urlFixSuggestionsIssues&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;header&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Authorization"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;getAuthorization&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

&lt;span class="nc"&gt;HttpResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;send&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;requestCheckIfIssueHasCodeFix&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;BodyHandlers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofString&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;contains&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"\"aiSuggestion\":\"AVAILABLE\""&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;issuesWithCodeFix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;issue&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Interacting with the IDE
&lt;/h2&gt;

&lt;p&gt;One feature of this Dashboard is the ability to send the AI Fix to the local running instance of an IDE and commit the change to our code base.&lt;/p&gt;

&lt;p&gt;SonarQube for IDE has an API you can use to send pieces of code that need to be refactored.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;sendCodeFixToSonarLint&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Issue&lt;/span&gt; &lt;span class="n"&gt;issue&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;AISuggestion&lt;/span&gt; &lt;span class="n"&gt;issueCodeFix&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;codeFile&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;JsonProcessingException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;uri&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;URI&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"http://localhost:"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="no"&gt;SONARLINT_API_FIX&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
                &lt;span class="s"&gt;"?server="&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nc"&gt;URLEncoder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;encode&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sonarqubeUrl&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="nc"&gt;StandardCharsets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;UTF_8&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
                &lt;span class="s"&gt;"&amp;amp;project="&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;project&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
                &lt;span class="s"&gt;"&amp;amp;issue="&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;issueCodeFix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;issueId&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
                &lt;span class="s"&gt;"&amp;amp;branch=master"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;codeFileLines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;codeFile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;split&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"\n"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;sonarLintSuggestion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SonarLintSuggestion&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;issueCodeFix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;explanation&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
                &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SonarLintSuggestion&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;FileEdit&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                        &lt;span class="n"&gt;issueCodeFix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;changes&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;change&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SonarLintSuggestion&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;FileEdit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Change&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                                &lt;span class="n"&gt;change&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newCode&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
                                &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"\n"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                                        &lt;span class="nc"&gt;Arrays&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;copyOfRange&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;codeFileLines&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;change&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;startLine&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;change&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;endLine&lt;/span&gt;&lt;span class="o"&gt;())),&lt;/span&gt;
                                &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SonarLintSuggestion&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;FileEdit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Change&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;LineRange&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                                        &lt;span class="n"&gt;change&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;startLine&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
                                        &lt;span class="n"&gt;change&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;endLine&lt;/span&gt;&lt;span class="o"&gt;())))&lt;/span&gt;
                                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toList&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
                        &lt;span class="n"&gt;getFileFromComponent&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;issue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getComponent&lt;/span&gt;&lt;span class="o"&gt;())),&lt;/span&gt;
                &lt;span class="n"&gt;issueCodeFix&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="nc"&gt;HttpRequest&lt;/span&gt; &lt;span class="n"&gt;sendCodeFixToSonarLintRequest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;HttpRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newBuilder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;URI&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;()))&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;POST&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BodyPublishers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ObjectMapper&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;writeValueAsString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sonarLintSuggestion&lt;/span&gt;&lt;span class="o"&gt;)))&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

        &lt;span class="nc"&gt;HttpClient&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;HttpClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newHttpClient&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;HttpResponse&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;send&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sendCodeFixToSonarLintRequest&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;BodyHandlers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofString&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
            &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;request&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"\n"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;

            &lt;span class="n"&gt;writeToFileAppliedCodeFix&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;issueCodeFix&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="nc"&gt;Notification&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;show&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Response from SonarLint: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;statusCode&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"\n"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;IOException&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;InterruptedException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;printStackTrace&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F215qo8fwzbw56oueak1q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F215qo8fwzbw56oueak1q.png" alt="Image description" width="800" height="304"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Building the UI with Vaadin
&lt;/h2&gt;

&lt;p&gt;Vaadin simplifies the process of building web UIs in Java by combining a component-based framework with server-side logic. &lt;/p&gt;

&lt;p&gt;The process is to create different components and add them to layout containers.&lt;/p&gt;

&lt;p&gt;Here’s how the project creates a dashboard page:&lt;/p&gt;

&lt;h3&gt;
  
  
  Vaadin Page for the dashboard
&lt;/h3&gt;

&lt;p&gt;Adding the components to the layouts :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;IssuesDashboard&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;sonarqubePanel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;HorizontalLayout&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;sonarqubeUrlEdit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TextField&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SonarQube Server URL"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;sonarqubeUrlEdit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setValue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"http://localhost:9000"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

  &lt;span class="n"&gt;sonarqubeUserEdit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TextField&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"User"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;sonarqubePasswordEdit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TextField&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Password"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

  &lt;span class="n"&gt;sonarqubePanel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sonarqubeUrlEdit&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sonarqubeUserEdit&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sonarqubePasswordEdit&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Listeners to button actions :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;applyFixesButton&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Send Selected Fix to SonarQube IDE"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;applyFixesButton&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addClickListener&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="nc"&gt;Notification&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;show&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Processing fixes"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
   &lt;span class="n"&gt;applyFixes&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
   &lt;span class="nc"&gt;Notification&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;show&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Processing fixes finished"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Bringing It All Together
&lt;/h2&gt;

&lt;p&gt;To run the project:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Start the Spring Boot application:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./mvnw spring-boot:run
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Access the Vaadin UI at &lt;code&gt;http://localhost:8080&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can then enter the project key, fetch issues, and explore the automation possibilities.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;sonarqube-bulk-ai-fix&lt;/code&gt; project demonstrates the power of combining the &lt;strong&gt;SonarQube API&lt;/strong&gt;, &lt;strong&gt;Vaadin&lt;/strong&gt;, and &lt;strong&gt;Spring Boot&lt;/strong&gt; to create a user-friendly and efficient dashboard for AI code fixes. Whether you're looking to streamline your workflows or explore innovative ways to interact with SonarQube, this project provides an excellent start point.&lt;/p&gt;

&lt;p&gt;Check out the full source code and contribute to the project on &lt;a href="https://github.com/jonathanvila/sonarqube-bulk-ai-fix" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>java</category>
      <category>ai</category>
      <category>vaadin</category>
      <category>springboot</category>
    </item>
  </channel>
</rss>
