<?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: Tiago Martinho</title>
    <description>The latest articles on DEV Community by Tiago Martinho (@tiagomartinho).</description>
    <link>https://dev.to/tiagomartinho</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%2F413276%2Fc75fc74b-791e-44fc-aaf9-2d11ac768726.jpg</url>
      <title>DEV Community: Tiago Martinho</title>
      <link>https://dev.to/tiagomartinho</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tiagomartinho"/>
    <language>en</language>
    <item>
      <title>A summary on Structured Concurrency in Java</title>
      <dc:creator>Tiago Martinho</dc:creator>
      <pubDate>Mon, 18 Dec 2023 17:08:01 +0000</pubDate>
      <link>https://dev.to/tiagomartinho/a-summary-on-structured-concurrency-in-java-5g25</link>
      <guid>https://dev.to/tiagomartinho/a-summary-on-structured-concurrency-in-java-5g25</guid>
      <description>&lt;p&gt;Structured concurrency is currently a preview feature in Java 21 that simplifies concurrent programming by treating groups of related tasks running in different threads as a single unit of work. This approach streamlines error handling, cancellation, and enhances observability, making it easier to build maintainable, reliable, and efficient concurrent applications.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Benefits of Structured Concurrency
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Simplified concurrent programming&lt;/strong&gt;: Structured concurrency allows developers to focus on the business at hand instead of orchestrating threading.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Improved error handling and cancellation&lt;/strong&gt;: By treating tasks as a single unit, structured concurrency makes it easier to handle errors and cancel tasks when necessary.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enhanced observability&lt;/strong&gt;: Structured concurrency helps developers better understand the performance impacts and possible bottlenecks in their concurrent applications.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Getting Started with Structured Concurrency
&lt;/h3&gt;

&lt;p&gt;To use the &lt;code&gt;StructuredTaskScope&lt;/code&gt; API in Java, you need to enable preview features in your IDE.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example of Structured Concurrency
&lt;/h3&gt;

&lt;p&gt;Here is an example of using the &lt;code&gt;StructuredTaskScope&lt;/code&gt; API (by the way, using an unnamed class, also a preview feature in Java 21):&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="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.concurrent.Callable&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.util.concurrent.ExecutionException&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.util.concurrent.StructuredTaskScope&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.util.function.Supplier&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

     &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&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;ExecutionException&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;InterruptedException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
         &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;scope&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;StructuredTaskScope&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ShutdownOnFailure&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
             &lt;span class="nc"&gt;Supplier&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fork&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fetchName&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
             &lt;span class="nc"&gt;Supplier&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fork&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fetchAge&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;

             &lt;span class="n"&gt;scope&lt;/span&gt;
                     &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;            &lt;span class="c1"&gt;// Join both subtasks&lt;/span&gt;
                     &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;throwIfFailed&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;  &lt;span class="c1"&gt;// ... and propagate errors&lt;/span&gt;

             &lt;span class="c1"&gt;// Here, both subtasks have succeeded, so compose their results&lt;/span&gt;
             &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Name is "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;". Age is "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
         &lt;span class="o"&gt;}&lt;/span&gt;
     &lt;span class="o"&gt;}&lt;/span&gt;

     &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Callable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;fetchName&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
         &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Tiago"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
     &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Callable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;fetchAge&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;29&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, the &lt;code&gt;StructuredTaskScope.ShutdownOnFailure()&lt;/code&gt; instance is used to fork two tasks, &lt;code&gt;fetchName&lt;/code&gt; and &lt;code&gt;fetchAge&lt;/code&gt;, which run concurrently. The main task waits for both subtasks to complete before continuing. If a subtask fails, the entire task scope is terminated, ensuring that resources are properly cleaned up.&lt;br&gt;
The use of &lt;code&gt;StructuredTaskScope&lt;/code&gt; ensures several valuable properties in concurrent programming. Firstly, it implements error handling with short-circuiting, meaning that if either the &lt;code&gt;fetchName()&lt;/code&gt; or &lt;code&gt;fetchAge()&lt;/code&gt; subtasks fail, the other is promptly cancelled if it has not completed yet, with the ability to customize this behavior using different shutdown policies. Additionally, cancellation propagation is seamlessly managed; if the thread running &lt;code&gt;main()&lt;/code&gt; is interrupted before or during the call to &lt;code&gt;join()&lt;/code&gt;, both subtasks are automatically cancelled when the thread exits the scope. This contributes to code clarity, as the structure is evident: setting up subtasks, awaiting their completion or cancellation, and making a decision based on the results. Lastly, for observability, a thread dump clearly illustrates the task hierarchy, depicting the threads executing &lt;code&gt;fetchName()&lt;/code&gt; and &lt;code&gt;fetchAge()&lt;/code&gt; as children of the scope. This enhances transparency and aids in understanding the concurrent execution flow.&lt;/p&gt;
&lt;h3&gt;
  
  
  Extending the StructuredTaskScope Class
&lt;/h3&gt;

&lt;p&gt;Developers can also create their own subclasses of &lt;code&gt;StructuredTaskScope&lt;/code&gt; to customize its behavior. For example, a subclass can override the &lt;code&gt;handleComplete&lt;/code&gt; method to define specific actions when a task is completed. The following is an example of a &lt;code&gt;StructuredTaskScope&lt;/code&gt; subclass that collects the results of subtasks that complete successfully. It defines the method &lt;code&gt;results()&lt;/code&gt; to be used by the main task to retrieve the results.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyScope&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;StructuredTaskScope&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Queue&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;results&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;ConcurrentLinkedQueue&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;

    &lt;span class="nc"&gt;MyScope&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="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofVirtual&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;factory&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;protected&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;handleComplete&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Subtask&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;subtask&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subtask&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nc"&gt;Subtask&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;State&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SUCCESS&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subtask&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;MyScope&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;join&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;InterruptedException&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="na"&gt;join&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Returns a stream of results from the subtasks that completed successfully&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Stream&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;results&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="na"&gt;ensureOwnerAndJoined&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This custom policy can be used like so:&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;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;allSuccessful&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Callable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;tasks&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;InterruptedException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;scope&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;MyScope&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;tasks&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fork&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;results&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;toList&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Structured concurrency is a promising addition to the Java standard API, simplifying concurrent programming and making it easier to build maintainable, reliable, and efficient applications. As this feature progresses from preview to stable, it is poised to unlock new possibilities in concurrent application development.&lt;/p&gt;

&lt;h3&gt;
  
  
  References
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://openjdk.org/jeps/453"&gt;https://openjdk.org/jeps/453&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Virtual Threads in Java 21</title>
      <dc:creator>Tiago Martinho</dc:creator>
      <pubDate>Thu, 02 Nov 2023 10:00:00 +0000</pubDate>
      <link>https://dev.to/tiagomartinho/virtual-threads-in-java-21-42k1</link>
      <guid>https://dev.to/tiagomartinho/virtual-threads-in-java-21-42k1</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;For developers entrenched in the complexities of concurrent programming, virtual threads represent more than just another update. It's a potential game-changer, a practical solution to the long-standing challenges of managing multiple tasks efficiently. With the promise of enhanced scalability and performance, these virtual threads are poised to simplify the intricacies of handling concurrent operations, enabling developers to streamline their workflows and optimize resource utilization. In this blog post, we'll take a pragmatic dive into the core functionalities and application of Java 21's virtual threads, examining their real-world implications and the ways in which they can revolutionize the development process. Get ready to uncover a powerful tool that's not just theoretical, but one that holds the promise of significantly improving the practical aspects of your coding endeavors.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are virtual threads exactly?
&lt;/h2&gt;

&lt;p&gt;Virtual threads represent a significant shift in how the Java Virtual Machine (JVM) handles threads. Unlike traditional threads (called Platform or Native threads), which are mapped directly to operating system (OS) threads, virtual threads are managed by the JVM itself. They are lightweight, highly scalable, and designed to enable more efficient use of system resources.&lt;/p&gt;

&lt;p&gt;These virtual threads operate within a shared pool of underlying OS threads, allowing the JVM to manage them dynamically, based on the available resources and the workload. This approach minimizes the overhead associated with creating and managing OS threads, making it possible to handle a much larger number of concurrent tasks without overburdening the system.&lt;/p&gt;

&lt;p&gt;By decoupling the association between Java threads and OS threads, virtual threads provide a more flexible and resource-efficient mechanism for managing concurrency in Java applications. This feature enables developers to create a significantly higher number of threads without the performance penalties typically associated with the traditional thread model. Additionally, virtual threads facilitate smoother integration with existing codebases and frameworks, making it easier to optimize the performance of concurrent applications without significant code changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to use virtual threads
&lt;/h2&gt;

&lt;p&gt;The following is a code example on how to use virtual threads using the &lt;code&gt;Thread&lt;/code&gt;class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;startVirtualThread&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Running virtual thread: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;currentThread&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
&lt;span class="o"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// or&lt;/span&gt;
&lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ofVirtual&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;start&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Running virtual thread: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;currentThread&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;thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// for allowing you to see the message as it waits for the thread to terminate, before the main thread terminates&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the following is a code example on how to use virtual threads using the &lt;code&gt;ExecutorService&lt;/code&gt;interface.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;ExecutorService&lt;/span&gt; &lt;span class="n"&gt;executor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Executors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newVirtualThreadPerTaskExecutor&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;executor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;submit&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Running virtual thread with ExecutorService: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;currentThread&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="o"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The last example is the recommended approach due to higher level abstraction and the fact that you don't have to worry about thread management yourself as &lt;code&gt;ExecutorService&lt;/code&gt; will reuse threads for multiple tasks, ultimately reducing overhead on creation and destruction of said threads.&lt;/p&gt;

&lt;h2&gt;
  
  
  Virtual Threads under the hood
&lt;/h2&gt;

&lt;p&gt;Internally, a specialized pool of platform threads, which is essentially a customized fork-join pool, is employed to execute virtual threads. These virtual threads are tethered to specific platform threads from the pool, utilizing them for task execution.&lt;/p&gt;

&lt;p&gt;Consider a scenario where your task involves a blocking I/O operation, such as a database request to retrieve user data. It's crucial to prevent the blocking of a platform thread. In such instances, the virtual thread identifies the blocking I/O operation and unmounts itself from the platform thread it's running on. It accomplishes this by moving its context/stack to the heap memory.&lt;/p&gt;

&lt;p&gt;More specifically, this detachment is done by a specialized object known as a &lt;code&gt;Continuation&lt;/code&gt;, which utilizes its &lt;code&gt;run()&lt;/code&gt; method to manage the execution of the virtual thread and, consequently, your task. When a blocking call occurs, a call to &lt;code&gt;Continuation.yield()&lt;/code&gt; initiates the process of unmounting the virtual thread from the platform thread and copying its stack to the heap memory. This process can be seen in the following animation:&lt;/p&gt;

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

&lt;p&gt;After the response data is available, the operating system handler responsible for monitoring the data triggers a signal that invokes &lt;code&gt;Continuation.run()&lt;/code&gt;. This action involves retrieving the stack of the virtual thread from the heap memory and placing it in the wait list of the original platform thread within the fork-join pool. This can be seen below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe7hzcecr1f9al71mwxgq.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe7hzcecr1f9al71mwxgq.gif" alt="heap memory to wait list of platform thread"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Furthermore, in situations where a thread is busy, and an alternative thread is accessible, the latter may 'steal' the task from the former. This phenomenon allows for the seamless transition of tasks between different platform threads when a thread is busy.&lt;/p&gt;

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

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

&lt;p&gt;As we've explored throughout this post, the benefits of virtual threads extend beyond mere optimization; they represent a fundamental shift in the way developers approach and implement concurrent operations in Java applications. With the ability to seamlessly integrate with existing codebases and frameworks, virtual threads empower developers to harness the full potential of concurrent programming, enabling the creation of highly responsive, resource-efficient, and scalable applications.&lt;br&gt;
As developers continue to leverage this groundbreaking feature, it is evident that virtual threads will play a pivotal role in shaping the future of high-performance, concurrent applications, ushering in a new era of efficiency and scalability in the world of Java programming.&lt;/p&gt;

&lt;h2&gt;
  
  
  Useful references
&lt;/h2&gt;

&lt;p&gt;2 minute video that explains virtual threads: &lt;a href="https://www.youtube.com/watch?v=bOnIYy3Y5OA" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=bOnIYy3Y5OA&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Deep dive video on virtual threads:&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=5E0LU85EnTI" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=5E0LU85EnTI&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Oracle documentation on virtual threads:&lt;br&gt;
&lt;a href="https://docs.oracle.com/en/java/javase/21/core/virtual-threads.html#GUID-DC4306FC-D6C1-4BCC-AECE-48C32C1A8DAA" rel="noopener noreferrer"&gt;https://docs.oracle.com/en/java/javase/21/core/virtual-threads.html#GUID-DC4306FC-D6C1-4BCC-AECE-48C32C1A8DAA&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Flyway Migrations: Simplifying Database Version Control</title>
      <dc:creator>Tiago Martinho</dc:creator>
      <pubDate>Thu, 12 Oct 2023 11:00:00 +0000</pubDate>
      <link>https://dev.to/tiagomartinho/flyway-migrations-simplifying-database-version-control-1e6k</link>
      <guid>https://dev.to/tiagomartinho/flyway-migrations-simplifying-database-version-control-1e6k</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In today's fast-paced software development world, managing database changes can be a challenging task. Database migrations play a crucial role in keeping the database schema in sync with the application code. One popular tool that simplifies this process is Flyway. In this blog post, we will explore the benefits of using Flyway for database migrations and how it can streamline the version control of your database.&lt;/p&gt;

&lt;h2&gt;
  
  
  Streamlining Database Migrations with Flyway
&lt;/h2&gt;

&lt;p&gt;Flyway is an open-source database migration tool that provides a simple and reliable solution for managing database changes. It follows a convention-over-configuration approach, making it easy to integrate into your existing projects. With Flyway, you can effortlessly migrate your database schema and keep it in sync with your application code, eliminating the need for manual intervention.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automating Database Version Control
&lt;/h2&gt;

&lt;p&gt;One of the key advantages of Flyway is its ability to automate database version control. It uses a versioned migration approach, where each migration script is associated with a version number. Flyway maintains a metadata table in the database to keep track of which migrations have been applied. This allows Flyway to apply only the necessary migrations, making it efficient and reliable.&lt;/p&gt;

&lt;p&gt;To create a Flyway migration, you need to follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Choose the scripting language: Flyway supports multiple scripting languages such as SQL, JavaScript, Groovy, and more. Choose the language that suits your needs.&lt;/li&gt;
&lt;li&gt;Create the migration script: Create a new file with a descriptive name and a version number. For example, &lt;code&gt;V1__create_table.sql&lt;/code&gt;. This version number is important as Flyway uses it to determine the order in which migrations should be applied.&lt;/li&gt;
&lt;li&gt;Write the migration script: In the migration script, you can include SQL statements to create or modify database objects such as tables, columns, indexes, etc. For example, you can use SQL statements like &lt;code&gt;CREATE TABLE&lt;/code&gt;, &lt;code&gt;ALTER TABLE&lt;/code&gt;, &lt;code&gt;INSERT INTO&lt;/code&gt;, etc.&lt;/li&gt;
&lt;li&gt;Place the migration script in the appropriate location: Flyway follows a convention where migration scripts are placed in a specific directory. For example, in a Maven project, you can place the migration script in the &lt;code&gt;src/main/resources/db/migration&lt;/code&gt; directory.&lt;/li&gt;
&lt;li&gt;Run Flyway: Once you have created the migration script, you can run Flyway to apply the migrations. Flyway will automatically detect and execute the pending migrations.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here's an example of a Flyway migration file:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Filename&lt;/strong&gt;: &lt;code&gt;V1__create_customers_table.sql&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Create the "customers" table&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;customers&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="nb"&gt;TIMESTAMP&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="k"&gt;CURRENT_TIMESTAMP&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, the migration file creates a table named "customers" with columns for "id", "name", "email", and "created_at". The migration file follows the naming convention of starting with a version number, in this case, "V1", followed by a double underscore "__" and a descriptive name.&lt;/p&gt;

&lt;p&gt;You can place this migration file in the appropriate directory for Flyway to detect and execute during the migration process.&lt;/p&gt;

&lt;p&gt;Here's an example of how you can run the database migrations using Flyway in Java code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.flywaydb.core.Flyway&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;DatabaseMigration&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;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Create a Flyway instance&lt;/span&gt;
        &lt;span class="nc"&gt;Flyway&lt;/span&gt; &lt;span class="n"&gt;flyway&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Flyway&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;configure&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;dataSource&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"jdbc:mysql://localhost:3306/mydb"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"username"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"password"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;load&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// Migrate the database&lt;/span&gt;
        &lt;span class="n"&gt;flyway&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;migrate&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// Print the status after migration&lt;/span&gt;
        &lt;span class="n"&gt;flyway&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;all&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;forEach&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, we create a Flyway instance and configure it with the necessary database connection details. The &lt;code&gt;migrate()&lt;/code&gt; method is then called to apply the pending migrations to the database. Finally, the &lt;code&gt;info()&lt;/code&gt; method is used to retrieve the current status of all migrations, which is printed to the console.&lt;/p&gt;

&lt;p&gt;Remember to replace &lt;code&gt;"jdbc:mysql://localhost:3306/mydb"&lt;/code&gt;, &lt;code&gt;"username"&lt;/code&gt;, and &lt;code&gt;"password"&lt;/code&gt; with your actual database connection details.&lt;/p&gt;

&lt;p&gt;With this Java code, you can easily incorporate the database migration functionality into your application and ensure that your database schema is always up to date with your application code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handling Database Rollbacks
&lt;/h2&gt;

&lt;p&gt;Another noteworthy feature of Flyway is its support for database rollbacks. In case of a failed migration or a need to revert a change, Flyway allows you to easily rollback the applied migrations. By executing the rollback command, Flyway will undo the last applied migration, ensuring that your database remains in a consistent state.&lt;/p&gt;

&lt;p&gt;For example, let's say you have applied a migration to create a new table in your database. If you encounter an issue with that migration or need to revert it, you can use the rollback command to undo the changes. Flyway will execute the corresponding "down" migration script, which is the opposite of the "up" migration script that created the table. This way, your database can be reverted to its previous state.&lt;/p&gt;

&lt;p&gt;Consider the previous migration file we created &lt;code&gt;V1__create_customers_table.sql&lt;/code&gt; that creates a table named &lt;code&gt;customers&lt;/code&gt;. If you want to rollback this migration, you can execute the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;flyway&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;undo&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Flyway will identify the last applied migration and execute the corresponding "down" migration script, which will drop the &lt;code&gt;customers&lt;/code&gt; table.&lt;/p&gt;

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

&lt;p&gt;Managing database changes is a critical aspect of software development, and Flyway simplifies this process by providing a robust and easy-to-use solution. With Flyway, you can automate database version control, streamline your build process, and handle rollbacks effortlessly. By adopting Flyway for your database migrations, you can ensure that your database schema and application code are always in sync, saving time and reducing the risk of errors.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Interacting with your database with jOOQ</title>
      <dc:creator>Tiago Martinho</dc:creator>
      <pubDate>Wed, 04 Oct 2023 08:55:00 +0000</pubDate>
      <link>https://dev.to/tiagomartinho/interacting-with-your-database-with-jooq-51ga</link>
      <guid>https://dev.to/tiagomartinho/interacting-with-your-database-with-jooq-51ga</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In the world of modern software development, interacting with databases is a common requirement. jOOQ, short for Java Object Oriented Querying, is a powerful and popular open-source library that provides a fluent API for building type-safe SQL queries. In this blog post, we will explore the process of setting up jOOQ and making queries using this versatile tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up jOOQ
&lt;/h2&gt;

&lt;p&gt;To begin using jOOQ, we first need to set it up in our project. The first step is to include the jOOQ dependency in our build configuration file. Whether you are using Maven or Gradle, you can easily add the jOOQ dependency by specifying the appropriate coordinates.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Maven:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;dependencies&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.jooq&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;jooq&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;3.18.6&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependencies&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Gradle:&lt;/strong&gt;&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;dependencies&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s1"&gt;'org.jooq:jooq:3.18.6'&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the dependency is added, we need to generate the jOOQ classes that will represent our database schema. jOOQ provides a code generation tool that can analyze the structure of our database and generate the necessary classes. This tool can be configured through an XML file or programmatically using the jOOQ API.&lt;/p&gt;

&lt;p&gt;Here is an example of configuring the code generation tool programmatically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Configuration&lt;/span&gt; &lt;span class="n"&gt;configuration&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;Configuration&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withJdbc&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;Jdbc&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withDriver&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"org.postgresql.Driver"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withUrl&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"jdbc:postgresql://localhost:5432/mydatabase"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withUser&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"username"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withPassword&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"password"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withGenerator&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;Generator&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withDatabase&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;Database&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"org.jooq.meta.postgres.PostgresDatabase"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withIncludes&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;".*"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withExcludes&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withInputSchema&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"public"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withGenerate&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;Generate&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withPojos&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="na"&gt;withDaos&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="na"&gt;withFluentSetters&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="na"&gt;withTarget&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;Target&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withPackageName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"com.example.jooq.generated"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withDirectory&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"src/main/java"&lt;/span&gt;&lt;span class="o"&gt;)));&lt;/span&gt;

&lt;span class="nc"&gt;GenerationTool&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;generate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;configuration&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After generating the jOOQ classes, we need to establish a connection to our database. jOOQ supports a wide range of database systems, including popular ones like MySQL, PostgreSQL, and Oracle. We can configure the database connection properties in our project's configuration file and use the jOOQ API to establish the connection.&lt;/p&gt;

&lt;p&gt;Here is an example of establishing a connection to a PostgreSQL database:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Connection&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DriverManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getConnection&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"jdbc:postgresql://localhost:5432/mydatabase"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"username"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"password"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Making Queries with jOOQ
&lt;/h2&gt;

&lt;p&gt;Once we have set up jOOQ and established a connection to our database, we can start making queries using the fluent API provided by jOOQ. jOOQ allows us to write SQL queries in a type-safe and convenient manner, making it easier to work with our database.&lt;/p&gt;

&lt;p&gt;To make a query, we first need to create a jOOQ DSLContext object, which serves as the entry point for executing queries.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;DSLContext&lt;/span&gt; &lt;span class="n"&gt;dslContext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;DSL&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;using&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;SQLDialect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;POSTGRES&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can then use the DSLContext object to build our query by chaining method calls to construct the desired SQL statement.&lt;/p&gt;

&lt;p&gt;Here is an example of a simple query that fetches all authors with the name “Tiago” from the &lt;code&gt;AUTHOR&lt;/code&gt; table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dslContext&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;select&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Tables&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;AUTHOR&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Tables&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;AUTHOR&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="na"&gt;eq&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Tiago"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fetch&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we can iterate through the &lt;code&gt;Result&lt;/code&gt; like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Record&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;record&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="nc"&gt;Tables&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;AUTHOR&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ID&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="nc"&gt;String&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;record&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="nc"&gt;Tables&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;AUTHOR&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="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Author ID: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;", Name: "&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="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, here is an example for inserting a record. In this case:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;dslContext&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;insertInto&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Tables&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;AUTHOR&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Tables&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;AUTHOR&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;2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Tables&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;AUTHOR&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;"Jane Doe"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;execute&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An alternative syntax for inserting the same record would be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;dslContext&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;insertInto&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Tables&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;AUTHOR&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="no"&gt;AUTHOR&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="no"&gt;AUTHOR&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="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;values&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Tiago"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;execute&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;jOOQ is a powerful tool that simplifies the process of interacting with databases in Java applications. By providing a fluent API for building type-safe SQL queries, jOOQ makes it easier to write and maintain database code. &lt;/p&gt;

&lt;p&gt;In this blog post, we discussed the process of setting up jOOQ and making queries using its intuitive API. With jOOQ, developers can focus more on the business logic of their applications and spend less time dealing with low-level database interactions.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Creating a backend API for uploading files to Amazon S3 and Google Cloud Storage</title>
      <dc:creator>Tiago Martinho</dc:creator>
      <pubDate>Wed, 27 Sep 2023 15:00:00 +0000</pubDate>
      <link>https://dev.to/tiagomartinho/creating-a-backend-api-for-uploading-files-to-amazon-s3-and-google-cloud-storage-3k79</link>
      <guid>https://dev.to/tiagomartinho/creating-a-backend-api-for-uploading-files-to-amazon-s3-and-google-cloud-storage-3k79</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In modern web development, it is common for users to upload files to websites or applications. Whether it's a profile picture, a document, or any other type of file, handling file uploads is an essential part of many web applications. In a &lt;a href="https://dev.to/tiagomartinho/exploring-the-power-of-sparkjava-framework-20fa"&gt;previous blogpost&lt;/a&gt; we saw how we could use SparkJava to define routes for GET and POST requests. Now we will explore how to parse files sent from the frontend in a POST request and how to store them in cloud providers like Amazon S3 and Google Cloud Platform.&lt;/p&gt;

&lt;h2&gt;
  
  
  Parsing Files with SparkJava
&lt;/h2&gt;

&lt;p&gt;To handle file uploads in SparkJava, we need to first parse the incoming request to extract the uploaded file. SparkJava provides a convenient way to parse files using the &lt;code&gt;Request&lt;/code&gt; object. We can access the uploaded file by calling the &lt;code&gt;raw&lt;/code&gt; method on the request and then retrieving the file using its parameter name. Once we have the file, we can perform various operations on it, such as retrieving its name, size, or content.&lt;/p&gt;

&lt;p&gt;Here's an example of how to parse a file from the request in SparkJava:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/upload"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;filePart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;raw&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getPart&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"file"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// Perform operations on the file&lt;/span&gt;
    &lt;span class="c1"&gt;// e.g. retrieve its name, size, or content&lt;/span&gt;
    &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;part&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getSubmittedFileName&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;part&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getInputStream&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"File uploaded successfully"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above code snippet, we define a POST endpoint at "/upload" that takes in a &lt;code&gt;Request&lt;/code&gt; object and a &lt;code&gt;Response&lt;/code&gt; object as parameters. Inside the post method, we get the input stream of the uploaded file part by calling &lt;code&gt;getInputStream()&lt;/code&gt;. From there, we can perform any necessary operations on the file part like  &lt;code&gt;getSubmittedFileName()&lt;/code&gt;.&lt;br&gt;
The &lt;code&gt;client&lt;/code&gt; object is an abstract class or interface that stores the file contents in the cloud provider of your choice. The actual implementation can be instantiated on your resource or controller depending on your application configuration.&lt;/p&gt;
&lt;h2&gt;
  
  
  Storage client interface
&lt;/h2&gt;

&lt;p&gt;The following is an example of the client interface we described previously.&lt;br&gt;
&lt;/p&gt;

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

   &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;put&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;filename&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;InputStream&lt;/span&gt; &lt;span class="n"&gt;inputstream&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;For simplicity sake we are defining the return type of the method as &lt;code&gt;void&lt;/code&gt; but there are advantages in defining some result type class that wraps the results returned by the cloud provider client methods. For example, you can get the uploaded file metadata. It also allows for easier unit testing. &lt;/p&gt;

&lt;h2&gt;
  
  
  Uploading Files to Amazon S3
&lt;/h2&gt;

&lt;p&gt;After parsing the file in SparkJava, the next step is to upload it to a storage service. To upload files to S3, we need to create an S3 client and specify the bucket where we want to store the file. We can then use the client to upload the file by providing the bucket name, a unique key for the file, and the file's content.&lt;/p&gt;

&lt;p&gt;Here's an example of how to upload a file to Amazon S3 using the AWS SDK for Java:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;AmazonS3&lt;/span&gt; &lt;span class="n"&gt;s3Client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;AmazonS3ClientBuilder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;standard&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
     &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withRegion&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Regions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;EU_WEST_1&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
     &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;withCredentials&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
         &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;AWSStaticCredentialsProvider&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
         &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;BasicAWSCredentials&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                 &lt;span class="n"&gt;s3BucketConfig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;accessKey&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; 
                 &lt;span class="n"&gt;s3BucketConfig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;secretKey&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="n"&gt;s3Client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;putObject&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PutObjectRequest&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;s3BucketConfig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;bucketName&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; 
        &lt;span class="n"&gt;inputstream&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above code snippet, we first create an instance of the Amazon S3 client using the &lt;code&gt;AmazonS3ClientBuilder&lt;/code&gt; class. We specify the desired region for the S3 bucket using the &lt;code&gt;withRegion&lt;/code&gt; method and instantiate the credentials using the necessary keys from our config. Then, we provide the bucket name from our &lt;code&gt;s3BucketConfig&lt;/code&gt;, the filename and the file input stream itself as parameters to the &lt;code&gt;putObject&lt;/code&gt; method of the S3 client. This will upload the file to the specified bucket in Amazon S3.&lt;br&gt;
The S3 client can be wrapped in your own client and implement the &lt;code&gt;StorageClient&lt;/code&gt; interface we defined previously.&lt;/p&gt;
&lt;h2&gt;
  
  
  Uploading Files to Google Cloud Storage
&lt;/h2&gt;

&lt;p&gt;A similar process is used to store the file in Google Cloud storage as can be seen below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;storage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;StorageOptions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;newBuilder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setCredentials&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cloudStorageConfig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;jwtPath&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setProjectId&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cloudStorageConfig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;projectId&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;getService&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;blob&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newBuilder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="nc"&gt;BlobId&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cloudStorageConfig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;bucket&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filename&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="n"&gt;storage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;blob&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;inputStream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;readAllBytes&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First we instantiate a &lt;code&gt;Storage&lt;/code&gt; object from our &lt;code&gt;cloudStorageConfig&lt;/code&gt; which contains the path to our service account key file &lt;code&gt;jwtPath&lt;/code&gt; and our google cloud &lt;code&gt;projectId&lt;/code&gt;.&lt;br&gt;
Then we create a &lt;code&gt;Blob&lt;/code&gt; object using the &lt;code&gt;BlobInfo.newBuilder&lt;/code&gt; method. We just need to provide a &lt;code&gt;BlobId&lt;/code&gt; which we can instantiate from the bucket where we want to store our files and the filename itself.&lt;br&gt;
Finally, the &lt;code&gt;Storage.create&lt;/code&gt; method will upload our file to the cloud storage bucket of our choice.&lt;br&gt;
Like the S3 client, the Google Storage client can be wrapped and implement the &lt;code&gt;StorageClient&lt;/code&gt; interface.&lt;/p&gt;

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

&lt;p&gt;Handling file uploads is a crucial aspect of web development, and with SparkJava and Amazon S3 or Google Cloud Storage, it becomes a seamless process. By parsing files with SparkJava and uploading them to the cloud provider of our choice we can securely store files in the cloud and access them whenever needed. This combination of technologies provides a robust solution for managing file uploads in web applications.&lt;/p&gt;

&lt;p&gt;So, the next time you need to implement file uploading in your web application, consider using SparkJava and Amazon S3 or Google Cloud Storage for a reliable and scalable solution. By following the examples outlined in this blog post, you'll be able to handle file uploads seamlessly and provide a great user experience.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Exploring the Power of SparkJava</title>
      <dc:creator>Tiago Martinho</dc:creator>
      <pubDate>Sun, 17 Sep 2023 17:31:34 +0000</pubDate>
      <link>https://dev.to/tiagomartinho/exploring-the-power-of-sparkjava-framework-20fa</link>
      <guid>https://dev.to/tiagomartinho/exploring-the-power-of-sparkjava-framework-20fa</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In the world of web development, there are countless frameworks available to choose from. Each framework has its own unique features and advantages. One framework that I discovered and have been using for the past 2 years since I joined Revolut is SparkJava. SparkJava is a lightweight web framework that allows you to quickly build web applications. In this blog post, I will explain some of the features and benefits of SparkJava and why I think it’s a great alternative to other, heavier, frameworks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Simplified Routing and Request Handling
&lt;/h2&gt;

&lt;p&gt;One of the key features that sets SparkJava apart from other frameworks is its simplified routing and request handling. With SparkJava, you can can easily define routes and handle incoming requests with just a few lines of code. The framework provides a clean and intuitive syntax that allows you to quickly map URLs to specific routes and define the corresponding actions to be taken.&lt;/p&gt;

&lt;p&gt;Here's an example of how to define a &lt;code&gt;GET&lt;/code&gt; method in SparkJava:&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="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;static&lt;/span&gt; &lt;span class="n"&gt;spark&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Spark&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;Main&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;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Define a route for the "/hello" URL&lt;/span&gt;
        &lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/hello"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"Hello, World!"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;});&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;In this example, the &lt;code&gt;get()&lt;/code&gt; method is used to define a route for the "/hello" URL. The lambda function &lt;code&gt;(request, response) -&amp;gt; { return "Hello, World!"; }&lt;/code&gt; represents the action to be taken when a GET request is made to the "/hello" URL. In this case, it simply returns the string "Hello, World!" as the response.&lt;/p&gt;

&lt;p&gt;And a &lt;code&gt;POST&lt;/code&gt; method:&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="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;static&lt;/span&gt; &lt;span class="n"&gt;spark&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Spark&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;Main&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;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Define a route for the "/new-post" URL with POST method&lt;/span&gt;
        &lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/new-post"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Get the data from the request and process it&lt;/span&gt;
            &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;postData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="c1"&gt;// Save the post to the database or perform any other actions&lt;/span&gt;
            &lt;span class="c1"&gt;// ...&lt;/span&gt;

            &lt;span class="c1"&gt;// Return a success message&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"Post created successfully!"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;});&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;In this example, the &lt;code&gt;post()&lt;/code&gt; method is used to define a route for the "/new-post" URL with the POST method. The lambda function &lt;code&gt;(request, response) -&amp;gt; { ... }&lt;/code&gt; represents the action to be taken when a POST request is made to the "/new-post" URL. Inside the lambda function, you can access the data from the request using &lt;code&gt;request.body()&lt;/code&gt; and process it accordingly. After processing the data, you can save it to the database or perform any other necessary actions. Finally, you can return a success message as the response.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lightweight and Fast Performance
&lt;/h2&gt;

&lt;p&gt;Another major advantage of SparkJava is its lightweight nature and fast performance. Unlike some other heavyweight frameworks, SparkJava is designed to be minimalistic and lightweight, making it perfect for building apps of any size. Its simplicity and minimal overhead result in faster response times and improved performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Comparing SparkJava with other popular frameworks like Spring Boot
&lt;/h2&gt;

&lt;p&gt;When comparing SparkJava with other frameworks like Spring Boot, one advantage of SparkJava is its lightweight nature which allows you to only import the functionality that you need. This is particularly useful when you only care about exposing specific routes in your application. With SparkJava, you can easily define and handle routes without importing unnecessary components or libraries. This helps to keep your application lean and efficient, as you only include the features that are required for your specific use case.&lt;/p&gt;

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

&lt;p&gt;In conclusion, SparkJava is a powerful and lightweight web framework that simplifies the process of building web applications. Its simplicity, fast performance, and extensibility make it a popular choice among developers. Whether you are a beginner or an experienced developer, SparkJava provides an intuitive and efficient way to create robust web applications. So, if you are looking for a framework that strikes the perfect balance between simplicity and functionality, SparkJava might just be the right choice for you.&lt;/p&gt;

</description>
      <category>java</category>
      <category>api</category>
      <category>backend</category>
    </item>
  </channel>
</rss>
