<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/"><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://mehmandarov.com/tag/java/feed.xml" rel="self" type="application/atom+xml"/><link href="https://mehmandarov.com/tag/java/" rel="alternate" type="text/html"/><updated>2026-05-25T10:00:00+02:00</updated><id>https://mehmandarov.com/tag/java/feed.xml</id><title type="html">Rustam Mehmandarov - tag: java</title><subtitle type="text">Posts tagged &quot;java&quot; on Rustam Mehmandarov.</subtitle><author><name>Rustam Mehmandarov</name></author><entry><title type="html">Sane API error handling with RFC 9457 Problem Details in Jakarta EE</title><link href="https://mehmandarov.com/rfc-9457-problem-details-jakarta-ee/" rel="alternate" type="text/html" title="Sane API error handling with RFC 9457 Problem Details in Jakarta EE"/><published>2026-05-25T10:00:00+02:00</published><updated>2026-05-25T10:00:00+02:00</updated><id>https://mehmandarov.com/rfc-9457-problem-details-jakarta-ee</id><content type="html" xml:base="https://mehmandarov.com/rfc-9457-problem-details-jakarta-ee/"><![CDATA[<p><em>When APIs end up with their own error format, it quickly gets annoying for anyone who has to consume more than one API. <a href="https://www.rfc-editor.org/rfc/rfc9457">RFC 9457</a> defines a standard envelope for HTTP API errors. Let&#8217;s have a look at how to do it in Jakarta EE: a small hand-made <code class="language-plaintext highlighter-rouge">ProblemDetail</code> plus one <code class="language-plaintext highlighter-rouge">ExceptionMapper</code> per error category; with the <a href="https://github.com/zalando/problem">Zalando Problem</a> library; followed by quick notes on Quarkus and Spring as alternatives.</em></p>

<ul>
  <li><a href="#introduction">Introduction</a></li>
  <li><a href="#tldr-why-rfc-9457">TL;DR: Why RFC 9457?</a></li>
  <li><a href="#lets-write-some-code">Let&#8217;s write some code!</a>
    <ul>
      <li><a href="#1-hand-made-problemdetail--exceptionmapper">1. Hand-made <code class="language-plaintext highlighter-rouge">ProblemDetail</code> + <code class="language-plaintext highlighter-rouge">ExceptionMapper</code></a></li>
      <li><a href="#2-zalando-problem">2. Zalando Problem</a></li>
      <li><a href="#3-quarkus-quarkus-http-problem">3. Quarkus: <code class="language-plaintext highlighter-rouge">quarkus-http-problem</code></a></li>
      <li><a href="#4-spring-boot--a-short-note">4. Spring Boot &#8211; a short note</a></li>
    </ul>
  </li>
  <li><a href="#conclusion">Conclusion</a></li>
  <li><a href="#whats-next">What&#8217;s Next?</a></li>
</ul>

<hr />

<h2 id="introduction">Introduction</h2>

<p>If you&#8217;ve consumed more than one or two REST APIs, you&#8217;ve seen the pattern. One service returns <code class="language-plaintext highlighter-rouge">{"error": "..."}</code>, another <code class="language-plaintext highlighter-rouge">{"message": "...", "code": 42}</code>, a third returns <code class="language-plaintext highlighter-rouge">200 OK</code> with an error hidden somewhere deep in the response. Your REST client code fills up with special cases for each one. Sounds familiar?</p>

<p><a href="https://www.rfc-editor.org/rfc/rfc9457">RFC 9457 &#8211; Problem Details for HTTP APIs</a> (the successor to RFC 7807) defines a single JSON envelope for errors, served as <code class="language-plaintext highlighter-rouge">application/problem+json</code> MIME type. It is a small spec: five well-defined bits of information and an <code class="language-plaintext highlighter-rouge">extensions</code> map for anything else you might need.</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"urn:problem-type:validation-error"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"title"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Validation Failed"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"status"</span><span class="p">:</span><span class="w"> </span><span class="mi">400</span><span class="p">,</span><span class="w">
  </span><span class="nl">"detail"</span><span class="p">:</span><span class="w"> </span><span class="s2">"The request body or parameters failed validation."</span><span class="p">,</span><span class="w">
  </span><span class="nl">"extensions"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"violations"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
      </span><span class="p">{</span><span class="w"> </span><span class="nl">"field"</span><span class="p">:</span><span class="w"> </span><span class="s2">"title"</span><span class="p">,</span><span class="w"> </span><span class="nl">"message"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Title is required"</span><span class="w"> </span><span class="p">}</span><span class="w">
    </span><span class="p">]</span><span class="w">
  </span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<h2 id="tldr-why-rfc-9457">TL;DR: Why RFC 9457?</h2>

<p>Why not keep creating your own?</p>

<ul>
  <li><strong>Consumers already know the shape.</strong> Generated SDKs, gateways, log pipelines, and tracing tools can parse <code class="language-plaintext highlighter-rouge">application/problem+json</code> without extra work.</li>
  <li><strong>You can extend it without breaking clients.</strong> The <code class="language-plaintext highlighter-rouge">extensions</code> map is part of the spec &#8211; put what you need in there.</li>
  <li><strong>It separates the <em>category</em> from the <em>instance</em>.</strong> <code class="language-plaintext highlighter-rouge">type</code> says &#8220;this is a validation error&#8221; (stable, machine-readable); <code class="language-plaintext highlighter-rouge">detail</code> and <code class="language-plaintext highlighter-rouge">instance</code> describe what happened <em>this</em> time.</li>
</ul>

<p>&#128161; <em><strong>Note:</strong> RFC 9457 is just a JSON structure and a content type. No library or framework is required. That&#8217;s why there are so many implementations &#8211; and why a hand-made one is often a reasonable choice.</em></p>

<hr />

<h2 id="lets-write-some-code">Let&#8217;s write some code!</h2>

<p>I have created a repository called <a href="https://github.com/mehmandarov/api-guide-java">API Guide for Java</a> to showcase the patterns for one of my talks. For this post, have a look at <a href="https://github.com/mehmandarov/api-guide-java/blob/main/src/main/java/com/mehmandarov/confapi/error/ProblemDetail.java"><code class="language-plaintext highlighter-rouge">ProblemDetail.java</code></a> and the mappers next to it under <a href="https://github.com/mehmandarov/api-guide-java/tree/main/src/main/java/com/mehmandarov/confapi/error"><code class="language-plaintext highlighter-rouge">com/mehmandarov/confapi/error/</code></a>.</p>

<h3 id="1-hand-made-problemdetail--exceptionmapper">1. Hand-made <code class="language-plaintext highlighter-rouge">ProblemDetail</code> + <code class="language-plaintext highlighter-rouge">ExceptionMapper</code></h3>

<h4 id="what-it-looks-like">What it looks like</h4>

<p>Imagine you have a REST interface looking like this:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@GET</span>
<span class="nd">@Path</span><span class="o">(</span><span class="s">"/{id}"</span><span class="o">)</span>
<span class="nd">@Operation</span><span class="o">(</span><span class="n">summary</span> <span class="o">=</span> <span class="s">"Get room by ID"</span><span class="o">)</span>
<span class="nd">@APIResponse</span><span class="o">(</span><span class="n">responseCode</span> <span class="o">=</span> <span class="s">"200"</span><span class="o">,</span> <span class="n">description</span> <span class="o">=</span> <span class="s">"Room found"</span><span class="o">)</span>
<span class="nd">@APIResponse</span><span class="o">(</span><span class="n">responseCode</span> <span class="o">=</span> <span class="s">"404"</span><span class="o">,</span> <span class="n">description</span> <span class="o">=</span> <span class="s">"Room not found"</span><span class="o">)</span>
<span class="kd">public</span> <span class="nc">Room</span> <span class="nf">getById</span><span class="o">(</span>
        <span class="nd">@Parameter</span><span class="o">(</span><span class="n">description</span> <span class="o">=</span> <span class="s">"Room ID"</span><span class="o">,</span> <span class="n">required</span> <span class="o">=</span> <span class="kc">true</span><span class="o">)</span>
        <span class="nd">@PathParam</span><span class="o">(</span><span class="s">"id"</span><span class="o">)</span> <span class="nc">String</span> <span class="n">id</span><span class="o">)</span> <span class="o">{</span>
    <span class="k">return</span> <span class="n">repo</span><span class="o">.</span><span class="na">findById</span><span class="o">(</span><span class="n">id</span><span class="o">)</span>
            <span class="o">.</span><span class="na">orElseThrow</span><span class="o">(()</span> <span class="o">-&gt;</span> <span class="k">new</span> <span class="nc">NotFoundException</span><span class="o">(</span><span class="s">"Room not found: "</span> <span class="o">+</span> <span class="n">id</span><span class="o">));</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Now, you can add a single <code class="language-plaintext highlighter-rouge">ProblemDetail</code> class &#8211; built around the five RFC 9457 elements and an <code class="language-plaintext highlighter-rouge">extensions</code> map &#8211; and one <a href="https://jakarta.ee/specifications/restful-ws/4.0/apidocs/jakarta.ws.rs/jakarta/ws/rs/ext/exceptionmapper"><code class="language-plaintext highlighter-rouge">ExceptionMapper</code></a> per error category.</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">ProblemDetail</span> <span class="o">{</span>
    <span class="kd">private</span> <span class="no">URI</span> <span class="n">type</span> <span class="o">=</span> <span class="no">URI</span><span class="o">.</span><span class="na">create</span><span class="o">(</span><span class="s">"about:blank"</span><span class="o">);</span>
    <span class="kd">private</span> <span class="nc">String</span> <span class="n">title</span><span class="o">;</span>
    <span class="kd">private</span> <span class="kt">int</span> <span class="n">status</span><span class="o">;</span>
    <span class="kd">private</span> <span class="nc">String</span> <span class="n">detail</span><span class="o">;</span>
    <span class="kd">private</span> <span class="no">URI</span> <span class="n">instance</span><span class="o">;</span>
    <span class="kd">private</span> <span class="kd">final</span> <span class="nc">Map</span><span class="o">&lt;</span><span class="nc">String</span><span class="o">,</span> <span class="nc">Object</span><span class="o">&gt;</span> <span class="n">extensions</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">LinkedHashMap</span><span class="o">&lt;&gt;();</span>

    <span class="kd">public</span> <span class="kd">static</span> <span class="nc">ProblemDetail</span> <span class="nf">of</span><span class="o">(</span><span class="kt">int</span> <span class="n">status</span><span class="o">,</span> <span class="nc">String</span> <span class="n">title</span><span class="o">)</span> <span class="o">{</span> <span class="cm">/* ... */</span> <span class="o">}</span>
    <span class="kd">public</span> <span class="nc">ProblemDetail</span> <span class="nf">withType</span><span class="o">(</span><span class="nc">String</span> <span class="n">typeUri</span><span class="o">)</span>            <span class="o">{</span> <span class="cm">/* ... */</span> <span class="o">}</span>
    <span class="kd">public</span> <span class="nc">ProblemDetail</span> <span class="nf">withExtension</span><span class="o">(</span><span class="nc">String</span> <span class="n">key</span><span class="o">,</span> <span class="nc">Object</span> <span class="n">v</span><span class="o">)</span> <span class="o">{</span> <span class="cm">/* ... */</span> <span class="o">}</span>
    <span class="c1">// + getters/setters</span>
<span class="o">}</span>
</code></pre></div></div>

<p>The interesting part is how it gets used. As you can see from the resource code above, there is <strong>no <code class="language-plaintext highlighter-rouge">try/catch</code> in resources, ever</strong> &#8211; every exception is turned into a Problem Details response by an <code class="language-plaintext highlighter-rouge">ExceptionMapper</code>:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@Provider</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">ConstraintViolationExceptionMapper</span>
        <span class="kd">implements</span> <span class="nc">ExceptionMapper</span><span class="o">&lt;</span><span class="nc">ConstraintViolationException</span><span class="o">&gt;</span> <span class="o">{</span>

    <span class="nd">@Override</span>
    <span class="kd">public</span> <span class="nc">Response</span> <span class="nf">toResponse</span><span class="o">(</span><span class="nc">ConstraintViolationException</span> <span class="n">ex</span><span class="o">)</span> <span class="o">{</span>
        <span class="nc">List</span><span class="o">&lt;</span><span class="nc">Map</span><span class="o">&lt;</span><span class="nc">String</span><span class="o">,</span> <span class="nc">String</span><span class="o">&gt;&gt;</span> <span class="n">violations</span> <span class="o">=</span> <span class="n">ex</span><span class="o">.</span><span class="na">getConstraintViolations</span><span class="o">()</span>
                <span class="o">.</span><span class="na">stream</span><span class="o">().</span><span class="na">map</span><span class="o">(</span><span class="k">this</span><span class="o">::</span><span class="n">toMap</span><span class="o">).</span><span class="na">toList</span><span class="o">();</span>

        <span class="nc">ProblemDetail</span> <span class="n">problem</span> <span class="o">=</span> <span class="nc">ProblemDetail</span><span class="o">.</span><span class="na">of</span><span class="o">(</span><span class="mi">400</span><span class="o">,</span> <span class="s">"Validation Failed"</span><span class="o">)</span>
            <span class="o">.</span><span class="na">withType</span><span class="o">(</span><span class="s">"urn:problem-type:validation-error"</span><span class="o">)</span>
            <span class="o">.</span><span class="na">withExtension</span><span class="o">(</span><span class="s">"violations"</span><span class="o">,</span> <span class="n">violations</span><span class="o">);</span>

        <span class="k">return</span> <span class="nc">Response</span><span class="o">.</span><span class="na">status</span><span class="o">(</span><span class="mi">400</span><span class="o">)</span>
                <span class="o">.</span><span class="na">type</span><span class="o">(</span><span class="s">"application/problem+json"</span><span class="o">)</span>
                <span class="o">.</span><span class="na">entity</span><span class="o">(</span><span class="n">problem</span><span class="o">).</span><span class="na">build</span><span class="o">();</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>One mapper per category keeps each file small and obvious: <code class="language-plaintext highlighter-rouge">ConstraintViolationExceptionMapper</code> &#8594; 400, <code class="language-plaintext highlighter-rouge">NotFoundExceptionMapper</code> &#8594; 404, <code class="language-plaintext highlighter-rouge">NotAuthorizedExceptionMapper</code> &#8594; 401, <code class="language-plaintext highlighter-rouge">ForbiddenExceptionMapper</code> &#8594; 403, and a <code class="language-plaintext highlighter-rouge">CatchAllExceptionMapper</code> &#8594; 500 that <strong>never leaks stack traces</strong> to clients.</p>

<p>&#9888;&#65039;<em><strong>A word of caution:</strong> The catch-all mapper is the safety net for everything you forgot to handle. Without one, an uncaught exception ends up in the server&#8217;s default error page, which often includes stack traces, server versions, and sometimes filesystem paths. However, it might be a good idea to handle most of the common exceptions explicitly, and leave the generic catch-all for something truly unexpected.</em></p>

<p><strong>&#9989; Pros:</strong></p>

<ul>
  <li><strong>Portable across runtimes.</strong> The same code runs on Quarkus, Helidon, and Open Liberty. No runtime-specific extension.</li>
  <li><strong>No extra dependencies.</strong> RFC 9457 is just a JSON structure; you don&#8217;t need a library to emit one.</li>
  <li><strong>Small, readable surface.</strong> The error model fits on one slide. When something goes wrong, you can read the source.</li>
</ul>

<p><strong>&#10060; Cons:</strong></p>

<ul>
  <li>You write the boilerplate yourself &#8211; one mapper per category.</li>
  <li>Nothing maps validation, <code class="language-plaintext highlighter-rouge">WebApplicationException</code>, or uncaught <code class="language-plaintext highlighter-rouge">Throwable</code> automatically &#8211; you wire each one up. (This can also be one of the pros, depending on the way you look at things.)</li>
  <li>No content negotiation between <code class="language-plaintext highlighter-rouge">application/json</code> and <code class="language-plaintext highlighter-rouge">application/problem+json</code> unless you add it yourself. (Spring, for example, has a built-in <code class="language-plaintext highlighter-rouge">ProblemDetail</code> that does this for you.)</li>
</ul>

<p>&#128161; <em><strong>Want to know more?</strong> The full code, including all five mappers, lives in <a href="https://github.com/mehmandarov/api-guide-java/tree/main/src/main/java/com/mehmandarov/confapi/error"><code class="language-plaintext highlighter-rouge">com/mehmandarov/confapi/error/</code></a>.</em></p>

<hr />

<h3 id="2-zalando-problem">2. Zalando Problem</h3>

<h4 id="what-it-looks-like-1">What it looks like</h4>

<p>The <a href="https://github.com/zalando/problem">Zalando Problem</a> library (<code class="language-plaintext highlighter-rouge">org.zalando:problem</code> + <code class="language-plaintext highlighter-rouge">jackson-datatype-problem</code>) gives you <code class="language-plaintext highlighter-rouge">Problem</code> and <code class="language-plaintext highlighter-rouge">ThrowableProblem</code> types and Jackson serialization. You still write an <code class="language-plaintext highlighter-rouge">ExceptionMapper</code> to bridge JAX-RS exceptions to <code class="language-plaintext highlighter-rouge">Problem</code>, but you don&#8217;t define the envelope yourself.</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">org.zalando.problem.Problem</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">org.zalando.problem.Status</span><span class="o">;</span>

<span class="nc">Problem</span> <span class="n">problem</span> <span class="o">=</span> <span class="nc">Problem</span><span class="o">.</span><span class="na">builder</span><span class="o">()</span>
        <span class="o">.</span><span class="na">withType</span><span class="o">(</span><span class="no">URI</span><span class="o">.</span><span class="na">create</span><span class="o">(</span><span class="s">"urn:problem-type:validation-error"</span><span class="o">))</span>
        <span class="o">.</span><span class="na">withTitle</span><span class="o">(</span><span class="s">"Validation Failed"</span><span class="o">)</span>
        <span class="o">.</span><span class="na">withStatus</span><span class="o">(</span><span class="nc">Status</span><span class="o">.</span><span class="na">BAD_REQUEST</span><span class="o">)</span>
        <span class="o">.</span><span class="na">with</span><span class="o">(</span><span class="s">"violations"</span><span class="o">,</span> <span class="n">violations</span><span class="o">)</span>
        <span class="o">.</span><span class="na">build</span><span class="o">();</span>

<span class="k">return</span> <span class="nc">Response</span><span class="o">.</span><span class="na">status</span><span class="o">(</span><span class="mi">400</span><span class="o">)</span>
        <span class="o">.</span><span class="na">type</span><span class="o">(</span><span class="s">"application/problem+json"</span><span class="o">)</span>
        <span class="o">.</span><span class="na">entity</span><span class="o">(</span><span class="n">problem</span><span class="o">).</span><span class="na">build</span><span class="o">();</span>
</code></pre></div></div>

<p><strong>&#9989; Pros:</strong></p>

<ul>
  <li><strong>Cross-runtime.</strong> Works on Quarkus, Helidon, and Open Liberty &#8211; the same artifact deploys on all three.</li>
  <li><strong>Used in production at Zalando</strong> (and elsewhere); the model handles <code class="language-plaintext highlighter-rouge">cause</code> chains, stack-trace processing, and a few edge cases you probably would not have thought of upfront.</li>
  <li><strong>Jackson integration is done for you</strong> via <code class="language-plaintext highlighter-rouge">jackson-datatype-problem</code>.</li>
</ul>

<p><strong>&#10060; Cons:</strong></p>

<ul>
  <li>One more dependency to track and upgrade.</li>
  <li>You still write the <code class="language-plaintext highlighter-rouge">ExceptionMapper</code>s &#8211; the library standardises the <em>payload</em>, not the <em>wiring</em>.</li>
  <li>If your stack is JSON-B rather than Jackson, you have a bit of extra work.</li>
</ul>

<hr />

<h3 id="3-quarkus-quarkus-http-problem">3. Quarkus: <code class="language-plaintext highlighter-rouge">quarkus-http-problem</code></h3>

<p>If you&#8217;re <em>only</em> targeting Quarkus, the <a href="https://github.com/quarkiverse/quarkus-http-problem"><code class="language-plaintext highlighter-rouge">quarkus-http-problem</code></a> Quarkiverse extension is the shortest path. It auto-maps <code class="language-plaintext highlighter-rouge">ConstraintViolationException</code>, <code class="language-plaintext highlighter-rouge">WebApplicationException</code>, and uncaught <code class="language-plaintext highlighter-rouge">Throwable</code> to <code class="language-plaintext highlighter-rouge">application/problem+json</code> with no boilerplate from you.</p>

<p><strong>&#9989; Pros:</strong></p>

<ul>
  <li>Add the dependency and you get Problem Details for exceptions. No need to write a mapper for each of them.</li>
  <li>Reasonable defaults for validation and security exceptions.</li>
</ul>

<p><strong>&#10060; Cons:</strong></p>

<ul>
  <li><strong>Quarkus only.</strong> Doesn&#8217;t help on Helidon (Jersey) or Open Liberty (CXF). If &#8220;runs on every Jakarta runtime&#8221; is a requirement, this is out.</li>
  <li>Less visibility into <em>what</em> gets mapped to <em>what</em> &#8211; fine until you need to override a default.</li>
</ul>

<hr />

<h3 id="4-spring-boot--a-short-note">4. Spring Boot &#8211; a short note</h3>

<p>For completeness, we need to mention Spring Boot 3+ as well, which has Problem Details built in as <a href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/ProblemDetail.html"><code class="language-plaintext highlighter-rouge">org.springframework.http.ProblemDetail</code></a>, with content negotiation and <code class="language-plaintext highlighter-rouge">@ExceptionHandler</code> integration already wired up. If you&#8217;re on Spring, just use it. The JSON structure is the same RFC 9457; only the wiring differs.</p>

<hr />

<h2 id="conclusion">Conclusion</h2>

<p>The point of RFC 9457 is not that there&#8217;s one correct implementation &#8211; there are several reasonable ones &#8211; but that there&#8217;s one correct envelope. Once your API speaks <code class="language-plaintext highlighter-rouge">application/problem+json</code>, clients stop hand-coding error parsers for each new service they consume.</p>

<p>A few rules of thumb:</p>

<ul>
  <li>On <strong>Spring</strong>, use the built-in <code class="language-plaintext highlighter-rouge">ProblemDetail</code>.</li>
  <li>On <strong>Quarkus only</strong>, reach for <code class="language-plaintext highlighter-rouge">quarkus-http-problem</code> and move on.</li>
  <li>For <strong>cross-runtime Jakarta</strong>, choose between <strong>Zalando Problem</strong> (one dependency, more handled for you) and the <strong>hand-made</strong> approach (no dependencies, about 30 lines you fully understand).</li>
</ul>

<p>I picked the hand-made approach for the demo project because portability across Quarkus, Helidon, and Open Liberty mattered, and because the <code class="language-plaintext highlighter-rouge">ExceptionMapper</code> <em>is</em> the demo &#8211; hiding it behind a library would have defeated the point of the talk.</p>

<p>However, &#8220;hand-made&#8221; doesn&#8217;t have to mean &#8220;everyone reinvents it from scratch&#8221;. Write it once, put it in a small internal library, and reuse it across services. That&#8217;s still less code than wiring up a third-party dependency in each runtime.</p>

<h3 id="summary-comparison">Summary Comparison</h3>

<table class="bordered-table">
  <thead>
    <tr>
      <th>Option</th>
      <th>What it gives you</th>
      <th>Runtimes</th>
      <th>Dependency cost</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><strong>Hand-made</strong> <em>(this post)</em></td>
      <td>~30-line <code class="language-plaintext highlighter-rouge">ProblemDetail</code> + one mapper per error category.</td>
      <td>&#160;&#9989; Quarkus &#160;&#9989; Helidon &#160;&#9989; Open Liberty</td>
      <td>None</td>
    </tr>
    <tr>
      <td><strong>Zalando Problem</strong></td>
      <td><code class="language-plaintext highlighter-rouge">Problem</code> / <code class="language-plaintext highlighter-rouge">ThrowableProblem</code> types + Jackson serialization. You still write the mappers.</td>
      <td>&#160;&#9989; Quarkus &#160;&#9989; Helidon &#160;&#9989; Open Liberty</td>
      <td>1&#8211;2 artifacts</td>
    </tr>
    <tr>
      <td><strong><code class="language-plaintext highlighter-rouge">quarkus-http-problem</code></strong></td>
      <td>Auto-maps validation, <code class="language-plaintext highlighter-rouge">WebApplicationException</code>, and uncaught <code class="language-plaintext highlighter-rouge">Throwable</code>. No boilerplate.</td>
      <td>&#160;&#9989; Quarkus only</td>
      <td>1 extension</td>
    </tr>
    <tr>
      <td><strong>Spring <code class="language-plaintext highlighter-rouge">ProblemDetail</code></strong></td>
      <td>Built into the framework. Content negotiation and <code class="language-plaintext highlighter-rouge">@ExceptionHandler</code> integration.</td>
      <td>&#160;&#9989; Spring Boot 3+</td>
      <td>None (built in)</td>
    </tr>
  </tbody>
</table>

<h2 id="whats-next">What&#8217;s Next?</h2>

<p>Error handling is one of the bonus topics in the <a href="https://github.com/mehmandarov/api-guide-java">API Guide for Java</a>. The same repo also covers OpenAPI documentation, security (RBAC, JWT), pagination, async, and versioning strategies &#8211; see my earlier post on <a href="/api-versioning/">API versioning in Java using JAX-RS</a>.</p>

<p><strong><em>Happy shipping of well-formed error messages, folks!</em></strong></p>

<hr />]]></content><author><name>Rustam Mehmandarov</name></author><summary type="html">A practical look at RFC 9457 Problem Details for HTTP APIs in Jakarta EE &#8211; a hand-made ProblemDetail + ExceptionMapper approach, the Zalando Problem library, and a short note on Quarkus and Spring.</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://mehmandarov.com/assets/images/posts-images/error.jpg"/><category term="blog"/><category term="english"/><category term="java"/><category term="architecture"/><category term="api"/><category term="jakarta ee"/><category term="microprofile"/><category term="jax-rs"/><category term="error handling"/><category term="quarkus"/><category term="spring"/></entry><entry><title type="html">API versioning in Java using JAX-RS with Jakarta EE and MicroProfile</title><link href="https://mehmandarov.com/api-versioning/" rel="alternate" type="text/html" title="API versioning in Java using JAX-RS with Jakarta EE and MicroProfile"/><published>2026-04-19T09:50:00+02:00</published><updated>2026-04-19T09:50:00+02:00</updated><id>https://mehmandarov.com/api-versioning</id><content type="html" xml:base="https://mehmandarov.com/api-versioning/"><![CDATA[<p><em>Creating APIs and maintaining them over time means often that we need to version them. We will be looking into several ways of doing so in Java using JAX-RS, while building our API end-points using Jakarta EE and MicroProfile. This post was inspired by my talk &#8220;API = Some REST and HTTP, right? RIGHT?!&#8221;</em></p>

<ul>
  <li><a href="#introduction">Introduction</a></li>
  <li><a href="#why-versioning">Why Versioning?</a></li>
  <li><a href="#show-me-the-code">Show Me The CODE!</a></li>
  <li><a href="#1-url-versioning">1. URL Versioning</a></li>
  <li><a href="#2-header-versioning">2. Header Versioning</a></li>
  <li><a href="#3-media-type-versioning-content-negotiation">3. Media Type Versioning</a></li>
  <li><a href="#4-request-parameter-versioning">4. Request Parameter Versioning</a></li>
  <li><a href="#5-bonus-combining-strategies---transparent-uri-rewriting-enterprise-pattern">5. Bonus: Combining Strategies</a></li>
  <li><a href="#6-end-point-deprecation">6. End-Point Deprecation</a></li>
  <li><a href="#summary-comparison">Summary Comparison</a></li>
  <li><a href="#conclusion">Conclusion</a></li>
  <li><a href="#whats-next">What&#8217;s Next?</a></li>
</ul>

<hr />

<h2 id="introduction">Introduction</h2>

<p>When working with APIs over time we would often need to make some changes to end-point definitions &#8211; like adding or deleting resources or changing the attributes for a resource. To ensure backwards compatibility, we often have to introduce <em>versioning</em> for our APIs. APIs, like all software, evolve. You might be adding optional fields or introducing a breaking change. At some point, you will need versioning to support coexistence of the old and new consumers.</p>

<p>However, versioning the API endpoint introduces a question of how this should be done. In this post, we&#8217;ll explore <strong>several common API versioning strategies</strong>, using Jakarta EE and Java.</p>

<blockquote>
  <p>&#128161; Note: There is no silver bullet &#8211; instead, we&#8217;ll explore <strong>pros, cons, and real-world fit</strong>.</p>
</blockquote>

<h2 id="why-versioning">Why Versioning?</h2>

<p>Why not just change the API?<br />
Because breaking contracts is dangerous &#8212; clients may not update in sync, and you&#8217;ll break production consumers.</p>

<p>Versioning allows you to:</p>
<ul>
  <li>Support legacy clients</li>
  <li>Introduce new features safely</li>
  <li>Deprecate responsibly</li>
</ul>

<blockquote>
  <p>&#9888;&#65039; <strong>Caution</strong>: Versioning can cause &#8220;version explosion.&#8221; Each version increases long-term maintenance cost &#8211; aka <em>technical debt</em>.</p>
</blockquote>

<p><strong>Best Practice</strong>: Prefer <em>backward-compatible changes</em> (e.g., adding fields) whenever possible. To mitigate risks, it&#8217;s important to follow best practices for versioning and provide clear documentation and migration paths for users. Also, remember to <em>deprecate</em> old versions to minimize maintenance efforts.</p>

<h2 id="show-me-the-code">Show me the CODE!</h2>

<p>I have created a repository called <a href="https://github.com/mehmandarov/randomstrings/">Random Strings</a> to showcase various concepts. For this blogpost, I would recommend having a look at <a href="https://github.com/mehmandarov/randomstrings/blob/master/src/main/java/com/mehmandarov/randomstrings/apidemo/RandomStringsAPIDemoController.java"><code class="language-plaintext highlighter-rouge">RandomStringsAPIDemoController.java</code></a> and <a href="https://github.com/mehmandarov/randomstrings/blob/master/request_examples.http"><code class="language-plaintext highlighter-rouge">request_examples.http</code></a>. You will find all the info on building and running the code in the repo&#8217;s <code class="language-plaintext highlighter-rouge">README.md</code> file. Each section below will contain &#8220;How to call it&#8221; part with an example using <code class="language-plaintext highlighter-rouge">curl</code> or HTTP-files, and will be based on this repo.</p>

<hr />

<h2 id="1-url-versioning">1. URL Versioning</h2>

<h3 id="what-it-looks-like">What it looks like</h3>
<p>A version appears directly in the URI path. If your API is at <code class="language-plaintext highlighter-rouge">https://example.com/api</code>, and the current version is version 1, the URL for a resource might look like this: <code class="language-plaintext highlighter-rouge">https://example.com/api/v1/resource</code>:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@GET</span>
<span class="nd">@Path</span><span class="o">(</span><span class="s">"/v2/"</span><span class="o">)</span>
<span class="nd">@Produces</span><span class="o">(</span><span class="nc">MediaType</span><span class="o">.</span><span class="na">APPLICATION_JSON</span><span class="o">)</span>
<span class="kd">public</span> <span class="nc">Response</span> <span class="nf">getV2</span><span class="o">()</span> <span class="o">{</span>
    <span class="k">return</span> <span class="nc">Response</span><span class="o">.</span><span class="na">status</span><span class="o">(</span><span class="nc">Response</span><span class="o">.</span><span class="na">Status</span><span class="o">.</span><span class="na">NOT_IMPLEMENTED</span><span class="o">)</span>
        <span class="o">.</span><span class="na">entity</span><span class="o">(</span><span class="s">"This v2 using *path versioning* of the API is not implemented."</span><span class="o">)</span>
        <span class="o">.</span><span class="na">build</span><span class="o">();</span>
<span class="o">}</span>
</code></pre></div></div>

<h3 id="how-to-call-it">How to call it</h3>

<p><strong>cURL:</strong></p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl <span class="nt">-X</span> GET http://localhost:8080/api/rnd/v2/ <span class="se">\</span>
  <span class="nt">-H</span> <span class="s2">"Accept: application/json"</span>
</code></pre></div></div>

<p><strong>HTTP Request (<code class="language-plaintext highlighter-rouge">.http</code> file):</strong></p>
<div class="language-http highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">GET http://localhost:8080/api/rnd/v2/
Accept: application/json
</span></code></pre></div></div>

<p><strong>&#9989; Pros:</strong></p>
<ul>
  <li>Simple and intuitive. Visible.</li>
  <li>Easy to test (e.g., with curl or Postman directly in a browser).</li>
  <li>Plays well with gateways and reverse proxies.</li>
  <li>Clear visual distinction between versions.</li>
</ul>

<p><strong>&#10060; Cons:</strong></p>
<ul>
  <li>Pollutes the URI with versioning logic.</li>
  <li>Breaks REST&#8217;s principle of stable resource identifiers.</li>
  <li>Clients have to update URLs when migrating.</li>
  <li>Risk of accumulating too many legacy versions.</li>
  <li>Can result in cluttered and difficult-to-read URLs if there are multiple versions of the API.</li>
</ul>

<p><strong>&#128269; However:</strong> Despite its REST purism flaw, URL versioning is extremely practical and widely adopted.</p>

<h2 id="2-header-versioning">2. Header Versioning</h2>

<h3 id="what-it-looks-like-1">What it looks like</h3>
<p>Client specifies version in a custom HTTP header (e.g., <code class="language-plaintext highlighter-rouge">Accept-Version</code>, <code class="language-plaintext highlighter-rouge">X-API-Version</code>, etc.):</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@Path</span><span class="o">(</span><span class="s">"/hi2"</span><span class="o">)</span>
<span class="nd">@GET</span>
<span class="nd">@Produces</span><span class="o">({</span><span class="s">"application/json"</span><span class="o">})</span>
<span class="kd">public</span> <span class="nc">String</span> <span class="nf">entryPoint2</span><span class="o">(</span><span class="nd">@HeaderParam</span><span class="o">(</span><span class="s">"Accept-Version"</span><span class="o">)</span> <span class="nc">String</span> <span class="n">apiVersion</span><span class="o">)</span> <span class="o">{</span>
    <span class="k">if</span> <span class="o">(</span><span class="n">apiVersion</span> <span class="o">==</span> <span class="kc">null</span> <span class="o">||</span> <span class="n">apiVersion</span><span class="o">.</span><span class="na">isEmpty</span><span class="o">())</span> <span class="o">{</span>
        <span class="k">return</span> <span class="s">"Default unversioned endpoint hit."</span><span class="o">;</span>
    <span class="o">}</span>
    <span class="nc">String</span> <span class="n">message</span> <span class="o">=</span> <span class="s">"Versioned: Using custom headers. Using version: "</span> <span class="o">+</span> <span class="n">apiVersion</span> <span class="o">+</span><span class="s">"."</span><span class="o">;</span>
    <span class="k">return</span> <span class="n">message</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>

<h3 id="how-to-call-it-1">How to call it</h3>

<p><em>Note: This is for demo purposes only. It has to have a different URL than the regular API; otherwise, it will also intercept calls that do not contain the <code class="language-plaintext highlighter-rouge">Accept-Version</code> header.</em></p>

<p><strong>cURL:</strong></p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl <span class="nt">-X</span> GET http://localhost:8080/api/rnd/versioned/ <span class="se">\</span>
  <span class="nt">-H</span> <span class="s2">"Accept: application/json"</span> <span class="se">\</span>
  <span class="nt">-H</span> <span class="s2">"Accept-Version: 2"</span>
</code></pre></div></div>

<p><strong>HTTP Request (<code class="language-plaintext highlighter-rouge">.http</code> file):</strong></p>
<div class="language-http highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">GET http://localhost:8080/api/rnd/versioned/
Accept: application/json
Accept-Version: 2
</span></code></pre></div></div>

<p><strong>&#9989; Pros:</strong></p>
<ul>
  <li>Keeps URL structure clean and predictable.</li>
  <li>Closer to HTTP semantics (headers = metadata).</li>
  <li>Allows centralized versioning logic in filters/interceptors.</li>
</ul>

<p><strong>&#10060; Cons:</strong></p>
<ul>
  <li>Not self-descriptive &#8212; clients must &#8220;know the secret handshake&#8221;.</li>
  <li>Poor discoverability (not visible in browser without tools).</li>
  <li>Breaks caching in some proxies/CDNs unless explicitly configured.</li>
  <li>Adds complexity to tooling and testing.</li>
</ul>

<p><strong>&#9888;&#65039; Challenge:</strong> Header versioning can feel &#8220;invisible&#8221; and cause developer confusion if not well-documented.</p>

<h2 id="3-media-type-versioning-content-negotiation">3. Media Type Versioning (Content Negotiation)</h2>

<h3 id="what-it-looks-like-2">What it looks like</h3>
<p>Client specifies version via a custom media type in the <code class="language-plaintext highlighter-rouge">Accept</code> header. This is sometimes called <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Content_negotiation">Content Negotiation</a> versioning.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Accept: application/hi.v3+json
</code></pre></div></div>

<p>In Jakarta EE:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@Path</span><span class="o">(</span><span class="s">"/hi"</span><span class="o">)</span>
<span class="nd">@GET</span>
<span class="nd">@Produces</span><span class="o">({</span><span class="s">"application/hi.v3+json"</span><span class="o">,</span> <span class="s">"application/hi.v4+json"</span><span class="o">})</span>
<span class="kd">public</span> <span class="nc">String</span> <span class="nf">entryPoint</span><span class="o">()</span> <span class="kd">throws</span> <span class="nc">URISyntaxException</span> <span class="o">{</span>
    <span class="nc">String</span> <span class="n">message</span> <span class="o">=</span> <span class="s">"Versioned: Hai there!"</span><span class="o">;</span>
    <span class="k">return</span> <span class="n">message</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>

<h3 id="how-to-call-it-2">How to call it</h3>

<p>You can request different versions (e.g., v3, v4, v5) by updating the media type:</p>

<p><strong>cURL:</strong></p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl <span class="nt">-X</span> GET http://localhost:8080/api/rnd/ <span class="se">\</span>
  <span class="nt">-H</span> <span class="s2">"Accept: application/rnd.v3+json"</span>
</code></pre></div></div>

<p><strong>HTTP Request (<code class="language-plaintext highlighter-rouge">.http</code> file):</strong></p>
<div class="language-http highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">GET http://localhost:8080/api/rnd/
Accept: application/rnd.v3+json
</span></code></pre></div></div>

<p><strong>&#9989; Pros:</strong></p>
<ul>
  <li>Very REST-compliant: changes representation, not resource.</li>
  <li>URI remains stable.</li>
  <li>Supports richer format negotiation (e.g., XML, HAL, etc.).</li>
</ul>

<p><strong>&#10060; Cons:</strong></p>
<ul>
  <li>Requires strict control over media types.</li>
  <li>Not all clients/tooling handle custom media types well.</li>
  <li>Breaks with some reverse proxies and middleware that don&#8217;t forward full Accept headers.</li>
  <li>More work to configure content negotiation.</li>
</ul>

<p><strong>&#129514; Observation:</strong> Elegant in design, but rarely used consistently in real-world public APIs.</p>

<h2 id="4-request-parameter-versioning">4. Request Parameter Versioning</h2>

<h3 id="what-it-looks-like-3">What it looks like</h3>
<p><em>Technically</em>, it is also possible for the client to specify the version in a URL query parameter (e.g., <code class="language-plaintext highlighter-rouge">?version=2</code>). This, however, might not be a suggested strategy, in my opinion.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>https://example.com/api/resource?version<span class="o">=</span>2
</code></pre></div></div>

<h3 id="how-to-call-it-3">How to call it</h3>

<p><strong>cURL:</strong></p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl <span class="nt">-X</span> GET http://localhost:8080/api/rnd?version<span class="o">=</span>2 <span class="se">\</span>
  <span class="nt">-H</span> <span class="s2">"Accept: application/json"</span>
</code></pre></div></div>

<p><strong>HTTP Request (<code class="language-plaintext highlighter-rouge">.http</code> file):</strong></p>
<div class="language-http highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">GET http://localhost:8080/api/rnd?version=2
Accept: application/json
</span></code></pre></div></div>

<p><strong>&#9989; Pros:</strong></p>
<ul>
  <li>Simplicity &amp; discoverability: Easy to test in a browser without specialized tools.</li>
  <li>Defaulting logic: Straightforward to implement &#8220;default to latest&#8221; if the parameter is omitted.</li>
  <li>Caching friendly: CDNs treat different query params as unique resources by default.</li>
</ul>

<p><strong>&#10060; Cons:</strong></p>
<ul>
  <li>URI Pollution: Mixes resource identification with technical metadata.</li>
  <li>Routing complexity: Routing based on query parameters usually requires custom middleware or manual logic inside the controller.</li>
  <li>Harder to generate clean, automated documentation (like OpenAPI) when multiple versions share the same path.</li>
</ul>

<h2 id="5-bonus-combining-strategies---transparent-uri-rewriting-enterprise-pattern">5. Bonus: Combining Strategies - Transparent URI Rewriting (Enterprise Pattern)</h2>

<p>In large enterprises, you might find that different clients have different needs. Some prefer the explicitness of URL versioning, while others require the clean URIs of Header versioning. You don&#8217;t have to choose just one&#8212;you can support both without duplicating your backend routing logic.</p>

<p>The common practice is to structure all your resource classes using <strong>URL versioning</strong> (e.g., <code class="language-plaintext highlighter-rouge">@Path("/v1/resource")</code>), but use a <strong><code class="language-plaintext highlighter-rouge">@PreMatching</code> Filter</strong> to intercept requests and transparently rewrite the URI if a client uses a header instead.</p>

<p>Here is what that looks like in Jakarta EE using a <code class="language-plaintext highlighter-rouge">ContainerRequestFilter</code>:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@Provider</span>
<span class="nd">@PreMatching</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">HeaderVersionFilter</span> <span class="kd">implements</span> <span class="nc">ContainerRequestFilter</span> <span class="o">{</span>

      <span class="nd">@Override</span>
      <span class="kd">public</span> <span class="kt">void</span> <span class="nf">filter</span><span class="o">(</span><span class="nc">ContainerRequestContext</span> <span class="n">ctx</span><span class="o">)</span> <span class="o">{</span>
          <span class="nc">String</span> <span class="n">path</span> <span class="o">=</span> <span class="n">ctx</span><span class="o">.</span><span class="na">getUriInfo</span><span class="o">().</span><span class="na">getPath</span><span class="o">();</span>

          <span class="c1">// If the path is already versioned (e.g., starts with v1, v2), let it pass</span>
          <span class="k">if</span> <span class="o">(</span><span class="n">path</span><span class="o">.</span><span class="na">matches</span><span class="o">(</span><span class="s">"v\\d+(/.*)?"</span><span class="o">))</span> <span class="k">return</span><span class="o">;</span>

          <span class="c1">// Otherwise, check if the client provided a version header</span>
          <span class="nc">String</span> <span class="n">version</span> <span class="o">=</span> <span class="n">ctx</span><span class="o">.</span><span class="na">getHeaderString</span><span class="o">(</span><span class="s">"X-API-Version"</span><span class="o">);</span>

          <span class="k">if</span> <span class="o">(</span><span class="n">version</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="n">version</span><span class="o">.</span><span class="na">isEmpty</span><span class="o">())</span> <span class="o">{</span>
              <span class="c1">// Transparently rewrite the URI internally to match our URL-based routes</span>
              <span class="nc">String</span> <span class="n">newPath</span> <span class="o">=</span> <span class="s">"v"</span> <span class="o">+</span> <span class="n">version</span> <span class="o">+</span> <span class="s">"/"</span> <span class="o">+</span> <span class="n">path</span><span class="o">;</span>
              <span class="no">URI</span> <span class="n">baseUri</span> <span class="o">=</span> <span class="n">ctx</span><span class="o">.</span><span class="na">getUriInfo</span><span class="o">().</span><span class="na">getBaseUri</span><span class="o">();</span>
              <span class="no">URI</span> <span class="n">newUri</span> <span class="o">=</span> <span class="nc">UriBuilder</span><span class="o">.</span><span class="na">fromUri</span><span class="o">(</span><span class="n">baseUri</span><span class="o">).</span><span class="na">path</span><span class="o">(</span><span class="n">newPath</span><span class="o">).</span><span class="na">build</span><span class="o">();</span>

              <span class="n">ctx</span><span class="o">.</span><span class="na">setRequestUri</span><span class="o">(</span><span class="n">baseUri</span><span class="o">,</span> <span class="n">newUri</span><span class="o">);</span>
          <span class="o">}</span>
      <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p><strong>&#9989; Pros:</strong></p>
<ul>
  <li><strong>Ultimate Flexibility:</strong> Clients can use <code class="language-plaintext highlighter-rouge">http://api.example.com/v2/resource</code> OR <code class="language-plaintext highlighter-rouge">http://api.example.com/resource</code> with an <code class="language-plaintext highlighter-rouge">X-API-Version: 2</code> header.</li>
  <li><strong>Single Source of Truth:</strong> Your backend controllers only need to use <code class="language-plaintext highlighter-rouge">@Path("/v2/")</code>. You don&#8217;t have to write duplicate methods to handle both headers and paths.</li>
</ul>

<p><strong>&#10060; Cons:</strong></p>
<ul>
  <li><strong>Magic Routing:</strong> It introduces a layer of &#8220;magic&#8221; where the requested URI differs from the routed URI, which can briefly confuse new developers debugging the application.</li>
</ul>

<p><strong>&#128161; Want to know more?</strong> Read up on terms <em><code class="language-plaintext highlighter-rouge">Version Normalization</code></em> and <em><code class="language-plaintext highlighter-rouge">Internal Decoupling</code></em>.</p>

<h2 id="6-end-point-deprecation">6. End-Point Deprecation</h2>

<p>Eventually, you will need to retire old API versions. Remember: every old version you keep around is <em>technical debt</em> &#8212; it increases long-term maintenance cost. When deprecating an endpoint, consider the following best practices:</p>

<ol>
  <li><strong>Update the Docs:</strong> Use OpenAPI&#8217;s <code class="language-plaintext highlighter-rouge">@Operation</code> annotation to clearly mark it as deprecated.</li>
  <li><strong>Add <code class="language-plaintext highlighter-rouge">@Deprecated</code>:</strong> Use the Java <code class="language-plaintext highlighter-rouge">@Deprecated</code> annotation where necessary.</li>
  <li><strong>HTTP Redirects:</strong> Consider returning HTTP codes like <code class="language-plaintext highlighter-rouge">302 Found</code> or <code class="language-plaintext highlighter-rouge">301 Moved Permanently</code> after some time.</li>
  <li><strong>Add a Link header:</strong> Provide a link to the new version in the response headers.</li>
  <li><strong>Log / Count calls:</strong> Track usage (e.g., with MicroProfile <code class="language-plaintext highlighter-rouge">@Counted</code>) to know when it is safe to finally remove the endpoint.</li>
</ol>

<p>Here is a practical example in Jakarta EE showing how to deprecate an endpoint, add a <code class="language-plaintext highlighter-rouge">Link</code> header, and track metrics:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@GET</span>
<span class="nd">@Path</span><span class="o">(</span><span class="s">"v0.1/"</span><span class="o">)</span>
<span class="nd">@Produces</span><span class="o">(</span><span class="nc">MediaType</span><span class="o">.</span><span class="na">APPLICATION_JSON</span><span class="o">)</span>
<span class="nd">@Operation</span><span class="o">(</span><span class="n">summary</span> <span class="o">=</span> <span class="s">"DEPRECATED. Use v2 now. Returns the adjective-noun pair"</span><span class="o">,</span>
           <span class="n">description</span> <span class="o">=</span> <span class="s">"Deprecated function. The pair of one random adjective and one random noun is returned as an array."</span><span class="o">)</span>
<span class="nd">@Counted</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">"totalCountToRandomPairCalls_Versioned_Path_DEPRECATED"</span><span class="o">,</span>
         <span class="n">absolute</span> <span class="o">=</span> <span class="kc">true</span><span class="o">,</span>
         <span class="n">description</span> <span class="o">=</span> <span class="s">"Deprecated function call: Total number of calls to random string pairs."</span><span class="o">,</span>
         <span class="n">tags</span> <span class="o">=</span> <span class="o">{</span><span class="s">"calls=pairs"</span><span class="o">})</span>
<span class="nd">@Deprecated</span>
<span class="kd">public</span> <span class="nc">Response</span> <span class="nf">getRndStringPathDeprecated</span><span class="o">()</span> <span class="o">{</span>
    <span class="no">URI</span> <span class="n">newVersionURI</span> <span class="o">=</span> <span class="nc">UriBuilder</span><span class="o">.</span><span class="na">fromUri</span><span class="o">(</span><span class="s">"/api/rnd/v2/"</span><span class="o">).</span><span class="na">build</span><span class="o">();</span>
    <span class="nc">Link</span> <span class="n">newVersionLink</span> <span class="o">=</span> <span class="nc">Link</span><span class="o">.</span><span class="na">fromUri</span><span class="o">(</span><span class="n">newVersionURI</span><span class="o">).</span><span class="na">rel</span><span class="o">(</span><span class="s">"alternate"</span><span class="o">).</span><span class="na">build</span><span class="o">();</span>
    <span class="k">return</span> <span class="nc">Response</span><span class="o">.</span><span class="na">ok</span><span class="o">(</span><span class="s">"Deprecated response"</span><span class="o">,</span> <span class="nc">MediaType</span><span class="o">.</span><span class="na">APPLICATION_JSON</span><span class="o">)</span>
            <span class="o">.</span><span class="na">header</span><span class="o">(</span><span class="n">jakarta</span><span class="o">.</span><span class="na">ws</span><span class="o">.</span><span class="na">rs</span><span class="o">.</span><span class="na">core</span><span class="o">.</span><span class="na">HttpHeaders</span><span class="o">.</span><span class="na">LINK</span><span class="o">,</span> <span class="n">newVersionLink</span><span class="o">.</span><span class="na">toString</span><span class="o">())</span>
            <span class="o">.</span><span class="na">header</span><span class="o">(</span><span class="s">"X-API-Version"</span><span class="o">,</span> <span class="s">"0.1"</span><span class="o">)</span>
            <span class="o">.</span><span class="na">build</span><span class="o">();</span>
<span class="o">}</span>
</code></pre></div></div>

<h3 id="how-to-call-it-deprecated-endpoint">How to call it (Deprecated endpoint)</h3>

<p><strong>cURL:</strong></p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl <span class="nt">-X</span> GET http://localhost:8080/api/rnd/v0.1/ <span class="se">\</span>
  <span class="nt">-H</span> <span class="s2">"Accept: application/json"</span>
</code></pre></div></div>

<p><strong>HTTP Request (<code class="language-plaintext highlighter-rouge">.http</code> file):</strong></p>
<div class="language-http highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">GET http://localhost:8080/api/rnd/v0.1/
Accept: application/json
</span></code></pre></div></div>

<h2 id="summary-comparison">Summary Comparison</h2>

<p>The following table summarizes all the different routing strategies implemented in the <a href="https://github.com/mehmandarov/randomstrings/">demo project</a>, illustrating how the HTTP method, path, and headers combine to invoke the correct Java method. The method names refer to the methods in <a href="https://github.com/mehmandarov/randomstrings/blob/master/src/main/java/com/mehmandarov/randomstrings/apidemo/RandomStringsAPIDemoController.java"><code class="language-plaintext highlighter-rouge">RandomStringsAPIDemoController.java</code></a> (or <code class="language-plaintext highlighter-rouge">RandomStringsController.java</code>):</p>

<table>
  <thead>
    <tr>
      <th>HTTP Method</th>
      <th>Path</th>
      <th>Headers</th>
      <th>Method Invoked</th>
      <th>Notes</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">GET</code></td>
      <td><code class="language-plaintext highlighter-rouge">/rnd</code></td>
      <td><em>None</em></td>
      <td><code class="language-plaintext highlighter-rouge">getRndString()</code></td>
      <td>Default (unversioned) endpoint</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">GET</code></td>
      <td><code class="language-plaintext highlighter-rouge">/rnd</code></td>
      <td><code class="language-plaintext highlighter-rouge">Accept: application/json</code></td>
      <td><code class="language-plaintext highlighter-rouge">getRndString()</code></td>
      <td>Standard media type</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">GET</code></td>
      <td><code class="language-plaintext highlighter-rouge">/rnd/v2/</code></td>
      <td><em>Any</em></td>
      <td><code class="language-plaintext highlighter-rouge">getRndStringV2path()</code></td>
      <td>Demo for <strong>path-based</strong> versioning</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">GET</code></td>
      <td><code class="language-plaintext highlighter-rouge">/rnd/versioned</code></td>
      <td><em>None</em></td>
      <td><code class="language-plaintext highlighter-rouge">getRndStringV2Header()</code></td>
      <td>Fallback to <code class="language-plaintext highlighter-rouge">getRndString()</code> if header is missing</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">GET</code></td>
      <td><code class="language-plaintext highlighter-rouge">/rnd/versioned</code></td>
      <td><code class="language-plaintext highlighter-rouge">Accept-Version: 2</code></td>
      <td><code class="language-plaintext highlighter-rouge">getRndStringV2Header()</code></td>
      <td><strong>Header-based</strong> versioning</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">GET</code></td>
      <td><code class="language-plaintext highlighter-rouge">/rnd</code></td>
      <td><code class="language-plaintext highlighter-rouge">Accept: application/rnd.v3+json</code></td>
      <td><code class="language-plaintext highlighter-rouge">getRndStringV3V4MediaType()</code></td>
      <td><strong>Media type versioning</strong> &#8212; v3</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">GET</code></td>
      <td><code class="language-plaintext highlighter-rouge">/rnd</code></td>
      <td><code class="language-plaintext highlighter-rouge">Accept: application/rnd.v4+json</code></td>
      <td><code class="language-plaintext highlighter-rouge">getRndStringV3V4MediaType()</code></td>
      <td><strong>Media type versioning</strong> &#8212; v4</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">GET</code></td>
      <td><code class="language-plaintext highlighter-rouge">/rnd</code></td>
      <td><code class="language-plaintext highlighter-rouge">Accept: application/rnd.v5+json</code></td>
      <td><code class="language-plaintext highlighter-rouge">getRndStringV5MediaType()</code></td>
      <td><strong>Media type versioning</strong> &#8212; v5</td>
    </tr>
  </tbody>
</table>

<h2 id="conclusion">Conclusion</h2>

<p>There is no single correct approach to API versioning. For most teams and public APIs, <strong>URL versioning</strong> is good enough&#8212;it&#8217;s visible, easy to test, and plays well with existing tooling. However, you might want to use <strong>header versioning</strong> if your APIs are primarily consumed by internal services or SDKs that can abstract away the complexity. Reserve <strong>media type versioning</strong> for hypermedia-rich or REST-purist APIs, and only if your tooling supports it end-to-end.</p>

<p>Consider who your consumers are, whether your API is public or internal, your infrastructure maturity, and your team&#8217;s ability to support multiple versions.</p>

<h2 id="whats-next">What&#8217;s Next?</h2>

<p>Versioning is just one part of building robust REST APIs. If you want to dive deeper, have a look at the <a href="https://github.com/mehmandarov/api-guide-java">API Guide for Java</a> repository and the slides in the <a href="https://github.com/mehmandarov/api-guide-java/tree/main/presentation">presentation folder</a>. They cover documentation with OpenAPI, security best practices (like RBAC and JWT integration), advanced patterns (pagination, async APIs), and going beyond REST with gRPC and GraphQL.</p>

<p><strong><em>Happy coding!</em></strong></p>

<hr />]]></content><author><name>Rustam Mehmandarov</name></author><summary type="html">Exploring common API versioning strategies in Java using JAX-RS with Jakarta EE and MicroProfile &#8211; URL, header, and media type versioning &#8211; with pros, cons, and practical code examples.</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://mehmandarov.com/assets/images/posts-images/container-ship.jpeg"/><category term="blog"/><category term="english"/><category term="java"/><category term="architecture"/><category term="api"/><category term="jakarta ee"/><category term="microprofile"/><category term="jax-rs"/><category term="openapi"/></entry><entry><title type="html">Multiplying The Developer Joy: Multiple Quarkus Containers + Simultaneous Remote Development Sessions</title><link href="https://mehmandarov.com/remote-dev-mode-quarkus/" rel="alternate" type="text/html" title="Multiplying The Developer Joy: Multiple Quarkus Containers + Simultaneous Remote Development Sessions"/><published>2024-03-30T10:50:00+01:00</published><updated>2024-03-30T10:50:00+01:00</updated><id>https://mehmandarov.com/remote-dev-mode-quarkus</id><content type="html" xml:base="https://mehmandarov.com/remote-dev-mode-quarkus/"><![CDATA[<p><em>Running several simultaneous Quarkus app containers on your machine with the Quarkus&#8217; remote development mode activated presents some challenges. Let&#8217;s have a look at how we can fix this.</em></p>

<ul>
  <li><a href="#introduction">Introduction</a></li>
  <li><a href="#setup">Setup</a></li>
  <li><a href="#conclusion">Conclusion</a></li>
</ul>

<h2 id="introduction">Introduction</h2>

<p>The built-in <a href="https://quarkus.io/guides/maven-tooling#dev-mode/">development mode</a> for Quarkus is a great functionality that lets you update the application code, resources, and configurations. Setting it up is a great way to develop your applications <em>locally</em>, as you can immediately see the changes reflected in your application.</p>

<p>Furthermore, we have a <a href="https://quarkus.io/guides/maven-tooling#remote-development-mode">remote development mode</a>, which lets you make changes to local files immediately available in a containerized environment. Remote development mode works excellently if the container runs in a local Docker or remote containerized environment.</p>

<p>However, running several simultaneous containers with the remote development mode on, mapped to the same domain, may result in warnings and erratic behavior from the client side.</p>

<h2 id="setup">Setup</h2>

<p>Imagine a setup where you are running a set of containers, for example, using <code class="language-plaintext highlighter-rouge">docker-compose</code> and mapping them all to <code class="language-plaintext highlighter-rouge">my.cluster.host.com</code> (or even <code class="language-plaintext highlighter-rouge">localhost</code>)through several ports:</p>

<p><img src="/assets/images/posts-images/2024-03-30-microservices.png" alt="Microservice Setup" /></p>
<figcaption class="caption">Microservice Setup Example</figcaption>

<p>First, you will need to update <code class="language-plaintext highlighter-rouge">quarkus.live-reload.url</code> in the properties for all the apps (see <a href="https://quarkus.io/guides/maven-tooling#remote-development-mode">docs</a> on where and how to do this). Update the settings to the correct domain and port (in our case, it is <code class="language-plaintext highlighter-rouge">8080</code>, <code class="language-plaintext highlighter-rouge">8081</code>, or <code class="language-plaintext highlighter-rouge">8082</code>):</p>

<div class="language-properties highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="py">quarkus.live-reload.url</span><span class="p">=</span><span class="s">http://localhost:8081</span>
</code></pre></div></div>

<p>Next, try starting your containers with the remote development mode enabled and connect to the application from a terminal or an IDE. For the second and the consecutive applications, the attempts to establish a connection you will see the following message in the logs:</p>

<pre><code class="language-commandline">$&gt; ./mvnw quarkus:remote-dev -Dquarkus.profile=dev

&lt; ... &gt;

[WARNING] Changed debug port to 57409 because of a port conflict
Listening for transport dt_socket at address: 57409

&lt; ... &gt;
</code></pre>

<p><em><strong>Note:</strong> Fallback ports will be random and may vary from the one above.</em></p>

<p>This setup will break the remote reloading from the terminal on the client side (i.e., your IDE). Two or more of your client applications now see that the default port <code class="language-plaintext highlighter-rouge">50005</code> for a remote debug is in use and start with a new, random port.</p>

<p>The simple fix is to update the debug ports for all other applications to something other than <code class="language-plaintext highlighter-rouge">5005</code>, such as <code class="language-plaintext highlighter-rouge">6006</code> and <code class="language-plaintext highlighter-rouge">6007</code>. Custom debug ports can be set in the <code class="language-plaintext highlighter-rouge">pom.xml</code> files, under <code class="language-plaintext highlighter-rouge">quarkus-maven-plugin</code>, for each of the applications that require this update:</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;build&gt;</span>
  <span class="nt">&lt;plugins&gt;</span>
    <span class="nt">&lt;plugin&gt;</span>
      <span class="nt">&lt;groupId&gt;</span>io.quarkus.platform<span class="nt">&lt;/groupId&gt;</span>
      <span class="nt">&lt;artifactId&gt;</span>quarkus-maven-plugin<span class="nt">&lt;/artifactId&gt;</span>
      <span class="nt">&lt;version&gt;</span>${quarkus.platform.version}<span class="nt">&lt;/version&gt;</span>
      <span class="c">&lt;!-- ADD THE CONFIGURATION MENTIONED BELOW THIS LINE --&gt;</span>
      <span class="nt">&lt;configuration&gt;</span>
        <span class="nt">&lt;debug&gt;</span>6006<span class="nt">&lt;/debug&gt;</span>
      <span class="nt">&lt;/configuration&gt;</span>
...
</code></pre></div></div>

<p>You can choose whether to update the debug ports for all applications in the cluster or for all applications except one, which will get the default port.</p>

<p>Now, you will need to rebuild your apps and re-initiate the remote development mode for each container. And, voil&#224;, everything works!</p>

<p><strong><em>One last note</em></strong>: Please ensure you do not use the remote development functionality in the production environment.</p>

<h2 id="conclusion">Conclusion</h2>
<p>A tiny config update brings back the development joy of using remote development mode for more than one container simultaneously.</p>

<p><strong><em>Happy coding!</em></strong></p>]]></content><author><name>Rustam Mehmandarov</name></author><summary type="html">Running several simultaneous Quarkus app containers on your machine with the Quarkus&#8217; remote development mode activated presents some challenges. Let&#8217;s have a look at how we can fix this.</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://mehmandarov.com/assets/images/posts-images/container-ship.jpeg"/><category term="blog"/><category term="english"/><category term="java"/><category term="containers"/><category term="quarkus"/><category term="docker"/></entry><entry><title type="html">Building a Basic Apache Beam Pipeline in 4 Steps with Java</title><link href="https://mehmandarov.com/beam-pipeline-in-four-steps/" rel="alternate" type="text/html" title="Building a Basic Apache Beam Pipeline in 4 Steps with Java"/><published>2020-02-21T07:35:00+01:00</published><updated>2020-02-21T07:35:00+01:00</updated><id>https://mehmandarov.com/beam-pipeline-in-four-steps</id><content type="html" xml:base="https://mehmandarov.com/beam-pipeline-in-four-steps/"><![CDATA[<p><em>Getting started with building data pipelines using Apache Beam.</em></p>

<ul>
  <li><a href="#step-1-define-pipeline-options">Step 1: Define Pipeline Options</a></li>
  <li><a href="#step-2-create-the-pipeline">Step 2: Create the Pipeline</a></li>
  <li><a href="#step-3-apply-transformations">Step 3: Apply Transformations</a></li>
  <li><a href="#step-4-run-it">Step 4: Run it!</a></li>
  <li><a href="#conclusion">Conclusion</a></li>
</ul>

<hr />

<p>In this post, I would like to show you how you can get started with Apache Beam and build the first, simple data pipeline in 4 steps.</p>

<h2 id="step-1-define-pipeline-options">Step 1: Define Pipeline Options</h2>

<p>Let&#8217;s start with creating a helper object to configure our pipelines. This is not an absolute necessity, however defining the pipeline options might save you some time later, especially if your pipeline is dependent on a few arguments, that might have pre-defined, default values that you don&#8217;t want to provide at every run.</p>

<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="kd">public</span> <span class="kd">interface</span> <span class="nc">OsloCityBikeOptions</span> <span class="kd">extends</span> <span class="nc">PipelineOptions</span> <span class="o">{</span>

    <span class="cm">/**
     * By default, the code reads from a public dataset containing a subset of
     * bike station metadata for city bikes. Set this option to choose a different input file or glob
     * (i.e. partial names with *, like "*-stations.txt").
     */</span>
    <span class="nd">@Description</span><span class="o">(</span><span class="s">"Path of the file with the availability data"</span><span class="o">)</span>
    <span class="nd">@Default</span><span class="o">.</span><span class="na">String</span><span class="o">(</span><span class="s">"src/main/resources/bikedata-stations-example.txt"</span><span class="o">)</span>
    <span class="nc">String</span> <span class="nf">getStationMetadataInputFile</span><span class="o">();</span>
    <span class="kt">void</span> <span class="nf">setStationMetadataInputFile</span><span class="o">(</span><span class="nc">String</span> <span class="n">value</span><span class="o">);</span>

    <span class="c1">// some other options here...</span>
<span class="o">}</span></code></pre></figure>

<h2 id="step-2-create-the-pipeline">Step 2: Create the Pipeline</h2>

<p>Now that you have created the pipeline options object, you will need to create the pipeline object itself and provide the options to it:</p>

<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="nc">OsloCityBikeOptions</span> <span class="n">options</span> <span class="o">=</span> 
        <span class="nc">PipelineOptionsFactory</span><span class="o">.</span><span class="na">fromArgs</span><span class="o">(</span><span class="n">args</span><span class="o">)</span>
                                <span class="o">.</span><span class="na">withValidation</span><span class="o">()</span>
                                <span class="o">.</span><span class="na">as</span><span class="o">(</span><span class="nc">OsloCityBikeOptions</span><span class="o">.</span><span class="na">class</span><span class="o">);</span>

<span class="nc">Pipeline</span> <span class="n">pipeline</span> <span class="o">=</span> <span class="nc">Pipeline</span><span class="o">.</span><span class="na">create</span><span class="o">(</span><span class="n">options</span><span class="o">);</span></code></pre></figure>

<p>(<em>Check out the documentation for the <a href="https://beam.apache.org/releases/javadoc/2.19.0/org/apache/beam/sdk/options/PipelineOptionsFactory.html">PipelineOptionsFactory</a> class for the description of the methods used above.</em>)</p>

<h2 id="step-3-apply-transformations">Step 3: Apply Transformations</h2>

<p>After defining the pipeline and providing the options class, we can start by applying the transformations using <code class="language-plaintext highlighter-rouge">.apply(...)</code>. Those can be chained after each other by applying yet another <code class="language-plaintext highlighter-rouge">.apply(...)</code>, for instance:</p>

<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="nc">PCollection</span> <span class="o">&lt;</span><span class="no">KV</span><span class="o">&lt;</span><span class="nc">Integer</span><span class="o">,</span> <span class="nc">LinkedHashMap</span><span class="o">&gt;&gt;</span> <span class="n">stationMetadata</span> <span class="o">=</span> <span class="n">pipeline</span>
                <span class="o">.</span><span class="na">apply</span><span class="o">(</span><span class="s">"ReadLines: StationMetadataInputFiles"</span><span class="o">,</span> <span class="nc">TextIO</span><span class="o">.</span><span class="na">read</span><span class="o">().</span><span class="na">from</span><span class="o">(</span><span class="n">options</span><span class="o">.</span><span class="na">getStationMetadataInputFile</span><span class="o">()))</span>
                <span class="o">.</span><span class="na">apply</span><span class="o">(</span><span class="s">"Station Metadata"</span><span class="o">,</span> <span class="nc">ParDo</span><span class="o">.</span><span class="na">of</span><span class="o">(</span><span class="n">fnExtractStationMetaDataFromJSON</span><span class="o">()));</span>
                <span class="o">.</span><span class="na">apply</span><span class="o">(</span><span class="nc">MapElements</span><span class="o">.</span><span class="na">into</span><span class="o">(</span><span class="nc">TypeDescriptor</span><span class="o">.</span><span class="na">of</span><span class="o">(</span><span class="nc">String</span><span class="o">.</span><span class="na">class</span><span class="o">)).</span><span class="na">via</span><span class="o">(</span><span class="n">o</span> <span class="o">-&gt;</span> <span class="n">o</span><span class="o">.</span><span class="na">toString</span><span class="o">()))</span>
                <span class="o">.</span><span class="na">apply</span><span class="o">(</span><span class="s">"WriteStationMetaData"</span><span class="o">,</span> <span class="nc">TextIO</span><span class="o">.</span><span class="na">write</span><span class="o">().</span><span class="na">to</span><span class="o">(</span><span class="n">options</span><span class="o">.</span><span class="na">getMetadataOutput</span><span class="o">()));</span></code></pre></figure>

<p>Note that a <a href="https://beam.apache.org/releases/javadoc/2.19.0/org/apache/beam/sdk/values/PCollection.html"><code class="language-plaintext highlighter-rouge">PCollection&lt;T&gt;</code></a> is an immutable collection of values of type <code class="language-plaintext highlighter-rouge">T</code> and that you can provide names for the transformations as the first string argument in the <code class="language-plaintext highlighter-rouge">apply()</code>, like in the first two and the last <code class="language-plaintext highlighter-rouge">apply</code> methods.</p>

<p>Here we can also specify custom transformations that can be done in parallel. In Beam, they are being referred to as <a href="https://beam.apache.org/releases/javadoc/2.19.0/org/apache/beam/sdk/transforms/ParDo.html"><code class="language-plaintext highlighter-rouge">ParDo</code></a> methods. They are similar to the <code class="language-plaintext highlighter-rouge">Mapper</code> or <code class="language-plaintext highlighter-rouge">Reducer</code> class of a MapReduce-style algorithm. In this post, we will not be focusing on the contents of such pipeline (i.e. what it is doing), but a simple example of a <code class="language-plaintext highlighter-rouge">ParDo</code> can be looking like the second <code class="language-plaintext highlighter-rouge">apply</code> in the code above (look for the link in the <a href="#conclusion">conclusion</a> for the entire running example).</p>

<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="n">pipeline</span><span class="o">.</span><span class="na">apply</span><span class="o">(</span><span class="s">"Station Metadata"</span><span class="o">,</span> <span class="nc">ParDo</span><span class="o">.</span><span class="na">of</span><span class="o">(</span><span class="n">fnExtractStationMetaDataFromJSON</span><span class="o">()));</span></code></pre></figure>

<h2 id="step-4-run-it">Step 4: Run it!</h2>

<p>After defining the pipeline, its options, and how they are connected, we can finally run the pipeline. The great thing about running the pipelines in Apache Beam is that it is very easy to switch between various runners. Beam provides a portable API layer for building sophisticated pipelines that may be executed across various execution engines or <em>runners</em>. In our example, we can switch from running the pipeline locally (with <a href="https://beam.apache.org/documentation/runners/direct/"><code class="language-plaintext highlighter-rouge">direct-runner</code></a>), to running the same pipeline in the Cloud as a managed service (with <a href="https://beam.apache.org/documentation/runners/dataflow/"><code class="language-plaintext highlighter-rouge">dataflow-runner</code></a>) by simply adjusting the values we provide when running the code.</p>

<h3 id="local-runner">Local runner</h3>

<p>Here is an example of running the pipeline with <code class="language-plaintext highlighter-rouge">direct-runner</code>:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">mvn compile <span class="nb">exec</span>:java <span class="se">\</span>
      <span class="nt">-Pdirect-runner</span> <span class="se">\</span>
      <span class="nt">-Dexec</span>.mainClass<span class="o">=</span>com.mehmandarov.beam.OsloCityBike <span class="se">\</span>
      <span class="nt">-Dexec</span>.args<span class="o">=</span><span class="s2">"--inputFile=src/data-example.txt </span><span class="se">\</span><span class="s2">
      --output=bikedatalocal"</span></code></pre></figure>

<h3 id="dataflow-runner">Dataflow runner</h3>

<p>And here is the example of running the same pipeline in the Cloud as a managed service, using Google Cloud Dataflow. Note that most of the parameters provided are still the same, with a few additional parameters needed for this specific runner.</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">mvn compile <span class="nb">exec</span>:java <span class="se">\</span>
      <span class="nt">-Pdataflow-runner</span> <span class="se">\</span>
      <span class="nt">-Dexec</span>.mainClass<span class="o">=</span>com.mehmandarov.beam.OsloCityBike <span class="se">\</span>
      <span class="nt">-Dexec</span>.args<span class="o">=</span><span class="s2">"--project=rm-cx-211107 </span><span class="se">\</span><span class="s2">
      --inputFile=gs://my_oslo_bike_data/data-2018-*.txt </span><span class="se">\</span><span class="s2">
      --stagingLocation=gs://my_oslo_bike_data/testing </span><span class="se">\</span><span class="s2">
      --output=gs://my_oslo_bike_data/testing/output </span><span class="se">\</span><span class="s2">
      --tempLocation=gs://my_oslo_bike_data/testing/ </span><span class="se">\</span><span class="s2">
      --runner=DataflowRunner </span><span class="se">\</span><span class="s2">
      --region=europe-west1"</span></code></pre></figure>

<h3 id="other-runners">Other runners</h3>
<p>In case you would like to be using various runners or interested in switching between them, it might be a good idea to check the <a href="https://beam.apache.org/documentation/runners/capability-matrix/">capability matrix</a> in the documentation, as the core concepts of Beam Model can sometimes be implemented to varying degrees in each of the Beam runners.</p>

<h2 id="conclusion">Conclusion</h2>
<p>We have now seen the basic steps needed to create a simple data-parallel processing pipeline and how that can be run and deployed both in the local and managed Cloud environments. We are were also able to run the same pipeline with just a few adjustments to the command line parameters and, in our case, without any changes to the pipeline code.</p>

<p>The entire working example that we have been using here can be found in <a href="https://github.com/mehmandarov/oslocitybike-basic-beam">my GitHub repository</a>, as well as a more advanced example in <a href="https://github.com/mehmandarov/oslocitybike-beam">another repository</a>.</p>]]></content><author><name>Rustam Mehmandarov</name></author><summary type="html">Getting started with building data pipelines using Apache Beam Java SDK</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://mehmandarov.com/assets/images/posts-images/pipes.jpg"/><category term="blog"/><category term="java"/><category term="apache beam"/><category term="data"/><category term="pipelines"/><category term="english"/></entry><entry><title type="html">Getting a Graph Representation of a Pipeline in Apache Beam</title><link href="https://mehmandarov.com/apache-beam-pipeline-graph/" rel="alternate" type="text/html" title="Getting a Graph Representation of a Pipeline in Apache Beam"/><published>2019-11-27T08:15:00+01:00</published><updated>2019-11-27T08:15:00+01:00</updated><id>https://mehmandarov.com/apache-beam-pipeline-graph</id><content type="html" xml:base="https://mehmandarov.com/apache-beam-pipeline-graph/"><![CDATA[<p><em>Getting a pipeline representation in Apache Beam explained step-by-step.</em></p>

<ul>
  <li><a href="#intro">Intro</a></li>
  <li><a href="#tldr-getting-graph-representation">TL;DR: Getting Graph Representation</a></li>
  <li><a href="#a-full-example">A Full Example</a></li>
  <li><a href="#what-now">What Now?</a></li>
</ul>

<hr />

<h2 id="intro">Intro</h2>
<p>Constructing advanced pipelines, or trying to wrap your head around the existing pipelines, in <a href="https://beam.apache.org/">Apache Beam</a> can sometimes be challenging. We have seen some nice visual representations of the pipelines in the managed Cloud versions of this software, but figuring out how to get a graph representation of the pipeline required a little bit of research. Here is how it is done in a few steps using Beam&#8217;s Java SDK.</p>

<h2 id="tldr-getting-graph-representation">TL;DR: Getting Graph Representation</h2>

<p>If you just want to see a few lines that let you generate the <a href="https://en.wikipedia.org/wiki/DOT_(graph_description_language)">DOT</a> representation of the graph, here it is:</p>

<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="kn">import</span> <span class="nn">org.apache.beam.runners.core.construction.renderer.PipelineDotRenderer</span><span class="o">;</span>

<span class="nc">Pipeline</span> <span class="n">p</span> <span class="o">=</span> <span class="nc">Pipeline</span><span class="o">.</span><span class="na">create</span><span class="o">(</span><span class="n">options</span><span class="o">);</span>
<span class="c1">// do stuff with your pipeline</span>
<span class="nc">String</span> <span class="n">dotString</span> <span class="o">=</span> <span class="nc">PipelineDotRenderer</span><span class="o">.</span><span class="na">toDotString</span><span class="o">(</span><span class="n">p</span><span class="o">);</span></code></pre></figure>

<p>Now, if you want a slightly more comprehensive example, keep on reading.</p>

<h2 id="a-full-example">A Full Example</h2>
<p>Here we will be using <a href="https://beam.apache.org/get-started/quickstart-java/#get-the-wordcount-code">word count example</a>, particularly the <a href="https://github.com/apache/beam/blob/master/examples/java/src/main/java/org/apache/beam/examples/MinimalWordCount.java"><code class="language-plaintext highlighter-rouge">MinimalWordCount</code></a> class.</p>

<h4 id="adding-maven-dependency">Adding Maven Dependency</h4>
<p>First, we need to add a dependency to the Maven file under <code class="language-plaintext highlighter-rouge">&lt;dependencies&gt;</code> section:</p>

<figure class="highlight"><pre><code class="language-xml" data-lang="xml"><span class="nt">&lt;dependencies&gt;</span>
    <span class="c">&lt;!-- ... all the other dependencies you may have --&gt;</span>
    <span class="nt">&lt;dependency&gt;</span>
        <span class="nt">&lt;groupId&gt;</span>org.apache.beam<span class="nt">&lt;/groupId&gt;</span>
        <span class="nt">&lt;artifactId&gt;</span>beam-runners-core-construction-java<span class="nt">&lt;/artifactId&gt;</span>
        <span class="nt">&lt;version&gt;</span>${beam.version}<span class="nt">&lt;/version&gt;</span>
    <span class="nt">&lt;/dependency&gt;</span>
<span class="nt">&lt;/dependencies&gt;</span></code></pre></figure>

<h4 id="the-code">The Code</h4>
<p>Now, we will need to add a few imports (assuming you already added the Maven dependency mentioned earlier):</p>

<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="kn">import</span> <span class="nn">org.apache.beam.runners.core.construction.renderer.PipelineDotRenderer</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">org.slf4j.Logger</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">org.slf4j.LoggerFactory</span><span class="o">;</span></code></pre></figure>

<p>To get the <a href="https://en.wikipedia.org/wiki/DOT_(graph_description_language)">DOT</a> representation of the pipeline graph we will be passing the pipeline object to the <code class="language-plaintext highlighter-rouge">PipelineDotRenderer</code> class, and in this example, we are only logging the output to the console (hence the log4j imports).</p>

<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="c1">// Create the Pipeline object with the options we defined above</span>
<span class="nc">Pipeline</span> <span class="n">p</span> <span class="o">=</span> <span class="nc">Pipeline</span><span class="o">.</span><span class="na">create</span><span class="o">(</span><span class="n">options</span><span class="o">);</span>

<span class="c1">// ... do stuff with your pipeline ...</span>

<span class="c1">// Add this piece of code just before running the pipeline:</span>
<span class="kd">final</span> <span class="nc">Logger</span> <span class="n">log</span> <span class="o">=</span> <span class="nc">LoggerFactory</span><span class="o">.</span><span class="na">getLogger</span><span class="o">(</span><span class="nc">MinimalWordCount</span><span class="o">.</span><span class="na">class</span><span class="o">);</span>
<span class="nc">String</span> <span class="n">dotString</span> <span class="o">=</span> <span class="nc">PipelineDotRenderer</span><span class="o">.</span><span class="na">toDotString</span><span class="o">(</span><span class="n">p</span><span class="o">);</span>
<span class="n">log</span><span class="o">.</span><span class="na">info</span><span class="o">(</span><span class="s">"MY GRAPH REPR: "</span> <span class="o">+</span> <span class="n">dotString</span><span class="o">);</span>

<span class="n">p</span><span class="o">.</span><span class="na">run</span><span class="o">().</span><span class="na">waitUntilFinish</span><span class="o">();</span></code></pre></figure>

<p>That&#8217;s it. To see the code in action, run it from the command line:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nv">$ </span>mvn compile <span class="nb">exec</span>:java <span class="se">\</span>
        <span class="nt">-Dexec</span>.mainClass<span class="o">=</span>org.apache.beam.examples.MinimalWordCount <span class="se">\</span>
        <span class="nt">-Pdirect-runner</span></code></pre></figure>

<p>This code will produce a DOT representation of the pipeline and log it to the console.</p>

<h4 id="a-complete-example">A Complete Example</h4>

<p>A fully working example can be found in <a href="https://github.com/mehmandarov/word-count-mini-beam">my repository</a>, based on <a href="https://github.com/apache/beam/blob/master/examples/java/src/main/java/org/apache/beam/examples/MinimalWordCount.java"><code class="language-plaintext highlighter-rouge">MinimalWordCount</code></a>
code. There, in addition to logging to the console, we will be storing the DOT representation to a file.</p>

<p>In the next section, we will have a brief look at what can be done with the DOT representations.</p>

<h2 id="what-now">What Now?</h2>
<p>Now that we have a DOT representation of the pipeline graph, we can use it to get a better understanding of the pipeline. For instance, you can generate an SVG or a PNG image from the data. Note that the generated graph might be a bit verbose, but gives a good overview of the pipeline graph.</p>

<p>Here, I have also included examples of the <a href="https://github.com/mehmandarov/word-count-mini-beam/blob/master/pipeline_graph.dot">DOT graph</a> and the <a href="https://github.com/mehmandarov/word-count-mini-beam/blob/master/pipeline_graph.png">PNG file</a> generated for that particular pipeline.</p>

<p>Assuming that you have Graphviz <a href="https://www.graphviz.org/download/">tools</a> installed, you can convert a DOT file to a PNG image using this command:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nv">$ </span>dot <span class="nt">-Tpng</span> <span class="nt">-o</span> pipeline_graph.png pipeline_graph.dot</code></pre></figure>

<p>In addition to <a href="https://www.graphviz.org/">Grapgviz</a> (Wikipedia <a href="https://en.wikipedia.org/wiki/Graphviz">link</a>), there are also online services for converting DOT graphs to graphical representations, like <a href="https://dreampuf.github.io/GraphvizOnline">this</a> one.</p>

<p><img src="https://raw.githubusercontent.com/mehmandarov/word-count-mini-beam/master/pipeline_graph_partial.png" alt="Training your own model" class="bigger-image" /></p>
<figcaption class="caption">A part of a graphical representation for the pipeline in the MinimalWordCount example. </figcaption>

<hr />]]></content><author><name>Rustam Mehmandarov</name></author><summary type="html">How to get a graph representation of your data pipeline in Apache Beam, step by step.</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://mehmandarov.com/assets/images/posts-images/golden-gate.jpg"/><category term="blog"/><category term="java"/><category term="apache beam"/><category term="data"/><category term="pipelines"/><category term="english"/></entry><entry><title type="html">MicroProfile &#8211; Part 1: Defining End-Points</title><link href="https://mehmandarov.com/microprofile-101-part1/" rel="alternate" type="text/html" title="MicroProfile &#8211; Part 1: Defining End-Points"/><published>2019-07-29T07:25:00+02:00</published><updated>2019-07-29T07:25:00+02:00</updated><id>https://mehmandarov.com/microprofile-101-part1</id><content type="html" xml:base="https://mehmandarov.com/microprofile-101-part1/"><![CDATA[<p><em>Part 1: End-points in MicroProfile. This is a part of a series of posts to help you get started with microservices in MicroProfile and showing off some of the features it brings to the table.</em></p>

<blockquote>
  <p><strong>Update (April 2026):</strong> This post has been refreshed to use the modern <code class="language-plaintext highlighter-rouge">jakarta.*</code> namespace introduced in Jakarta EE 9+. If you are working with an older codebase that still uses the legacy <code class="language-plaintext highlighter-rouge">javax.*</code> namespace, the concepts described here apply identically &#8212; only the package prefix differs.</p>
</blockquote>

<ul>
  <li><a href="#intro">Intro</a></li>
  <li><a href="#getting-started">Getting started</a></li>
  <li><a href="#defining-end-points">Defining End-Points</a>
    <ul>
      <li><a href="#a-regular-json-end-point">A (Regular) JSON End-Point</a></li>
      <li><a href="#an-end-point-returning-an-image">An End-Point Returning an Image</a></li>
      <li><a href="#an-end-point-returning-a-pdf">An End-Point Returning a PDF</a></li>
    </ul>
  </li>
  <li><a href="#whats-next">What&#8217;s Next?</a></li>
</ul>

<hr />

<h2 id="intro">Intro</h2>

<p>In my previous two posts, I have been describing parts of a system for &#8220;checking-in&#8221; to a location using QR codes in Java. We started with <a href="/generating-qr-codes-with-secure-hashes-using-java/">generating QR codes</a>, followed by <a href="/generating-pdf-files-using-java/">generating PDF files</a>.</p>

<p>Now, I would like to focus on building microservices around that functionality. We will be creating a few HTTP end-points built with <a href="https://microprofile.io/">MicroProfile</a>. I will be using the next few posts as an opportunity to show off some of the features that you will be getting out of the box or with minimal effort using MicroProfile.</p>

<h2 id="getting-started">Getting started</h2>

<p><em>(Assuming that you have Git, Java 9+, and Maven installed.)</em></p>

<p>Since we will continue using the QR code generator project to showcase various features of MicroProfile, it might be a good idea to familiarize yourself with the code. You might want to start with taking a look at my previous two posts that explain the code for <a href="/generating-qr-codes-with-secure-hashes-using-java/">generating QR codes</a>, and <a href="/generating-pdf-files-using-java/">generating PDF files</a> in detail.</p>

<p>Now you can clone the <a href="https://github.com/mehmandarov/microprofile-qrcodes/">project</a> and examine the Maven dependencies in the <a href="https://github.com/mehmandarov/microprofile-qrcodes/blob/master/pom.xml"><code class="language-plaintext highlighter-rouge">pom.xml</code></a> file, as well as any other MicroProfile related dependencies.</p>

<p>After cloning and opening the project in your favorite IDE, build it (again, assuming that you have Java and Maven installed) with the following command in a terminal:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nv">$ </span>mvn clean package</code></pre></figure>

<p>When the project is done building and you have got a <code class="language-plaintext highlighter-rouge">Build Success</code> from Maven, you can run the project to make sure everything runs fine:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nv">$ </span>java <span class="nt">-jar</span> target/qrcreator.jar</code></pre></figure>

<p>In a few seconds it takes for the app server to start-up, you should be able to access the starter page at <a href="http://localhost:8181/qrcreator/index.html"><code class="language-plaintext highlighter-rouge">http://localhost:8181/qrcreator/index.html</code></a>.</p>

<h2 id="defining-end-points">Defining End-Points</h2>

<p>One of the most obvious features any microservice needs is an end-point to receive requests and respond with some kind of data back. Let&#8217;s have a closer look into how this is done in MicroProfile. First of all, we will need to define the application path that serves as the base URI for all resource URIs (think of it as a &#8220;root&#8221; URL) and make sure that the class where it is defined extends <code class="language-plaintext highlighter-rouge">jakarta.ws.rs.core.Application</code>, like in <a href="https://github.com/mehmandarov/microprofile-qrcodes/blob/master/src/main/java/com/mehmandarov/qrcreator/ApplicationEntryPoint.java"><code class="language-plaintext highlighter-rouge">ApplicationEntryPoint</code></a> class here:</p>

<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="kn">package</span> <span class="nn">com.mehmandarov.qrcreator</span><span class="o">;</span>

<span class="kn">import</span> <span class="nn">jakarta.ws.rs.ApplicationPath</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">jakarta.ws.rs.core.Application</span><span class="o">;</span>

<span class="cm">/**
 * Sets the application path that serves as the base URI for
 * all resource URIs provided by @Path annotation.
 */</span>
<span class="nd">@ApplicationPath</span><span class="o">(</span><span class="s">"/api"</span><span class="o">)</span>

<span class="kd">public</span> <span class="kd">class</span> <span class="nc">ApplicationEntryPoint</span> <span class="kd">extends</span> <span class="nc">Application</span> <span class="o">{</span>
<span class="o">}</span></code></pre></figure>

<p>This will set up all the end-point URLs to start with <code class="language-plaintext highlighter-rouge">/api</code>, in our case <a href="http://localhost:8181/qrcreator/api/"><code class="language-plaintext highlighter-rouge">http://localhost:8181/qrcreator/api/</code></a>.</p>

<h4 id="a-regular-json-end-point">A (Regular) JSON End-Point</h4>

<p>Now, let&#8217;s define some endpoints. We will start with a most regular kind &#8211; a JSON end-point. This is probably the most common end-point you will encounter.</p>

<p>We will start with creating one that would respond to requests sent to <a href="http://localhost:8181/qrcreator/api/somestring/json"><code class="language-plaintext highlighter-rouge">/api/somestring/json</code></a>. Note that as you can see from the code below, <code class="language-plaintext highlighter-rouge">@Path</code> defines <code class="language-plaintext highlighter-rouge">somestring</code> in the URL as an <code class="language-plaintext highlighter-rouge">id</code> that is passed on as an argument to the <code class="language-plaintext highlighter-rouge">createIdKeyTuple</code> method.</p>

<p>We will also define a type of a request (in this case it is a <code class="language-plaintext highlighter-rouge">GET</code> request) and specify that it will be returning a JSON document with <code class="language-plaintext highlighter-rouge">@Produces</code> annotation.</p>

<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="nd">@GET</span>
<span class="nd">@Path</span><span class="o">(</span><span class="s">"{id}/json"</span><span class="o">)</span>
<span class="nd">@Produces</span><span class="o">(</span><span class="s">"application/json"</span><span class="o">)</span>
<span class="kd">public</span> <span class="nc">Response</span> <span class="nf">createIdKeyTuple</span><span class="o">(</span><span class="nd">@PathParam</span><span class="o">(</span><span class="s">"id"</span><span class="o">)</span> <span class="nc">String</span> <span class="n">id</span><span class="o">)</span> <span class="o">{</span>
    <span class="o">...</span>
<span class="o">}</span></code></pre></figure>

<p>Now, that we are done with annotations for the method, let&#8217;s have a look at the code for this method, that defines a JSON end-point in the <a href="https://github.com/mehmandarov/microprofile-qrcodes/blob/master/src/main/java/com/mehmandarov/qrcreator/QRController.java"><code class="language-plaintext highlighter-rouge">QRController</code></a> class:</p>

<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="nd">@GET</span>
<span class="nd">@Path</span><span class="o">(</span><span class="s">"{id}/json"</span><span class="o">)</span>
<span class="nd">@Produces</span><span class="o">(</span><span class="s">"application/json"</span><span class="o">)</span>
<span class="kd">public</span> <span class="nc">Response</span> <span class="nf">createIdKeyTuple</span><span class="o">(</span><span class="nd">@PathParam</span><span class="o">(</span><span class="s">"id"</span><span class="o">)</span> <span class="nc">String</span> <span class="n">id</span><span class="o">)</span> <span class="o">{</span>
    <span class="nc">String</span> <span class="n">nameKeyTuple</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
    <span class="k">try</span> <span class="o">{</span>
        <span class="n">nameKeyTuple</span> <span class="o">=</span> <span class="n">qrCodeContentsSupplier</span><span class="o">.</span><span class="na">getQRCodeContents</span><span class="o">(</span><span class="n">id</span><span class="o">);</span>
        <span class="k">return</span> <span class="nc">Response</span><span class="o">.</span><span class="na">ok</span><span class="o">(</span><span class="n">nameKeyTuple</span><span class="o">).</span><span class="na">build</span><span class="o">();</span>
    <span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">InvalidKeySpecException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
        <span class="n">e</span><span class="o">.</span><span class="na">printStackTrace</span><span class="o">();</span>
    <span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">NoSuchAlgorithmException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
        <span class="n">e</span><span class="o">.</span><span class="na">printStackTrace</span><span class="o">();</span>
    <span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">Exception</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
        <span class="n">e</span><span class="o">.</span><span class="na">printStackTrace</span><span class="o">();</span>
    <span class="o">}</span>
    <span class="k">return</span> <span class="nc">Response</span><span class="o">.</span><span class="na">serverError</span><span class="o">().</span><span class="na">build</span><span class="o">();</span>
<span class="o">}</span></code></pre></figure>

<p>Note that in this code we have only simple exception handling that makes sure we return a correct HTTP status code &#8211; OK (200) on a success and server error (500) on an internal error. You can later add other HTTP codes based on your needs.</p>

<h4 id="an-end-point-returning-an-image">An End-Point Returning an Image</h4>

<p>Returning an image instead of a JSON document is quite similar to the code we have already seen. Here we will have to pay attention to three aspects:</p>

<ul>
  <li>Different MIME type defined in <code class="language-plaintext highlighter-rouge">@Produces</code> annotation: <code class="language-plaintext highlighter-rouge">@Produces("image/png")</code></li>
  <li>Additional elements in the response header that let you control how the created file is displayed in the browser, i.e. shown in the browser &#8220;inline&#8221;, or made available through a download dialog &#8211; <code class="language-plaintext highlighter-rouge">"Content-Disposition", "inline;"</code> (see specs for <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition"><code class="language-plaintext highlighter-rouge">Content-Disposition</code></a> for more details)</li>
  <li>Additional elements in the response header that let you control the name for the created file: <code class="language-plaintext highlighter-rouge">filename=\"" + id + ".png\"</code></li>
</ul>

<p>Let&#8217;s have a look at the whole method:</p>

<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="nd">@GET</span>
<span class="nd">@Path</span><span class="o">(</span><span class="s">"{id}"</span><span class="o">)</span>
<span class="nd">@Produces</span><span class="o">(</span><span class="s">"image/png"</span><span class="o">)</span>
<span class="kd">public</span> <span class="nc">Response</span> <span class="nf">createQR</span><span class="o">(</span><span class="nd">@PathParam</span><span class="o">(</span><span class="s">"id"</span><span class="o">)</span> <span class="nc">String</span> <span class="n">id</span><span class="o">)</span> <span class="o">{</span>
    <span class="k">try</span> <span class="o">{</span>
        <span class="kt">byte</span><span class="o">[]</span> <span class="n">imageData</span> <span class="o">=</span> <span class="n">qrCodeSupplier</span><span class="o">.</span><span class="na">qrCodeGenerator</span><span class="o">(</span><span class="n">id</span><span class="o">);</span>
        <span class="k">return</span> <span class="nc">Response</span><span class="o">.</span><span class="na">ok</span><span class="o">(</span><span class="n">imageData</span><span class="o">)</span>
            <span class="o">.</span><span class="na">header</span><span class="o">(</span><span class="s">"Content-Disposition"</span><span class="o">,</span> <span class="s">"inline; filename=\""</span> <span class="o">+</span> <span class="n">id</span> <span class="o">+</span> <span class="s">".png\""</span><span class="o">)</span>
            <span class="o">.</span><span class="na">build</span><span class="o">();</span>
    <span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">WriterException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
        <span class="n">e</span><span class="o">.</span><span class="na">printStackTrace</span><span class="o">();</span>
    <span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">IOException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
        <span class="n">e</span><span class="o">.</span><span class="na">printStackTrace</span><span class="o">();</span>
    <span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">NoSuchAlgorithmException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
        <span class="n">e</span><span class="o">.</span><span class="na">printStackTrace</span><span class="o">();</span>
    <span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">InvalidKeySpecException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
        <span class="n">e</span><span class="o">.</span><span class="na">printStackTrace</span><span class="o">();</span>
    <span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">Exception</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
        <span class="n">e</span><span class="o">.</span><span class="na">printStackTrace</span><span class="o">();</span>
    <span class="o">}</span>
    <span class="k">return</span> <span class="nc">Response</span><span class="o">.</span><span class="na">serverError</span><span class="o">().</span><span class="na">build</span><span class="o">();</span>
<span class="o">}</span></code></pre></figure>

<p>It is worth noting that the number of <code class="language-plaintext highlighter-rouge">catch</code> statements in the <code class="language-plaintext highlighter-rouge">try...catch</code> clause will vary and depend on the number and type of exceptions that can be thrown by the underlying methods.</p>

<h4 id="an-end-point-returning-a-pdf">An End-Point Returning a PDF</h4>

<p>The last method for today &#8211; defining an end-point for returning PDF files &#8211; is nearly identical to the one we used for returning images, except for one thing:</p>

<ul>
  <li>Different MIME type and explicit file encoding in <code class="language-plaintext highlighter-rouge">@Produces</code>: <code class="language-plaintext highlighter-rouge">@Produces("application/pdf; charset=utf-8")</code>.</li>
</ul>

<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="nd">@GET</span>
<span class="nd">@Path</span><span class="o">(</span><span class="s">"{id}/pdf"</span><span class="o">)</span>
<span class="nd">@Produces</span><span class="o">(</span><span class="s">"application/pdf; charset=utf-8"</span><span class="o">)</span>
<span class="kd">public</span> <span class="nc">Response</span> <span class="nf">createQRPDF</span><span class="o">(</span><span class="nd">@PathParam</span><span class="o">(</span><span class="s">"id"</span><span class="o">)</span> <span class="nc">String</span> <span class="n">id</span><span class="o">)</span> <span class="o">{</span>
    <span class="k">try</span> <span class="o">{</span>
        <span class="kt">byte</span><span class="o">[]</span> <span class="n">pdfDocument</span> <span class="o">=</span> <span class="n">pdfDocumentSupplier</span><span class="o">.</span><span class="na">pdfDocumentGenerator</span><span class="o">(</span><span class="n">id</span><span class="o">);</span>
        <span class="k">return</span> <span class="nc">Response</span><span class="o">.</span><span class="na">ok</span><span class="o">(</span><span class="n">pdfDocument</span><span class="o">)</span>
            <span class="o">.</span><span class="na">header</span><span class="o">(</span><span class="s">"Content-Disposition"</span><span class="o">,</span> <span class="s">"inline; filename=\""</span> <span class="o">+</span> <span class="n">id</span> <span class="o">+</span> <span class="s">".pdf\""</span><span class="o">)</span>
            <span class="o">.</span><span class="na">build</span><span class="o">();</span>
    <span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">WriterException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
        <span class="n">e</span><span class="o">.</span><span class="na">printStackTrace</span><span class="o">();</span>
    <span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">IOException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
        <span class="n">e</span><span class="o">.</span><span class="na">printStackTrace</span><span class="o">();</span>
    <span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">NoSuchAlgorithmException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
        <span class="n">e</span><span class="o">.</span><span class="na">printStackTrace</span><span class="o">();</span>
    <span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">InvalidKeySpecException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
        <span class="n">e</span><span class="o">.</span><span class="na">printStackTrace</span><span class="o">();</span>
    <span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">Exception</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
        <span class="n">e</span><span class="o">.</span><span class="na">printStackTrace</span><span class="o">();</span>
    <span class="o">}</span>
    <span class="k">return</span> <span class="nc">Response</span><span class="o">.</span><span class="na">serverError</span><span class="o">().</span><span class="na">build</span><span class="o">();</span>
<span class="o">}</span></code></pre></figure>

<p>Of course, there are also obvious differences in the contents of the <code class="language-plaintext highlighter-rouge">byte[]</code> array, but I consider that being outside the scope of this post &#8211; you can study those differences on your own.</p>

<h2 id="whats-next">What&#8217;s Next?</h2>

<p>Here we have seen how easy it is to define an end-point that can return documents with various MIME types. In the next posts, we will be taking a closer look at things like how you can equip your end-points with metrics, provide auto-generated documentation based on OpenAPI, and add more resilience with fail-over and circuit-breakers.</p>

<hr />]]></content><author><name>Rustam Mehmandarov</name></author><summary type="html">Getting started with MicroProfile &#8211; defining end-points for JSON, images, and PDF responses.</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://mehmandarov.com/assets/images/posts-images/lego-record-shop.jpg"/><category term="blog"/><category term="java"/><category term="microservices"/><category term="microprofile"/><category term="jakarta ee"/><category term="english"/></entry><entry><title type="html">Generating PDF Files Using Java</title><link href="https://mehmandarov.com/generating-pdf-files-using-java/" rel="alternate" type="text/html" title="Generating PDF Files Using Java"/><published>2019-06-21T07:01:00+02:00</published><updated>2019-06-21T07:01:00+02:00</updated><id>https://mehmandarov.com/generating-pdf-files-using-java</id><content type="html" xml:base="https://mehmandarov.com/generating-pdf-files-using-java/"><![CDATA[<p><em>A step by step tutorial on how to generate PDF files in Java.</em></p>

<ul>
  <li><a href="#intro">Intro</a></li>
  <li><a href="#choosing-a-library">Choosing a Library</a></li>
  <li><a href="#generating-pdf-files">Generaring PDF Files</a>
    <ul>
      <li><a href="#adding-maven-dependency">Adding Maven Dependency</a></li>
      <li><a href="#getting-started-with-the-code">Getting Started With the Code</a></li>
      <li><a href="#adding-text">Adding Text</a></li>
      <li><a href="#adding-images">Adding Images</a></li>
      <li><a href="#adding-metadata-to-the-document">Adding Metadata to the Document</a></li>
      <li><a href="#closing-saving-and-returning-the-document">Closing, Saving and Returning the Document</a></li>
    </ul>
  </li>
  <li><a href="#what-now">What Now?</a></li>
</ul>

<hr />

<h2 id="intro">Intro</h2>

<p>In my previous post, I have started describing a <a href="/generating-qr-codes-with-secure-hashes-using-java/">system for &#8220;checking-in&#8221; to a location using QR codes in Java</a>. Now, I would like to describe another part of that system that will show you how to get started with generating PDF files using Java.</p>

<p>So, let&#8217;s have a look at how this can be implemented in your solution &#8211; step by step.</p>

<h2 id="choosing-a-library">Choosing a Library</h2>

<p>Generating PDFs is normally something you would like to do using 3rd party libraries, and there are quite a few alternatives available. While choosing a library it might be a good idea to have a closer look at the licensing for that library &#8211; some of them might be very permissive and some might force your code to comply to a specific licensing. Some libraries even come with dual licensing, one under a proprietary model and one supporting an open source model.</p>

<p>One should also consider other aspects like maturity and whether it is a high- or low-level library. The latter will tell you how much code you will actually end up writing to implement your features. In the course of this project, I ended up trying two different libraries &#8211; <a href="https://itextpdf.com/en">iText</a> and, later, <a href="https://pdfbox.apache.org/">Apache PDFBox</a>. Since the point of this code was a tutorial, I decided to stick with PDFBox as it is distributed under more permissive license &#8211;&#160;<a href="https://tldrlegal.com/license/apache-license-2.0-(apache-2.0)">Apache License 2.0</a>, as opposed to dual licensed iText that is under <a href="https://tldrlegal.com/license/gnu-affero-general-public-license-v3-(agpl-3.0)">AGPL</a> and a commercial license.</p>

<h2 id="generating-pdf-files">Generating PDF Files</h2>

<p>As mentioned earlier, this library provides quite extensive functionality for generating PDF files, but it is also quite low-level, so you will have to be prepared to implement a few things you might usually take for granted, e.g. things like calculating coordinates for text that has to be centered on a page and a few other things. However, the library has a great community, so it is quite easy to get help.</p>

<h4 id="adding-maven-dependency">Adding Maven Dependency</h4>
<p>Ok, let&#8217;s get started. First things first, you will need to add the following dependencies to your <code class="language-plaintext highlighter-rouge">pom.xml</code> to use PDFBox (assuming you are using Maven to build your project):</p>

<figure class="highlight"><pre><code class="language-xml" data-lang="xml">    <span class="nt">&lt;dependency&gt;</span>
      <span class="nt">&lt;groupId&gt;</span>org.apache.pdfbox<span class="nt">&lt;/groupId&gt;</span>
      <span class="nt">&lt;artifactId&gt;</span>pdfbox<span class="nt">&lt;/artifactId&gt;</span>
      <span class="nt">&lt;version&gt;</span>2.0.15<span class="nt">&lt;/version&gt;</span>
    <span class="nt">&lt;/dependency&gt;</span></code></pre></figure>

<h4 id="getting-started-with-the-code">Getting Started With the Code</h4>
<p>For this post, I decided to paste the source code for the whole function doing the PDF generation and separate it with a few sentences, explaining the most interesting parts of the code. You can always piece the code together, or just have a look at the code in <a href="https://github.com/mehmandarov/microprofile-qrcodes/blob/master/src/main/java/com/mehmandarov/qrcreator/document/PDFDocumentSupplier.java">my repo</a>. (<em>Bonus: If you are interested in how much work it was to port the code from iText to PDFBox, this <a href="https://github.com/mehmandarov/microprofile-qrcodes/commit/bf53ec918dbc0a2e64c1c830aa4995ef63cee52e">commit</a> should give you a rough idea.</em>)</p>

<p>We start with defining a document object, a page object and add a page to a document. Afterwards, we create a content stream object that will be added to the page and document objects. This object will be responsible for holding the text and images we will be generating here.</p>

<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="c1">// Assume that the following variables are declared and set:</span>
<span class="c1">//   QRCodeSupplier qrCodeSupplier - to generate QR codes, shown in the previous post</span>
<span class="c1">//   String id - a string that will be shown on the top of the PDF file and used in the QR code</span>
<span class="c1">//   String timeZone - a string containing current time zone</span>

<span class="nc">String</span> <span class="n">headerTitle</span> <span class="o">=</span> <span class="n">id</span><span class="o">;</span>
<span class="nc">PDFont</span> <span class="n">headerFont</span> <span class="o">=</span> <span class="nc">PDType1Font</span><span class="o">.</span><span class="na">COURIER_BOLD</span><span class="o">;</span>

<span class="kt">int</span> <span class="n">marginTop</span> <span class="o">=</span> <span class="mi">30</span><span class="o">;</span>
<span class="kt">int</span> <span class="n">fontSize</span> <span class="o">=</span> <span class="mi">30</span><span class="o">;</span>

<span class="nc">PDDocument</span> <span class="n">document</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">PDDocument</span><span class="o">();</span>

<span class="nc">PDPage</span> <span class="n">page</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">PDPage</span><span class="o">(</span><span class="nc">PDRectangle</span><span class="o">.</span><span class="na">A4</span><span class="o">);</span>
<span class="nc">PDRectangle</span> <span class="n">mediaBox</span> <span class="o">=</span> <span class="n">page</span><span class="o">.</span><span class="na">getMediaBox</span><span class="o">();</span>
<span class="n">document</span><span class="o">.</span><span class="na">addPage</span><span class="o">(</span><span class="n">page</span><span class="o">);</span>

<span class="nc">PDPageContentStream</span> <span class="n">contentStream</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">PDPageContentStream</span><span class="o">(</span><span class="n">document</span><span class="o">,</span> 
                                                            <span class="n">page</span><span class="o">,</span> 
                                                            <span class="nc">PDPageContentStream</span><span class="o">.</span><span class="na">AppendMode</span><span class="o">.</span><span class="na">APPEND</span><span class="o">,</span> 
                                                            <span class="kc">true</span><span class="o">);</span></code></pre></figure>

<h4 id="adding-text">Adding Text</h4>
<p>Now we will need to calculate the coordinates for the header text string and make sure it will appear centered independent of the font and size. This is one of the &#8220;low-level&#8221; parts you will have to deal with when using PDFBox.</p>

<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="c1">// calculate coordinates to center the header text</span>
<span class="kt">float</span> <span class="n">titleWidth</span> <span class="o">=</span> <span class="n">headerFont</span><span class="o">.</span><span class="na">getStringWidth</span><span class="o">(</span><span class="n">headerTitle</span><span class="o">)</span> <span class="o">/</span> <span class="mi">1000</span> <span class="o">*</span> <span class="n">fontSize</span><span class="o">;</span>
<span class="kt">float</span> <span class="n">titleHeight</span> <span class="o">=</span> <span class="n">headerFont</span><span class="o">.</span><span class="na">getFontDescriptor</span><span class="o">().</span><span class="na">getFontBoundingBox</span><span class="o">().</span><span class="na">getHeight</span><span class="o">()</span> <span class="o">/</span> <span class="mi">1000</span> <span class="o">*</span> <span class="n">fontSize</span><span class="o">;</span>
<span class="kt">float</span> <span class="n">titleStartX</span> <span class="o">=</span> <span class="o">(</span><span class="n">mediaBox</span><span class="o">.</span><span class="na">getWidth</span><span class="o">()</span> <span class="o">-</span> <span class="n">titleWidth</span><span class="o">)</span> <span class="o">/</span> <span class="mi">2</span><span class="o">;</span>
<span class="kt">float</span> <span class="n">titleStartY</span> <span class="o">=</span> <span class="n">mediaBox</span><span class="o">.</span><span class="na">getHeight</span><span class="o">()</span> <span class="o">-</span> <span class="n">marginTop</span> <span class="o">-</span> <span class="n">titleHeight</span><span class="o">;</span></code></pre></figure>

<p>Next, we will be adding the text itself and setting font and coordinates for it on the page:</p>

<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="c1">// add header text to the document</span>
<span class="c1">// Note: This solution will not support fixed-width paragraphs and text flow</span>
<span class="n">contentStream</span><span class="o">.</span><span class="na">beginText</span><span class="o">();</span>
<span class="n">contentStream</span><span class="o">.</span><span class="na">setFont</span><span class="o">(</span><span class="n">headerFont</span><span class="o">,</span> <span class="n">fontSize</span><span class="o">);</span>
<span class="n">contentStream</span><span class="o">.</span><span class="na">newLineAtOffset</span><span class="o">(</span><span class="n">titleStartX</span><span class="o">,</span> <span class="n">titleStartY</span><span class="o">);</span>
<span class="n">contentStream</span><span class="o">.</span><span class="na">showText</span><span class="o">(</span><span class="n">headerTitle</span><span class="o">);</span>
<span class="n">contentStream</span><span class="o">.</span><span class="na">endText</span><span class="o">();</span></code></pre></figure>

<h4 id="adding-images">Adding Images</h4>
<p>Now, let&#8217;s examine how to add an image to a PDF document. Here, you can use <code class="language-plaintext highlighter-rouge">createFromFile()</code> in case your image is already available, or <code class="language-plaintext highlighter-rouge">createFromImage()</code> is you are generating the image on the fly and/or returning it from another function.</p>

<p>Below, you will also find examples of code to scale and to calculate coordinates for centering the image:</p>

<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="c1">// get image as a byte array</span>
<span class="nc">ByteArrayInputStream</span> <span class="n">bais</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ByteArrayInputStream</span><span class="o">(</span><span class="n">qrCodeSupplier</span><span class="o">.</span><span class="na">qrCodeGenerator</span><span class="o">(</span><span class="n">id</span><span class="o">));</span>
<span class="nc">BufferedImage</span> <span class="n">bim</span> <span class="o">=</span> <span class="nc">ImageIO</span><span class="o">.</span><span class="na">read</span><span class="o">(</span><span class="n">bais</span><span class="o">);</span>

<span class="c1">// convert image to an object that can be added to the PDF document</span>
<span class="nc">PDImageXObject</span> <span class="n">pdImage</span> <span class="o">=</span> <span class="nc">LosslessFactory</span><span class="o">.</span><span class="na">createFromImage</span><span class="o">(</span><span class="n">document</span><span class="o">,</span> <span class="n">bim</span><span class="o">);</span>

<span class="c1">// calculate coordinates to center the image</span>
<span class="kt">float</span> <span class="n">scale</span> <span class="o">=</span> <span class="mi">1</span><span class="n">f</span><span class="o">;</span>
<span class="kt">int</span> <span class="n">imageOffset</span> <span class="o">=</span> <span class="mi">100</span><span class="o">;</span>

<span class="kt">float</span> <span class="n">imageWidth</span> <span class="o">=</span> <span class="n">pdImage</span><span class="o">.</span><span class="na">getWidth</span><span class="o">()</span> <span class="o">*</span> <span class="n">scale</span><span class="o">;</span>
<span class="kt">float</span> <span class="n">imageHeight</span> <span class="o">=</span> <span class="n">pdImage</span><span class="o">.</span><span class="na">getHeight</span><span class="o">()</span> <span class="o">*</span> <span class="n">scale</span><span class="o">;</span>
<span class="kt">float</span> <span class="n">imageStartX</span> <span class="o">=</span> <span class="o">(</span><span class="n">mediaBox</span><span class="o">.</span><span class="na">getWidth</span><span class="o">()</span> <span class="o">-</span> <span class="n">imageWidth</span><span class="o">)</span> <span class="o">/</span> <span class="mi">2</span><span class="o">;</span>
<span class="kt">float</span> <span class="n">imageStartY</span> <span class="o">=</span> <span class="n">titleStartY</span> <span class="o">-</span> <span class="n">imageHeight</span> <span class="o">-</span> <span class="n">imageOffset</span><span class="o">;</span>

<span class="c1">// add image into the document</span>
<span class="n">contentStream</span><span class="o">.</span><span class="na">drawImage</span><span class="o">(</span><span class="n">pdImage</span><span class="o">,</span> <span class="n">imageStartX</span><span class="o">,</span> <span class="n">imageStartY</span><span class="o">,</span> 
                        <span class="n">pdImage</span><span class="o">.</span><span class="na">getWidth</span><span class="o">()</span> <span class="o">*</span> <span class="n">scale</span><span class="o">,</span> <span class="n">pdImage</span><span class="o">.</span><span class="na">getHeight</span><span class="o">()</span> <span class="o">*</span> <span class="n">scale</span><span class="o">);</span>

<span class="c1">// closing the stream</span>
<span class="n">contentStream</span><span class="o">.</span><span class="na">close</span><span class="o">();</span></code></pre></figure>

<h4 id="adding-metadata-to-the-document">Adding Metadata to the Document</h4>
<p>Here, you can see a few examples of how you can add metadata to your document. This is done with a help of <a href="https://pdfbox.apache.org/docs/2.0.13/javadocs/org/apache/pdfbox/pdmodel/PDDocumentInformation.html">a few methods available thought the API</a>:</p>

<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="c1">// add metadata</span>
<span class="n">document</span><span class="o">.</span><span class="na">getDocumentInformation</span><span class="o">().</span><span class="na">setTitle</span><span class="o">(</span><span class="s">"Generated QR code for "</span> <span class="o">+</span> <span class="n">id</span> <span class="o">+</span> <span class="s">"."</span><span class="o">);</span>
<span class="n">document</span><span class="o">.</span><span class="na">getDocumentInformation</span><span class="o">().</span><span class="na">setSubject</span><span class="o">(</span><span class="s">"with a secure string"</span><span class="o">);</span>
<span class="n">document</span><span class="o">.</span><span class="na">getDocumentInformation</span><span class="o">().</span><span class="na">setAuthor</span><span class="o">(</span><span class="s">"rm"</span><span class="o">);</span>
<span class="n">document</span><span class="o">.</span><span class="na">getDocumentInformation</span><span class="o">().</span><span class="na">setCreator</span><span class="o">(</span><span class="s">"rm"</span><span class="o">);</span>
<span class="n">document</span><span class="o">.</span><span class="na">getDocumentInformation</span><span class="o">().</span><span class="na">setCreationDate</span><span class="o">(</span><span class="n">date</span><span class="o">);</span></code></pre></figure>

<h4 id="closing-saving-and-returning-the-document">Closing, Saving and Returning the Document</h4>
<p>After your document is built and you have added all the contents, remember to save and close your document. Now you can either save the document to the file with <a href="https://pdfbox.apache.org/1.8/cookbook/documentcreation.html"><code class="language-plaintext highlighter-rouge">document.save()</code></a>, or returning the document as a byte array to another function with <code class="language-plaintext highlighter-rouge">byteArrayOutputStream.toByteArray()</code>:</p>

<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="c1">// save and close document</span>
<span class="nc">ByteArrayOutputStream</span> <span class="n">byteArrayOutputStream</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ByteArrayOutputStream</span><span class="o">();</span>
<span class="n">document</span><span class="o">.</span><span class="na">save</span><span class="o">(</span><span class="n">byteArrayOutputStream</span><span class="o">);</span>
<span class="n">document</span><span class="o">.</span><span class="na">close</span><span class="o">();</span>

<span class="c1">// return document as byte[]</span>
<span class="k">return</span> <span class="n">byteArrayOutputStream</span><span class="o">.</span><span class="na">toByteArray</span><span class="o">();</span></code></pre></figure>

<h2 id="what-now">What Now?</h2>

<p>In the last two posts, we have seen how to generate QR codes with a hashed string and PDF files with Java. In the next post, I will be showing how to put it all together into a <a href="https://tldrlegal.com/license/gnu-affero-general-public-license-v3-(agpl-3.0)">MicroProfile</a> microservice.</p>

<hr />]]></content><author><name>Rustam Mehmandarov</name></author><summary type="html">A step-by-step tutorial on generating PDF files in Java with text, images, and metadata.</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://mehmandarov.com/assets/images/posts-images/pages.jpg"/><category term="blog"/><category term="java"/><category term="pdf"/><category term="english"/></entry><entry><title type="html">Generating QR Codes With Secure Hashes Using Java</title><link href="https://mehmandarov.com/generating-qr-codes-with-secure-hashes-using-java/" rel="alternate" type="text/html" title="Generating QR Codes With Secure Hashes Using Java"/><published>2019-06-10T07:01:00+02:00</published><updated>2019-06-10T07:01:00+02:00</updated><id>https://mehmandarov.com/generating-qr-codes-with-secure-hashes-using-java</id><content type="html" xml:base="https://mehmandarov.com/generating-qr-codes-with-secure-hashes-using-java/"><![CDATA[<p><em>A step by step tutorial on how to generate QR codes and secure hashed strings with salt in Java.</em></p>

<ul>
  <li><a href="#intro">Intro</a></li>
  <li><a href="#generating-qr-codes">Generaring QR Codes</a></li>
  <li><a href="#hashing-strings">Hashing Strings</a></li>
  <li><a href="#what-now">What Now?</a></li>
</ul>

<hr />

<h2 id="intro">Intro</h2>

<p>I have been testing out new functionality for &#8220;checking-in&#8221; to a location using QR codes. To make sure the user is at the specified location and is scanning my QR code (and not a &#8220;fake&#8221; code created by someone else), I needed to add a way of &#8220;signing&#8221; each code with a value that only I &#8211; the provider of the QR code &#8211; could know. This would also make it simple enough to be able to implement the same mechanism in the app used to scan the codes to verify the validity on the client side.</p>

<p>I ended up with a solution where I would have a QR code containing a JSON object with a <code class="language-plaintext highlighter-rouge">Name</code> and a <code class="language-plaintext highlighter-rouge">Key</code> &#8211; a hashed and salted name string. The string will be read by the client app used to scan the code and hashed using the same algorithm with the same secret salt value, and compared to the value in the QR code on the client side.</p>

<p>The data structure inside a generated QR code would be like this:</p>

<figure class="highlight"><pre><code class="language-json" data-lang="json"><span class="p">{</span><span class="w"> 
    </span><span class="s2">"Name"</span><span class="p">,</span><span class="w"> </span><span class="s2">"MyString"</span><span class="p">,</span><span class="w">
    </span><span class="s2">"Key"</span><span class="p">,</span><span class="w"> </span><span class="s2">"HashedMyStringWithSecretSalt"</span><span class="w">
</span><span class="p">}</span></code></pre></figure>

<p>When it comes to the implementation, I decided to do the generation or codes in Java and, later, implement this as a standalone microservice. Here, I must admit that I was surprised by how simple it was using a specialized library. More about that below.</p>

<p>So, let&#8217;s have a look at how this can be implemented in your solution &#8211; step by step.</p>

<h2 id="generating-qr-codes">Generating QR Codes</h2>

<p>First, I needed a library that can handle QR codes, and I decided to use <a href="https://github.com/zxing/zxing">Zebra Crossing  (&#8220;ZXing&#8221;)</a> library because of its simplicity and popularity (i.e. community around it).</p>

<p>All you need to get started is to add the following dependencies to your <code class="language-plaintext highlighter-rouge">pom.xml</code> (assuming you are using Maven to build your project):</p>

<figure class="highlight"><pre><code class="language-xml" data-lang="xml"><span class="nt">&lt;dependency&gt;</span>
  <span class="nt">&lt;groupId&gt;</span>com.google.zxing<span class="nt">&lt;/groupId&gt;</span>
  <span class="nt">&lt;artifactId&gt;</span>core<span class="nt">&lt;/artifactId&gt;</span>
  <span class="nt">&lt;version&gt;</span>3.4.0<span class="nt">&lt;/version&gt;</span>
<span class="nt">&lt;/dependency&gt;</span>
<span class="nt">&lt;dependency&gt;</span>
  <span class="nt">&lt;groupId&gt;</span>com.google.zxing<span class="nt">&lt;/groupId&gt;</span>
  <span class="nt">&lt;artifactId&gt;</span>javase<span class="nt">&lt;/artifactId&gt;</span>
  <span class="nt">&lt;version&gt;</span>3.4.0<span class="nt">&lt;/version&gt;</span>
<span class="nt">&lt;/dependency&gt;</span></code></pre></figure>

<p>This library provides quite an extensive functionality both for generating and reading codes. This was more than enough for my use case where I just needed to generate a QR code with a simple JSON object:</p>

<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="kd">public</span> <span class="kt">byte</span><span class="o">[]</span> <span class="nf">qrCodeGenerator</span><span class="o">(</span><span class="nc">String</span> <span class="n">id</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">IOException</span><span class="o">,</span> 
                                                <span class="nc">WriterException</span><span class="o">,</span> 
                                                <span class="nc">InvalidKeySpecException</span><span class="o">,</span> 
                                                <span class="nc">NoSuchAlgorithmException</span> <span class="o">{</span>

    <span class="nc">String</span> <span class="n">filePath</span> <span class="o">=</span> <span class="s">"QRCode.png"</span><span class="o">;</span>
    <span class="nc">String</span> <span class="n">charset</span> <span class="o">=</span> <span class="s">"UTF-8"</span><span class="o">;</span>
    <span class="nc">Map</span> <span class="n">hintMap</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">HashMap</span><span class="o">();</span>
    <span class="n">hintMap</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="nc">EncodeHintType</span><span class="o">.</span><span class="na">ERROR_CORRECTION</span><span class="o">,</span> <span class="nc">ErrorCorrectionLevel</span><span class="o">.</span><span class="na">L</span><span class="o">);</span>

    <span class="nc">Map</span><span class="o">&lt;</span><span class="nc">String</span><span class="o">,</span> <span class="nc">String</span><span class="o">&gt;</span> <span class="n">qrCodeDataMap</span> <span class="o">=</span> <span class="nc">Map</span><span class="o">.</span><span class="na">of</span><span class="o">(</span>
            <span class="s">"Name"</span><span class="o">,</span> <span class="n">id</span><span class="o">,</span>
            <span class="s">"Key"</span><span class="o">,</span> <span class="n">keyProvider</span><span class="o">.</span><span class="na">generateVerificationKey</span><span class="o">(</span><span class="n">id</span><span class="o">)</span> 
            <span class="c1">// see next section for &#180;generateVerificationKey&#180; method</span>
    <span class="o">);</span>

    <span class="nc">String</span> <span class="n">jsonString</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">JSONObject</span><span class="o">(</span><span class="n">qrCodeDataMap</span><span class="o">).</span><span class="na">toString</span><span class="o">();</span>
    <span class="n">createQRCode</span><span class="o">(</span><span class="n">jsonString</span><span class="o">,</span> <span class="n">filePath</span><span class="o">,</span> <span class="n">charset</span><span class="o">,</span> <span class="n">hintMap</span><span class="o">,</span> <span class="mi">500</span><span class="o">,</span> <span class="mi">500</span><span class="o">);</span>

    <span class="nc">BufferedImage</span> <span class="n">image</span> <span class="o">=</span> <span class="nc">ImageIO</span><span class="o">.</span><span class="na">read</span><span class="o">(</span><span class="k">new</span> <span class="nc">File</span><span class="o">(</span><span class="n">filePath</span><span class="o">));</span>
    <span class="nc">ByteArrayOutputStream</span> <span class="n">baos</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ByteArrayOutputStream</span><span class="o">();</span>
    <span class="nc">ImageIO</span><span class="o">.</span><span class="na">write</span><span class="o">(</span><span class="n">image</span><span class="o">,</span> <span class="s">"png"</span><span class="o">,</span> <span class="n">baos</span><span class="o">);</span>
    <span class="kt">byte</span><span class="o">[]</span> <span class="n">imageData</span> <span class="o">=</span> <span class="n">baos</span><span class="o">.</span><span class="na">toByteArray</span><span class="o">();</span>

    <span class="k">return</span> <span class="n">imageData</span><span class="o">;</span>
<span class="o">}</span>

<span class="kd">private</span> <span class="kt">void</span> <span class="nf">createQRCode</span><span class="o">(</span><span class="nc">String</span> <span class="n">qrCodeData</span><span class="o">,</span> 
                          <span class="nc">String</span> <span class="n">filePath</span><span class="o">,</span> 
                          <span class="nc">String</span> <span class="n">charset</span><span class="o">,</span> 
                          <span class="nc">Map</span> <span class="n">hintMap</span><span class="o">,</span> 
                          <span class="kt">int</span> <span class="n">qrCodeHeight</span><span class="o">,</span> 
                          <span class="kt">int</span> <span class="n">qrCodeWidth</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">WriterException</span><span class="o">,</span> 
                                                  <span class="nc">IOException</span> <span class="o">{</span>

    <span class="nc">BitMatrix</span> <span class="n">matrix</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">MultiFormatWriter</span><span class="o">().</span><span class="na">encode</span><span class="o">(</span>
            <span class="k">new</span> <span class="nf">String</span><span class="o">(</span><span class="n">qrCodeData</span><span class="o">.</span><span class="na">getBytes</span><span class="o">(</span><span class="n">charset</span><span class="o">),</span> <span class="n">charset</span><span class="o">),</span>
            <span class="nc">BarcodeFormat</span><span class="o">.</span><span class="na">QR_CODE</span><span class="o">,</span>
            <span class="n">qrCodeWidth</span><span class="o">,</span>
            <span class="n">qrCodeHeight</span><span class="o">,</span>
            <span class="n">hintMap</span>
    <span class="o">);</span>

    <span class="nc">MatrixToImageWriter</span><span class="o">.</span><span class="na">writeToPath</span><span class="o">(</span>
            <span class="n">matrix</span><span class="o">,</span>
            <span class="n">filePath</span><span class="o">.</span><span class="na">substring</span><span class="o">(</span><span class="n">filePath</span><span class="o">.</span><span class="na">lastIndexOf</span><span class="o">(</span><span class="sc">'.'</span><span class="o">)</span> <span class="o">+</span> <span class="mi">1</span><span class="o">),</span>
            <span class="nc">FileSystems</span><span class="o">.</span><span class="na">getDefault</span><span class="o">().</span><span class="na">getPath</span><span class="o">(</span><span class="n">filePath</span><span class="o">)</span>
    <span class="o">);</span>
<span class="o">}</span></code></pre></figure>

<p>Note also fun little thing &#8211; the conversion of Java hashmaps to a JSON object using <code class="language-plaintext highlighter-rouge">JSONObject</code>. Sometimes it is much easier to build up data structure the way you want it, and then serialize to JSON:</p>

<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="nc">Map</span><span class="o">&lt;</span><span class="nc">String</span><span class="o">,</span> <span class="nc">String</span><span class="o">&gt;</span> <span class="n">qrCodeDataMap</span> <span class="o">=</span> <span class="nc">Map</span><span class="o">.</span><span class="na">of</span><span class="o">(</span>
        <span class="s">"Name"</span><span class="o">,</span> <span class="s">"SampleText"</span><span class="o">,</span>
        <span class="s">"Key"</span><span class="o">,</span> <span class="s">"SomeHashedValue"</span>
<span class="o">);</span>
<span class="nc">String</span> <span class="n">jsonString</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">JSONObject</span><span class="o">(</span><span class="n">qrCodeDataMap</span><span class="o">).</span><span class="na">toString</span><span class="o">();</span></code></pre></figure>

<p>To be able to use <code class="language-plaintext highlighter-rouge">JSONObject</code> class, you would need to add the following dependency to your <code class="language-plaintext highlighter-rouge">pom.xml</code>:</p>

<figure class="highlight"><pre><code class="language-xml" data-lang="xml"><span class="nt">&lt;dependency&gt;</span>
  <span class="nt">&lt;groupId&gt;</span>org.json<span class="nt">&lt;/groupId&gt;</span>
  <span class="nt">&lt;artifactId&gt;</span>json<span class="nt">&lt;/artifactId&gt;</span>
  <span class="nt">&lt;version&gt;</span>20180813<span class="nt">&lt;/version&gt;</span>
<span class="nt">&lt;/dependency&gt;</span></code></pre></figure>

<p>If you are looking for a more simplified interface, you might also check out <a href="https://github.com/kenglxn/QRGen">QRGen</a> that claims to simplify QR code generation API for Java even further and is built on top ZXing. However, ZXing was absolutely fine in my case.</p>

<h2 id="hashing-strings">Hashing Strings</h2>

<p>Now, I needed to be able to hash a string in a quick and secure manner. For this, I decided to use the <a href="https://www.owasp.org/index.php/Hashing_Java">method suggested by OWASP for Java</a>. To implement this method you will need to start with updating your <code class="language-plaintext highlighter-rouge">pom.xml</code>:</p>

<figure class="highlight"><pre><code class="language-xml" data-lang="xml"><span class="nt">&lt;dependency&gt;</span>
  <span class="nt">&lt;groupId&gt;</span>commons-codec<span class="nt">&lt;/groupId&gt;</span>
  <span class="nt">&lt;artifactId&gt;</span>commons-codec<span class="nt">&lt;/artifactId&gt;</span>
  <span class="nt">&lt;version&gt;</span>1.12<span class="nt">&lt;/version&gt;</span>
<span class="nt">&lt;/dependency&gt;</span></code></pre></figure>

<p>And here is the (somewhat simplified) implmentation of the said method in Java:</p>

<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="kd">public</span> <span class="nc">String</span> <span class="nf">generateVerificationKey</span><span class="o">(</span><span class="nc">String</span> <span class="n">str</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">NoSuchAlgorithmException</span><span class="o">,</span>
                                                         <span class="nc">InvalidKeySpecException</span> <span class="o">{</span>
    <span class="kt">int</span> <span class="n">iterations</span> <span class="o">=</span> <span class="mi">10000</span><span class="o">;</span>
    <span class="kt">int</span> <span class="n">keyLength</span> <span class="o">=</span> <span class="mi">512</span><span class="o">;</span>

    <span class="kt">char</span><span class="o">[]</span> <span class="n">strChars</span> <span class="o">=</span> <span class="n">str</span><span class="o">.</span><span class="na">toCharArray</span><span class="o">();</span>
    <span class="kt">byte</span><span class="o">[]</span> <span class="n">saltBytes</span> <span class="o">=</span> <span class="n">salt</span><span class="o">.</span><span class="na">getBytes</span><span class="o">();</span>

    <span class="nc">SecretKeyFactory</span> <span class="n">skf</span> <span class="o">=</span> <span class="nc">SecretKeyFactory</span><span class="o">.</span><span class="na">getInstance</span><span class="o">(</span><span class="s">"PBKDF2WithHmacSHA512"</span><span class="o">);</span>
    <span class="nc">PBEKeySpec</span> <span class="n">spec</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">PBEKeySpec</span><span class="o">(</span><span class="n">strChars</span><span class="o">,</span> <span class="n">saltBytes</span><span class="o">,</span> <span class="n">iterations</span><span class="o">,</span> <span class="n">keyLength</span><span class="o">);</span>
    <span class="nc">SecretKey</span> <span class="n">key</span> <span class="o">=</span> <span class="n">skf</span><span class="o">.</span><span class="na">generateSecret</span><span class="o">(</span> <span class="n">spec</span> <span class="o">);</span>
    <span class="kt">byte</span><span class="o">[]</span> <span class="n">hashedBytes</span> <span class="o">=</span> <span class="n">key</span><span class="o">.</span><span class="na">getEncoded</span><span class="o">(</span> <span class="o">);</span>

    <span class="k">return</span> <span class="nc">Hex</span><span class="o">.</span><span class="na">encodeHexString</span><span class="o">(</span><span class="n">hashedBytes</span><span class="o">);</span>
<span class="o">}</span></code></pre></figure>

<h2 id="what-now">What Now?</h2>

<p>By now you should be able to generate QR codes with a hashed string. In the next post, I will be sharing code on how to embed and generate PDF files with this information with Java, followed by a post where it all will be put together into a <a href="https://microprofile.io/">MicroProfile</a> microservice. Stay tuned!</p>

<hr />]]></content><author><name>Rustam Mehmandarov</name></author><summary type="html">A step-by-step tutorial on generating QR codes and secure hashed strings with salt in Java.</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://mehmandarov.com/assets/images/posts-images/black-and-white-java.jpg"/><category term="blog"/><category term="java"/><category term="english"/></entry><entry><title type="html">Escaping Developer Nightmares</title><link href="https://mehmandarov.com/escaping-developer-nigthmares/" rel="alternate" type="text/html" title="Escaping Developer Nightmares"/><published>2017-12-01T07:23:00+01:00</published><updated>2017-12-01T07:23:00+01:00</updated><id>https://mehmandarov.com/escaping-developer-nigthmares</id><content type="html" xml:base="https://mehmandarov.com/escaping-developer-nigthmares/"><![CDATA[<p><em>A short write up of the bad things we do in software development and some suggestions on how to fix them.</em></p>

<ul>
  <li><a href="#the-existing-state-of-affairs">The Existing State of Affairs</a></li>
  <li><a href="#the-moving-parts">The Moving Parts</a></li>
  <li><a href="#conclusion">Conclusion</a></li>
</ul>

<hr />

<p>Let&#8217;s take a look into what we can do to achieve a better development environment than an average development project &#8211; a project that most of us have seen at some point in our professional lives, or maybe even are a part of right now. We will also look into some tools and patterns that will help us convert those projects into a paradise for the developers.</p>

<p>Just a few decades ago, we were working in ways that might look like unproductive, in the best case. Our development models were predominated by waterfalls, our IDEs were basic and we were compiling our projects by hand, using <code class="language-plaintext highlighter-rouge">javac</code>, or building up the <code class="language-plaintext highlighter-rouge">CLASSPATH</code> depending on the <code class="language-plaintext highlighter-rouge">GOTO</code> statements in a huge spaghetti code contained in countless <code class="language-plaintext highlighter-rouge">bat</code> files. Our code lived in a very simple versioning systems that were not distributed or supported branching strategies that are praised by the developers today. Our documentation lived in <code class="language-plaintext highlighter-rouge">doc</code> files on shared network drives, side by side with the simple issue tracking systems, that don&#8217;t even get close to what we have today.</p>

<p>Today, it is all different &#8211; we have Git, real issue tracking, IDEs, all that integrated with build servers and collaborative platforms. Yes, everything is much better, more effective and user-friendly, one might think that we are in the paradise already? Well&#8230; yes, things are fortunately getting better, however, we are still doing things in a way that might still give you nightmares, several decades from now.</p>

<p>Last years I have been working and invited to evaluate and help with an audit of various projects. Here are some of my observations and thoughts.</p>

<h2 id="the-existing-state-of-affairs">The Existing State of Affairs</h2>

<p>This <a href="https://twitter.com/brianwisti/status/503987766032494592?lang=en">tweet</a> describes it pretty well:</p>

<figure class="highlight"><pre><code class="language-text" data-lang="text">YOU ARE IN A LEGACY CODEBASE
&gt; RUN TESTS
YOU HAVE NO TESTS
&gt; READ SPEC
YOU HAVE NO SPEC
&gt; WRITE FIX
YOU ARE EATEN BY AN ELDER CODE HACK.</code></pre></figure>

<p>Some of the issues are, naturally, remnants of the past &#8211; the legacy systems; but even those systems and most of the other problems we see today can be avoided if we slightly change our view at some of the main parts of the development process. In most of the cases, we would be aware of those issues, but we might need to explain and motivate the others &#8211; often people are responsible for the projects and those who prioritize the development and maintenance backlog.</p>

<h2 id="the-moving-parts">The Moving Parts</h2>

<p>The road to a great nightmare-free future consists of three components: the code quality, the development and build tools, and a good documentation and collaboration systems. When evaluating systems I often start asking some simple questions listed below to get an idea of the system.</p>

<h3 id="1-the-code">1. The Code</h3>
<h4 id="the-code-quality">The Code Quality</h4>

<p>First thing off is the general code quality. I often start by asking about simple things &#8211; if the project has a coding standard, and if it is being followed. I also ask to take a quick peek at the code and check minor things like file encodings and MIME types. I also follow up with a question if the team is practicing code reviews, and how they are doing that.</p>

<p>While those things alone don&#8217;t have to mean anything, and are minor issues individually, together with other factors they still are initial indicators of possible neglect. This gives me a possibility to map areas where to look further.</p>

<p>In addition to that, there are also some more specific parts that will be listed as sub-sections below.</p>

<h4 id="the-third-party-libraries">The third-party libraries</h4>
<p>The role of the third party libraries and their use is often forgotten and neglected when considering code and system quality. This is quite unfortunate as this is the part of the code that you might not be able to patch easily, and is harder to maintain compared to your own codebase. Here are some simple questions that might help with getting a better grip on third-party libraries:</p>

<ul>
  <li>Do you keep track of your third-party libraries?</li>
  <li>Do you regularly check if there are known issues or vulnerabilities in them?</li>
  <li>Do you have a plan for keeping them updated?</li>
  <li>Are the libraries you are using being actively maintained by the authors?</li>
  <li>Are the libraries you are using compatible with each other?</li>
  <li>Do the libraries you are using have appropriate licenses that are compatible with your system? <em>(This also applies to the open source software licenses.)</em></li>
</ul>

<p>Issues and vulnerabilities are being found and patched all the time. As an example for this, let me point to Google&#8217;s <a href="https://github.com/google/oss-fuzz">OSS-Fuzz Project</a> that has found <a href="https://testing.googleblog.com/2017/05/oss-fuzz-five-months-later-and.html">numerous security vulnerabilities</a> in several critical open source projects. Unfortunately, even though many people are aware of the security issues in software in general, the library updates still often tend to be forgotten.</p>

<p>It is also worth noting that while most of the issues on my list above are security related, the last one might be of a legal sort, and probably is the most neglected of the issues listed.</p>

<h4 id="the-architecture">The Architecture</h4>

<p>I am often being asked to assess a system and tell something about its architecture compared to more modern systems. The different aspects of the system&#8217;s architecture will tell a lot about its maintainability both when it comes to further development, bug fixing, and keeping the system running. Some questions that might help with determining the state of the system would be:</p>

<ul>
  <li>Does your architecture support automated deployment?</li>
  <li>Does your architecture support continuous deploy and delivery?</li>
  <li>Does your architecture support load balancing?</li>
  <li>Does your architecture support microservices?</li>
  <li>How is the architecture implemented in the code?</li>
</ul>

<h4 id="tools-for-maintaining-the-code-quality">Tools for Maintaining the Code Quality</h4>

<p>Some of this might sound familiar to you when you think of one or several systems you had been working with and you might now be wondering what you can do to improve the code quality? Further steps here would be starting to use proper tools that will be able to tell more about the various aspects of your code. Some of them can be used as plugins to your build system (like Maven), and some could be stand-alone tools.</p>

<p>Stand-alone tools for code analysis:</p>
<ul>
  <li><a href="https://www.sonarqube.org/">SonarQube</a></li>
  <li><a href="https://pmd.github.io/">PMD</a></li>
  <li><a href="http://findbugs.sourceforge.net/">FindBugs</a></li>
</ul>

<p>Maven plugins to consider (more about plugins in my <a href="/five-pillars-of-a-good-maven-project/">previous post</a>):</p>
<ul>
  <li>Assembly</li>
  <li>Versions</li>
  <li>Dependency</li>
  <li>Enforcer</li>
  <li>Surefire</li>
  <li>Failsafe</li>
  <li>Sonar</li>
  <li>Findbugs</li>
  <li>pmd</li>
</ul>

<p><em><strong>Bonus:</strong></em> See this post on <a href="/cmd-tools-for-developers/">command line tools for Java projects</a>.</p>

<hr />

<h3 id="2-development-tools-and-strategies">2. Development Tools and Strategies</h3>

<p>Now, let&#8217;s talk about the development tools. All that fancy code and great architecture will not bring you any closer to a developer&#8217;s paradise if there will not be some proper tools to support the development. The code should live in a proper version control system that supports collaboration and things like branching and tagging. There should also be tools that help you with code quality analysis, static code analysis, etc. A good starting point here would be to start with answering the following about the project in question:</p>

<ul>
  <li>Do you use a proper code versioning tool &#8211; Git, or even SVN?</li>
  <li>Do you have a branching (and tagging) strategy?</li>
  <li>Do you have a way of measuring code complexity?</li>
  <li>Do you have a way of measuring test coverage and results?</li>
  <li>Do you run static code analysis?</li>
</ul>

<p>Some tools that can help you here (again, for Java-based systems):</p>

<ul>
  <li><strong>IDEs and IDE plug-ins</strong> that can do checks at commits, integrate with test and QA tools, etc.</li>
  <li><strong>Build tools:</strong> Maven, Gradle, etc.</li>
  <li><strong>Continuous integration tools:</strong> Jenkins, TeamCity, Bamboo, etc.</li>
  <li><strong>Frameworks and tools for testing</strong>: to run unit tests, integration tests, UI tests, and end-to-end tests.</li>
</ul>

<p>There are some further strategies and questions to consider:</p>

<ul>
  <li>Are your environments easy to reproduce with minimal efforts &#8211; can you rebuild it by simply running a script?</li>
  <li>Do you have a proper pipeline from <em>packaging</em>, to <em>delivery</em>, to <em>deploy</em>?</li>
  <li>To what environments can you deploy automatically? With the same script, or command?</li>
  <li>Are your environments (like <em>development</em>, <em>testing</em>, <em>staging</em>, <em>pre-prod</em>, <em>production</em>) similar to each other?</li>
  <li>Do you follow the same process to deploy to each environment?</li>
  <li>Are <em>QA</em> and <em>production</em> running on physically separate hardware?</li>
  <li>Are you monitoring all of the environments? (i.e. are you able to see errors before they make it to <em>QA</em> or even <em>production</em>?)</li>
</ul>

<hr />

<h3 id="3-documentation-and-collaboration-tools">3. Documentation and Collaboration Tools</h3>

<p>Last, but not least, we will need to talk about the tools for collaboration and documentation. Without these tools, we will be back to the way things were several decades ago &#8211; with documents on shared network drives and other horrors of the 90&#8217;s that I mentioned at the beginning of this post. However, good wikis, other collaboration tools, and proper issue tracking will bring your software to another level, encouraging continuous improvement of the system.</p>

<ul>
  <li>Wiki</li>
  <li>Collaboration &#8211; chat, etc.</li>
  <li>Issue tracking tools</li>
</ul>

<p>No matter how obvious it might seem, it is still important to note that one should avoid multiple documentation and issue tracking systems. Unfortunately, even though it might sound obvious, it is more common than you think &#8211; I have seen my share of systems for documentation and issue tracking resulting in fragmented information and confusion.</p>

<h2 id="conclusion">Conclusion</h2>

<p>There are several challenges connected with having and maintaining the good code quality. The first challenge is that a good code quality is not something you can achieve overnight. It takes time and energy to achieve that and it is a continuous process. You will need some tools, techniques, and methodology to prevail, and it will probably be easier to introduce all that from the beginning of a project.</p>

<p>The second challenge would be that it might be hard to convince the stakeholders of the project to invest time and resources into something that does not bring any visible improvements to the table &#8211; things like new features and bug fixes are more likely to get prioritized over something that cannot be easily measured.</p>

<p>Actually, while presenting on this topic at JavaOne 2017 in San Francisco, several of the attendees asked me about the ways of getting to a beautiful nightmare-free code and infrastructure, and the ways of convincing the stakeholders that this is the way to go. Unfortunately, there is no one simple solution to this, and the most valuable thing, in this case, would be to show the real value of the good quality code.</p>

<p>The measurements parameters to show the value can be:</p>

<ul>
  <li>time it takes from the code is written to deploy,</li>
  <li>system stability,</li>
  <li>how often bugs are reported compared to earlier, or</li>
  <li>frequency of errors in logs.</li>
</ul>

<p>So, what can you do as a developer on a project that might need some help, you might ask? You can just start by continuously suggesting improvements and showing their value to the customer, or the project manager. Now you just need to keep going and gradually improving the system, one small bit at a time.</p>

<hr />]]></content><author><name>Rustam Mehmandarov</name></author><summary type="html">Common pitfalls in software development and practical suggestions on how to fix them.</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://mehmandarov.com/assets/images/posts-images/mindthegap.png"/><category term="blog"/><category term="java"/><category term="field notes"/><category term="software development"/><category term="english"/></entry><entry><title type="html">Start Docker Containers Automatically</title><link href="https://mehmandarov.com/start-docker-containers-automatically/" rel="alternate" type="text/html" title="Start Docker Containers Automatically"/><published>2017-07-09T10:50:00+02:00</published><updated>2017-07-09T10:50:00+02:00</updated><id>https://mehmandarov.com/start-docker-containers-automatically</id><content type="html" xml:base="https://mehmandarov.com/start-docker-containers-automatically/"><![CDATA[<p><em>Starting your Docker containers automatically using <code class="language-plaintext highlighter-rouge">systemd</code>.</em></p>

<ul>
  <li><a href="#introduction">Introduction</a></li>
  <li><a href="#create-the-service-file">Create the Service File</a></li>
  <li><a href="#activate-the-service">Activate the Service</a></li>
</ul>

<hr />

<h2 id="introduction">Introduction</h2>

<p>After your Docker containers are set up and running, you might need to be able to start some of them automatically on a reboot or a crash. There are several ways of getting this done.</p>

<p>One of them is to use <a href="https://docs.docker.com/engine/admin/start-containers-automatically/" target="_blank">restart policies</a> provided by Docker. They can be set to control whether your containers start automatically when they exit, or when Docker restarts.</p>

<p>Alternatively, you can use a process manager such as <code class="language-plaintext highlighter-rouge">upstart</code>, <code class="language-plaintext highlighter-rouge">systemd</code>, or <code class="language-plaintext highlighter-rouge">supervisor</code> instead. In this post, I want to show you how it is done with <a href="https://freedesktop.org/wiki/Software/systemd/" target="_blank"><code class="language-plaintext highlighter-rouge">systemd</code></a>.</p>

<h2 id="create-the-service-file">Create the Service File</h2>

<p>To create a service file that will be used by <code class="language-plaintext highlighter-rouge">systemd</code> (<code class="language-plaintext highlighter-rouge">systemctl</code> command), we will first need to get your container name. This can be done by running the following command in your shell:</p>

<figure class="highlight"><pre><code class="language-shell_session" data-lang="shell_session"><span class="gp">$</span><span class="w"> </span>docker ps <span class="nt">-a</span></code></pre></figure>

<p>The output will look something like this. Select the right container from the list, and note its name in the last column. In this example, we will be using <code class="language-plaintext highlighter-rouge">mywiki</code> container.</p>

<figure class="highlight"><pre><code class="language-text" data-lang="text">CONTAINER ID        IMAGE                       COMMAND                  CREATED             STATUS                    PORTS                NAMES
573193cf1d5e        hypriot/rpi-busybox-httpd   "/bin/busybox http..."   2 days ago          Exited (0) 5 hours ago                         mytest
e85753d57a67        easypi/dokuwiki-arm         "/bin/sh -c 'php-f..."   1 days ago          Up 23 hours               0.0.0.0:80-&gt;80/tcp   mywiki</code></pre></figure>

<p>Now, we will need to create a file (choose an appropriate file name for the service):</p>

<figure class="highlight"><pre><code class="language-shell_session" data-lang="shell_session"><span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>nano /etc/systemd/system/docker-dokuwiki.service</code></pre></figure>

<p>Paste the following into the file. Set a proper <code class="language-plaintext highlighter-rouge">Description</code>, and make sure to update the container name in <code class="language-plaintext highlighter-rouge">ExecStart</code> and <code class="language-plaintext highlighter-rouge">ExecStop</code>:</p>

<figure class="highlight"><pre><code class="language-yml" data-lang="yml"><span class="pi">[</span><span class="nv">Unit</span><span class="pi">]</span>
<span class="s">Description=DokuWiki Container</span>
<span class="s">Requires=docker.service</span>
<span class="s">After=docker.service</span>

<span class="pi">[</span><span class="nv">Service</span><span class="pi">]</span>
<span class="s">Restart=always</span>
<span class="s">ExecStart=/usr/bin/docker start -a mywiki</span>
<span class="s">ExecStop=/usr/bin/docker stop -t 2 mywiki</span>

<span class="pi">[</span><span class="nv">Install</span><span class="pi">]</span>
<span class="s">WantedBy=local.target</span></code></pre></figure>

<p>A couple of notes about the script above:</p>
<ol>
  <li>This file is called a <a href="https://www.freedesktop.org/software/systemd/man/systemd.unit.html" target="_blank">unit file</a> for <code class="language-plaintext highlighter-rouge">systemd</code>.</li>
  <li>Make sure you don&#8217;t have any extra line brakes within the sections, like <code class="language-plaintext highlighter-rouge">Unit</code>, or <code class="language-plaintext highlighter-rouge">Service</code>.</li>
  <li>The <code class="language-plaintext highlighter-rouge">-a</code> option in the Docker command for <code class="language-plaintext highlighter-rouge">ExecStart</code> makes sure it is running in attached mode, i.e., attaching STDOUT/STDERR and forwarding signals.</li>
  <li>The <code class="language-plaintext highlighter-rouge">-t</code> option in the Docker command for <code class="language-plaintext highlighter-rouge">ExecStop</code> specifies seconds to wait for it to stop before killing the container.</li>
</ol>

<h2 id="activate-the-service">Activate the Service</h2>

<p>Before we can activate the service we have created, we need to reload the unit file. You will also need to run this command anytime you do any modifications to the unit files:</p>

<figure class="highlight"><pre><code class="language-shell_session" data-lang="shell_session"><span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>systemctl daemon-reload</code></pre></figure>

<p>To activate the service run the following commands (<em>remember to change the service name</em>):</p>

<figure class="highlight"><pre><code class="language-shell_session" data-lang="shell_session"><span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>systemctl start docker-dokuwiki.service
<span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>systemctl <span class="nb">enable </span>docker-dokuwiki.service</code></pre></figure>

<p>To disable the service run the following commands (<em>remember to change the service name</em>):</p>

<figure class="highlight"><pre><code class="language-shell_session" data-lang="shell_session"><span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>systemctl stop docker-dokuwiki.service
<span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>systemctl disable docker-dokuwiki.service</code></pre></figure>

<p>Changes will come to effect on a reboot:</p>

<figure class="highlight"><pre><code class="language-shell_session" data-lang="shell_session"><span class="gp">$</span><span class="w"> </span><span class="nb">sudo </span>reboot</code></pre></figure>

<p>Now you should have a container that will start on a server reboot, Docker restart, or a crash. <em>Congratulations!</em></p>

<p>As a next step, you might want to look at (external documentation links):</p>

<ul>
  <li>Adding some more parameters to the <a href="https://www.freedesktop.org/software/systemd/man/systemd.unit.html" target="_blank">unit file</a>.</li>
  <li>Available <a href="https://docs.docker.com/engine/reference/commandline/start/" target="_blank"><code class="language-plaintext highlighter-rouge">docker start</code></a> options.</li>
  <li>Available <a href="https://docs.docker.com/engine/reference/commandline/start/" target="_blank"><code class="language-plaintext highlighter-rouge">docker start</code></a> options.</li>
</ul>

<hr />]]></content><author><name>Rustam Mehmandarov</name></author><summary type="html">Starting your Docker containers automatically using systemd.</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://mehmandarov.com/assets/images/posts-images/whale_small.jpeg"/><category term="blog"/><category term="java"/><category term="docker"/><category term="field notes"/><category term="english"/></entry><entry><title type="html">Command Line Tools for Your Java Projects</title><link href="https://mehmandarov.com/cmd-tools-for-developers/" rel="alternate" type="text/html" title="Command Line Tools for Your Java Projects"/><published>2017-05-15T20:46:00+02:00</published><updated>2017-05-15T20:46:00+02:00</updated><id>https://mehmandarov.com/cmd-tools-for-developers</id><content type="html" xml:base="https://mehmandarov.com/cmd-tools-for-developers/"><![CDATA[<p><em>Getting an overview of your project with some simple command line tools.</em></p>

<ul>
  <li><a href="#introduction">Introduction</a></li>
  <li><a href="#directory-structure">Directory Structure</a></li>
  <li><a href="#code-metrics">Code Metrics</a></li>
  <li><a href="#encoding-and-mime-types">Encoding and MIME types</a></li>
  <li><a href="#dependencies">Dependencies</a></li>
  <li><a href="#sonarqube">SonarQube</a></li>
</ul>

<hr />

<h2 id="introduction">Introduction</h2>
<p>This post will give you an overview of some command line tools that will be able to help you to get the feeling on how your project is doing. Most of the tools are widely available in the main Linux distributions and MacOS (some of them might need installation of <a href="https://brew.sh/" target="_blank">Homebrew</a> for Mac). On Windows it can be also made available via <a href="http://www.cygwin.com/" target="_blank">Cygwin</a>, or <a href="https://msdn.microsoft.com/en-us/commandline/wsl/about" target="_blank">Bash on Windows</a>.</p>

<p>The commands below have been run and tested on a MacOS machine, and might sometimes need some slight modifications to be run on a Linux or a Windows machine. However, it should be able to give an idea of what it is possible to do with these tools. I will also be linking to the documentation for each of the programs in the post.</p>

<hr />

<h2 id="directory-structure">Directory Structure</h2>
<p>Let&#8217;s start with something simple. Sometimes all you want to see is the contents and structure of the project without leaving the command line. The <code class="language-plaintext highlighter-rouge">tree</code> <a href="http://mama.indstate.edu/users/ice/tree/" target="_blank">command</a> might be able to help you out here.</p>

<p>It is highly customizable, takes lots of parameters, and is widely available for an installation via most of the package mangers. Command Prompt on Windows also contains a native alternative with the same name.</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nv">$ </span>tree sourcecodefolder/ <span class="nt">-L</span> 1 <span class="nt">-d</span>
sourcecodefolder
&#9500;&#9472;&#9472; src
&#9500;&#9472;&#9472; tests
&#9500;&#9472;&#9472; sql
&#9492;&#9472;&#9472; docs</code></pre></figure>

<h2 id="code-metrics">Code Metrics</h2>
<p>If you want to see some metrics about the code in your project, like what languages that are used in the project, as well as information about number files, blank lines, comments, and lines of code, you might want to try the <code class="language-plaintext highlighter-rouge">cloc</code> <a href="https://github.com/AlDanial/cloc" target="_blank">command</a> (it stands for <em>Count Lines of Code</em>).</p>

<p>Simply install the program and point it at the project directory, or a zip file:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nv">$ </span>cloc sourcecodefolder/</code></pre></figure>

<p>It will give you a result that might look something like this:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nt">-------------------------------------------------------------------------------</span>
Language                     files          blank        comment           code
<span class="nt">-------------------------------------------------------------------------------</span>
Java                            33           1226           1026           3017
Python                           4            327            337            888
Markdown                         1             11              0             28
SQL                             10             10             12            212
<span class="nt">-------------------------------------------------------------------------------</span>
SUM:                            48           1574           1375           4145
<span class="nt">-------------------------------------------------------------------------------</span></code></pre></figure>

<p>Also, it is possible to show all the information by percent:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nv">$ </span>cloc <span class="nt">--by-percent</span> cmb sourcecode.zip</code></pre></figure>

<h2 id="encoding-and-mime-types">Encoding and MIME types</h2>

<p>Files, within a single project, with different, or wrong, encoding might mean trouble with showing non-ASCII characters correctly. They might even give you compilation errors. Therefore, finding and marking those files as quickly as possible might help you manage your project.</p>

<p>While MIME types, on the other hand, are not as bad at causing trouble, the diversity of the MIME types among the same kind of files, like <code class="language-plaintext highlighter-rouge">*.java</code> files in this example, might indicate a lack of a standard for developer tools and code standard in the project.</p>

<p>This kind of information can be extracted with <code class="language-plaintext highlighter-rouge">file</code> command for each file, or it might be done a bit more automatic for the whole project, and it might look like this:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nv">$ </span>find <span class="nb">.</span> <span class="nt">-name</span> <span class="k">*</span>.java | <span class="se">\</span>
    xargs file <span class="nt">-I</span> <span class="nv">$1</span> | <span class="se">\ </span>
    gawk <span class="s1">'match($0, /.* (.*); charset=(.*)$/, gr) {print gr[2]}'</span> | <span class="se">\</span>
    <span class="nb">sort</span> | <span class="nb">uniq</span> <span class="nt">-c</span></code></pre></figure>

<p>A short explanation for the script:</p>

<ol>
  <li>find all java files recursively (<code class="language-plaintext highlighter-rouge">find</code> command)</li>
  <li>process them with the <code class="language-plaintext highlighter-rouge">file</code> command</li>
  <li>grab the output and extract data with regex (<code class="language-plaintext highlighter-rouge">gawk</code>)</li>
  <li>sort, extract unique values and count (<code class="language-plaintext highlighter-rouge">sort</code>, <code class="language-plaintext highlighter-rouge">uniq</code>)</li>
</ol>

<p>The result will look something like this:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"> 257 iso-8859-1
 117 unknown-8bit
 678 us-ascii</code></pre></figure>

<p>If you want to drill down a bit further and search for both MIME types and encoding, showing the distribution of encoding per MIME type, you can also extract that from the information supplied by the <code class="language-plaintext highlighter-rouge">file</code> command like this:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nv">$ </span>find <span class="nb">.</span> <span class="nt">-name</span> <span class="k">*</span>.java | <span class="se">\ </span>
    xargs file <span class="nt">-I</span> <span class="nv">$1</span> | <span class="se">\</span>
    gawk <span class="s1">'match($0, /.* (.*); charset=(.*)$/, gr) \
    {print gr[1] " --- " gr[2]}'</span> | <span class="se">\</span>
    <span class="nb">sort</span> | <span class="nb">uniq</span> <span class="nt">-c</span></code></pre></figure>

<p>A short explanation for the script is almost the same as above. The only difference is that we use information from both of the regex groups (<em>gr[1]</em>, and <em>gr[2]</em>). The result will look something like this:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">  15 text/html <span class="nt">---</span> iso-8859-1
  34 text/html <span class="nt">---</span> us-ascii
 134 text/plain <span class="nt">---</span> iso-8859-1
  16 text/plain <span class="nt">---</span> unknown-8bit
   1 text/plain <span class="nt">---</span> us-ascii
   1 text/x-c <span class="nt">---</span> iso-8859-1
   8 text/x-c <span class="nt">---</span> us-ascii
   5 text/x-c++ <span class="nt">---</span> iso-8859-1
   6 text/x-c++ <span class="nt">---</span> us-ascii</code></pre></figure>

<h2 id="dependencies">Dependencies</h2>
<p>Now, over to a bit more advanced stuff &#8211; analyzing dependencies in your project. Why would you want to do that? Well, in short: dependencies increase complexity, and cyclic dependencies are bad for your project and your health. They also hurt your modularity and complicate the build process.</p>

<p>This kind of analysis can be done with <a href="https://github.com/clarkware/jdepend" target="_blank">jdepend</a>. It is easy to run and can be run both separately, and as a part of a build tool, like <a href="http://www.mojohaus.org/jdepend-maven-plugin/" target="_blank">Maven</a>.</p>

<p>For some basic dependency analysis you can also use the command line, and do something like this:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nv">$ </span>find some_module/ <span class="nt">-name</span> <span class="k">*</span>.java | <span class="se">\</span>
    xargs <span class="nb">cat</span> <span class="nv">$1</span> | <span class="se">\</span>
    gawk <span class="s1">'match($0, /import (no.*);/, gr) {print gr[1]}'</span> | <span class="se">\</span>
    <span class="nb">sort</span> | <span class="nb">uniq</span>  | <span class="se">\</span>
    <span class="nb">grep</span> <span class="nt">-v</span> no.ignore.this.namespace <span class="c"># -v option add strings to ignore</span></code></pre></figure>

<p>A short explanation for the script:</p>

<ol>
  <li>find all java files recursively (<code class="language-plaintext highlighter-rouge">find</code> command)</li>
  <li>print them to console with the <code class="language-plaintext highlighter-rouge">cat</code> command</li>
  <li>grab the output and extract import statements with some specific pattern with regex (<code class="language-plaintext highlighter-rouge">gawk</code>)</li>
  <li>sort, extract unique values (<code class="language-plaintext highlighter-rouge">sort</code>, <code class="language-plaintext highlighter-rouge">uniq</code>)</li>
  <li>add some namespaces to ignore some strings (<code class="language-plaintext highlighter-rouge">grep</code> with a <code class="language-plaintext highlighter-rouge">-v</code> option)</li>
</ol>

<h2 id="sonarqube">SonarQube</h2>
<p>Last but not least, you might want to load your code for further analysis to <a href="https://www.sonarqube.org/" target="_blank">SonarQube</a>. This is an extremely powerful and free tool for doing the static analysis of your code. Normally, you would do that via a plug-in in your continuous integration (CI) software, like <a href="https://jenkins.io/" target="_blank">Jenkins</a>. However, there might be some cases when you might want to load this data manually, via a command-line.</p>

<p>To load the code to SonarQube you will first need to add a property file in the root directory of each module. It might look like this:</p>

<figure class="highlight"><pre><code class="language-text" data-lang="text"># Contents of sonar-project.properties file:
sonar.projectKey=my:SomeFancyProject
sonar.projectName=My SomeFancyProject
sonar.projectVersion=1.0
sonar.sources=.
sonar.sourceEncoding=ISO-8859-1</code></pre></figure>

<p>Then you will need to install and run <a href="https://docs.sonarqube.org/display/SCAN/Analyzing+with+SonarQube+Scanner" target="_blank">SonarQube Scanner</a> from each module directory that contains <code class="language-plaintext highlighter-rouge">sonar-project.properties</code> file:</p>

<figure class="highlight"><pre><code class="language-bash" data-lang="bash">sonar-scanner</code></pre></figure>

<p>As a <strong><em>bonus</em></strong> feature, I might also suggest that if you don&#8217;t have time setting up SonarQube on a separate machine, but want  to take a quick peek on how your project is doing, you can download and boot it up as a <a href="https://store.docker.com/images/sonarqube" target="_blank">Docker image</a> in no time, and later decide whether you want to create a dedicated machine for running SonarQube, or keep it as it is. Just remember that the database the SonarQube image uses out of the box should not be used for anything other than testing.</p>

<hr />]]></content><author><name>Rustam Mehmandarov</name></author><summary type="html">Getting an overview of your project with simple command-line tools.</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://mehmandarov.com/assets/images/posts-images/graph.jpg"/><category term="blog"/><category term="java"/><category term="software development"/><category term="english"/></entry><entry><title type="html">Five Pillars of a Good Maven Project</title><link href="https://mehmandarov.com/five-pillars-of-a-good-maven-project/" rel="alternate" type="text/html" title="Five Pillars of a Good Maven Project"/><published>2016-07-23T08:26:00+02:00</published><updated>2016-07-23T08:26:00+02:00</updated><id>https://mehmandarov.com/five-pillars-of-a-good-maven-project</id><content type="html" xml:base="https://mehmandarov.com/five-pillars-of-a-good-maven-project/"><![CDATA[<p><em>What makes a Maven project good to work with and easy to maintain? There are five types of Maven plugins that will simplify the development process and increase maintainability of a project.</em></p>

<ul>
  <li><a href="#1-technical-aspects">1. Technical Aspects</a></li>
  <li><a href="#2-legal-aspects">2. Legal Aspects</a></li>
  <li><a href="#3-rapid-development">3. Rapid Development</a></li>
  <li><a href="#4-documentation">4. Documentation</a></li>
  <li><a href="#5-testing-and-qa">5. Testing and QA</a></li>
  <li><a href="#bonus-video">Bonus: Video</a></li>
</ul>

<hr />

<p><a href="https://maven.apache.org/">Apache Maven</a> is a build automation tool used primarily for Java projects. It has been around for a while, and it does not seem to be going anywhere anytime soon (whether some of you like it or not). Recently, it has been confirmed yet again, this time in ZeroTurnaround&#8217;s <a href="http://zeroturnaround.com/rebellabs/java-tools-and-technologies-landscape-2016-trends/">Java Tools and Technologies Landscape Report 2016</a> (see the <em>Build Tools</em> section).</p>

<p>The good thing about Maven is that you can do almost anything with it and its plugins. With such a great ecosystem of plugins, able to do nearly anything, one might wonder where to begin when setting up a new Maven project or improving your old one.</p>

<p>I usually like to think of five main categories &#8211; or pillars &#8211; that we will be looking into in this post. Each category will have a set of example plugins that are meant to serve merely as a starting point.</p>

<p>In this post, I will assume that you have some experience with build tools in general and Maven in particular.</p>

<hr />

<h2 id="1-technical-aspects">1. Technical Aspects</h2>

<p>First of all, you would like to make sure that all the technical stuff is in place. You might want to automate the packaging, the checks if the project is running the latest version of all artifacts, that all the dependencies are met, and that the unused dependencies are removed. You might even want to define your own rules for all the things that cause troubles, or just simply annoy you down the line, making the build fail if they are not met.</p>

<p>With all that automation in place, you will be getting predictable results and nice packaging from the first day of the project.</p>

<p>Some of the plugins that should be mentioned here:</p>

<ul>
  <li><strong><a href="http://www.mojohaus.org/versions-maven-plugin/">Versions</a> plugin</strong> does the versions management of artifacts in a project&#8217;s POM file</li>
  <li><strong><a href="http://maven.apache.org/plugins/maven-dependency-plugin/">Dependency</a> plugin</strong> helps you analyzing dependencies, building dependency trees, showing unused dependencies, etc</li>
  <li><strong><a href="http://maven.apache.org/plugins/maven-assembly-plugin/">Assembly</a> plugin</strong> helps you packaging all the dependencies, modules, site documentation, and other files into a single distributable archive</li>
  <li><strong><a href="http://maven.apache.org/enforcer/maven-enforcer-plugin/">Enforcer</a> plugin</strong> lets you make your own rules! You can set up your build to break if some of your requirements are not met</li>
</ul>

<hr />

<h2 id="2-legal-aspects">2. Legal Aspects</h2>

<p>With all the technical stuff out of the way, we might want to make sure that the legal side is taken care of as well.</p>

<p>Yes, I know, it might be less fun thinking about licenses than writing code, but it is still something that has to be done. You still have to release your code under some kind of license, and you will have to make sure that the third-party licenses do not violate your own licensing. So, why not leave that job to a plugin?</p>

<p>The following plugin will manage the license of a maven project and its dependencies; it will also update file headers, download dependency licenses, check third-party licenses, etc.</p>

<ul>
  <li><strong><a href="http://www.mojohaus.org/license-maven-plugin/">License</a> plugin</strong></li>
</ul>

<hr />

<h2 id="3-rapid-development">3. Rapid Development</h2>

<p>Now, back to coding. Or even better &#8211; to seeing the results of your hard work. The chances are that you will need some kind of web or application server for running your code, and you want to able to deploy to that server in no time. Another kind of plugins that will be helping you from the very first day of the project.</p>

<p>Some of the plugins that can be mentioned here:</p>

<ul>
  <li><strong><a href="http://tomcat.apache.org/maven-plugin.html">Apache Tomcat</a> plugin</strong></li>
  <li><strong><a href="https://mvnrepository.com/artifact/org.eclipse.jetty/jetty-maven-plugin">Jetty</a> plugin</strong></li>
  <li><strong><a href="https://docs.jboss.org/wildfly/plugins/maven/latest/">WildFly</a> plugin</strong></li>
  <li><em>&#8230;or any other deploy plugin, depending on your application</em></li>
</ul>

<hr />

<h2 id="4-documentation">4. Documentation</h2>

<p>Every decent project must also be properly documented. However, this is something that developers might postpone until the end. Well, no more! This kind of plugins will help you to get started early and will help you to produce some beautiful (<em>maybe?</em>) and maintainable docs.</p>

<p>You might even consider coupling these with some rules in the Enforcer plugin, but tread carefully as too many, and too strict rules can, and usually do, backfire.</p>

<ul>
  <li><strong><a href="https://maven.apache.org/plugins/maven-site-plugin/">Site</a> plugin</strong></li>
  <li><strong><a href="http://asciidoctor.org/docs/asciidoctor-maven-plugin/">Asciidoctor</a> plugin</strong></li>
</ul>

<hr />

<h2 id="5-testing-and-qa">5. Testing and QA</h2>

<p>By now, your code should be looking great, with all the right licenses, and up and running in no time. So, how about squashing some [virtual] bugs? The list below might help you setting up a proper QA environment and fixing bugs before the come crawling to your production servers.</p>

<ul>
  <li><strong><a href="http://maven.apache.org/surefire/maven-surefire-plugin/">Surefire</a> plugin</strong></li>
  <li><strong><a href="http://maven.apache.org/surefire/maven-failsafe-plugin/">Failsafe</a> plugin</strong></li>
  <li><strong><a href="http://www.mojohaus.org/sonar-maven-plugin/project-info.html">SonarQube</a> plugin</strong></li>
  <li><strong><a href="http://gleclaire.github.io/findbugs-maven-plugin/">FindBugs</a> plugin</strong></li>
  <li><strong><a href="https://maven.apache.org/plugins/maven-pmd-plugin/">PMD</a> plugin</strong></li>
</ul>

<hr />

<h2 id="bonus-video">Bonus: Video</h2>

<p>A video of a talk I gave about this topic at <a href="http://2015.javazone.no/details.html?talk=86734cc36c24b081d399454534248f3aad7062ce30de5aea27de84f80a476269">JavaZone</a> in Oslo (in Norwegian).</p>

<iframe src="https://player.vimeo.com/video/138955650?byline=0&amp;portrait=0" width="640" height="360" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen=""></iframe>

<hr />]]></content><author><name>Rustam Mehmandarov</name></author><summary type="html">The five main types of Maven plugins that will simplify the development process and increase maintainability of a project.</summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://mehmandarov.com/assets/images/posts-images/desk-pencils_1200x800.jpg"/><category term="blog"/><category term="field notes"/><category term="maven"/><category term="software development"/><category term="build and deploy"/><category term="automation"/><category term="java"/><category term="english"/></entry><entry><title type="html">Solving Problems with Reasoning, Semantic Wizardry, and Java</title><link href="https://mehmandarov.com/reasoning-and-semantic-wizardry/" rel="alternate" type="text/html" title="Solving Problems with Reasoning, Semantic Wizardry, and Java"/><published>2016-06-09T00:00:00+02:00</published><updated>2016-06-09T00:00:00+02:00</updated><id>https://mehmandarov.com/reasoning-and-semantic-wizardry</id><content type="html" xml:base="https://mehmandarov.com/reasoning-and-semantic-wizardry/"><![CDATA[<p><em><strong>Update 2016-10-21</strong>: In addition to Barcelona, I also did this workshop for javaBin S&#248;rlandet, javaBin Trondheim, and javaBin Oslo (in cooperation with Semantic Meetup in Oslo) this autumn.</em></p>

<hr />

<p><em>On June 16th, I will be doing a <a href="http://www.jbcnconf.com/2016/infoSpeaker.html?ref=rmehmandarov">workshop</a> at JBCNConf in Barcelona, Spain. I will be talking about semantic technologies, reasoning, and Java. I have been asked to post some information about the workshop, so here it comes.</em></p>

<ul>
  <li><a href="#what-is-it-all-about">What is it all about?</a></li>
  <li><a href="#contents">Contents</a></li>
  <li><a href="#workshop-requirements">Workshop requirements</a></li>
</ul>

<hr />

<h2 id="what-is-it-all-about">What is it all about?</h2>

<p>Ever heard of Zebra Puzzles? Those logical puzzles that are claimed to be invented by Albert Einstein as a little boy? Those that are based on simple logical facts and go something like this:</p>

<blockquote>
  <p><em>&#8220;The Brit lives in the Red house. The Swede keeps dogs as pets. The Dane drinks tea&#8230; Who owns the zebra?&#8221;</em></p>
</blockquote>

<p>Some claim that only 2% of the population can solve it without any help.</p>

<p>However, with the help of semantic technologies, we can solve it in (almost) no time. Of course, you have to know RDF, OWL, Jena, reasoning, inference. The good news is that I will be showing you how it works in this session.</p>

<p>Later, I will also post a link to the code for the rest of you to try all that at home.</p>

<hr />

<h2 id="contents">Contents</h2>

<p>We will start with introducing the puzzle. Then we will continue by looking at the toolbox for solving it. We will build a semantic representation of the puzzle (basically, a graph!), programmatically add some inferred facts and reason and solve the puzzle.</p>

<p>Suddenly solving puzzles is a piece of cake for the other 98%.</p>

<hr />

<h2 id="workshop-requirements">Workshop requirements</h2>

<p>Now, over to what you will need:</p>

<ul>
  <li>Your super computer</li>
  <li>Java 7, or later</li>
  <li>Git</li>
  <li>IDE of your choice</li>
  <li><a href="https://maven.apache.org/">Maven 3.x</a></li>
</ul>

<p>Looking forward to running this workshop next week! See you there!</p>

<p><em>p.s. Want to read more about Zebra Puzzles? <a href="https://en.wikipedia.org/wiki/Zebra_Puzzle">Go ahead</a>, but beware of some potential spoilers!</em></p>

<hr />]]></content><author><name>Rustam Mehmandarov</name></author><summary type="html">On June 16th, I will be doing a workshop at JBCNConf in Barcelona, Spain. I will be talking about semantic technologies, reasoning, and Java. I have been asked to post some information about the workshop, so here it comes.</summary><category term="blog"/><category term="workshop"/><category term="conferences"/><category term="semantic technologies"/><category term="java"/><category term="english"/></entry></feed>
