<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="rss.xsl"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>SugarFreeBytes Blog</title>
        <link>https://sugarfreebytes.com/</link>
        <description>SugarFreeBytes Blog</description>
        <lastBuildDate>Fri, 24 Jan 2025 00:00:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <item>
            <title><![CDATA[Sandboxing AI Codegen CLIs: Part 1 - CLI Tooling]]></title>
            <link>https://sugarfreebytes.com/ionut-baranga/sandboxing-ai-codegen-clis-with-aidevtools</link>
            <guid>https://sugarfreebytes.com/ionut-baranga/sandboxing-ai-codegen-clis-with-aidevtools</guid>
            <pubDate>Fri, 24 Jan 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Containers]]></description>
            <content:encoded><![CDATA[<p><img decoding="async" loading="lazy" alt="Containers" src="https://sugarfreebytes.com/assets/images/pexels-tom-fisk-1427107-b17c389abe42fdd324383aba9fbb1efb.jpg" width="1260" height="708" class="img_ev3q"></p>
<div class="photo-attribution">Photo by <a href="https://www.pexels.com/@tomfisk" target="_blank" rel="noopener noreferrer" class="">Tom Fisk</a> on <a href="https://www.pexels.com/photo/1427107/" target="_blank" rel="noopener noreferrer" class="">Pexels</a></div>
<p>AI-powered code generation CLIs like Claude Code, Gemini CLI, OpenAI Codex, and GitHub Copilot are incredibly productive tools. They can scaffold projects, refactor code, and even run bash commands on your behalf.</p>
<p>But here's the catch: they can also hallucinate. And a hallucinated <code>rm -rf</code> or a runaway <code>npm install</code> that fills your disk is not something you want happening on your main OS.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-problem">The Problem<a href="https://sugarfreebytes.com/ionut-baranga/sandboxing-ai-codegen-clis-with-aidevtools#the-problem" class="hash-link" aria-label="Direct link to The Problem" title="Direct link to The Problem" translate="no">​</a></h2>
<p>These tools are powerful, but when you grant them shell access, you're essentially trusting an LLM to not mess up your system. That's a gamble I'm not willing to take on my daily driver.</p>
<p>Consider these scenarios:</p>
<ul>
<li class="">A hallucinated command wipes important files</li>
<li class="">An infinite loop fills your disk with garbage</li>
<li class="">A misconfigured script modifies system files</li>
<li class="">Dependencies get installed globally, polluting your environment</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-solution-sandboxed-docker-containers">The Solution: Sandboxed Docker Containers<a href="https://sugarfreebytes.com/ionut-baranga/sandboxing-ai-codegen-clis-with-aidevtools#the-solution-sandboxed-docker-containers" class="hash-link" aria-label="Direct link to The Solution: Sandboxed Docker Containers" title="Direct link to The Solution: Sandboxed Docker Containers" translate="no">​</a></h2>
<p>This is the first part in a series on sandboxing AI codegen CLIs. We're starting with the simplest, most portable approach: a Docker image with a lightweight wrapper script.</p>
<p>By running AI codegen CLIs inside a Docker container, you get:</p>
<ol>
<li class=""><strong>Full isolation</strong> - The container can't touch your main OS</li>
<li class=""><strong>No root access</strong> - The container runs as a non-root user with no sudo</li>
<li class=""><strong>Persistent AI config</strong> - The <code>.ai/</code> folder survives between runs</li>
<li class=""><strong>Batteries included</strong> - Claude, Codex, Copilot, Gemini, plus language runtimes and dev tools</li>
<li class=""><strong>One command</strong> - A wrapper script handles everything</li>
</ol>
<p>The beauty of this approach is its simplicity. No IDE plugins or special configuration needed - just Docker and a shell script.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="whats-in-the-box">What's in the Box?<a href="https://sugarfreebytes.com/ionut-baranga/sandboxing-ai-codegen-clis-with-aidevtools#whats-in-the-box" class="hash-link" aria-label="Direct link to What's in the Box?" title="Direct link to What's in the Box?" translate="no">​</a></h2>
<p>The <a href="https://github.com/sugarfreebytes/aidevtools" target="_blank" rel="noopener noreferrer" class="">aidevtools</a> Docker image ships with:</p>
<p><strong>AI Assistants:</strong> Claude CLI, OpenAI Codex, GitHub Copilot, Google Gemini CLI</p>
<p><strong>Language Runtimes:</strong> Java (SDKMAN), Node.js (NVM), Python, Go, Rust, Deno</p>
<p><strong>Dev Tools:</strong> GitHub CLI, Neovim, tmux, direnv</p>
<p>The image is fully customizable via build args - disable what you don't need:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">docker</span><span class="token plain"> build --build-arg </span><span class="token assign-left variable" style="color:#36acaa">INSTALL_JAVA</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">false --build-arg </span><span class="token assign-left variable" style="color:#36acaa">INSTALL_RUST</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">false </span><span class="token builtin class-name">.</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="getting-started">Getting Started<a href="https://sugarfreebytes.com/ionut-baranga/sandboxing-ai-codegen-clis-with-aidevtools#getting-started" class="hash-link" aria-label="Direct link to Getting Started" title="Direct link to Getting Started" translate="no">​</a></h2>
<p>Getting started is straightforward:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># Pull the pre-built image</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">docker</span><span class="token plain"> pull ghcr.io/sugarfreebytes/aidevtools:latest</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Run from your project directory</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">./aidevtools.sh          </span><span class="token comment" style="color:#999988;font-style:italic"># Interactive shell</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">./aidevtools.sh claude   </span><span class="token comment" style="color:#999988;font-style:italic"># Launch Claude directly</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">./aidevtools.sh gemini   </span><span class="token comment" style="color:#999988;font-style:italic"># Launch Gemini directly</span><br></span></code></pre></div></div>
<p>The wrapper script mounts your current directory into the container and persists AI tool configurations in a local <code>.ai/</code> folder between sessions.</p>
<p><strong><a class="" href="https://sugarfreebytes.com/tutorials/aidevtools/sandboxed-ai-clis">Read the full tutorial: Sandboxing AI CLIs with Docker</a></strong></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="whats-next">What's Next?<a href="https://sugarfreebytes.com/ionut-baranga/sandboxing-ai-codegen-clis-with-aidevtools#whats-next" class="hash-link" aria-label="Direct link to What's Next?" title="Direct link to What's Next?" translate="no">​</a></h2>
<p>This is Part 1 of a series on sandboxing AI codegen CLIs. In upcoming posts, we'll explore DevContainers, IDE integration, and more advanced isolation strategies.</p>]]></content:encoded>
            <category>docker</category>
            <category>ai</category>
            <category>claude</category>
            <category>gemini</category>
            <category>codex</category>
            <category>copilot</category>
            <category>security</category>
            <category>aidevtools</category>
        </item>
        <item>
            <title><![CDATA[Spring Boot Integration Testing with Testcontainers and JUnit5]]></title>
            <link>https://sugarfreebytes.com/ionut-baranga/spring-boot-test-containers-junit-jupiter</link>
            <guid>https://sugarfreebytes.com/ionut-baranga/spring-boot-test-containers-junit-jupiter</guid>
            <pubDate>Sat, 18 Mar 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[Testing]]></description>
            <content:encoded><![CDATA[<p><img decoding="async" loading="lazy" alt="Testing" src="https://sugarfreebytes.com/assets/images/chuttersnap-9cCeS9Sg6nU-unsplash-e86f8b3843414531ffa384255d60a17d.jpg" width="3991" height="2661" class="img_ev3q"></p>
<div class="photo-attribution">Photo by <a href="https://unsplash.com/@chuttersnap" target="_blank" rel="noopener noreferrer" class="">CHUTTERSNAP</a> on <a href="https://unsplash.com/photos/9cCeS9Sg6nU" target="_blank" rel="noopener noreferrer" class="">Unsplash</a></div>
<p>Spring Boot testing library offers an out-of-the box <code>@SpringBootTest</code> annotation that boots the entire application and gets it ready for testing.</p>
<p>However, getting backing services (e.g. databases, caches, message brokers) available and not interfering with
development or other environments might still be a challenging task.</p>
<p>In this post, I'm going to introduce a way to benefit from using containers and JUnit Jupiter extension model to test a
Spring Boot application in an environment that closely resembles the production environment (e.g. a real database instead of an in-memory one).</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="testcontainers">Testcontainers<a href="https://sugarfreebytes.com/ionut-baranga/spring-boot-test-containers-junit-jupiter#testcontainers" class="hash-link" aria-label="Direct link to Testcontainers" title="Direct link to Testcontainers" translate="no">​</a></h2>
<blockquote>
<p>Testcontainers for Java is a Java library that supports JUnit tests, providing lightweight, throwaway instances of
common databases, Selenium web browsers, or anything else that can run in a Docker container.
a project whose purpose is to uniformize and facilitate managing containers from a jvm runtime.</p>
</blockquote>
<p>When combined with the JUnit Jupiter extension model, <a href="https://www.testcontainers.org/" target="_blank" rel="noopener noreferrer" class="">Testcontainers for Java</a> provide
a simple yet powerful way to spin up the necessary backing services in a declarative way.</p>
<p>The <code>@Testcontainers</code> extension supports two container lifecycle modes, depending on how the contained field is
declared.</p>
<ol>
<li class="">
<p>An instance-level <code>@Container</code> annotated container will be restarted after every test method.
This is a good use-case example for a fast-bootstrap container.</p>
<div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token annotation punctuation" style="color:#393A34">@Testcontainers</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">CacheTests</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token annotation punctuation" style="color:#393A34">@Container</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">private</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">final</span><span class="token plain"> </span><span class="token class-name">GenericConainer</span><span class="token plain"> container </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">GenericContainer</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"image-name"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
</li>
<li class="">
<p>A class-level <code>@Container</code> annotated container will be shared across test methods heavy container.
This is a better choice for heavier containers, that takes longer to become available, like a database or a message
broker.</p>
<div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token annotation punctuation" style="color:#393A34">@Testcontainers</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">RepositoryTests</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token annotation punctuation" style="color:#393A34">@Container</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">private</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">static</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">final</span><span class="token plain"> </span><span class="token class-name">GenericConainer</span><span class="token plain"> container </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">GenericContainer</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"image-name"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
</li>
</ol>
<p>In some cases, is worth reusing the containers across the entire set of integration tests.
This can be accomplished by
introducing <a href="https://www.testcontainers.org/test_framework_integration/manual_lifecycle_control/" target="_blank" rel="noopener noreferrer" class="">singleton containers</a>
in a common class that every test-class can extend.</p>
<p>Using static initializers helps to bind the necessary dynamic parameters to the Spring configuration keys using system
properties.</p>
<p>However, using base classes comes with some limitations, as tests that need to reuse multiple containers introduce
complex hierarchies.</p>
<p>One way to overcome these limitations is to introduce custom extensions for each container.</p>
<div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">TestcontainersExtensions</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">static</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">Postgres</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">implements</span><span class="token plain"> </span><span class="token class-name">Extension</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">private</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">static</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">final</span><span class="token plain"> </span><span class="token class-name">PostgreSQLContainer</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics operator" style="color:#393A34">?</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> container</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">static</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">         container </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">PostgreSQLContainer</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"postgres:15.2"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">         container</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">start</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">         </span><span class="token class-name">System</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">setProperty</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"spring.datasource.url"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> container</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">getJdbcUrl</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">         </span><span class="token class-name">System</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">setProperty</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"spring.datasource.username"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> container</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">getUsername</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">         </span><span class="token class-name">System</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">setProperty</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"spring.datasource.password"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> container</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">getPassword</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">static</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">Redis</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">implements</span><span class="token plain"> </span><span class="token class-name">Extension</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">private</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">static</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">final</span><span class="token plain"> </span><span class="token class-name">GenericContainer</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics operator" style="color:#393A34">?</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> container</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token keyword" style="color:#00009f">static</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">         container </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name">GenericContainer</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"redis:7.0.9"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">         container</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">withExposedPorts</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">6379</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">start</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">         </span><span class="token class-name">System</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">setProperty</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"spring.data.redis.host"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"localhost"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">         </span><span class="token class-name">System</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">setProperty</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"spring.data.redis.port"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">String</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">valueOf</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">container</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">getMappedPort</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">6379</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">   </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p>This way, infrastructure details like image name/version and Spring configuration are moved away from test classes and
contained in the custom <code>Extension</code> implementations.</p>
<p>Individual test-classes can choose only the extensions they need. At the same time, extensions imported in multiple
tests will reuse the containers they manage.</p>
<div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token annotation punctuation" style="color:#393A34">@SpringBootTest</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token annotation punctuation" style="color:#393A34">@ExtendWith</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">TestcontainersExtensions</span><span class="token class-name punctuation" style="color:#393A34">.</span><span class="token class-name">Postgres</span><span class="token punctuation" style="color:#393A34">.</span><span class="token keyword" style="color:#00009f">class</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">SomeRepositoryTests</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token annotation punctuation" style="color:#393A34">@SpringBootTest</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token annotation punctuation" style="color:#393A34">@ExtendWith</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">{</span><span class="token class-name">TestcontainersExtensions</span><span class="token class-name punctuation" style="color:#393A34">.</span><span class="token class-name">Postgres</span><span class="token punctuation" style="color:#393A34">.</span><span class="token keyword" style="color:#00009f">class</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">TestcontainersExtensions</span><span class="token class-name punctuation" style="color:#393A34">.</span><span class="token class-name">Redis</span><span class="token punctuation" style="color:#393A34">.</span><span class="token keyword" style="color:#00009f">class</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">SomeRestControllerTests</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>]]></content:encoded>
            <category>spring-boot</category>
            <category>java</category>
            <category>testing</category>
            <category>testcontainers</category>
            <category>junit</category>
        </item>
        <item>
            <title><![CDATA[Sugar-like Series (II): Copy-pasting Code]]></title>
            <link>https://sugarfreebytes.com/ionut-baranga/sugar-like-series-2</link>
            <guid>https://sugarfreebytes.com/ionut-baranga/sugar-like-series-2</guid>
            <pubDate>Thu, 17 Sep 2020 00:00:00 GMT</pubDate>
            <description><![CDATA[Code Quality]]></description>
            <content:encoded><![CDATA[<p><img decoding="async" loading="lazy" alt="Code Quality" src="https://sugarfreebytes.com/assets/images/pexels-34153-computer-keyboard-9a342ef9708965eba44ef9581ed0e58e.jpg" width="1880" height="1253" class="img_ev3q"></p>
<div class="photo-attribution">Photo by <a href="https://www.pexels.com/@negativespace/" target="_blank" rel="noopener noreferrer" class="">Negative Space</a> on <a href="https://www.pexels.com/photo/computer-keyboard-34153/" target="_blank" rel="noopener noreferrer" class="">Pexels</a></div>
<p>It's good, tempting, it comes instantly, but on a long run it will most probably cause some issues. What are the similarities when it comes to building applications?</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="copy-pasting-code">Copy-pasting code<a href="https://sugarfreebytes.com/ionut-baranga/sugar-like-series-2#copy-pasting-code" class="hash-link" aria-label="Direct link to Copy-pasting code" title="Direct link to Copy-pasting code" translate="no">​</a></h2>
<p>So, the requirement is clear-enough so that can be coded.</p>
<p>Other project's sources or some stackoverflow.com snippets seem to be the perfect solution and ready to be integrated with the rest of the codebase.</p>
<p>The problem I see with this approach is that the code being copy-pasted is at most the best version of what a developer could think of at a given point in time, in a given context, for a given problem.</p>
<p>Even if the problem to solve is identical, better options could be currently available:</p>
<ul>
<li class=""><strong>Language improvements</strong> (e.g. using a lambda expression instead of an anonymous instance when creating a Comparator)</li>
<li class=""><strong>API improvements</strong> (e.g. using List.of() instead of a custom method for creating a constant list)</li>
<li class=""><strong>Dependencies improvements</strong>: libraries used by the copied code could no longer be needed, as similar features are now available in the JDK (e.g. benefit from the Stream API instead of depending on guava)</li>
</ul>
<p>By not considering these concerns, the code will inherit the technical debt of the one being copied.</p>
<p>Even if the code is pretty recent and technical debt free, the coding style might not fit the one of the codebase being developed or the requirements related to quality (e.g. Sonar rules).</p>
<p>But it could also be the case that the problem is just similar, but not identical.</p>
<p>It can be simpler, which makes the inserted code over-complex. For instance, the desired return value of a method can be a just a Collection - it doesn't need to be a List, as ordering doesn't matter.</p>
<p>It can have different requirements when it comes to validation. Maybe the copied code is considered safe, as it's intended to be used only internally, while the desired code is intended to be called from the outside world (e.g. from a REST endpoint).</p>
<p>The differences can be so subtle that can only be identified during the testing phases.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="unit-tests">Unit tests<a href="https://sugarfreebytes.com/ionut-baranga/sugar-like-series-2#unit-tests" class="hash-link" aria-label="Direct link to Unit tests" title="Direct link to Unit tests" translate="no">​</a></h2>
<p>There is also a series of things to question when it comes to unit tests and which might signal some red flags if the answer is 'No':</p>
<ul>
<li class="">Is the copied code covered by unit tests?</li>
<li class="">If it does, are they going to get copied as well?</li>
<li class="">Do they still make sense for the functionality being developed?</li>
</ul>
<p>With all that in mind, when it comes to writing code for solving a problem that cannot benefit from using a library or a service or any sort of reusable software component, I find it way cleaner and in the end easier to just write code from scratch, rather than copying code and making all sort of adjustments in order to make it fit the functional, coding style &amp; quality and testing coverage requirements.</p>]]></content:encoded>
            <category>java</category>
            <category>best-practices</category>
            <category>code-quality</category>
        </item>
        <item>
            <title><![CDATA[Wrk-ing Micro-Frameworks' Flavors]]></title>
            <link>https://sugarfreebytes.com/ionut-baranga/wrk-ing-micro-frameworks-flavors</link>
            <guid>https://sugarfreebytes.com/ionut-baranga/wrk-ing-micro-frameworks-flavors</guid>
            <pubDate>Sun, 19 Jul 2020 00:00:00 GMT</pubDate>
            <description><![CDATA[Benchmarks]]></description>
            <content:encoded><![CDATA[<p><img decoding="async" loading="lazy" alt="Benchmarks" src="https://sugarfreebytes.com/assets/images/pexels-pixabay-315934-6a1e61f9efb4603aa30b6daaf23ba3c7.jpg" width="4500" height="3000" class="img_ev3q"></p>
<div class="photo-attribution">Photo by <a href="https://www.pexels.com/@pixabay" target="_blank" rel="noopener noreferrer" class="">Pixabay</a> on <a href="https://www.pexels.com/photo/315934/" target="_blank" rel="noopener noreferrer" class="">Pexels</a></div>
<p>There are many options when it comes to which framework to use for developing JVM-based microservices these days.</p>
<p>In this post, I'm going to summarize how they perform on two simple day-to-day scenarios (with some variations) from
wrk's point of view.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="wrk-tool">Wrk Tool<a href="https://sugarfreebytes.com/ionut-baranga/wrk-ing-micro-frameworks-flavors#wrk-tool" class="hash-link" aria-label="Direct link to Wrk Tool" title="Direct link to Wrk Tool" translate="no">​</a></h2>
<p>While searching a simple cli tool for measuring performance of REST services, I found plenty of references to wrk - a
HTTP benchmarking tool able to generate a significant load while running on a single multi-core CPU of an usual dev
workstation.</p>
<p>Its usage is pretty straightforward: set the test duration, the number of threads and connections those threads are
going to use during the test and optionally add a custom Lua script for making more than a simple GET request.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="test-scenarios">Test Scenarios<a href="https://sugarfreebytes.com/ionut-baranga/wrk-ing-micro-frameworks-flavors#test-scenarios" class="hash-link" aria-label="Direct link to Test Scenarios" title="Direct link to Test Scenarios" translate="no">​</a></h2>
<p>The two test scenarios consist of GETting and POSTing Articles resources, as defined in the gothinkster/realworld
"mother of all demo apps" project.</p>
<p>Both scenarios include:</p>
<ul>
<li class="">Reading the data from memory</li>
<li class="">Using POJOs (requests) responses, (de)serialized with Jackson</li>
<li class="">Varying the resource size, from 50B to 500K</li>
<li class="">Using 10 threads and 100 connections (which will put a decent load on the tested applications)</li>
<li class="">Starting, warming-up the application for 60s, run the test for another 60s, then stopping it</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="spring-boot---the-classic-flavour">Spring Boot - the "Classic Flavour"<a href="https://sugarfreebytes.com/ionut-baranga/wrk-ing-micro-frameworks-flavors#spring-boot---the-classic-flavour" class="hash-link" aria-label="Direct link to Spring Boot - the &quot;Classic Flavour&quot;" title="Direct link to Spring Boot - the &quot;Classic Flavour&quot;" translate="no">​</a></h2>
<p>A Spring <a href="https://github.com/ibaranga/sugarfreebytes/tree/master/wrking-mframeworks/spring-boot" target="_blank" rel="noopener noreferrer" class=""><code>@RestController</code></a></p>
<div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">Controller</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token annotation punctuation" style="color:#393A34">@GetMapping</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token class-name">ResponseEntity</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics operator" style="color:#393A34">?</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getArticles</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token annotation punctuation" style="color:#393A34">@PathVariable</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"path"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token class-name">String</span><span class="token plain"> path</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token annotation punctuation" style="color:#393A34">@PostMapping</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token class-name">ResponseEntity</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics operator" style="color:#393A34">?</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">saveArticles</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token annotation punctuation" style="color:#393A34">@PathVariable</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"path"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token class-name">String</span><span class="token plain"> path</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token annotation punctuation" style="color:#393A34">@RequestBody</span><span class="token plain"> </span><span class="token class-name">Articles</span><span class="token plain"> articles</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="spring-boot-web-flux">Spring Boot Web Flux<a href="https://sugarfreebytes.com/ionut-baranga/wrk-ing-micro-frameworks-flavors#spring-boot-web-flux" class="hash-link" aria-label="Direct link to Spring Boot Web Flux" title="Direct link to Spring Boot Web Flux" translate="no">​</a></h2>
<p>Functional-style <a href="https://github.com/ibaranga/sugarfreebytes/tree/master/wrking-mframeworks/spring-boot-webflux" target="_blank" rel="noopener noreferrer" class="">routes</a></p>
<div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">Configuration</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token class-name">RouterFunction</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">ServerResponse</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">routerFunction</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token function" style="color:#d73a49">route</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">GET</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"/spring-boot-webflux/{path}"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> req </span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">/* ... */</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">and</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">route</span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">POST</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"/spring-boot-webflux/{path}"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> req </span><span class="token operator" style="color:#393A34">-&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">/* */</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="quarkus-w-vertx">Quarkus w/ Vertx<a href="https://sugarfreebytes.com/ionut-baranga/wrk-ing-micro-frameworks-flavors#quarkus-w-vertx" class="hash-link" aria-label="Direct link to Quarkus w/ Vertx" title="Direct link to Quarkus w/ Vertx" translate="no">​</a></h2>
<p>A declarative <a href="https://github.com/ibaranga/sugarfreebytes/tree/master/wrking-mframeworks/quarkus-vertx-web" target="_blank" rel="noopener noreferrer" class="">vertx route</a></p>
<div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">Controller</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token annotation punctuation" style="color:#393A34">@Route</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">path </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"quarkus-vertx-web/:path"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            methods </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">HttpMethod</span><span class="token punctuation" style="color:#393A34">.</span><span class="token constant" style="color:#36acaa">GET</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getArticles</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">RoutingContext</span><span class="token plain"> rc</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token annotation punctuation" style="color:#393A34">@Route</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">path </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"quarkus-vertx-web/:path"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            methods </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">HttpMethod</span><span class="token punctuation" style="color:#393A34">.</span><span class="token constant" style="color:#36acaa">POST</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">saveArticles</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">RoutingContext</span><span class="token plain"> rc</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="micronaut">Micronaut<a href="https://sugarfreebytes.com/ionut-baranga/wrk-ing-micro-frameworks-flavors#micronaut" class="hash-link" aria-label="Direct link to Micronaut" title="Direct link to Micronaut" translate="no">​</a></h2>
<p>A Micronaut <a href="https://github.com/ibaranga/sugarfreebytes/tree/master/wrking-mframeworks/micronaut" target="_blank" rel="noopener noreferrer" class=""><code>@Controller</code></a></p>
<div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">Controller</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token annotation punctuation" style="color:#393A34">@Get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">uri </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"/micronaut/{path}"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token class-name">HttpResponse</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics operator" style="color:#393A34">?</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getArticles</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token annotation punctuation" style="color:#393A34">@PathVariable</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"path"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token class-name">String</span><span class="token plain"> path</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token annotation punctuation" style="color:#393A34">@Post</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">uri </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"/micronaut/{path}"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token class-name">HttpResponse</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics operator" style="color:#393A34">?</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">saveArticles</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token annotation punctuation" style="color:#393A34">@PathVariable</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"path"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token class-name">String</span><span class="token plain"> path</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token annotation punctuation" style="color:#393A34">@Body</span><span class="token plain"> </span><span class="token class-name">Single</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">Articles</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> articles</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="micronaut-reactive">Micronaut Reactive<a href="https://sugarfreebytes.com/ionut-baranga/wrk-ing-micro-frameworks-flavors#micronaut-reactive" class="hash-link" aria-label="Direct link to Micronaut Reactive" title="Direct link to Micronaut Reactive" translate="no">​</a></h2>
<p>A Micronaut <a href="https://github.com/ibaranga/sugarfreebytes/tree/master/wrking-mframeworks/micronaut-reactive" target="_blank" rel="noopener noreferrer" class=""><code>@Controller</code></a> with RxJava requests and responses</p>
<div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">Controller</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token annotation punctuation" style="color:#393A34">@Get</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token class-name">Maybe</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">Articles</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">getArticles</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token annotation punctuation" style="color:#393A34">@PathVariable</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"path"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token class-name">String</span><span class="token plain"> path</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token annotation punctuation" style="color:#393A34">@Post</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token class-name">Maybe</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">Articles</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">saveArticles</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token annotation punctuation" style="color:#393A34">@PathVariable</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"path"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token class-name">String</span><span class="token plain"> path</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token annotation punctuation" style="color:#393A34">@Body</span><span class="token plain"> </span><span class="token class-name">Single</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">Articles</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> articles</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p>The code and <a href="https://github.com/ibaranga/sugarfreebytes/blob/master/wrking-mframeworks/runner/run.sh" target="_blank" rel="noopener noreferrer" class="">test scripts</a> can be found <a href="https://github.com/ibaranga/sugarfreebytes/tree/master/wrking-mframeworks" target="_blank" rel="noopener noreferrer" class="">here</a></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="results">Results<a href="https://sugarfreebytes.com/ionut-baranga/wrk-ing-micro-frameworks-flavors#results" class="hash-link" aria-label="Direct link to Results" title="Direct link to Results" translate="no">​</a></h2>
<p>The smaller the payload is, the bigger the differences between frameworks (and the same framework flavors) are, while when using an extreme payload size it doesn't seem to matter any longer.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="get-scenario">GET Scenario<a href="https://sugarfreebytes.com/ionut-baranga/wrk-ing-micro-frameworks-flavors#get-scenario" class="hash-link" aria-label="Direct link to GET Scenario" title="Direct link to GET Scenario" translate="no">​</a></h3>
<table><thead><tr><th>Mode \ Response Size</th><th>50</th><th>1k</th><th>10K</th><th>100K</th><th>500K</th></tr></thead><tbody><tr><td>quarkus-resteasy</td><td>6000</td><td>5460</td><td>3170</td><td>522</td><td>108</td></tr><tr><td>quarkus-vertx-web</td><td>8030</td><td>7540</td><td>4680</td><td>668</td><td>137</td></tr><tr><td>spring-boot</td><td>4010</td><td>3690</td><td>2520</td><td>585</td><td>134</td></tr><tr><td>spring-boot-webflux</td><td>6860</td><td>6170</td><td>3470</td><td>732</td><td>162</td></tr><tr><td>micronaut</td><td>5610</td><td>4980</td><td>2860</td><td>660</td><td>153</td></tr><tr><td>micronaut-reactive</td><td>6330</td><td>5290</td><td>2840</td><td>599</td><td>130</td></tr></tbody></table>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="post-scenario">POST Scenario<a href="https://sugarfreebytes.com/ionut-baranga/wrk-ing-micro-frameworks-flavors#post-scenario" class="hash-link" aria-label="Direct link to POST Scenario" title="Direct link to POST Scenario" translate="no">​</a></h3>
<table><thead><tr><th>Mode \ Response Size</th><th>50</th><th>1k</th><th>10K</th><th>100K</th><th>500K</th></tr></thead><tbody><tr><td>quarkus-resteasy</td><td>4970</td><td>3850</td><td>1390</td><td>184</td><td>36</td></tr><tr><td>quarkus-vertx-web</td><td>7390</td><td>6000</td><td>1430</td><td>174</td><td>34</td></tr><tr><td>spring-boot</td><td>3340</td><td>2840</td><td>1220</td><td>185</td><td>37</td></tr><tr><td>spring-boot-webflux</td><td>5490</td><td>4030</td><td>1460</td><td>217</td><td>160</td></tr><tr><td>micronaut</td><td>4080</td><td>2910</td><td>1160</td><td>167</td><td>32</td></tr><tr><td>micronaut-reactive</td><td>4360</td><td>3060</td><td>1160</td><td>164</td><td>31</td></tr></tbody></table>]]></content:encoded>
            <category>java</category>
            <category>spring-boot</category>
            <category>quarkus</category>
            <category>micronaut</category>
            <category>performance</category>
            <category>benchmarks</category>
        </item>
        <item>
            <title><![CDATA[Sugar-like Series (I): Unnecessary Mix of Frameworks and Libraries]]></title>
            <link>https://sugarfreebytes.com/ionut-baranga/sugar-like-series-1</link>
            <guid>https://sugarfreebytes.com/ionut-baranga/sugar-like-series-1</guid>
            <pubDate>Mon, 22 Jun 2020 00:00:00 GMT</pubDate>
            <description><![CDATA[Dependencies]]></description>
            <content:encoded><![CDATA[<p><img decoding="async" loading="lazy" alt="Dependencies" src="https://sugarfreebytes.com/assets/images/pexels-kevin-ku-577585-1b336ad8668953c0a113d50cccaf9875.jpg" width="3353" height="2514" class="img_ev3q"></p>
<div class="photo-attribution">Photo by <a href="https://www.pexels.com/@kevin-ku-92347" target="_blank" rel="noopener noreferrer" class="">Kevin Ku</a> on <a href="https://www.pexels.com/photo/577585/" target="_blank" rel="noopener noreferrer" class="">Pexels</a></div>
<p>It's good, tempting, it comes instantly, but on a long run it will most probably cause some issues. What are the similarities when it comes to building applications?</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="unnecessary-mix-of-frameworks-and-libraries">Unnecessary mix of frameworks and libraries<a href="https://sugarfreebytes.com/ionut-baranga/sugar-like-series-1#unnecessary-mix-of-frameworks-and-libraries" class="hash-link" aria-label="Direct link to Unnecessary mix of frameworks and libraries" title="Direct link to Unnecessary mix of frameworks and libraries" translate="no">​</a></h2>
<p>So, adding yet another maven dependency might solve a particular problem "easily" and "for free", we might say. Indeed, adding just a few lines of code in your codebase for using that library seems really tempting, and in the end productive, but:</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="dependency-clash">Dependency Clash<a href="https://sugarfreebytes.com/ionut-baranga/sugar-like-series-1#dependency-clash" class="hash-link" aria-label="Direct link to Dependency Clash" title="Direct link to Dependency Clash" translate="no">​</a></h3>
<p>Is this going to make the dependency hell even worse?</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="licensing">Licensing<a href="https://sugarfreebytes.com/ionut-baranga/sugar-like-series-1#licensing" class="hash-link" aria-label="Direct link to Licensing" title="Direct link to Licensing" translate="no">​</a></h3>
<p>How is that library licensed? Is it in line with the rest of the policies?</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="size">Size<a href="https://sugarfreebytes.com/ionut-baranga/sugar-like-series-1#size" class="hash-link" aria-label="Direct link to Size" title="Direct link to Size" translate="no">​</a></h3>
<p>What is the size of that library? Will it significantly increase your build size, transfer time, application memory usage?</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="security">Security<a href="https://sugarfreebytes.com/ionut-baranga/sugar-like-series-1#security" class="hash-link" aria-label="Direct link to Security" title="Direct link to Security" translate="no">​</a></h3>
<p>How about the security? Does it come from a trustworthy source? (<a href="https://qz.com/646467/how-one-programmer-broke-the-internet-by-deleting-a-tiny-piece-of-code/" target="_blank" rel="noopener noreferrer" class="">How one programmer broke the internet</a>)</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="coding-style">Coding style<a href="https://sugarfreebytes.com/ionut-baranga/sugar-like-series-1#coding-style" class="hash-link" aria-label="Direct link to Coding style" title="Direct link to Coding style" translate="no">​</a></h3>
<p>Does that library API affect the overall coding style of the codebase?
E.g. Is it worth introducing an Rx-ified library while the rest of the code is entirely synchronous?</p>
<hr>
<p>In order to properly address this kind of checklist, you might need to spend some serious time.</p>
<p>In the end, it could take less to just implement yourself that functionality.</p>
<p>On top of that, using one of the "pure" platforms (JavaEE containers, Spring Boot, Quarkus, Micronaut, Helidon) should usually cover most of the needs for regular applications. And such an approach comes with a huge advantage - all the pieces are tested and released together and you don't need to worry about individual libraries versions (e.g. Jackson).</p>]]></content:encoded>
            <category>java</category>
            <category>best-practices</category>
            <category>dependencies</category>
        </item>
        <item>
            <title><![CDATA[Declarative Spring Application Events]]></title>
            <link>https://sugarfreebytes.com/ionut-baranga/declarative-spring-application-events</link>
            <guid>https://sugarfreebytes.com/ionut-baranga/declarative-spring-application-events</guid>
            <pubDate>Fri, 12 Jun 2020 00:00:00 GMT</pubDate>
            <description><![CDATA[Spring Events]]></description>
            <content:encoded><![CDATA[<p><img decoding="async" loading="lazy" alt="Spring Events" src="https://sugarfreebytes.com/assets/images/pexels-pixabay-414579-5e8beef75e82da375d6d89c06e8ae88f.jpg" width="4032" height="3024" class="img_ev3q"></p>
<div class="photo-attribution">Photo by <a href="https://www.pexels.com/@pixabay" target="_blank" rel="noopener noreferrer" class="">Pixabay</a> on <a href="https://www.pexels.com/photo/414579/" target="_blank" rel="noopener noreferrer" class="">Pexels</a></div>
<p>Spring allows us to publish <code>ApplicationEvent</code> instances using the managed <code>ApplicationEventPublisher</code> instance.</p>
<p>Each such ApplicationEvent can be consumed by the interested parties by annotating methods with <code>@EventListener</code> or
<code>@TransactionalEventListener</code>.</p>
<p>Let's consider the following example: during development and testing, each time we get an UserEvent event, we want to
log it.</p>
<div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">UserEvent</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">extends</span><span class="token plain"> </span><span class="token class-name">ApplicationEvent</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// ...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">UserLoginEvent</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">extends</span><span class="token plain"> </span><span class="token class-name">UserEvent</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// ...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">UserRegisterEvent</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">extends</span><span class="token plain"> </span><span class="token class-name">UserEvent</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// ...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">UserLoginService</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">private</span><span class="token plain"> </span><span class="token class-name">ApplicationEventPublisher</span><span class="token plain"> applicationEventPublisher</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">//...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token class-name">UserLoginEvent</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">login</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">String</span><span class="token plain"> loginToken</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token class-name">UserLoginEvent</span><span class="token plain"> userEvent</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">//  =  ...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        applicationEventPublisher</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">publish</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">userEvent</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> userEvent</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token annotation punctuation" style="color:#393A34">@Component</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token annotation punctuation" style="color:#393A34">@Profile</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"dev"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">UserEventLogger</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token annotation punctuation" style="color:#393A34">@EventListener</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">onUserEvent</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">UserEvent</span><span class="token plain"> userEvent</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token constant" style="color:#36acaa">LOGGER</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">info</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"User event {}"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> userEvent</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p>From a consumer perspective, it seems very loose-coupling.</p>
<p><strong>But how about the producer?</strong></p>
<p>Every class that is interested in publishing application events needs an <code>ApplicationEventPublisher</code> instance.
And even though Spring provides one out-of-the-box, it's still another dependency to add to all the classes that need it.
Maybe it's not so demanding, but how about having more classes publishing events? Is it worth doing the same work everywhere?</p>
<div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">UserRegistrationService</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">private</span><span class="token plain"> </span><span class="token class-name">ApplicationEventPublisher</span><span class="token plain"> applicationEventPublisher</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token class-name">UserRegisterEvent</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">register</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">UserRegistrationData</span><span class="token plain"> data</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// ...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token class-name">UserRegisterEvent</span><span class="token plain"> userEvent</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// = ...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        applicationEventPublisher</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">publish</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">userEvent</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> userEvent</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p>How about having a corresponding declarative mechanism for publishing application events the same way we have for
consuming them?</p>
<p>For this, we need a way to identify those methods interested in publishing events.
And what could be more useful to get from a method signature than the return value?</p>
<p>So we need to identify some (public) non-void methods
that can return ... anything. Not so suitable for interfaces, right?</p>
<p>Here's where AOP might help us.</p>
<p>Let's keep it exactly the same as Spring already allows methods to declare themselves event consumers; let
EventPublisher be the equivalent annotation. In this case:</p>
<div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">UserLoginService</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// ...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token annotation punctuation" style="color:#393A34">@EventPublisher</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token class-name">UserLoginEvent</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">login</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">String</span><span class="token plain"> loginToken</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token class-name">UserLoginEvent</span><span class="token plain"> userEvent</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// = ...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> userEvent</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">UserRegistrationService</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// ...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token annotation punctuation" style="color:#393A34">@EventPublisher</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token class-name">UserRegisterEvent</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">register</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">UserRegistrationData</span><span class="token plain"> data</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic">// ...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token class-name">UserRegisterEvent</span><span class="token plain"> userEvent</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// = ...</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> userEvent</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p>Now we still need to inject the <code>ApplicationEventPublisher</code>, but it's going to happen in a single place:
that is an aspect that is executed after each <code>@EventPublisher</code> that returns a subclass of <code>ApplicationEvent</code>.</p>
<div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">class</span><span class="token plain"> </span><span class="token class-name">EventPublisherAspect</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">private</span><span class="token plain"> </span><span class="token class-name">ApplicationEventPublisher</span><span class="token plain"> applicationEventPublisher</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token annotation punctuation" style="color:#393A34">@AfterReturning</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"@annotation(EventPublisher) &amp;&amp; execution(ApplicationEvent+ *(..)"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">public</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">publishApplicationEvent</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">ApplicationEvent</span><span class="token plain"> event</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        applicationEventPublisher</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">publish</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">event</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>]]></content:encoded>
            <category>spring</category>
            <category>java</category>
            <category>aop</category>
            <category>events</category>
        </item>
    </channel>
</rss>