<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Artem Ptushkin</title>
    <description>The latest articles on DEV Community by Artem Ptushkin (@art_ptushkin).</description>
    <link>https://dev.to/art_ptushkin</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F333535%2Fcde9c8c7-e1d7-47d1-936a-9f4dfb849a77.png</url>
      <title>DEV Community: Artem Ptushkin</title>
      <link>https://dev.to/art_ptushkin</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/art_ptushkin"/>
    <language>en</language>
    <item>
      <title>Gitlab python-based job to remove stale branches</title>
      <dc:creator>Artem Ptushkin</dc:creator>
      <pubDate>Mon, 15 Jul 2024 07:54:22 +0000</pubDate>
      <link>https://dev.to/art_ptushkin/gitlab-python-based-job-to-remove-stale-branches-1i6i</link>
      <guid>https://dev.to/art_ptushkin/gitlab-python-based-job-to-remove-stale-branches-1i6i</guid>
      <description>&lt;h2&gt;
  
  
  Problem
&lt;/h2&gt;

&lt;p&gt;GitLab has a concept of &lt;a href="https://docs.gitlab.com/ee/user/project/repository/branches/" rel="noopener noreferrer"&gt;stale branches&lt;/a&gt;, where they defined all the branches updated more than 3 months ago as &lt;strong&gt;stale&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;However, it's not possible to do &lt;a href="https://gitlab.com/gitlab-org/gitlab/-/issues/357095" rel="noopener noreferrer"&gt;a bulk removal&lt;/a&gt; or have a more sophisticated control of these branches.&lt;/p&gt;

&lt;p&gt;Here is a full example of how you can set this up. As for scheduled tasks you can use &lt;a href="https://docs.gitlab.com/ee/ci/pipelines/schedules.html" rel="noopener noreferrer"&gt;Gitlab scheduled jobs&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


</description>
      <category>gitlab</category>
    </item>
    <item>
      <title>How to configure DNS caching timeout in a Spring Boot docker image?</title>
      <dc:creator>Artem Ptushkin</dc:creator>
      <pubDate>Tue, 26 Mar 2024 15:30:53 +0000</pubDate>
      <link>https://dev.to/art_ptushkin/how-to-configure-dns-caching-timeout-in-a-spring-boot-docker-image-1n4e</link>
      <guid>https://dev.to/art_ptushkin/how-to-configure-dns-caching-timeout-in-a-spring-boot-docker-image-1n4e</guid>
      <description>&lt;p&gt;&lt;em&gt;JVM build used for this article &lt;code&gt;eclipse-temurin:21-jdk&lt;/code&gt;:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;openjdk 21.0.2 2024-01-16 LTS
OpenJDK Runtime Environment Temurin-21.0.2+13 (build 21.0.2+13-LTS)
OpenJDK 64-Bit Server VM Temurin-21.0.2+13 (build 21.0.2+13-LTS, mixed mode, sharing)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We must differentiate JVM Security properties and System properties.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Security properties:

&lt;ul&gt;
&lt;li&gt;can &lt;strong&gt;not&lt;/strong&gt; be affected directly by the command line&lt;/li&gt;
&lt;li&gt;accessed with class &lt;code&gt;java.security.Security&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;can be modified through the file &lt;code&gt;-Djava.security.properties=/java-additional.security&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;System properties

&lt;ul&gt;
&lt;li&gt;can be affected directly by the command line&lt;/li&gt;
&lt;li&gt;accessed with class &lt;code&gt;java.lang.System&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Important to know:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Default value of the property is &lt;strong&gt;30&lt;/strong&gt; (seconds) and can be found in &lt;code&gt;sun.net.InetAddressCachePolicy#DEFAULT_POSITIVE&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;This class reads the property &lt;strong&gt;once during the class initialization in the static method&lt;/strong&gt; - this is important for further conclusions&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How to debug: open &lt;code&gt;java.net.InetAddress&lt;/code&gt; line ~1141 &lt;code&gt;cachePolicy = InetAddressCachePolicy.get();&lt;/code&gt; and call the code &lt;code&gt;InetAddressCachePolicy.get()&lt;/code&gt; through the debug execution&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Initial options to set the value:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Security property &lt;code&gt;networkaddress.cache.ttl&lt;/code&gt; (through the file)&lt;/li&gt;
&lt;li&gt;System property &lt;code&gt;sun.net.inetaddr.ttl&lt;/code&gt; (through JVM command line)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Technical in JVM it's &lt;strong&gt;possible&lt;/strong&gt; to set a value in runtime (e.g. &lt;code&gt;System.setProperty&lt;/code&gt; or &lt;code&gt;Security.setProperty&lt;/code&gt; but this is misleading here's why:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You don't know when a property will be accessed by any code. You must either determine that you set it &lt;strong&gt;before&lt;/strong&gt; other code &lt;strong&gt;accesses&lt;/strong&gt; it or there is a risk that it will be not applied.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Therefore, to mediate the risk and the checks we &lt;strong&gt;should set the value as JVM startup parameters (not runtime)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Let's consider 3 typical build setups:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;fat jar&lt;/li&gt;
&lt;li&gt;Spring Boot docker build&lt;/li&gt;
&lt;li&gt;Goole jib&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Fat jar
&lt;/h2&gt;

&lt;p&gt;There are plenty of options on how to set a JVM property, one example&lt;/p&gt;

&lt;h3&gt;
  
  
  Security properties with Gradle example
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="c"&gt;# gradle.properties
&lt;/span&gt;&lt;span class="py"&gt;org.gradle.org.gradle.jvmargs&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"-Djava.security.properties=/your/path/java-additional.security"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Security properties with Googe Jib plugin
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# build.gradle.kts
jib {
    extraDirectories {
        paths {
            path {
                setFrom("java-additional.security")
                into = "/etc/java-additional.security"
            }
        }
    }
    container {
        jvmFlags = listOf("-Djava.security.properties=/etc/java-additional.security/java.security")
    }
    from {
        image = "eclipse-temurin:21-jre"
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can reproduce the same code with other build tools and with the Dockerfile too.&lt;/p&gt;

&lt;h2&gt;
  
  
  Event this is not enough
&lt;/h2&gt;

&lt;p&gt;Spring uses Apache HTTP client underneath and by default connection TTL there is infinite. You can change it to (&lt;a href="https://stackoverflow.com/questions/29107681/httpclients-poolinghttpclientconnectionmanager-and-dns-caching"&gt;see&lt;/a&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Bean&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;poolingHttpClientConnectionManager&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;PoolingHttpClientConnectionManager&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
        &lt;span class="nc"&gt;PoolingHttpClientConnectionManagerBuilder&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;apply&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

                &lt;span class="nf"&gt;setDefaultConnectionConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ConnectionConfig&lt;/span&gt;
                    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;custom&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setTimeToLive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;TimeValue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ofMinutes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;// which you set to &lt;/span&gt;

&lt;span class="nc"&gt;HttpClients&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;custom&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;setConnectionManager&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;poolingHttpClientConnectionManager&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/net/doc-files/net-properties.html#address-cache-heading"&gt;Current Oracle JDK documentation&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://stackoverflow.com/questions/1256556/how-to-make-java-honor-the-dns-caching-timeout#comment21965197_15282042"&gt;StackOverflow the best answer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dzone.com/articles/how-override-java-security"&gt;Sub-article JDK-related&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/GoogleContainerTools/jib/issues/3640"&gt;Jib containerization tool relevant issue&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/spring-projects/spring-boot/issues/19376"&gt;Spring Boot relevant issue&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>docker</category>
      <category>springboot</category>
      <category>jvm</category>
    </item>
    <item>
      <title>Handle Gitlab pipeline duplication</title>
      <dc:creator>Artem Ptushkin</dc:creator>
      <pubDate>Mon, 19 Jun 2023 11:04:27 +0000</pubDate>
      <link>https://dev.to/art_ptushkin/handle-gitlab-pipeline-duplication-4oc7</link>
      <guid>https://dev.to/art_ptushkin/handle-gitlab-pipeline-duplication-4oc7</guid>
      <description>&lt;h2&gt;
  
  
  Problem
&lt;/h2&gt;

&lt;p&gt;There is &lt;a href="https://gitlab.com/gitlab-org/gitlab/-/issues/332501"&gt;a known problem&lt;/a&gt; that in Gitlab it's not possible to avoid pipeline duplication in some scenarios.&lt;/p&gt;

&lt;h2&gt;
  
  
  Context
&lt;/h2&gt;

&lt;p&gt;Let's assume you combine merge and branch pipelines. You can follow &lt;a href="https://docs.gitlab.com/ee/ci/yaml/workflow.html#switch-between-branch-pipelines-and-merge-request-pipelines"&gt;the Gitlab guideline&lt;/a&gt; or here is an improved one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;workflow&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$CI_PIPELINE_SOURCE&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"merge_request_event"'&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$CI_PIPELINE_SOURCE&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"web"'&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$CI_COMMIT_BRANCH&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;$CI_OPEN_MERGE_REQUESTS'&lt;/span&gt;
      &lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;never&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$CI_COMMIT_BRANCH'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;When you push and then you open a MR immediately it's not possible to avoid getting a second pipeline (though if you &lt;strong&gt;have one&lt;/strong&gt; open then it's not an issue).&lt;/p&gt;
&lt;h2&gt;
  
  
  Solution with git options
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;See &lt;a href="https://docs.gitlab.com/ee/user/project/push_options.html"&gt;Gitlab CI push options&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git push -o merge_request.create
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  This solution with the script below
&lt;/h2&gt;

&lt;p&gt;Here is a script that supposed to be run after the push to cancel the duplication.&lt;/p&gt;
&lt;h2&gt;
  
  
  How to use?
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Create an alias in your bash profile / .zshrc file, e.g.: &lt;code&gt;alias cancel-branch-pipeline="sh ~/gitlab/gitlab-cancel-branch-pipeline.sh"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Set you &lt;a href="https://docs.gitlab.com/ee/user/project/settings/project_access_tokens.html"&gt;Gitlab personal access token&lt;/a&gt; with scopes &lt;code&gt;api&lt;/code&gt; and &lt;code&gt;read_api&lt;/code&gt; as &lt;code&gt;GITLAB_TOKEN&lt;/code&gt; environment variable (you can set it in your bash profile file to have in every session: &lt;code&gt;export GITLAB_TOKEN=&amp;lt;your-token&amp;gt;&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Call it after with the alias anytime you push, and you want to open a MR: &lt;code&gt;$ cancel-branch-pipeline&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



</description>
      <category>gitlab</category>
      <category>devops</category>
      <category>cicd</category>
      <category>git</category>
    </item>
    <item>
      <title>Best practices for writing contract tests</title>
      <dc:creator>Artem Ptushkin</dc:creator>
      <pubDate>Thu, 06 Apr 2023 11:41:52 +0000</pubDate>
      <link>https://dev.to/art_ptushkin/best-practices-for-writing-contract-tests-with-pact-in-jvm-stack-124l</link>
      <guid>https://dev.to/art_ptushkin/best-practices-for-writing-contract-tests-with-pact-in-jvm-stack-124l</guid>
      <description>&lt;p&gt;Contract testing is a broad topic that includes such areas as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Building reliable pipeline&lt;/li&gt;
&lt;li&gt;Framework concepts and key functionalities knowledge&lt;/li&gt;
&lt;li&gt;Writing consumer contract tests in a scalable design and covering it on the provider side with the easily maintainable verifications&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first two points usually appear to be on the shoulders of a smaller group of people (Devops, platform engineers and team leads) but the &lt;strong&gt;latter one&lt;/strong&gt; affects every developer who wants to write contract tests following the set of design patterns in his project. Here let's talk about this point.&lt;/p&gt;

&lt;h2&gt;
  
  
  Maturity level:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;You know contract testing&lt;/li&gt;
&lt;li&gt;You know consumer-driven contract testing&lt;/li&gt;
&lt;li&gt;You know API&lt;/li&gt;
&lt;li&gt;You care about the project and standards in your company&lt;/li&gt;
&lt;li&gt;You already have written your first contract&lt;/li&gt;
&lt;li&gt;You know how to run the provider tests and verify the consumer's contract&lt;/li&gt;
&lt;li&gt;You focus to get as much as possible from contract tests&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Writing your best contracts
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Focus on the actual API rather than on the code
&lt;/h3&gt;

&lt;p&gt;Before writing the contract test I always recommend &lt;strong&gt;calling the actual endpoint&lt;/strong&gt; to see the request and response then the goal is simple - reproduce the contract in the test. You can use any tool like Postman, curl, etc.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Call the endpoint in Postman before writing the test&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;HTTP contract test is about HTTP semantics&lt;/strong&gt; and you can't always see or can't find the required semantics that will be taken into the actual request effect in one place. For example:

&lt;ul&gt;
&lt;li&gt;Authorization is not visible very often&lt;/li&gt;
&lt;li&gt;The base path defined in some configuration&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Write the contract in a way it reflects the actual integration that &lt;strong&gt;you expect&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This point comes along with the first one. Trusting a message from your colleague or your intuition and even openapi (swagger) is not enough. You should see the actual integration in front of you. If the actual endpoint doesn't exist then &lt;strong&gt;align the contract with your provider before the merge&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Be flexible in your expectations
&lt;/h3&gt;

&lt;p&gt;I often find that only &lt;strong&gt;exact&lt;/strong&gt; values are being used in the contract though it's not expected that API returns or expects &lt;strong&gt;always&lt;/strong&gt; a constant value - it's the only case when you should use the exact value.&lt;/p&gt;

&lt;p&gt;In all the other cases try following &lt;a href="https://en.wikipedia.org/wiki/Robustness_principle"&gt;the robustness principle&lt;/a&gt;. Find more about this in &lt;a href="https://dev.to/art_ptushkin/consumer-and-provider-binding-in-contract-testing-2ib1"&gt;this article&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The best practices for writing &lt;strong&gt;any part&lt;/strong&gt; of the contract are:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Always use example value and a matcher (regex, type, date formats, etc.)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For example, this code expects that query parameter &lt;code&gt;amount&lt;/code&gt; will be any integer but &lt;code&gt;2&lt;/code&gt; as an example and an exact value in the request on the provider side :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.matchQuery("amount", ".d*", "2") 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Use fewer constants and common components in tests
&lt;/h3&gt;

&lt;p&gt;If you like and know how to write reusable code it's not necessary these patterns must be applied to &lt;strong&gt;any&lt;/strong&gt; testing code. We make it worse when we write common components in tests chasing the DRY principle. It brings unnecessary cohesion to your tests thus when you change a value in a common place you break N tests instead of one.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Try using fewer constants and common components in your tests&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Making tests cohesive we:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;make the HTTP semantic less visible by looking at the pact code&lt;/li&gt;
&lt;li&gt;add redundant coupling: it's not easy to &lt;em&gt;play&lt;/em&gt; with your code changing a constant because other tests will fail using that constant value&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5. Use fewer production model classes in your tests code
&lt;/h3&gt;

&lt;p&gt;This point is close to the 4th and the 1st. Relying on any production code or giving credit of trust to the developer who wrote that. Though that model doesn't need to reflect 1:1 the integration, there might be in place: converts, serialisation configurations, etc. You may miss this, so it's easier just to use plain JSONs and, respecting the 3d point, library DSLs.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Relying on the production code in your tests inputs we make it difficult following the TDD pattern&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Another argument, respecting the 1st point, is that you think about the code instead of the actual JSON writing the test which brings you to &lt;em&gt;assumptions&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Always verify the contract on the provider side
&lt;/h3&gt;

&lt;p&gt;The contract testing with Pact is about the consumer and provider. Writing just the pact and finishing your work you can not be a curtain that you covered the integration.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Every pact must be verified on the provider side to bind the consumer and the provider&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In my experience, developers that write tests separately end up in a situation where after the merge they have to do an additional job &lt;em&gt;later&lt;/em&gt; to align/verify the contract on the provider side. It might be very exhausting work so:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Better writing fewer tests but always verifying all of them on the provider side &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  7. Mock as deeper as it's possible on the provider side
&lt;/h3&gt;

&lt;p&gt;tl;dr&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Mock the repository level or insert it into your database in the tests&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here is &lt;a href="https://www.youtube.com/watch?v=wkld_wRsTDE&amp;amp;t=1561s&amp;amp;ab_channel=PactFoundation"&gt;a great explanation video&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You might get an idea to mock the controller level and this idea is bad here is why:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All the following tests will follow the same principle because it costs a lot to restart the application for every test - no one does that, you will have the same set of beans (mocks)&lt;/li&gt;
&lt;li&gt;You isolate the major part of your application and you simply can't get some layer that causes an exception that you need to cover a contract&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  More examples:
&lt;/h4&gt;

&lt;p&gt;&lt;em&gt;Context&lt;/em&gt;: in Spring Boot applications classically we have &lt;em&gt;layers&lt;/em&gt;: controller, repository, service etc. You can mock any layer of those by mocking a bean so that a mock returns the result of the corresponding method.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Less cohesive&lt;/strong&gt;. The mocks do not really describe a state of a system (service) rather they do a small snapshot of a layer that depends on DTO classes. It makes mocks less cohesive with tests,
thus it's a high chance that tests based on mocks will pass but on practice, the example data in mocks will never appear.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Making assumptions of application behavior&lt;/strong&gt;. Development by mocks makes developers think about exceptions rather than the actual application behavior.
Imagine you want to prepare a state that your service returns 400 when the inputs are invalid. Here as well, it makes it difficult for non-owner of the provider application to write and understand the state.
The provider developer relying on a mock, e.g. exception class will prepare the state &lt;em&gt;assuming&lt;/em&gt; that the exact exception causes the issue. Though it can be any other exception, hence when something changes the exception in the production code - the test will be not reliable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tests as examples&lt;/strong&gt;. Pact with consumer-driven contracts is development-by-example, and if a layer is mocked, it says nothing to the observer about the actual system behavior. You can't use the test with mock as an example because &lt;strong&gt;you do not know how to reproduce this layer behavior&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Follow TDD in your tests thinking about the API rather then the production code&lt;/li&gt;
&lt;li&gt;Think about reusability and how others will copy your approaches in your company&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I know this article contains no code examples though I have ones in this Github repository &lt;a href="https://github.com/artemptushkin/breaking-api-bad/tree/main/contract-testing/pact"&gt;breaking-api-bad&lt;/a&gt; and please not do hesitate to &lt;a href="https://twitter.com/art_ptushkin"&gt;contact me&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>pact</category>
      <category>contracttesting</category>
      <category>testing</category>
    </item>
    <item>
      <title>Kotlin Spring Boot Configuration properties best practices</title>
      <dc:creator>Artem Ptushkin</dc:creator>
      <pubDate>Thu, 14 Jul 2022 14:59:55 +0000</pubDate>
      <link>https://dev.to/art_ptushkin/kotlin-spring-boot-configuration-properties-best-practices-13e6</link>
      <guid>https://dev.to/art_ptushkin/kotlin-spring-boot-configuration-properties-best-practices-13e6</guid>
      <description>&lt;p&gt;&lt;em&gt;Jump to the example if you're quite advanced in Spring already&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What do we have
&lt;/h3&gt;

&lt;p&gt;Working in Spring Boot stack one of the first features that every developer is taking the advantage of is &lt;a href="https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.external-config"&gt;Configuration Properties&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Which could be configured as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;class level beans&lt;/li&gt;
&lt;li&gt;method based beans&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Basically method level beans are the same as class level but you can create N properties beans from a single class.&lt;/p&gt;

&lt;p&gt;The properties itself can be propagated in different ways but the most common is through application properties / yaml files.&lt;/p&gt;

&lt;p&gt;What's important about the properties that they can be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;null&lt;/li&gt;
&lt;li&gt;defaulted&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Naming
&lt;/h3&gt;

&lt;p&gt;Spring follows the next conventions as for the configuration (class with beans) and configuration properties classes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;@Configuration&lt;/code&gt; - &lt;code&gt;*Configuration.kt&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@ConfigurationProperties&lt;/code&gt; - &lt;code&gt;*Properties.kt&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's good to follow the standards from the ecosystem you use to prevent confusions as:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Properties class is not a configuration&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Anti-patterns
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Difference between configuration and properties
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Configuration - is a class that defines beans&lt;/li&gt;
&lt;li&gt;Properties - is a class that defines data structure to describe the application properties, e.g. to map the properties to an object&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The next example is &lt;strong&gt;anti-pattern&lt;/strong&gt; because spring works differently with these concepts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Configuration&lt;/span&gt;
&lt;span class="nd"&gt;@ConfigurationProperties&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyProperties&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  Configuration properties bean must be initialised by Spring not manually
&lt;/h4&gt;

&lt;p&gt;The next example is &lt;strong&gt;anti-pattern&lt;/strong&gt; because configuration properties is a bean can be initialised much more naturally when it's loosely coupled with it's configuration, for instance it's &lt;a href="https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.external-config.typesafe-configuration-properties.constructor-binding"&gt;a problem&lt;/a&gt; if you use &lt;code&gt;@ConstructorBinding&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Component&lt;/span&gt;
&lt;span class="nd"&gt;@ConfigurationProperties&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyProperties&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Standards, code consistency
&lt;/h3&gt;

&lt;p&gt;The goal of the best practices is to find the golden mean. Where we expect that the data-structure represents in a neat way the mapping between the properties and the class.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;default value should be located as close as possible to the field so developer can immediately see it&lt;/li&gt;
&lt;li&gt;nullability should represent the actual necessity of the property&lt;/li&gt;
&lt;li&gt;it should be simple&lt;/li&gt;
&lt;li&gt;composite children fields are designed in the same way&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Having all the requirements we have the next example: &lt;/p&gt;
&lt;h4&gt;
  
  
  Demo
&lt;/h4&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Let's say we have this set of properties defined:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;io.github.artemptushkin.example&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;defaultOverriddenProperty&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;overridden&lt;/span&gt;
  &lt;span class="na"&gt;requiredStringProperty&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;required-value&lt;/span&gt;
  &lt;span class="na"&gt;notNullListProperty&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;foo"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;baz"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;it will give us the next &lt;em&gt;runtime&lt;/em&gt; properties:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;io.github.artemptushkin.example.defaultedStringProperty&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;default&lt;/span&gt;
&lt;span class="py"&gt;io.github.artemptushkin.example.defaultOverriddenProperty&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;overridden&lt;/span&gt;
&lt;span class="py"&gt;io.github.artemptushkin.example.requiredStringProperty&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;required-value&lt;/span&gt;
&lt;span class="py"&gt;io.github.artemptushkin.example.optionalStringProperty&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;null&lt;/span&gt;
&lt;span class="err"&gt;io.github.artemptushkin.example.notNullListProperty[0]=foo&lt;/span&gt;
&lt;span class="err"&gt;io.github.artemptushkin.example.notNullListProperty[1]=baz&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Key points are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;@ConstructorBinding&lt;/code&gt; let's us &lt;a href="https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.external-config.typesafe-configuration-properties.constructor-binding"&gt;use create immutable objects&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Kotlin default constructor values let us use to have default values right in place in one single line&lt;/li&gt;
&lt;li&gt;Always initialise collections as empty by default to prevent nullable field&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;It's possible to write clean classes and keep them concise from one project to another and within your company.&lt;/p&gt;

&lt;p&gt;I hope this noted helped you.&lt;/p&gt;

</description>
      <category>spring</category>
      <category>kotlin</category>
      <category>java</category>
      <category>developmentexperience</category>
    </item>
    <item>
      <title>How to migrate a directory from git repository to another one preserving git history. Bitbucket example</title>
      <dc:creator>Artem Ptushkin</dc:creator>
      <pubDate>Thu, 20 Jan 2022 10:20:48 +0000</pubDate>
      <link>https://dev.to/art_ptushkin/how-to-migrate-a-directory-from-git-repository-to-another-one-preserving-git-history-bitbucket-example-15m5</link>
      <guid>https://dev.to/art_ptushkin/how-to-migrate-a-directory-from-git-repository-to-another-one-preserving-git-history-bitbucket-example-15m5</guid>
      <description>&lt;p&gt;Assume we migrate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;folder2&lt;/code&gt; from &lt;code&gt;git@bitbucket.org:myproject/myrepo.git&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  myrepo
  │   README.md
  └───folder1
  └───folder2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;to &lt;code&gt;git@bitbucket.org:newrepo.git&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How to do this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;To make it safe, clone &lt;code&gt;myrepo.git&lt;/code&gt; into a new directory&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;myrepo-folder2-migration
&lt;span class="nb"&gt;cd &lt;/span&gt;myrepo-folder2-migration

git clone 
git@bitbucket.org:myproject/myrepo.git

&lt;span class="nb"&gt;cd &lt;/span&gt;myrepo

&lt;span class="c"&gt;#prevent pushing into it&lt;/span&gt;
git remote &lt;span class="nb"&gt;rm &lt;/span&gt;origin
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Filter git history to keep only files in &lt;code&gt;folder2&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git filter-branch &lt;span class="nt"&gt;--subdirectory-filter&lt;/span&gt; folder2 &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nt"&gt;--all&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Clean unwanted data&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git reset &lt;span class="nt"&gt;--hard&lt;/span&gt;
git gc &lt;span class="nt"&gt;--aggressive&lt;/span&gt; 
git prune
git clean &lt;span class="nt"&gt;-fd&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It should contain only the files from &lt;code&gt;folder2&lt;/code&gt; in the root git directory now&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Go back and prepare to work for the newrepo&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ..

&lt;span class="nb"&gt;pwd&lt;/span&gt;
&lt;span class="c"&gt;#make sure you're in myrepo-folder2-migration&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Clone the empty repository&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone git@bitbucket.org:newrepo.git

&lt;span class="nb"&gt;cd &lt;/span&gt;newrepo
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a connection to local repository, we're going to pull from it&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git remote add old-repo ../myrepo
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Pull files from the old repo&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git pull old-repo master &lt;span class="nt"&gt;--allow-unrelated-histories&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Remove the connection with local&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git remote remove old-repo
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Push the changes to the remote origin&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git push
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The new remote repository should contain files from &lt;code&gt;folder2&lt;/code&gt; inside the root directory now.&lt;/p&gt;

&lt;p&gt;I followed &lt;a href="https://medium.com/@ayushya/move-directory-from-one-repository-to-another-preserving-git-history-d210fa049d4b"&gt;https://medium.com/@ayushya/move-directory-from-one-repository-to-another-preserving-git-history-d210fa049d4b&lt;/a&gt; with adjustments I found important and clear for understanding.&lt;/p&gt;

</description>
      <category>git</category>
    </item>
    <item>
      <title>How to properly ignore Junit 4 in Gradle and Maven</title>
      <dc:creator>Artem Ptushkin</dc:creator>
      <pubDate>Tue, 24 Aug 2021 11:11:32 +0000</pubDate>
      <link>https://dev.to/art_ptushkin/how-to-properly-ignore-junit-4-in-gradle-and-maven-3o82</link>
      <guid>https://dev.to/art_ptushkin/how-to-properly-ignore-junit-4-in-gradle-and-maven-3o82</guid>
      <description>&lt;p&gt;Jump to the best example here for Gradle and Maven&lt;/p&gt;

&lt;h3&gt;
  
  
  Problem
&lt;/h3&gt;

&lt;p&gt;Quite a lot of Java dependencies bring &lt;a href="https://junit.org/junit4/"&gt;Junit 4&lt;/a&gt; or &lt;a href="https://junit.org/junit5/docs/current/user-guide/"&gt;Junit vintage engine&lt;/a&gt; as a transitive dependency.&lt;/p&gt;

&lt;p&gt;As well as Junit vintage engine is &lt;a href="https://github.com/junit-team/junit5-samples/tree/master/junit5-migration-gradle"&gt;designed to integrate 4 and 5 version&lt;/a&gt;, it allows to use both at the same time. When you want to finally migrate, it leads to problems such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Runtime issues: a junit4 class not found&lt;/li&gt;
&lt;li&gt;A test has run, but no coverage aggregated&lt;/li&gt;
&lt;li&gt;Not concise annotations usage&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Solution
&lt;/h3&gt;

&lt;p&gt;All these problems have only one proper solution:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Use one particular version of Junit to prevent misleading and misusage&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here I focus on the latest - Junit 5 version usage, hence, excluding of Junit 4.&lt;/p&gt;

&lt;p&gt;One of the options is to ignore this dependency from a specific dependency:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;testImplementation&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'org.springframework.boot:spring-boot-starter-test'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;exclude&lt;/span&gt; &lt;span class="nl"&gt;group:&lt;/span&gt; &lt;span class="s1"&gt;'org.junit.vintage'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;module:&lt;/span&gt; &lt;span class="s1"&gt;'junit-vintage-engine'&lt;/span&gt;  
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-boot-starter-test&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;test&lt;span class="nt"&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;exclusions&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;exclusion&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.junit.vintage&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;junit-vintage-engine&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/exclusion&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/exclusions&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;But&lt;/strong&gt;, it requires you to know &lt;em&gt;which&lt;/em&gt; dependency brings unpleasant dependency for you. In this case, you can use this command to track:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./gradlew dependencyInsight &lt;span class="nt"&gt;--dependency&lt;/span&gt; &lt;span class="s2"&gt;"junit:junit"&lt;/span&gt; &lt;span class="nt"&gt;--configuration&lt;/span&gt; &lt;span class="s2"&gt;"testCompileClasspath"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another option is to exclude not necessary dependencies from &lt;strong&gt;all the configurations&lt;/strong&gt;. It leads you another problems such as: some library still requires Junit 4 / vintage. But, the compilation / runtime reflection errors actually only makes these dependencies visual and help to mark &lt;strong&gt;explicitly&lt;/strong&gt; those Java modules, that still require on any reason to work with a legacy library.&lt;/p&gt;

&lt;h4&gt;
  
  
  Gradle:
&lt;/h4&gt;

&lt;p&gt;Having &lt;a href="https://docs.gradle.org/current/dsl/org.gradle.api.artifacts.Configuration.html"&gt;configurations in Gradle&lt;/a&gt; it is easy to exclude a dependency in one particular place:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="cm"&gt;/* for all the configurations */&lt;/span&gt;
&lt;span class="n"&gt;configurations&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;all&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="cm"&gt;/* only junit 5 should be used */&lt;/span&gt;
    &lt;span class="n"&gt;exclude&lt;/span&gt; &lt;span class="nl"&gt;group:&lt;/span&gt; &lt;span class="s1"&gt;'junit'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;module:&lt;/span&gt; &lt;span class="s1"&gt;'junit'&lt;/span&gt;
    &lt;span class="n"&gt;exclude&lt;/span&gt; &lt;span class="nl"&gt;group:&lt;/span&gt; &lt;span class="s1"&gt;'org.junit.vintage'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;module:&lt;/span&gt; &lt;span class="s1"&gt;'junit-vintage-engine'&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="cm"&gt;/* for a particular test module */&lt;/span&gt;
&lt;span class="n"&gt;configurations&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;testCompile&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="cm"&gt;/* only junit 5 should be used */&lt;/span&gt;
    &lt;span class="n"&gt;exclude&lt;/span&gt; &lt;span class="nl"&gt;group:&lt;/span&gt; &lt;span class="s1"&gt;'junit'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;module:&lt;/span&gt; &lt;span class="s1"&gt;'junit'&lt;/span&gt;
    &lt;span class="n"&gt;exclude&lt;/span&gt; &lt;span class="nl"&gt;group:&lt;/span&gt; &lt;span class="s1"&gt;'org.junit.vintage'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;module:&lt;/span&gt; &lt;span class="s1"&gt;'junit-vintage-engine'&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;testRuntime&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="cm"&gt;/* only junit 5 should be used */&lt;/span&gt;
    &lt;span class="n"&gt;exclude&lt;/span&gt; &lt;span class="nl"&gt;group:&lt;/span&gt; &lt;span class="s1"&gt;'junit'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;module:&lt;/span&gt; &lt;span class="s1"&gt;'junit'&lt;/span&gt;
    &lt;span class="n"&gt;exclude&lt;/span&gt; &lt;span class="nl"&gt;group:&lt;/span&gt; &lt;span class="s1"&gt;'org.junit.vintage'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;module:&lt;/span&gt; &lt;span class="s1"&gt;'junit-vintage-engine'&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And don't forget to leave a comment for the future!&lt;/p&gt;

&lt;h3&gt;
  
  
  Resume
&lt;/h3&gt;

&lt;p&gt;Hope this note helped to ignore unpleased dependency and keep control over your build configuration. &lt;/p&gt;

</description>
      <category>testing</category>
      <category>java</category>
      <category>gradle</category>
    </item>
    <item>
      <title>Best practices on using Jackson and Lombok</title>
      <dc:creator>Artem Ptushkin</dc:creator>
      <pubDate>Tue, 17 Aug 2021 11:31:25 +0000</pubDate>
      <link>https://dev.to/art_ptushkin/best-practices-on-using-jackson-and-lombok-2lpm</link>
      <guid>https://dev.to/art_ptushkin/best-practices-on-using-jackson-and-lombok-2lpm</guid>
      <description>&lt;p&gt;Jump to the examples here!&lt;/p&gt;

&lt;h3&gt;
  
  
  Issues
&lt;/h3&gt;

&lt;p&gt;In modern Java stack &lt;a href="https://projectlombok.org/"&gt;Lombok&lt;/a&gt; and &lt;a href="https://github.com/FasterXML/jackson"&gt;Jackson&lt;/a&gt; are the most widely used frameworks and as those help to work with DTO there are a bunch of questions and problems might come for the library users.&lt;/p&gt;

&lt;p&gt;There are 631 questions on StackOverflow by the search query &lt;code&gt;https://stackoverflow.com/search?q=lombok+jackson&lt;/code&gt; on the date of writing this article.&lt;/p&gt;

&lt;p&gt;Definitely, a major part of this is specific problems but still a huge part of questions and answers leads to high diversity of examples, annotations usage. Following which, developers spread around repositories very different sets of annotations and configurations. It leaves lack of standards and best practices.&lt;/p&gt;

&lt;h4&gt;
  
  
  Expectations
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Annotations are uniform within different cases&lt;/li&gt;
&lt;li&gt;Jackson serializes and deserialises objects:

&lt;ul&gt;
&lt;li&gt;mutable&lt;/li&gt;
&lt;li&gt;immutable&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Jackson serializes and deserialises objects of classes that are bounded by &lt;strong&gt;inheritance&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Classes contains as less Jackson annotations as possible to keep it framework agnostic and cleaner&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Implementation
&lt;/h4&gt;

&lt;h5&gt;
  
  
  Inheritance case
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;lombok.RequiredArgsConstructor&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;lombok.Value&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;lombok.experimental.NonFinal&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;lombok.experimental.SuperBuilder&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@Value&lt;/span&gt;
&lt;span class="nd"&gt;@NonFinal&lt;/span&gt;
&lt;span class="nd"&gt;@SuperBuilder&lt;/span&gt;
&lt;span class="nd"&gt;@RequiredArgsConstructor&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Card&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nc"&gt;Status&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nc"&gt;Balance&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.beans.ConstructorProperties&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.math.BigDecimal&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;lombok.EqualsAndHashCode&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;lombok.Value&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;lombok.experimental.SuperBuilder&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@Value&lt;/span&gt;
&lt;span class="nd"&gt;@SuperBuilder&lt;/span&gt;
&lt;span class="nd"&gt;@EqualsAndHashCode&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;callSuper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CreditCard&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Card&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;rate&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@ConstructorProperties&lt;/span&gt;&lt;span class="o"&gt;({&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"status"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"balance"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"rate"&lt;/span&gt;&lt;span class="o"&gt;})&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;CreditCard&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Status&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Balance&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt; &lt;span class="n"&gt;rate&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;super&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;rate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rate&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verifying by simple tests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;itSerializes&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;CreditCard&lt;/span&gt; &lt;span class="n"&gt;creditCard&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CreditCard&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"The credit card"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;rate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"5.0"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;ACTIVE&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;balance&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Balance&lt;/span&gt;
                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1L&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"1000.0"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;expectedJson&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;readFromFile&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"credit-card-serialize.json"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;actualJson&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;objectMapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;writeValueAsString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;creditCard&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="nc"&gt;JSONAssert&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;assertEquals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expectedJson&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;actualJson&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;itDeserializes&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;inputJson&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;readFromFile&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"credit-card-deserialize.json"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="nc"&gt;CreditCard&lt;/span&gt; &lt;span class="n"&gt;actual&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;objectMapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;readValue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inputJson&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;CreditCard&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"5.0"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="n"&gt;actual&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getRate&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"The credit card"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;actual&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;assertSame&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;ACTIVE&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;actual&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getStatus&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;assertNotNull&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;actual&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getBalance&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1L&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;actual&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getBalance&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getId&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"1000.0"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="n"&gt;actual&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getBalance&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getValue&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  Mutable with inheritance
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;lombok.Data&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;lombok.NoArgsConstructor&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;lombok.experimental.SuperBuilder&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@Data&lt;/span&gt;
&lt;span class="nd"&gt;@SuperBuilder&lt;/span&gt;
&lt;span class="nd"&gt;@NoArgsConstructor&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Animal&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Data&lt;/span&gt;
&lt;span class="nd"&gt;@SuperBuilder&lt;/span&gt;
&lt;span class="nd"&gt;@AllArgsConstructor&lt;/span&gt;
&lt;span class="nd"&gt;@EqualsAndHashCode&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;callSuper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Cat&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Animal&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt; &lt;span class="n"&gt;lives&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Conclusions
&lt;/h4&gt;

&lt;p&gt;In order to keep your objects immutable and be in the best compliance with Jackson use annotations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;lombok.Value&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;java.beans.ConstructorProperties&lt;/code&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In order to keep object creation clean in DSL style with explicit fields mapping use annotations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;lombok.experimental.SuperBuilder&lt;/code&gt; on both parent and children classes
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;CreditCard&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;rate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"5.0"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"The credit card"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;//parent field&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;ACTIVE&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;balance&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Balance&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;                         
           &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1L&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
           &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BigDecimal&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"1000.0"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;                  
           &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I believe using a standard set of annotations within your project will simplify the maintenance. Reducing the amount of dependencies such as Jackson annotation will make it framework agnostic and plain tests will help you to verify the expected behaviour without a need to run the costly, slow tests.&lt;/p&gt;

&lt;p&gt;Focus on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;immutability&lt;/li&gt;
&lt;li&gt;tests&lt;/li&gt;
&lt;li&gt;uniformity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;a href="https://github.com/artemptushkin/java-dto-playground"&gt;GitHub project&lt;/a&gt; with examples&lt;/p&gt;

</description>
      <category>java</category>
      <category>codequality</category>
    </item>
    <item>
      <title>Best practices on Spring Cloud Kubernetes bootstrap configuration</title>
      <dc:creator>Artem Ptushkin</dc:creator>
      <pubDate>Sun, 30 May 2021 13:22:30 +0000</pubDate>
      <link>https://dev.to/art_ptushkin/best-practices-on-spring-cloud-kubernetes-bootstrap-configuration-4n6k</link>
      <guid>https://dev.to/art_ptushkin/best-practices-on-spring-cloud-kubernetes-bootstrap-configuration-4n6k</guid>
      <description>&lt;p&gt;In this article I want to show the best way to configure any Spring Cloud bootstrap properties in your application, making it the a most flexible and future-proof way.&lt;/p&gt;

&lt;p&gt;Jump to the code here!&lt;/p&gt;

&lt;h3&gt;
  
  
  Microservices stack
&lt;/h3&gt;

&lt;p&gt;Following or switching into more microservice architecture, most modern Spring boot applications start using one day something from &lt;a href="https://github.com/spring-cloud"&gt;Spring Cloud&lt;/a&gt; stack additionally due to its features and compatibility with Spring Boot stack it already has, i.e. you take the whole &lt;em&gt;ecosystem&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I describe an example in &lt;a href="https://dev.to/art_ptushkin/clean-code-in-spring-ecosystem-n4p"&gt;this article&lt;/a&gt; of how neat you it is possible to integrate Spring and Spring Boot by using starters.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Along side with Spring Cloud stack, most applications start using Kubernetes as microservices orchestration service, and for this we have the growing &lt;a href="https://github.com/spring-cloud/spring-cloud-kubernetes"&gt;Spring Cloud Kubernetes&lt;/a&gt; project.&lt;/p&gt;

&lt;p&gt;On purpose to externalise application's properties there are two most commons ways to implement this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;k8s configmap&lt;/li&gt;
&lt;li&gt;Spring Cloud Config server&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Considering &lt;a href="https://stackoverflow.com/questions/59139965/spring-cloud-config-server-vs-configmaps-for-cloud-kubernetes"&gt;pros and cons&lt;/a&gt; both of these are worth to use and none is really &lt;em&gt;better&lt;/em&gt; than another.&lt;/p&gt;

&lt;p&gt;Definitely, stack and complexity grows with this and following the &lt;em&gt;hello world&lt;/em&gt; approaches online developers rather implement configuration in a way that still brings problems and/or kept unclear for other developers.&lt;/p&gt;

&lt;p&gt;One of the crucial and the most important things is enabling/disabling of configuration, as it brings the most influence to your runtime, activating or disabling beans. This is partially confirmed by Stackoverflow questions, querying:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;spring configuration doesn't start&lt;/em&gt;: 973&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;spring configuration disable&lt;/em&gt;: 2748&lt;/li&gt;
&lt;li&gt;and all the other questions on bean duplication / missing problems&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In order to make the best out of your configuration, I'd like to show some best practices on an example with Spring Cloud Kubernetes config.&lt;/p&gt;

&lt;p&gt;Before jumping to the example it's better to know the basis about the Spring application properties order of precedence:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;application properties  &lt;a href="https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.external-config"&gt;https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.external-config&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;bootstrap properties &lt;a href="https://cloud.spring.io/spring-cloud-commons/multi/multi__spring_cloud_context_application_context_services.html"&gt;https://cloud.spring.io/spring-cloud-commons/multi/multi__spring_cloud_context_application_context_services.html&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;a&gt;&lt;/a&gt;How to configure bootstrap properties
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;What are the requirements to the best configuration?&lt;/em&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It always starts in each k8s environment&lt;/li&gt;
&lt;li&gt;It doesn't start in tests&lt;/li&gt;
&lt;li&gt;It start's for a local application run easily when you need it&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;What do we know?&lt;/em&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;bootstrap&lt;/code&gt; properties start before &lt;code&gt;application&lt;/code&gt; one&lt;/li&gt;
&lt;li&gt;application in k8s cluster container fetchs data from k8s configmap only if it's enabled beforehand&lt;/li&gt;
&lt;li&gt;application must know &lt;em&gt;where&lt;/em&gt; to take the properties from before the load&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;spring.cloud.kubernetes.enabled&lt;/code&gt; enables all the sub-configurations&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;spring.cloud.kubernetes.config.enabled&lt;/code&gt; enables fetching configmap&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;kubernetes&lt;/code&gt; profile exists out of box and will be activated always &lt;a href="https://docs.spring.io/spring-cloud-kubernetes/docs/current/reference/html/index.html#kubernetes-profile-autoconfiguration"&gt;when the application runs as a pod inside Kubernetes&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Then we need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;bootstrap.yaml&lt;/code&gt; in resources directory containing:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;spring&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;cloud&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;kubernetes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
      &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;bootstrap-kubernetes.yaml&lt;/code&gt; containing:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;spring&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;cloud&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;kubernetes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
      &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;application.yaml&lt;/code&gt; or &lt;code&gt;application-kubernetes.yaml&lt;/code&gt; containing:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;spring&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;cloud&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;kubernetes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;your-configmap-name&lt;/span&gt;
        &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${KUBERNETES_NAMESPACE}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Env variable &lt;code&gt;KUBERNETES_NAMESPACE&lt;/code&gt; can't be determined on bootstrap configuration loading as the k8s configmap won't be fetched yet. Hence, we put it into &lt;code&gt;application&lt;/code&gt; properties.&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;k8s &lt;code&gt;service.yaml&lt;/code&gt; containing:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;KUBERNETES_NAMESPACE"&lt;/span&gt;
      &lt;span class="na"&gt;valueFrom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;fieldRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;fieldPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;metadata.namespace"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;[OPTIONAL] To make it more transparent to developers and let everyone know that &lt;code&gt;kubernetes&lt;/code&gt; profile will be enabled I'd advice to put this profile explicitly, &lt;code&gt;service.yaml&lt;/code&gt;. Another argument here, that if you already use &lt;code&gt;SPRING_PROFILES_ACTIVE&lt;/code&gt; than it definitely will be clearer if you put &lt;em&gt;additionally&lt;/em&gt; the &lt;code&gt;kubernetes&lt;/code&gt; profile, defining all the profiles list at the same place:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SPRING_PROFILES_ACTIVE&lt;/span&gt;
      &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;your-profile,kubernetes"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Conclusions
&lt;/h3&gt;

&lt;p&gt;With this configuration you can easily enable k8s by activating &lt;code&gt;kubernetes&lt;/code&gt; profile and it will disabled on any other run.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hints
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Staring common &lt;code&gt;@SpringBootApplication&lt;/code&gt; main class with &lt;code&gt;kubernetes&lt;/code&gt; profile we aware that

&lt;ol&gt;
&lt;li&gt;You might need env variable &lt;code&gt;KUBERNETES_NAMESPACE&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;It uses k8s context and namespace from the one that is used in your configuration (kubectl) now&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>spring</category>
      <category>java</category>
      <category>codequality</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>Consumer and provider binding in contract-testing</title>
      <dc:creator>Artem Ptushkin</dc:creator>
      <pubDate>Mon, 22 Feb 2021 16:45:21 +0000</pubDate>
      <link>https://dev.to/art_ptushkin/consumer-and-provider-binding-in-contract-testing-2ib1</link>
      <guid>https://dev.to/art_ptushkin/consumer-and-provider-binding-in-contract-testing-2ib1</guid>
      <description>&lt;p&gt;I believe the fact that you are using contract-testing already has brought you here.&lt;/p&gt;

&lt;p&gt;This approach seems simple for the first look but brings new questions and discoveries upon getting into it.&lt;/p&gt;

&lt;p&gt;One of them is the understanding of how actually the contract corresponds with the consumer and provider.&lt;/p&gt;

&lt;p&gt;Let's consider HTTP integration as a classic one and &lt;a href="https://docs.pact.io/"&gt;Pact&lt;/a&gt; as a consumer-driven-contracts framework here but &lt;a href="https://cloud.spring.io/spring-cloud-contract/"&gt;Spring Cloud Contract&lt;/a&gt; follows the same rules.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The contract will be always used as a stub on the consumer side and as a set of validation criteria on the provider side&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JxbZW8nV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r59rie82h996z48ijj4a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JxbZW8nV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r59rie82h996z48ijj4a.png" alt="1_TCch2EAD4JSDkFhWOhM3ew"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;How does it affect me?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Each time you run consumer contract tests, it uses the contract data to start on it a stub server with &lt;strong&gt;expectations&lt;/strong&gt; on a &lt;strong&gt;request&lt;/strong&gt; and prepared stub data for &lt;strong&gt;response&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Each time you run provider tests, it uses the contract test to build a &lt;strong&gt;request&lt;/strong&gt; to your actual server. Then it verifies the actual &lt;strong&gt;response&lt;/strong&gt; against a set of validation criteria in the contact.&lt;/p&gt;

&lt;p&gt;What's actually might be interesting here is to get an understanding of the concept of the strictness of the request/response data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Request
&lt;/h3&gt;

&lt;p&gt;Consider, you expect that a server accepts your authorization header with a Bearer JWT token.&lt;/p&gt;

&lt;p&gt;Speaking without code: &lt;em&gt;I expect when my app calls you with any valid JWT token you respond 200&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Header&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;Authorization&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Bearer eyJraWQiOiJ0aGlzLWlzLXJ&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Consumer
&lt;/h4&gt;

&lt;p&gt;You might not care about the strictness of the request data, i.e. you can use a stub that expects: &lt;em&gt;any JWT bearer token&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It means that matters only the &lt;strong&gt;format&lt;/strong&gt; of data and not the data itself.&lt;/p&gt;

&lt;h4&gt;
  
  
  Provider
&lt;/h4&gt;

&lt;p&gt;The request &lt;strong&gt;must&lt;/strong&gt; be strict otherwise, the framework won't be able to build an actual request.&lt;/p&gt;

&lt;p&gt;Options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Framework generates a random value&lt;/li&gt;
&lt;li&gt;Consumer prepare an example that will be used as a strict value&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Having random values can be viable for some cases, but it leaves uncertainty as &lt;em&gt;the example&lt;/em&gt;, that comes with the contract, will be non-informative.&lt;/p&gt;

&lt;p&gt;In other words, the &lt;strong&gt;data&lt;/strong&gt; of the request is crucial technically. And it is better to keep it strict as opposed to random.&lt;/p&gt;

&lt;p&gt;That's why Pact framework has this option to provide the example for any data or not, btw.&lt;/p&gt;

&lt;h3&gt;
  
  
  Response
&lt;/h3&gt;

&lt;p&gt;Vice versa for the response.&lt;/p&gt;

&lt;p&gt;The consumer must receive &lt;strong&gt;strict&lt;/strong&gt; values in the response from the stub server.&lt;/p&gt;

&lt;p&gt;The provider can respond with something that &lt;strong&gt;matches&lt;/strong&gt; some data by a patter.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;request&lt;/th&gt;
&lt;th&gt;response&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;consumer&lt;/td&gt;
&lt;td&gt;not&lt;/td&gt;
&lt;td&gt;strict&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;provider&lt;/td&gt;
&lt;td&gt;strict&lt;/td&gt;
&lt;td&gt;not&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  The reference in the contract
&lt;/h3&gt;

&lt;p&gt;That's when you put the expectations like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;matchHeader&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Authorization"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Bearer.*"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Bearer eyJraWQiOiJ0aGlzLWlzLXJ"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where the second parameter is the regexp that you expect to match the header.&lt;/p&gt;

&lt;p&gt;It will be converted in the pact to the &lt;strong&gt;scrict&lt;/strong&gt; values:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="s2"&gt;"request"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GET"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/your/path"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"headers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"Authorization"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bearer eyJraWQiOiJ0aGlzLWlzLXJ"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Plus &lt;code&gt;matchingRules&lt;/code&gt; that come from the regexp property we passed above:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"matchingRules"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"header"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Authorization"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"matchers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="nl"&gt;"match"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"regex"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                  &lt;/span&gt;&lt;span class="nl"&gt;"regex"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bearer.*"&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"combine"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AND"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Having the table above and the pact you can link them now and refer to this in your investigations.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;request&lt;/th&gt;
&lt;th&gt;response&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;consumer&lt;/td&gt;
&lt;td&gt;matchingRules&lt;/td&gt;
&lt;td&gt;strict values&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;provider&lt;/td&gt;
&lt;td&gt;strict values&lt;/td&gt;
&lt;td&gt;matchingRules&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Thinking about the format and data it is also right to consider it like this:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;request&lt;/th&gt;
&lt;th&gt;response&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;consumer&lt;/td&gt;
&lt;td&gt;format&lt;/td&gt;
&lt;td&gt;data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;provider&lt;/td&gt;
&lt;td&gt;data&lt;/td&gt;
&lt;td&gt;format&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Sure, don't forget that for 'data' you can use random values.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusions
&lt;/h3&gt;

&lt;p&gt;Here I'd like to remind you that contract testing is &lt;a href="https://docs.pact.io/#consumer-driven-contracts"&gt;the testing by the example approach&lt;/a&gt;. Thus, if you pay attention to the examples and understand the logic behind them, it will help you to have a great set of request/response samples that you can share with your teammates in combination with tests.&lt;/p&gt;

&lt;p&gt;For more reference about the strict request and loose response read about &lt;a href="https://en.wikipedia.org/wiki/Robustness_principle"&gt;Robustness principle&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I think one of the most important parts of understanding contract testing is the behavior of stubs and verifications. Hope this note can help you to think through this concept.&lt;/p&gt;

&lt;p&gt;PS. I wrote about the contract testing approach &lt;a href="https://medium.com/everon-engineering/contract-testing-in-everon-751e739038eb"&gt;here&lt;/a&gt;. Please join for more.&lt;/p&gt;

</description>
      <category>testing</category>
      <category>pact</category>
    </item>
    <item>
      <title>How does Jacoco work with Sonar?</title>
      <dc:creator>Artem Ptushkin</dc:creator>
      <pubDate>Tue, 29 Dec 2020 11:05:45 +0000</pubDate>
      <link>https://dev.to/art_ptushkin/how-do-jacoco-and-sonar-works-in-integration-1ofn</link>
      <guid>https://dev.to/art_ptushkin/how-do-jacoco-and-sonar-works-in-integration-1ofn</guid>
      <description>&lt;p&gt;This pair of frameworks: Jacoco+Sonar is very popular in the Java stack applications. Despite it most of Gradle/Maven files look unclear and it can take time to figure out how it is configured for the arbitrary repository.&lt;/p&gt;

&lt;p&gt;I would like to clarify it with the schema to give developers a chance not to spend time on some things while working on a question about code coverage.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7kz-yoU3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/wel7a7b2oeezqjq66l6y.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7kz-yoU3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/wel7a7b2oeezqjq66l6y.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rectangle - files as inputs and outputs&lt;/li&gt;
&lt;li&gt;Rhombus - Gradle/Maven commands&lt;/li&gt;
&lt;li&gt;Circle - external soft/jars&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hope it helps you to sort out the process!&lt;/p&gt;

</description>
      <category>testing</category>
      <category>java</category>
    </item>
    <item>
      <title>How to build jdbc url to Google SQL instance?</title>
      <dc:creator>Artem Ptushkin</dc:creator>
      <pubDate>Thu, 25 Jun 2020 13:36:44 +0000</pubDate>
      <link>https://dev.to/art_ptushkin/how-to-build-jdbc-url-to-google-sql-instance-1g4b</link>
      <guid>https://dev.to/art_ptushkin/how-to-build-jdbc-url-to-google-sql-instance-1g4b</guid>
      <description>&lt;p&gt;I find it pretty tricky and not transparent on how to build JDBC URL to Google SQL Database instance.&lt;/p&gt;

&lt;p&gt;Postgresql example placeholder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;jdbc:postgresql:///{database_name}?socketFactory=com.google.cloud.sql.postgres.SocketFactory&amp;amp;cloudSqlInstance={connection_name}:{instance_id}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6PRHEZw8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/60d444106v8lc6yozaha.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6PRHEZw8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/60d444106v8lc6yozaha.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6FeKoxyz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/dpvknt8883vooxub8ax9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6FeKoxyz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/dpvknt8883vooxub8ax9.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can find drivers at &lt;a href="https://github.com/GoogleCloudPlatform/cloud-sql-jdbc-socket-factory/releases"&gt;github&lt;/a&gt; to setup connection&lt;/p&gt;

&lt;p&gt;Hope it helps!&lt;/p&gt;

</description>
      <category>googlecloud</category>
      <category>database</category>
      <category>java</category>
      <category>sql</category>
    </item>
  </channel>
</rss>
