<?xml version="1.0" encoding="utf-8"?>
<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>Maciej Walkowiak - Java &amp; Spring</title>
        <link>https://maciejwalkowiak.com</link>
        <description>Maciej Walkowiak - Java &amp; Spring - Freelance Software Consultant</description>
        <lastBuildDate>Wed, 28 Aug 2024 17:19:12 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <copyright>Copyright (c) 2019-present, Maciej Walkowiak</copyright>
        <item>
            <title><![CDATA[Generating HTTP clients in Spring Boot application from OpenAPI spec]]></title>
            <link>https://maciejwalkowiak.com/blog/spring-boot-openapi-generate-client/</link>
            <guid>https://maciejwalkowiak.com/blog/spring-boot-openapi-generate-client/</guid>
            <pubDate>Thu, 25 Jul 2024 09:00:00 GMT</pubDate>
            <description><![CDATA[<p>In this step-by-step tutorial you will learn how to generate <strong>HTTP client code</strong> for <strong>Spring Boot</strong> application from <strong>OpenAPI</strong> spec using <a href="https://openapi-generator.tech/" target="_blank" rel="noreferrer">openapi-generator</a> <strong>Gradle</strong> plugin.</p>
]]></description>
            <content:encoded><![CDATA[<p>In this step-by-step tutorial you will learn how to generate <strong>HTTP client code</strong> for <strong>Spring Boot</strong> application from <strong>OpenAPI</strong> spec using <a href="https://openapi-generator.tech/" target="_blank" rel="noreferrer">openapi-generator</a> <strong>Gradle</strong> plugin.</p>
]]></content:encoded>
            <enclosure url="https://maciejwalkowiak.com/og-images/spring-boot-openapi-generate-client.jpeg" length="0" type="image/jpeg"/>
        </item>
        <item>
            <title><![CDATA[PostgreSQL and UUID as primary key]]></title>
            <link>https://maciejwalkowiak.com/blog/postgres-uuid-primary-key/</link>
            <guid>https://maciejwalkowiak.com/blog/postgres-uuid-primary-key/</guid>
            <pubDate>Thu, 18 Apr 2024 09:00:00 GMT</pubDate>
            <description><![CDATA[<p><strong>UUID</strong>s are often used as database table <strong>primary keys</strong>. They are easy to generate, easy to share between distributed systems and guarantee uniqueness.</p>
<p>Considering the size of UUID it is questionable if it is a right choice, but often it is not up to us to decide.</p>
<p>This article does not focus on &quot;<em>if UUID is the right format for a key</em>&quot;, but how to use <strong>UUID</strong> as a primary key with <strong>PostgreSQL</strong> efficiently.</p>
]]></description>
            <content:encoded><![CDATA[<p><strong>UUID</strong>s are often used as database table <strong>primary keys</strong>. They are easy to generate, easy to share between distributed systems and guarantee uniqueness.</p>
<p>Considering the size of UUID it is questionable if it is a right choice, but often it is not up to us to decide.</p>
<p>This article does not focus on &quot;<em>if UUID is the right format for a key</em>&quot;, but how to use <strong>UUID</strong> as a primary key with <strong>PostgreSQL</strong> efficiently.</p>
]]></content:encoded>
            <enclosure url="https://maciejwalkowiak.com/og-images/postgresql-uuid-primary-key.jpeg" length="0" type="image/jpeg"/>
        </item>
        <item>
            <title><![CDATA[Dynamic Projections with Spring Data JPA]]></title>
            <link>https://maciejwalkowiak.com/blog/spring-data-jpa-dynamic-projections/</link>
            <guid>https://maciejwalkowiak.com/blog/spring-data-jpa-dynamic-projections/</guid>
            <pubDate>Mon, 15 Apr 2024 09:00:00 GMT</pubDate>
            <description><![CDATA[<div class="tip custom-block"><p class="custom-block-title">TIP</p>
<p><strong>Projection</strong> is a subset of an <strong>aggregate</strong> loaded from a <strong>repository</strong> for <strong>read-only</strong> purposes.</p>
</div>
<p>Methods returning projections are typically defined on the repository level, making the repository interface aware of all possible types of projections used in the application.</p>
<div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre v-pre class="shiki one-dark-pro" ><code><span class="line"><span style="color: #C678DD">package</span><span style="color: #E06C75"> </span><span style="color: #C678DD">com.app.account.domain</span><span style="color: #ABB2BF">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #C678DD">public</span><span style="color: #E06C75"> </span><span style="color: #C678DD">interface</span><span style="color: #E06C75"> </span><span style="color: #E5C07B">AccountRepository</span><span style="color: #E06C75"> </span><span style="color: #C678DD">extends</span><span style="color: #E06C75"> </span><span style="color: #E5C07B">Repository</span><span style="color: #ABB2BF">&lt;</span><span style="color: #E5C07B">Account</span><span style="color: #ABB2BF">,</span><span style="color: #E06C75"> </span><span style="color: #E5C07B">String</span><span style="color: #ABB2BF">&gt;</span><span style="color: #E06C75"> </span><span style="color: #ABB2BF">{</span></span>
<span class="line"><span style="color: #E06C75">    </span><span style="color: #E5C07B">AccountBasic</span><span style="color: #61AFEF"> findAccountBasicById</span><span style="color: #ABB2BF">(</span><span style="color: #E5C07B">String</span><span style="color: #ABB2BF"> </span><span style="color: #E06C75; font-style: italic">id</span><span style="color: #ABB2BF">);</span></span>
<span class="line"><span style="color: #E06C75">    </span><span style="color: #E5C07B">AccountComplete</span><span style="color: #61AFEF"> findAccountCompleteById</span><span style="color: #ABB2BF">(</span><span style="color: #E5C07B">String</span><span style="color: #ABB2BF"> </span><span style="color: #E06C75; font-style: italic">id</span><span style="color: #ABB2BF">);</span></span>
<span class="line"><span style="color: #ABB2BF">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #C678DD">public</span><span style="color: #E06C75"> </span><span style="color: #C678DD">record</span><span style="color: #E06C75"> </span><span style="color: #E5C07B">AccountBasic</span><span style="color: #E06C75">(</span><span style="color: #E5C07B">String</span><span style="color: #E06C75"> id</span><span style="color: #ABB2BF">,</span><span style="color: #E06C75"> </span></span>
<span class="line"><span style="color: #E06C75">                           </span><span style="color: #E5C07B">String</span><span style="color: #E06C75"> iban</span><span style="color: #ABB2BF">,</span></span>
<span class="line"><span style="color: #E06C75">                           </span><span style="color: #E5C07B">String</span><span style="color: #E06C75"> bic) </span><span style="color: #ABB2BF">{}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #C678DD">public</span><span style="color: #E06C75"> </span><span style="color: #C678DD">record</span><span style="color: #E06C75"> </span><span style="color: #E5C07B">AccountComplete</span><span style="color: #E06C75">(</span><span style="color: #E5C07B">String</span><span style="color: #E06C75"> id</span><span style="color: #ABB2BF">,</span></span>
<span class="line"><span style="color: #E06C75">                       </span><span style="color: #E5C07B">String</span><span style="color: #E06C75"> iban</span><span style="color: #ABB2BF">,</span></span>
<span class="line"><span style="color: #E06C75">                       </span><span style="color: #E5C07B">String</span><span style="color: #E06C75"> bic</span><span style="color: #ABB2BF">,</span></span>
<span class="line"><span style="color: #E06C75">                       </span><span style="color: #E5C07B">State</span><span style="color: #E06C75"> state</span><span style="color: #ABB2BF">,</span></span>
<span class="line"><span style="color: #E06C75">                       </span><span style="color: #E5C07B">Type</span><span style="color: #E06C75"> type</span><span style="color: #ABB2BF">,</span></span>
<span class="line"><span style="color: #E06C75">                       </span><span style="color: #E5C07B">LocalDateTime</span><span style="color: #E06C75"> createdAt) </span><span style="color: #ABB2BF">{}</span></span></code></pre>
</div><p>This approach has some drawbacks:</p>
<ul>
<li>if there is a projection that <em>almost</em> fits our use case, it is tempting to modify it and add needed field - at the same time defeating a bit the main purpose of projections - fetching only what's needed.</li>
<li>naming projections becomes a challenge - how to name them? <code>AccountBasic</code>? <code>AccountLight</code>? <code>AccountData</code>? All these names are quite meaningless.</li>
<li>repository becomes difficult to use as it contains a long list of method, and to find out which one should be used you need to visit every projection.</li>
<li>because projections are shared between use cases, they become a coupling point, making future refactoring more difficult.</li>
<li>projections must have the same visibility level as the repository, for example if repository is public, projections must be public too.</li>
</ul>
<p>Instead of making the repository aware of all types projections used by all the use cases, we can use <strong>dynamic projections</strong>.</p>
]]></description>
            <content:encoded><![CDATA[<div class="tip custom-block"><p class="custom-block-title">TIP</p>
<p><strong>Projection</strong> is a subset of an <strong>aggregate</strong> loaded from a <strong>repository</strong> for <strong>read-only</strong> purposes.</p>
</div>
<p>Methods returning projections are typically defined on the repository level, making the repository interface aware of all possible types of projections used in the application.</p>
<div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre v-pre class="shiki one-dark-pro" ><code><span class="line"><span style="color: #C678DD">package</span><span style="color: #E06C75"> </span><span style="color: #C678DD">com.app.account.domain</span><span style="color: #ABB2BF">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #C678DD">public</span><span style="color: #E06C75"> </span><span style="color: #C678DD">interface</span><span style="color: #E06C75"> </span><span style="color: #E5C07B">AccountRepository</span><span style="color: #E06C75"> </span><span style="color: #C678DD">extends</span><span style="color: #E06C75"> </span><span style="color: #E5C07B">Repository</span><span style="color: #ABB2BF">&lt;</span><span style="color: #E5C07B">Account</span><span style="color: #ABB2BF">,</span><span style="color: #E06C75"> </span><span style="color: #E5C07B">String</span><span style="color: #ABB2BF">&gt;</span><span style="color: #E06C75"> </span><span style="color: #ABB2BF">{</span></span>
<span class="line"><span style="color: #E06C75">    </span><span style="color: #E5C07B">AccountBasic</span><span style="color: #61AFEF"> findAccountBasicById</span><span style="color: #ABB2BF">(</span><span style="color: #E5C07B">String</span><span style="color: #ABB2BF"> </span><span style="color: #E06C75; font-style: italic">id</span><span style="color: #ABB2BF">);</span></span>
<span class="line"><span style="color: #E06C75">    </span><span style="color: #E5C07B">AccountComplete</span><span style="color: #61AFEF"> findAccountCompleteById</span><span style="color: #ABB2BF">(</span><span style="color: #E5C07B">String</span><span style="color: #ABB2BF"> </span><span style="color: #E06C75; font-style: italic">id</span><span style="color: #ABB2BF">);</span></span>
<span class="line"><span style="color: #ABB2BF">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #C678DD">public</span><span style="color: #E06C75"> </span><span style="color: #C678DD">record</span><span style="color: #E06C75"> </span><span style="color: #E5C07B">AccountBasic</span><span style="color: #E06C75">(</span><span style="color: #E5C07B">String</span><span style="color: #E06C75"> id</span><span style="color: #ABB2BF">,</span><span style="color: #E06C75"> </span></span>
<span class="line"><span style="color: #E06C75">                           </span><span style="color: #E5C07B">String</span><span style="color: #E06C75"> iban</span><span style="color: #ABB2BF">,</span></span>
<span class="line"><span style="color: #E06C75">                           </span><span style="color: #E5C07B">String</span><span style="color: #E06C75"> bic) </span><span style="color: #ABB2BF">{}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #C678DD">public</span><span style="color: #E06C75"> </span><span style="color: #C678DD">record</span><span style="color: #E06C75"> </span><span style="color: #E5C07B">AccountComplete</span><span style="color: #E06C75">(</span><span style="color: #E5C07B">String</span><span style="color: #E06C75"> id</span><span style="color: #ABB2BF">,</span></span>
<span class="line"><span style="color: #E06C75">                       </span><span style="color: #E5C07B">String</span><span style="color: #E06C75"> iban</span><span style="color: #ABB2BF">,</span></span>
<span class="line"><span style="color: #E06C75">                       </span><span style="color: #E5C07B">String</span><span style="color: #E06C75"> bic</span><span style="color: #ABB2BF">,</span></span>
<span class="line"><span style="color: #E06C75">                       </span><span style="color: #E5C07B">State</span><span style="color: #E06C75"> state</span><span style="color: #ABB2BF">,</span></span>
<span class="line"><span style="color: #E06C75">                       </span><span style="color: #E5C07B">Type</span><span style="color: #E06C75"> type</span><span style="color: #ABB2BF">,</span></span>
<span class="line"><span style="color: #E06C75">                       </span><span style="color: #E5C07B">LocalDateTime</span><span style="color: #E06C75"> createdAt) </span><span style="color: #ABB2BF">{}</span></span></code></pre>
</div><p>This approach has some drawbacks:</p>
<ul>
<li>if there is a projection that <em>almost</em> fits our use case, it is tempting to modify it and add needed field - at the same time defeating a bit the main purpose of projections - fetching only what's needed.</li>
<li>naming projections becomes a challenge - how to name them? <code>AccountBasic</code>? <code>AccountLight</code>? <code>AccountData</code>? All these names are quite meaningless.</li>
<li>repository becomes difficult to use as it contains a long list of method, and to find out which one should be used you need to visit every projection.</li>
<li>because projections are shared between use cases, they become a coupling point, making future refactoring more difficult.</li>
<li>projections must have the same visibility level as the repository, for example if repository is public, projections must be public too.</li>
</ul>
<p>Instead of making the repository aware of all types projections used by all the use cases, we can use <strong>dynamic projections</strong>.</p>
]]></content:encoded>
            <enclosure url="https://maciejwalkowiak.com/og-images/spring-data-jpa-dynamic-projections.jpeg" length="0" type="image/jpeg"/>
        </item>
        <item>
            <title><![CDATA[Container logs with Spring Boot and Testcontainers]]></title>
            <link>https://maciejwalkowiak.com/blog/testcontainers-spring-boot-container-logs/</link>
            <guid>https://maciejwalkowiak.com/blog/testcontainers-spring-boot-container-logs/</guid>
            <pubDate>Sat, 23 Mar 2024 09:00:00 GMT</pubDate>
            <description><![CDATA[<p>In this article you will learn how to enable <strong>container debug logs</strong> with <strong>Testcontainers</strong> and <strong>Spring Boot</strong> and how to leverage Spring Framework flexibility to turn logs on and off with a custom <code>@EnableContainerLogs</code> annotation.
As a side effect you'll learn a little about Spring Framework internals enabling Spring's <strong>magic ✨</strong>.</p>
]]></description>
            <content:encoded><![CDATA[<p>In this article you will learn how to enable <strong>container debug logs</strong> with <strong>Testcontainers</strong> and <strong>Spring Boot</strong> and how to leverage Spring Framework flexibility to turn logs on and off with a custom <code>@EnableContainerLogs</code> annotation.
As a side effect you'll learn a little about Spring Framework internals enabling Spring's <strong>magic ✨</strong>.</p>
]]></content:encoded>
            <enclosure url="https://maciejwalkowiak.com/og-images/testcontainers-spring-boot-container-logs.jpeg" length="0" type="image/jpeg"/>
        </item>
        <item>
            <title><![CDATA[Reified Generics in Java?]]></title>
            <link>https://maciejwalkowiak.com/blog/java-reified-generics/</link>
            <guid>https://maciejwalkowiak.com/blog/java-reified-generics/</guid>
            <pubDate>Mon, 23 Oct 2023 09:00:00 GMT</pubDate>
            <description><![CDATA[<p>A common pattern in Java, whenever there is a need retrieve data from a database or deserialize JSON is to pass the target object class as a parameter.</p>
<p>A good example is Jackson's <code>ObjectMapper#readValue</code> method with following signature:</p>
<div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre v-pre class="shiki one-dark-pro" ><code><span class="line"><span style="color: #C678DD">public</span><span style="color: #E06C75"> </span><span style="color: #56B6C2">&lt;</span><span style="color: #E06C75">T</span><span style="color: #56B6C2">&gt;</span><span style="color: #E06C75"> </span><span style="color: #E5C07B">T</span><span style="color: #E06C75"> </span><span style="color: #61AFEF">readValue</span><span style="color: #E06C75">(</span><span style="color: #E5C07B">String</span><span style="color: #E06C75"> content</span><span style="color: #ABB2BF">,</span><span style="color: #E06C75"> </span><span style="color: #E5C07B">Class</span><span style="color: #56B6C2">&lt;</span><span style="color: #E06C75">T</span><span style="color: #56B6C2">&gt;</span><span style="color: #E06C75"> valueType) {</span></span>
<span class="line"><span style="color: #E06C75">    </span><span style="color: #ABB2BF">...</span></span>
<span class="line"><span style="color: #E06C75">}</span></span></code></pre>
</div><p>Passing class as a parameter looks repetitive. Since <code>&lt;T&gt;</code> defines the type, why do we need to pass <code>Class&lt;T&gt;</code>? Why it can't be simplified to:</p>
<div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre v-pre class="shiki one-dark-pro" ><code><span class="line"><span style="color: #C678DD">public</span><span style="color: #E06C75"> </span><span style="color: #56B6C2">&lt;</span><span style="color: #E06C75">T</span><span style="color: #56B6C2">&gt;</span><span style="color: #E06C75"> </span><span style="color: #E5C07B">T</span><span style="color: #E06C75"> </span><span style="color: #61AFEF">readValue</span><span style="color: #E06C75">(</span><span style="color: #E5C07B">String</span><span style="color: #E06C75"> content) {</span></span>
<span class="line"><span style="color: #E06C75">    </span><span style="color: #ABB2BF">...</span></span>
<span class="line"><span style="color: #E06C75">}</span></span></code></pre>
</div><p>And most importantly, how is Mockito able to find out the type of mock in such code?</p>
<div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre v-pre class="shiki one-dark-pro" ><code><span class="line"><span style="color: #E5C07B">Book</span><span style="color: #E06C75"> book </span><span style="color: #56B6C2">=</span><span style="color: #E06C75"> </span><span style="color: #61AFEF">mock</span><span style="color: #E06C75">()</span><span style="color: #ABB2BF">;</span></span>
<span class="line"><span style="color: #E5C07B">Person</span><span style="color: #E06C75"> person </span><span style="color: #56B6C2">=</span><span style="color: #E06C75"> </span><span style="color: #61AFEF">mock</span><span style="color: #E06C75">()</span><span style="color: #ABB2BF">;</span></span></code></pre>
</div><p><img src="/what-kind-of-sorcery.jpeg" alt="What kind of sorcery is that?"></p>
]]></description>
            <content:encoded><![CDATA[<p>A common pattern in Java, whenever there is a need retrieve data from a database or deserialize JSON is to pass the target object class as a parameter.</p>
<p>A good example is Jackson's <code>ObjectMapper#readValue</code> method with following signature:</p>
<div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre v-pre class="shiki one-dark-pro" ><code><span class="line"><span style="color: #C678DD">public</span><span style="color: #E06C75"> </span><span style="color: #56B6C2">&lt;</span><span style="color: #E06C75">T</span><span style="color: #56B6C2">&gt;</span><span style="color: #E06C75"> </span><span style="color: #E5C07B">T</span><span style="color: #E06C75"> </span><span style="color: #61AFEF">readValue</span><span style="color: #E06C75">(</span><span style="color: #E5C07B">String</span><span style="color: #E06C75"> content</span><span style="color: #ABB2BF">,</span><span style="color: #E06C75"> </span><span style="color: #E5C07B">Class</span><span style="color: #56B6C2">&lt;</span><span style="color: #E06C75">T</span><span style="color: #56B6C2">&gt;</span><span style="color: #E06C75"> valueType) {</span></span>
<span class="line"><span style="color: #E06C75">    </span><span style="color: #ABB2BF">...</span></span>
<span class="line"><span style="color: #E06C75">}</span></span></code></pre>
</div><p>Passing class as a parameter looks repetitive. Since <code>&lt;T&gt;</code> defines the type, why do we need to pass <code>Class&lt;T&gt;</code>? Why it can't be simplified to:</p>
<div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre v-pre class="shiki one-dark-pro" ><code><span class="line"><span style="color: #C678DD">public</span><span style="color: #E06C75"> </span><span style="color: #56B6C2">&lt;</span><span style="color: #E06C75">T</span><span style="color: #56B6C2">&gt;</span><span style="color: #E06C75"> </span><span style="color: #E5C07B">T</span><span style="color: #E06C75"> </span><span style="color: #61AFEF">readValue</span><span style="color: #E06C75">(</span><span style="color: #E5C07B">String</span><span style="color: #E06C75"> content) {</span></span>
<span class="line"><span style="color: #E06C75">    </span><span style="color: #ABB2BF">...</span></span>
<span class="line"><span style="color: #E06C75">}</span></span></code></pre>
</div><p>And most importantly, how is Mockito able to find out the type of mock in such code?</p>
<div class="language-java"><button title="Copy Code" class="copy"></button><span class="lang">java</span><pre v-pre class="shiki one-dark-pro" ><code><span class="line"><span style="color: #E5C07B">Book</span><span style="color: #E06C75"> book </span><span style="color: #56B6C2">=</span><span style="color: #E06C75"> </span><span style="color: #61AFEF">mock</span><span style="color: #E06C75">()</span><span style="color: #ABB2BF">;</span></span>
<span class="line"><span style="color: #E5C07B">Person</span><span style="color: #E06C75"> person </span><span style="color: #56B6C2">=</span><span style="color: #E06C75"> </span><span style="color: #61AFEF">mock</span><span style="color: #E06C75">()</span><span style="color: #ABB2BF">;</span></span></code></pre>
</div><p><img src="/what-kind-of-sorcery.jpeg" alt="What kind of sorcery is that?"></p>
]]></content:encoded>
            <enclosure url="https://maciejwalkowiak.com/og-images/reified-generics-java.jpeg" length="0" type="image/jpeg"/>
        </item>
        <item>
            <title><![CDATA[Faster integration tests with reusable Testcontainers and Flyway]]></title>
            <link>https://maciejwalkowiak.com/blog/testcontainers-reusable-flyway/</link>
            <guid>https://maciejwalkowiak.com/blog/testcontainers-reusable-flyway/</guid>
            <pubDate>Sun, 15 Oct 2023 09:00:00 GMT</pubDate>
            <description><![CDATA[<div class="info custom-block"><p class="custom-block-title">INFO</p>
<p>Advice given in this article is especially relevant to applications with hundreds of Flyway migration files.</p>
</div>
<p>In <a href="/blog/spring-boot-flyway-clear-database-integration-tests/">Spring Boot &amp; Flyway - clear database between integration tests</a> I described how to ensure that each integration test starts with clean state - wipe out content from the database, and all database migrations applied from scratch. Such approach simplifies writing tests but comes with one significant drawback - running database migration takes time. The more migration files, the longer it takes. I still believe this is a solution worth considering for small services, but for large applications with hundreds or thousands of migrations, time needed to run migrations may become a biggest factor contributing to slow integration tests.</p>
<p>In this article I'll explore how <a href="https://java.testcontainers.org/features/reuse/" target="_blank" rel="noreferrer">reusable containers</a> can significantly <strong>speed up integration tests during development phase</strong> and how to configure Flyway to use them efficiently.</p>
]]></description>
            <content:encoded><![CDATA[<div class="info custom-block"><p class="custom-block-title">INFO</p>
<p>Advice given in this article is especially relevant to applications with hundreds of Flyway migration files.</p>
</div>
<p>In <a href="/blog/spring-boot-flyway-clear-database-integration-tests/">Spring Boot &amp; Flyway - clear database between integration tests</a> I described how to ensure that each integration test starts with clean state - wipe out content from the database, and all database migrations applied from scratch. Such approach simplifies writing tests but comes with one significant drawback - running database migration takes time. The more migration files, the longer it takes. I still believe this is a solution worth considering for small services, but for large applications with hundreds or thousands of migrations, time needed to run migrations may become a biggest factor contributing to slow integration tests.</p>
<p>In this article I'll explore how <a href="https://java.testcontainers.org/features/reuse/" target="_blank" rel="noreferrer">reusable containers</a> can significantly <strong>speed up integration tests during development phase</strong> and how to configure Flyway to use them efficiently.</p>
]]></content:encoded>
            <enclosure url="https://maciejwalkowiak.com/og-images/testcontainers-reusable-flyway.jpeg" length="0" type="image/jpeg"/>
        </item>
        <item>
            <title><![CDATA[Running one-time jobs with Quartz and Spring Boot]]></title>
            <link>https://maciejwalkowiak.com/blog/spring-boot-quartz-one-time-job/</link>
            <guid>https://maciejwalkowiak.com/blog/spring-boot-quartz-one-time-job/</guid>
            <pubDate>Thu, 27 Apr 2023 09:00:00 GMT</pubDate>
            <description><![CDATA[<p>Scheduling jobs with <a href="http://www.quartz-scheduler.org/" target="_blank" rel="noreferrer">Quartz</a> has been discussed numerous times. However, it is worth to know that Quartz can be used not just
to run jobs every X hours or based on a CRON expression, but also to execute specific code <strong>once at a specified time in the future</strong>.</p>
<p>I believe that in some specific use cases, following this approach can dramatically simplify your architecture and implementation.
Let's see step by step how to do it.</p>
]]></description>
            <content:encoded><![CDATA[<p>Scheduling jobs with <a href="http://www.quartz-scheduler.org/" target="_blank" rel="noreferrer">Quartz</a> has been discussed numerous times. However, it is worth to know that Quartz can be used not just
to run jobs every X hours or based on a CRON expression, but also to execute specific code <strong>once at a specified time in the future</strong>.</p>
<p>I believe that in some specific use cases, following this approach can dramatically simplify your architecture and implementation.
Let's see step by step how to do it.</p>
]]></content:encoded>
            <enclosure url="https://maciejwalkowiak.com/og-images/spring-boot-quartz-one-time-job.jpeg" length="0" type="image/jpeg"/>
        </item>
        <item>
            <title><![CDATA[The best way to use Testcontainers with Spring Boot]]></title>
            <link>https://maciejwalkowiak.com/blog/testcontainers-spring-boot-setup/</link>
            <guid>https://maciejwalkowiak.com/blog/testcontainers-spring-boot-setup/</guid>
            <pubDate>Wed, 22 Feb 2023 09:00:00 GMT</pubDate>
            <description><![CDATA[<p>&quot;How to set up <a href="https://testcontainers.org/" target="_blank" rel="noreferrer">Testcontainers</a> with Spring Boot&quot; has already been described hundreds times. I am not going to write the same things that have already been said but rather discuss the pros and cons of the existing solutions and present one that works for me and I believe <strong>works for majority of projects</strong>.</p>
<p>Specifically, I am looking for a solution that meets following criteria:</p>
<ul>
<li><strong>as little overhead as possible</strong>
<ul>
<li>containers are started only <strong>once</strong> for all tests</li>
<li>containers are started in <strong>parallel</strong></li>
</ul>
</li>
<li><strong>no requirement for test inheritance</strong></li>
<li><strong>declarative</strong> usage</li>
</ul>
]]></description>
            <content:encoded><![CDATA[<p>&quot;How to set up <a href="https://testcontainers.org/" target="_blank" rel="noreferrer">Testcontainers</a> with Spring Boot&quot; has already been described hundreds times. I am not going to write the same things that have already been said but rather discuss the pros and cons of the existing solutions and present one that works for me and I believe <strong>works for majority of projects</strong>.</p>
<p>Specifically, I am looking for a solution that meets following criteria:</p>
<ul>
<li><strong>as little overhead as possible</strong>
<ul>
<li>containers are started only <strong>once</strong> for all tests</li>
<li>containers are started in <strong>parallel</strong></li>
</ul>
</li>
<li><strong>no requirement for test inheritance</strong></li>
<li><strong>declarative</strong> usage</li>
</ul>
]]></content:encoded>
            <enclosure url="https://maciejwalkowiak.com/og-images/testcontainers-spring-boot-setup.jpeg" length="0" type="image/jpeg"/>
        </item>
        <item>
            <title><![CDATA[Spring Boot & Flyway - clear database between integration tests]]></title>
            <link>https://maciejwalkowiak.com/blog/spring-boot-flyway-clear-database-integration-tests/</link>
            <guid>https://maciejwalkowiak.com/blog/spring-boot-flyway-clear-database-integration-tests/</guid>
            <pubDate>Mon, 20 Feb 2023 09:00:00 GMT</pubDate>
            <description><![CDATA[<p>To make sure that tests are repeatable and isolated, it is a good practice to ensure that they always start with a clean state. In unit testing this could be mocking dependencies, or setting certain properties on objects. In integration testing it often means bringing the database to a well known state - usually erasing all the tables, and inserting the data that the integration tests expect.</p>
<p>In this short tutorial you'll see how to clean a database between integration tests. The recipe assumes that you use: relational database (like MySQL or PostgreSQL), <strong>Spring Boot</strong>, <a href="https://flywaydb.org/" target="_blank" rel="noreferrer">Flyway</a> - for database migrations, <strong>JUnit 5</strong>.</p>
<p>Even if you don't use exactly these technologies, overall idea is quite generic, so I am sure you can adjust it to your needs.</p>
<p><strong>You will also learn the following:</strong></p>
<ul>
<li>why it is important to <strong>clear the database in integration tests</strong></li>
<li>how to clear the database using <code>JdbcTemplate</code>, Spring Data repositories and <strong>Flyway</strong></li>
<li>how to create custom JUnit 5 extension</li>
<li>how to create JUnit 5 meta-annotations</li>
</ul>
]]></description>
            <content:encoded><![CDATA[<p>To make sure that tests are repeatable and isolated, it is a good practice to ensure that they always start with a clean state. In unit testing this could be mocking dependencies, or setting certain properties on objects. In integration testing it often means bringing the database to a well known state - usually erasing all the tables, and inserting the data that the integration tests expect.</p>
<p>In this short tutorial you'll see how to clean a database between integration tests. The recipe assumes that you use: relational database (like MySQL or PostgreSQL), <strong>Spring Boot</strong>, <a href="https://flywaydb.org/" target="_blank" rel="noreferrer">Flyway</a> - for database migrations, <strong>JUnit 5</strong>.</p>
<p>Even if you don't use exactly these technologies, overall idea is quite generic, so I am sure you can adjust it to your needs.</p>
<p><strong>You will also learn the following:</strong></p>
<ul>
<li>why it is important to <strong>clear the database in integration tests</strong></li>
<li>how to clear the database using <code>JdbcTemplate</code>, Spring Data repositories and <strong>Flyway</strong></li>
<li>how to create custom JUnit 5 extension</li>
<li>how to create JUnit 5 meta-annotations</li>
</ul>
]]></content:encoded>
            <enclosure url="https://maciejwalkowiak.com/og-images/spring-boot-flyway-clear-database-integration-tests.jpeg" length="0" type="image/jpeg"/>
        </item>
        <item>
            <title><![CDATA[What's new in Spring?]]></title>
            <link>https://maciejwalkowiak.com/blog/whats-new-in-spring/</link>
            <guid>https://maciejwalkowiak.com/blog/whats-new-in-spring/</guid>
            <pubDate>Mon, 28 Nov 2022 09:00:00 GMT</pubDate>
            <description><![CDATA[<p><img src="/whats-new-in-spring-cover-keanu.jpg" alt="Agent Smith from The Matrix"></p>
<p>If you feel a little overwhelmed with the constant stream of news from the Spring team - I hear you. November was a very hot month for Spring developers.
In addition to plenty of Spring project portfolio releases there were few interesting changes that you might have missed.</p>
<p>Below I collected <strong>the most important things</strong> (and added some notes) that I believe you - as a <strong>Spring</strong> developer - should know to stay up to date.</p>
]]></description>
            <content:encoded><![CDATA[<p><img src="/whats-new-in-spring-cover-keanu.jpg" alt="Agent Smith from The Matrix"></p>
<p>If you feel a little overwhelmed with the constant stream of news from the Spring team - I hear you. November was a very hot month for Spring developers.
In addition to plenty of Spring project portfolio releases there were few interesting changes that you might have missed.</p>
<p>Below I collected <strong>the most important things</strong> (and added some notes) that I believe you - as a <strong>Spring</strong> developer - should know to stay up to date.</p>
]]></content:encoded>
            <enclosure url="https://maciejwalkowiak.com/og-images/whats-new-in-spring.jpeg" length="0" type="image/jpeg"/>
        </item>
        <item>
            <title><![CDATA[Activate Maven Profile by Operating System]]></title>
            <link>https://maciejwalkowiak.com/blog/activate-maven-profile-by-operating-system/</link>
            <guid>https://maciejwalkowiak.com/blog/activate-maven-profile-by-operating-system/</guid>
            <pubDate>Thu, 10 Nov 2022 09:00:00 GMT</pubDate>
            <description><![CDATA[<p><img src="/matrix1.jpg" alt="Agent Smith from The Matrix"></p>
<p>In rare cases, project build may require different configuration depending on operating system that runs the build.</p>
<p>In Maven, it can be done with <a href="https://maven.apache.org/guides/introduction/introduction-to-profiles.html" target="_blank" rel="noreferrer">Maven Profiles</a>.</p>
<ul>
<li><a href="#configure-profiles">how to configure profiles per operating system</a></li>
<li><a href="#activate-profile-on-linux-but-not-on-mac">the trick to activate profile on Linux but not on Mac</a></li>
<li><a href="#how-to-prevent-from-running-on-different-os-or-on-unsupported-architecture">how to enforce presence of active profile with <code>maven-enforcer-plugin</code></a></li>
<li><a href="#run-build-on-different-operating-systems-with-github-action">how to run build on different operating systems with GitHub action</a></li>
</ul>
]]></description>
            <content:encoded><![CDATA[<p><img src="/matrix1.jpg" alt="Agent Smith from The Matrix"></p>
<p>In rare cases, project build may require different configuration depending on operating system that runs the build.</p>
<p>In Maven, it can be done with <a href="https://maven.apache.org/guides/introduction/introduction-to-profiles.html" target="_blank" rel="noreferrer">Maven Profiles</a>.</p>
<ul>
<li><a href="#configure-profiles">how to configure profiles per operating system</a></li>
<li><a href="#activate-profile-on-linux-but-not-on-mac">the trick to activate profile on Linux but not on Mac</a></li>
<li><a href="#how-to-prevent-from-running-on-different-os-or-on-unsupported-architecture">how to enforce presence of active profile with <code>maven-enforcer-plugin</code></a></li>
<li><a href="#run-build-on-different-operating-systems-with-github-action">how to run build on different operating systems with GitHub action</a></li>
</ul>
]]></content:encoded>
            <enclosure url="https://maciejwalkowiak.com/og-images/activate-maven-profile-by-operating-system.jpeg" length="0" type="image/jpeg"/>
        </item>
        <item>
            <title><![CDATA[Spring Boot with Thymeleaf and Tailwind CSS - Complete Guide]]></title>
            <link>https://maciejwalkowiak.com/blog/spring-boot-thymeleaf-tailwindcss/</link>
            <guid>https://maciejwalkowiak.com/blog/spring-boot-thymeleaf-tailwindcss/</guid>
            <pubDate>Wed, 09 Nov 2022 09:00:00 GMT</pubDate>
            <enclosure url="https://maciejwalkowiak.com/og-images/spring-boot-thymeleaf-tailwindcss.jpeg" length="0" type="image/jpeg"/>
        </item>
        <item>
            <title><![CDATA[How to publish a Java library to Maven Central - Complete Guide]]></title>
            <link>https://maciejwalkowiak.com/blog/publish-java-library-maven-central/</link>
            <guid>https://maciejwalkowiak.com/blog/publish-java-library-maven-central/</guid>
            <pubDate>Mon, 07 Nov 2022 09:00:00 GMT</pubDate>
            <enclosure url="https://maciejwalkowiak.com/og-images/guide-java-publish-to-maven-central.jpeg" length="0" type="image/jpeg"/>
        </item>
        <item>
            <title><![CDATA[Docker Compose - waiting until containers are ready]]></title>
            <link>https://maciejwalkowiak.com/blog/docker-compose-waiting-containers-ready/</link>
            <guid>https://maciejwalkowiak.com/blog/docker-compose-waiting-containers-ready/</guid>
            <pubDate>Thu, 03 Nov 2022 09:00:00 GMT</pubDate>
            <enclosure url="https://maciejwalkowiak.com/og-images/docker-compose-waiting-containers-ready.jpeg" length="0" type="image/jpeg"/>
        </item>
        <item>
            <title><![CDATA[Single file Java applications with JBang]]></title>
            <link>https://maciejwalkowiak.com/blog/single-file-java-with-jbang/</link>
            <guid>https://maciejwalkowiak.com/blog/single-file-java-with-jbang/</guid>
            <pubDate>Wed, 02 Nov 2022 09:00:00 GMT</pubDate>
            <enclosure url="https://maciejwalkowiak.com/og-images/single-file-java-with-jbang.jpeg" length="0" type="image/jpeg"/>
        </item>
        <item>
            <title><![CDATA[Beautiful bash scripts with Gum]]></title>
            <link>https://maciejwalkowiak.com/blog/beautiful-bash-scripts-with-gum/</link>
            <guid>https://maciejwalkowiak.com/blog/beautiful-bash-scripts-with-gum/</guid>
            <pubDate>Tue, 01 Nov 2022 09:00:00 GMT</pubDate>
            <enclosure url="https://maciejwalkowiak.com/og-images/beautiful-bash-scripts-with-gum.jpeg" length="0" type="image/jpeg"/>
        </item>
        <item>
            <title><![CDATA[Running Java on CRaC]]></title>
            <link>https://maciejwalkowiak.com/blog/running-java-on-crac/</link>
            <guid>https://maciejwalkowiak.com/blog/running-java-on-crac/</guid>
            <pubDate>Fri, 28 Oct 2022 09:00:00 GMT</pubDate>
            <enclosure url="https://maciejwalkowiak.com/og-images/running-java-on-crac.jpeg" length="0" type="image/jpeg"/>
        </item>
        <item>
            <title><![CDATA[How to log PostgreSQL queries with Testcontainers]]></title>
            <link>https://maciejwalkowiak.com/blog/postgresql-testcontainers-sql-query-logs/</link>
            <guid>https://maciejwalkowiak.com/blog/postgresql-testcontainers-sql-query-logs/</guid>
            <pubDate>Tue, 25 Oct 2022 09:00:00 GMT</pubDate>
            <enclosure url="https://maciejwalkowiak.com/og-images/postgresql-testcontainers-sql-query-logs.jpeg" length="0" type="image/jpeg"/>
        </item>
        <item>
            <title><![CDATA[Spring Boot 3.0 & GraalVM Native Image - not a free lunch]]></title>
            <link>https://maciejwalkowiak.com/blog/spring-boot-3-native-image-not-a-free-lunch/</link>
            <guid>https://maciejwalkowiak.com/blog/spring-boot-3-native-image-not-a-free-lunch/</guid>
            <pubDate>Mon, 24 Oct 2022 09:00:00 GMT</pubDate>
            <enclosure url="https://maciejwalkowiak.com/og-images/spring-boot-3-native-image-not-a-free-lunch.jpeg" length="0" type="image/jpeg"/>
        </item>
        <item>
            <title><![CDATA[Creating Spring Cloud Function projects with AWS SAM]]></title>
            <link>https://maciejwalkowiak.com/blog/create-spring-cloud-function-aws-sam/</link>
            <guid>https://maciejwalkowiak.com/blog/create-spring-cloud-function-aws-sam/</guid>
            <pubDate>Wed, 03 Aug 2022 12:00:00 GMT</pubDate>
            <enclosure url="https://maciejwalkowiak.com/og-images/create-spring-cloud-function-aws-sam.jpeg" length="0" type="image/jpeg"/>
        </item>
        <item>
            <title><![CDATA[Loading classpath resources to String with a custom JUnit extension]]></title>
            <link>https://maciejwalkowiak.com/blog/resource-as-string-junit-extension/</link>
            <guid>https://maciejwalkowiak.com/blog/resource-as-string-junit-extension/</guid>
            <pubDate>Fri, 29 Jul 2022 19:00:00 GMT</pubDate>
            <enclosure url="https://maciejwalkowiak.com/og-images/resource-as-string-junit-extension.jpeg" length="0" type="image/jpeg"/>
        </item>
        <item>
            <title><![CDATA[Creating Project Templates with Cookiecutter]]></title>
            <link>https://maciejwalkowiak.com/blog/creating-project-templates-with-cookiecutter/</link>
            <guid>https://maciejwalkowiak.com/blog/creating-project-templates-with-cookiecutter/</guid>
            <pubDate>Thu, 28 Jul 2022 09:00:00 GMT</pubDate>
            <description><![CDATA[<p>Can you create a new Java project from scratch, manually, without copy &amp; pasting? I don't. And probably you shouldn't as this is
a pure waste of time considering how repetitive the base code and the directory structure is.</p>
]]></description>
            <content:encoded><![CDATA[<p>Can you create a new Java project from scratch, manually, without copy &amp; pasting? I don't. And probably you shouldn't as this is
a pure waste of time considering how repetitive the base code and the directory structure is.</p>
]]></content:encoded>
            <enclosure url="https://maciejwalkowiak.com/og-images/creating-project-templates-with-cookiecutter.jpeg" length="0" type="image/jpeg"/>
        </item>
        <item>
            <title><![CDATA[Blog]]></title>
            <link>https://maciejwalkowiak.com/blog/</link>
            <guid>https://maciejwalkowiak.com/blog/</guid>
            <pubDate>Thu, 28 Jul 2022 09:00:00 GMT</pubDate>
            <enclosure url="https://maciejwalkowiak.com/og-images/undefined.jpeg" length="0" type="image/jpeg"/>
        </item>
        <item>
            <title><![CDATA[Auto-Registering JUnit 5 extensions]]></title>
            <link>https://maciejwalkowiak.com/blog/auto-registering-junit-5-extensions/</link>
            <guid>https://maciejwalkowiak.com/blog/auto-registering-junit-5-extensions/</guid>
            <pubDate>Wed, 27 Jul 2022 09:00:00 GMT</pubDate>
            <enclosure url="https://maciejwalkowiak.com/og-images/auto-registering-junit-5-extensions.jpeg" length="0" type="image/jpeg"/>
        </item>
        <item>
            <title><![CDATA[Spring Boot component scanning without annotations]]></title>
            <link>https://maciejwalkowiak.com/blog/spring-boot-component-scan-without-annotations/</link>
            <guid>https://maciejwalkowiak.com/blog/spring-boot-component-scan-without-annotations/</guid>
            <pubDate>Tue, 26 Jul 2022 17:43:03 GMT</pubDate>
            <enclosure url="https://maciejwalkowiak.com/og-images/spring-boot-component-scan-without-annotations.jpeg" length="0" type="image/jpeg"/>
        </item>
        <item>
            <title><![CDATA[Listing Maven dependencies in Spring Boot Actuator Info endpoint]]></title>
            <link>https://maciejwalkowiak.com/blog/maven-dependencies-spring-boot-actuator-info/</link>
            <guid>https://maciejwalkowiak.com/blog/maven-dependencies-spring-boot-actuator-info/</guid>
            <pubDate>Mon, 25 Jul 2022 17:43:03 GMT</pubDate>
            <enclosure url="https://maciejwalkowiak.com/og-images/maven-dependencies-spring-boot-actuator-info.jpeg" length="0" type="image/jpeg"/>
        </item>
        <item>
            <title><![CDATA[Spring Cloud AWS 2.3 RC2 Released]]></title>
            <link>https://maciejwalkowiak.com/blog/spring-cloud-aws-2-3-rc2-released/</link>
            <guid>https://maciejwalkowiak.com/blog/spring-cloud-aws-2-3-rc2-released/</guid>
            <pubDate>Wed, 10 Feb 2021 17:43:03 GMT</pubDate>
            <enclosure url="https://maciejwalkowiak.com/og-images/spring-cloud-aws-2-3-rc2-released.jpeg" length="0" type="image/jpeg"/>
        </item>
        <item>
            <title><![CDATA[How I built vlad-cli - command line interface to Vlad Mihalcea]]></title>
            <link>https://maciejwalkowiak.com/blog/how-i-built-vlad-cli/</link>
            <guid>https://maciejwalkowiak.com/blog/how-i-built-vlad-cli/</guid>
            <pubDate>Wed, 06 May 2020 17:43:03 GMT</pubDate>
            <enclosure url="https://maciejwalkowiak.com/og-images/how-i-built-vlad-cli.jpeg" length="0" type="image/jpeg"/>
        </item>
        <item>
            <title><![CDATA[The State of Java Relational Persistence]]></title>
            <link>https://maciejwalkowiak.com/blog/the-state-of-java-relational-persistence/</link>
            <guid>https://maciejwalkowiak.com/blog/the-state-of-java-relational-persistence/</guid>
            <pubDate>Thu, 16 May 2019 22:12:03 GMT</pubDate>
            <enclosure url="https://maciejwalkowiak.com/og-images/the-state-of-java-relational-persistence.jpeg" length="0" type="image/jpeg"/>
        </item>
        <item>
            <title><![CDATA[On Choosing a Tech Stack]]></title>
            <link>https://maciejwalkowiak.com/blog/how-to-choose-tech-stack/</link>
            <guid>https://maciejwalkowiak.com/blog/how-to-choose-tech-stack/</guid>
            <pubDate>Fri, 26 Apr 2019 22:12:03 GMT</pubDate>
            <enclosure url="https://maciejwalkowiak.com/og-images/how-to-choose-tech-stack.jpeg" length="0" type="image/jpeg"/>
        </item>
    </channel>
</rss>