<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>blog:dashorst</title>
    <subtitle>A blog written and maintained by Martijn Dashorst</subtitle>
    <link rel="alternate" type="text/html" href="https://martijndashorst.com" />
    <link rel="self" type="application/atom+xml" href="https://martijndashorst.com/feed.xml" />
    <id>https://martijndashorst.com/feed.xml</id>
    <updated>2025-07-15T22:36:25Z</updated>
    <rights>Copyright © 2025, Martijn Dashorst</rights>
    
    <entry>
        <id>tag:martijndashorst.com,2025-05-28:/blog/2025/05/28/quarkus-wicket</id>
        <title>A new Quarkus extension: Wicket</title>
        <summary type="html"><![CDATA[<p>As you might expect from one of the earliest contributors to Apache Wicket, it is hard to let go of such a great product (especially if you work every day with it).</p>]]></summary>
        <published>2025-05-28T00:00:00Z</published>
        <updated>2025-05-28T00:00:00Z</updated>
        <author>
            <name>Martijn Dashorst</name>
            <uri>https://martijndashorst.com</uri>
        </author>
        <link rel="alternate" type="text/html" href="https://martijndashorst.com/blog/2025/05/28/quarkus-wicket"/>
        <content type="html" xml:base="https://martijndashorst.com" xml:lang="en"><![CDATA[
<p>As you might expect from one of the earliest contributors to Apache Wicket, it is hard to let go of such a great product (especially if you work every day with it).</p>

<p>And if you also enjoy working with <a href="https://quarkus.io">Quarkus</a>, it is only logical that you want to combine the two of them. So I did.</p>

<p>I’ve crafted an extension for Quarkus for Wicket. 
This enables injection of CDI beans into your Wicket components, behaviors and sessions. 
It also configures Wicket based on the Quarkus profile (prod, dev, …).</p>

<h2 id="getting-started-with-the-extension">Getting started with the extension</h2>

<p>As the extension is as of yet not officially released, you have to <code class="language-plaintext highlighter-rouge">mvn install</code> it into your local repository after checking out the source.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gh repo clone dashorst/quarkus-wicket <span class="o">&amp;&amp;</span> <span class="nb">cd </span>quarkus-wicket <span class="o">&amp;&amp;</span> mvn <span class="nb">install
cd</span> ..
mvn io.quarkus.platform:quarkus-maven-plugin:3.23.0:create <span class="se">\ </span>                                                                                                                                                    ─╯
    <span class="nt">-DprojectGroupId</span><span class="o">=</span>com.martijndashorst.quarkus <span class="se">\</span>
    <span class="nt">-DprojectArtifactId</span><span class="o">=</span>wicket-getting-started <span class="se">\</span>
    <span class="nt">-Dextensions</span><span class="o">=</span><span class="s1">'io.quarkiverse.wicket:quarkus-wicket:999-SNAPSHOT,jdbc-h2,hibernate-orm-panache'</span> <span class="se">\</span>
    <span class="nt">-Dcode</span> <span class="se">\</span>
    <span class="nt">-Djava</span><span class="o">=</span>21
<span class="nb">cd </span>wicket-getting-started
</code></pre></div></div>

<p>This generates a project with the following structure:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pom.xml
src/main/java/com/martijndashorst/quarkus/
    MyApplication.java
    MyEntity.java
    MyPage.java
src/main/resources/
     application.properties
     import.sql
src/main/resources/META-INF/
    web.xml
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">MyApplication</code> class is the Wicket Application you use to configure Wicket and provide the <em>home page</em> to Wicket, which is the default page that gets rendered when the user hits your application.
The codestart defines that the <code class="language-plaintext highlighter-rouge">MyPage</code> class is the home page and is automatically generated for you.
The <code class="language-plaintext highlighter-rouge">MyEntity</code> class is a Panache ORM entity generated by the codestart.
The <code class="language-plaintext highlighter-rouge">web.xml</code> file defines the servlet filter that directs traffic to Wicket.
The file <code class="language-plaintext highlighter-rouge">import.sql</code> is the sql script generated by Panache to provide an initial filling for your database.</p>

<blockquote>
  <p>[!NOTE]<br />
you should uncomment the lines in the import.sql script to get an initial database filling.</p>
</blockquote>

<p>When you start the application using quarkus the following happens:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>quarkus dev
2025-05-28 21:27:04,440 INFO  <span class="o">[</span>io.qua.hib.orm.dep.dev.HibernateOrmDevServicesProcessor] <span class="o">(</span>build-13<span class="o">)</span> Setting quarkus.hibernate-orm.database.generation<span class="o">=</span>drop-and-create to initialize Dev Services managed database
<span class="k">********************************************************************</span>
<span class="k">***</span> WARNING: Wicket is running <span class="k">in </span>DEVELOPMENT mode.              <span class="k">***</span>
<span class="k">***</span>                               ^^^^^^^^^^^                    <span class="k">***</span>
<span class="k">***</span> Do NOT deploy to your live server<span class="o">(</span>s<span class="o">)</span> without changing this.  <span class="k">***</span>
<span class="k">***</span> See Application#getConfigurationType<span class="o">()</span> <span class="k">for </span>more information. <span class="k">***</span>
<span class="k">********************************************************************</span>

__  ____  __  _____   ___  __ ____  ______ 
 <span class="nt">--</span>/ __ <span class="se">\/</span> / / / _ | / _ <span class="se">\/</span> //_/ / / / __/ 
 -/ /_/ / /_/ / __ |/ , _/ ,&lt; / /_/ /<span class="se">\ \ </span>  
<span class="nt">--</span><span class="se">\_</span>__<span class="se">\_\_</span>___/_/ |_/_/|_/_/|_|<span class="se">\_</span>___/___/   
2025-05-28 21:27:04,550 INFO  <span class="o">[</span>io.qua.wic.run.arc.ArcInjector] <span class="o">(</span>Quarkus Main Thread<span class="o">)</span> ArcComponentInjector initialized

2025-05-28 21:27:04,556 INFO  <span class="o">[</span>org.apa.wic.Application] <span class="o">(</span>Quarkus Main Thread<span class="o">)</span> <span class="o">[</span>wicket.wicket-quarkus] init: Wicket core library initializer
2025-05-28 21:27:04,556 INFO  <span class="o">[</span>org.apa.wic.pro.htt.WebApplication] <span class="o">(</span>Quarkus Main Thread<span class="o">)</span> <span class="o">[</span>wicket.wicket-quarkus] Started Wicket version 10.5.0 <span class="k">in </span>DEVELOPMENT mode
2025-05-28 21:27:04,598 INFO  <span class="o">[</span>io.quarkus] <span class="o">(</span>Quarkus Main Thread<span class="o">)</span> wicket-getting-started 1.0.0-SNAPSHOT on JVM <span class="o">(</span>powered by Quarkus 3.19.4<span class="o">)</span> started <span class="k">in </span>0.300s. Listening on: http://localhost:8080
2025-05-28 21:27:04,598 INFO  <span class="o">[</span>io.quarkus] <span class="o">(</span>Quarkus Main Thread<span class="o">)</span> Profile dev activated. Live Coding activated.
2025-05-28 21:27:04,598 INFO  <span class="o">[</span>io.quarkus] <span class="o">(</span>Quarkus Main Thread<span class="o">)</span> Installed features: <span class="o">[</span>agroal, cdi, hibernate-orm, hibernate-orm-panache, jdbc-h2, narayana-jta, servlet, smallrye-context-propagation, vertx, wicket]
2025-05-28 21:27:04,599 INFO  <span class="o">[</span>io.qua.dep.dev.RuntimeUpdatesProcessor] <span class="o">(</span>vert.x-worker-thread-1<span class="o">)</span> Live reload total <span class="nb">time</span>: 0.656s 
</code></pre></div></div>
<p>And when you open the browser and go to http://localhost:8080, you get this image</p>

<p><img width="686" alt="image" src="https://github.com/user-attachments/assets/7318d2e0-265e-4bf0-bd4e-538c5e0fce58" /></p>

<h2 id="getting-data-into-and-from-the-database">Getting data into and from the database</h2>

<p>So the import script takes care of getting the first data into the database.
Now we want to show that on the page in a list, so the <code class="language-plaintext highlighter-rouge">MyPage</code> class gets the following code:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">java.util.List</span><span class="o">;</span>

<span class="kn">import</span> <span class="nn">org.apache.wicket.markup.html.WebPage</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">org.apache.wicket.markup.html.basic.Label</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">org.apache.wicket.markup.html.list.ListItem</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">org.apache.wicket.markup.html.list.ListView</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">org.apache.wicket.model.LoadableDetachableModel</span><span class="o">;</span>

<span class="kd">public</span> <span class="kd">class</span> <span class="nc">MyPage</span> <span class="kd">extends</span> <span class="nc">WebPage</span> <span class="o">{</span>
    <span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="kt">long</span> <span class="n">serialVersionUID</span> <span class="o">=</span> <span class="mi">1L</span><span class="o">;</span>

    <span class="kd">public</span> <span class="nf">MyPage</span><span class="o">()</span> <span class="o">{</span>
        <span class="n">add</span><span class="o">(</span><span class="k">new</span> <span class="nc">ListView</span><span class="o">&lt;</span><span class="nc">MyEntity</span><span class="o">&gt;(</span><span class="s">"entities"</span><span class="o">,</span> <span class="nc">LoadableDetachableModel</span><span class="o">.</span><span class="na">of</span><span class="o">(</span><span class="k">this</span><span class="o">::</span><span class="n">getEntities</span><span class="o">))</span> <span class="o">{</span>
            <span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="kt">long</span> <span class="n">serialVersionUID</span> <span class="o">=</span> <span class="mi">1L</span><span class="o">;</span>

            <span class="nd">@Override</span>
            <span class="kd">protected</span> <span class="kt">void</span> <span class="nf">populateItem</span><span class="o">(</span><span class="nc">ListItem</span><span class="o">&lt;</span><span class="nc">MyEntity</span><span class="o">&gt;</span> <span class="n">item</span><span class="o">)</span> <span class="o">{</span>
                <span class="n">item</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="k">new</span> <span class="nc">Label</span><span class="o">(</span><span class="s">"field"</span><span class="o">,</span> <span class="n">item</span><span class="o">.</span><span class="na">getModel</span><span class="o">().</span><span class="na">map</span><span class="o">(</span><span class="nl">MyEntity:</span><span class="o">:</span><span class="n">getField</span><span class="o">)));</span>
            <span class="o">}</span>
        <span class="o">});</span>
    <span class="o">}</span>

    <span class="kd">private</span> <span class="nc">List</span><span class="o">&lt;</span><span class="nc">MyEntity</span><span class="o">&gt;</span> <span class="nf">getEntities</span><span class="o">()</span> <span class="o">{</span>
        <span class="k">return</span> <span class="nc">MyEntity</span><span class="o">.</span><span class="na">listAll</span><span class="o">();</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>This creates a <code class="language-plaintext highlighter-rouge">ListView</code> and adds a <code class="language-plaintext highlighter-rouge">Label</code> component for each entity found in the database.
I had to add a getter/setter to <code class="language-plaintext highlighter-rouge">MyEntity</code> in order to bind the getter to the label.</p>

<p>This also needs some markup to go with it:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;!DOCTYPE html&gt;</span>
<span class="nt">&lt;html</span> <span class="na">xmlns:wicket=</span><span class="s">"http://wicket.apache.org"</span> <span class="na">lang=</span><span class="s">"en"</span> <span class="na">dir=</span><span class="s">"ltr"</span><span class="nt">&gt;</span>
<span class="nt">&lt;head&gt;</span>
    <span class="nt">&lt;meta</span> <span class="na">charset=</span><span class="s">"UTF-8"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;title&gt;</span>My Page<span class="nt">&lt;/title&gt;</span>
<span class="nt">&lt;/head&gt;</span>
<span class="nt">&lt;body&gt;</span>
    <span class="nt">&lt;h1&gt;</span>My Page<span class="nt">&lt;/h1&gt;</span>
    <span class="nt">&lt;ul&gt;</span>
        <span class="nt">&lt;li</span> <span class="na">wicket:id=</span><span class="s">"entities"</span><span class="nt">&gt;&lt;span</span> <span class="na">wicket:id=</span><span class="s">"field"</span><span class="nt">&gt;&lt;/span&gt;&lt;/li&gt;</span>
    <span class="nt">&lt;/ul&gt;</span>
<span class="nt">&lt;/body&gt;</span>
<span class="nt">&lt;/html&gt;</span>
</code></pre></div></div>

<p>So if you refresh the page now, this will show the 3 entities that have been added to the database using the import script as shown in the following screen shot.</p>

<p><img width="686" alt="image" src="https://github.com/user-attachments/assets/5195d1b0-0d72-480c-9289-5671e5ca5dba" /></p>

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

<p>In this article I presented you with the Quarkus Wicket extension. 
I showed how to use that to generate a Quarkus + Wicket + Hibernate + Panache application to display a list of entities on a Wicket page.</p>

<p>The Quarkus Wicket extension is a very young technology, and comes with some limitations you can read in the <a href="https://github.com/dashorst/quarkus-wicket">project’s documentation</a>.</p>

<p>Now go ahead and try Wicket and Quarkus yourself!</p>

<div>
    <a  title="Permanent link to ‘A new Quarkus extension: Wicket’"  href="https://martijndashorst.com/blog/2025/05/28/quarkus-wicket">&nbsp;&#x260D;&nbsp;</a>
</div>
	]]></content>
    </entry>
    
    <entry>
        <id>tag:martijndashorst.com,2025-05-19:/blog/2025/05/19/clean-stack-traces</id>
        <title>Clean your stack traces with one line of shell script</title>
        <summary type="html"><![CDATA[<p>One of the biggest issues with stack traces in Java web applications (Jakarta EE and/or Spring alike) is the enormous stack traces they produce when you get an error.</p>]]></summary>
        <published>2025-05-19T00:00:00Z</published>
        <updated>2025-05-19T00:00:00Z</updated>
        <author>
            <name>Martijn Dashorst</name>
            <uri>https://martijndashorst.com</uri>
        </author>
        <link rel="alternate" type="text/html" href="https://martijndashorst.com/blog/2025/05/19/clean-stack-traces"/>
        <content type="html" xml:base="https://martijndashorst.com" xml:lang="en"><![CDATA[
<p>One of the biggest issues with stack traces in Java web applications (Jakarta EE and/or Spring alike) is the enormous stack traces they produce when you get an error.</p>

<p>It is easy to just give up and start drinking. But you can make the stack traces a bit more palatable by just filtering the stack trace such that only the method calls from your own classes remain.</p>

<p>A typical stack trace in one of our applications has 3 caused by’s and counts 127 lines. 
After my trick, which keeps the ERROR line (the log level), all lines with our company’s package name and all Caused By’s, the remaining line count is 17.</p>

<p>Going from 127 lines of stack trace to just 17…</p>

<p>This simple one-liner for macOS cleans your stack trace into something readable:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pbpaste | <span class="nb">grep</span> <span class="nt">-i</span> <span class="nt">-E</span> <span class="s1">'nl.topicus.|ERROR|caused'</span> | pbcopy
</code></pre></div></div>

<p>For linux users:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>xsel <span class="nt">--clipboard</span> <span class="nt">--output</span> | <span class="nb">grep</span> <span class="nt">-i</span> <span class="nt">-E</span> <span class="s1">'nl.topicus.|ERROR|caused'</span> | xsel <span class="nt">--clipboard</span> <span class="nt">--input</span>
</code></pre></div></div>

<p>For Windows users (“it’s complicated”):</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>powershell.exe -Command "Get-Clipboard" | grep -i -E 'nl.topicus.|ERROR|caused' | clip
</code></pre></div></div>

<p>You have to substitute <code class="language-plaintext highlighter-rouge">nl.topicus.</code> with your own package name of course, but for our <a href="https://topicus.nl/onderwijs">company</a> this works really well.</p>

<div>
    <a  title="Permanent link to ‘Clean your stack traces with one line of shell script’"  href="https://martijndashorst.com/blog/2025/05/19/clean-stack-traces">&nbsp;&#x260D;&nbsp;</a>
</div>
	]]></content>
    </entry>
    
    <entry>
        <id>tag:martijndashorst.com,2025-02-04:/blog/2025/02/04/htmx-cdi</id>
        <title>CDI producer for HTMX headers (in Qute templates)</title>
        <summary type="html"><![CDATA[<p>At €€€-dayjob I’m in the fortunate position to be able to write a <a href="https://htmx.org">HTMX</a> application using<a href="https://quarkus.io">Quarkus</a> and <a href="https://quarkus.io/guides/qute">Qute</a>’s HTML templates. As such I had the need to identify if a request wasperformed regularly or through a HTMX call. With a small amount of CDI code this wasachieved without much fuzz.</p>]]></summary>
        <published>2025-02-04T00:00:00Z</published>
        <updated>2025-02-04T00:00:00Z</updated>
        <author>
            <name>Martijn Dashorst</name>
            <uri>https://martijndashorst.com</uri>
        </author>
        <link rel="alternate" type="text/html" href="https://martijndashorst.com/blog/2025/02/04/htmx-cdi"/>
        <content type="html" xml:base="https://martijndashorst.com" xml:lang="en"><![CDATA[
<p>At €€€-dayjob I’m in the fortunate position to be able to write a <a href="https://htmx.org">HTMX</a> application using
<a href="https://quarkus.io">Quarkus</a> and <a href="https://quarkus.io/guides/qute">Qute</a>’s HTML templates. As such I had the need to identify if a request was
performed regularly or through a HTMX call. With a small amount of CDI code this was
achieved without much fuzz.</p>

<p>An example of its use in a template:</p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code>{#if cdi:htmx.isHtmxRequest}
<span class="nt">&lt;small</span> <span class="na">hx-swap-oob=</span><span class="s">"outerHTML"</span> <span class="na">id=</span><span class="s">"lastUpdated"</span><span class="nt">&gt;</span>{lastUpdated}<span class="nt">&lt;/small&gt;</span>
{/if}
</code></pre></div></div>
<p>The example above will include the <code class="language-plaintext highlighter-rouge">&lt;small&gt;</code> HTML fragment to be swapped out-of-bounds
in the response when the request was performed using HTMX, and omit the <code class="language-plaintext highlighter-rouge">&lt;small&gt;</code> 
fragment when the Qute template is rendered using a normal, non-HTMX request.</p>

<p>HTMX will set the <code class="language-plaintext highlighter-rouge">HX-Request: true</code> header in the request to your server when it
issues a request. Using the JAX-RS <code class="language-plaintext highlighter-rouge">@HeatherParam("XX-Request)</code> annotation we can
retrieve this value for use in our detector.</p>

<p>The following CDI producer that ensures the <a href="https://htmx.org/reference/#request_headers">proper HTMX headers</a> are retrieved
and made available through a request scoped <code class="language-plaintext highlighter-rouge">Htmx</code> object.</p>

<p>Design considerations:</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">Htmx</code> can’t be a Java record, as those are <code class="language-plaintext highlighter-rouge">final</code> and CDI requires beans not to be such</li>
  <li><code class="language-plaintext highlighter-rouge">Htmx</code> must be a top level class, or a static one as CDI requires a default constructor</li>
  <li>you can’t just produce a <code class="language-plaintext highlighter-rouge">boolean</code> or <code class="language-plaintext highlighter-rouge">Boolean</code> as those are not subclasseable (because CDI)</li>
  <li>because Quarkus uses ARC as the CDI implementation, they advise (require?) injections to be package private</li>
  <li>to retrieve CDI beans in your Qute template, the bean must be <code class="language-plaintext highlighter-rouge">@Named</code></li>
  <li>you can’t use <code class="language-plaintext highlighter-rouge">@HeaderParam</code> annotations because those are unknown to CDI</li>
</ul>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">jakarta.enterprise.context.RequestScoped</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">jakarta.enterprise.inject.Produces</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">jakarta.inject.Named</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">jakarta.inject.Singleton</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">jakarta.ws.rs.HeaderParam</span><span class="o">;</span>

<span class="nd">@Singleton</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">HtmxHeaderProducer</span> <span class="o">{</span>
    <span class="kd">public</span> <span class="kd">static</span> <span class="kd">class</span> <span class="nc">Htmx</span> <span class="o">{</span>
        <span class="kd">private</span> <span class="kt">boolean</span> <span class="n">htmxRequest</span><span class="o">;</span>

        <span class="kd">private</span> <span class="kt">boolean</span> <span class="n">htmxBoosted</span><span class="o">;</span>

        <span class="nc">Htmx</span><span class="o">(</span><span class="kt">boolean</span> <span class="n">htmxRequest</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">htmxBoosted</span><span class="o">)</span> <span class="o">{</span>
            <span class="k">this</span><span class="o">.</span><span class="na">htmxRequest</span> <span class="o">=</span> <span class="n">htmxRequest</span><span class="o">;</span>
            <span class="k">this</span><span class="o">.</span><span class="na">htmxBoosted</span> <span class="o">=</span> <span class="n">htmxBoosted</span><span class="o">;</span>
        <span class="o">}</span>

        <span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">isHtmxRequest</span><span class="o">()</span> <span class="o">{</span>
            <span class="k">return</span> <span class="n">htmxRequest</span><span class="o">;</span>
        <span class="o">}</span>

        <span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">isHtmxBoosted</span><span class="o">()</span> <span class="o">{</span>
            <span class="k">return</span> <span class="n">htmxBoosted</span><span class="o">;</span>
        <span class="o">}</span>
    <span class="o">}</span>

    <span class="nd">@Inject</span>
    <span class="nc">HttpHeaders</span> <span class="n">headers</span><span class="o">;</span>

    <span class="nd">@Produces</span>
    <span class="nd">@Named</span><span class="o">(</span><span class="s">"htmx"</span><span class="o">)</span>
    <span class="nd">@RequestScoped</span>
    <span class="kd">public</span> <span class="nc">Htmx</span> <span class="nf">getHtmx</span><span class="o">()</span> <span class="o">{</span>
        <span class="kt">var</span> <span class="n">hxRequest</span> <span class="o">=</span> <span class="n">headers</span><span class="o">.</span><span class="na">getHeaderString</span><span class="o">(</span><span class="s">"HX-Request"</span><span class="o">);</span>
        <span class="kt">var</span> <span class="n">hxBoosted</span> <span class="o">=</span> <span class="n">headers</span><span class="o">.</span><span class="na">getHeaderString</span><span class="o">(</span><span class="s">"HX-Boosted"</span><span class="o">);</span>

        <span class="k">return</span> <span class="k">new</span> <span class="nf">Htmx</span><span class="o">(</span><span class="s">"true"</span><span class="o">.</span><span class="na">equals</span><span class="o">(</span><span class="n">hxRequest</span><span class="o">),</span> <span class="s">"true"</span><span class="o">.</span><span class="na">equals</span><span class="o">(</span><span class="n">hxBoosted</span><span class="o">));</span>
    <span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>

<p>If you want provide more HTMX-header functionality, it should be fairly easy to
implement those in this CDI producer. Enjoy!</p>


<div>
    <a  title="Permanent link to ‘CDI producer for HTMX headers (in Qute templates)’"  href="https://martijndashorst.com/blog/2025/02/04/htmx-cdi">&nbsp;&#x260D;&nbsp;</a>
</div>
	]]></content>
    </entry>
    
    <entry>
        <id>tag:martijndashorst.com,2024-08-30:/blog/2024/08/30/remove-rebased-branches</id>
        <title>List (and delete) git branches that have been rebased and merged</title>
        <summary type="html"><![CDATA[<p>Whenever you rebase and merge a branch, git will not discover the localbranch as being merged. So as I use ticket numbers as branch names anduse the ticket number in the commit summary (together with a moredescriptive summary and body) I can use the log to see if a branch wasmerged.</p>]]></summary>
        <published>2024-08-30T00:00:00Z</published>
        <updated>2024-08-30T00:00:00Z</updated>
        <author>
            <name>Martijn Dashorst</name>
            <uri>https://martijndashorst.com</uri>
        </author>
        <link rel="alternate" type="text/html" href="https://martijndashorst.com/blog/2024/08/30/remove-rebased-branches"/>
        <content type="html" xml:base="https://martijndashorst.com" xml:lang="en"><![CDATA[
<p>Whenever you rebase and merge a branch, git will not discover the local
branch as being merged. So as I use ticket numbers as branch names and
use the ticket number in the commit summary (together with a more
descriptive summary and body) I can use the log to see if a branch was
merged.</p>

<p>The following oneliner bash script below will check if the branch name 
exists in the log of the current branch (usually main) and generate
corresponding delete branch git calls.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git <span class="k">for</span><span class="nt">-each-ref</span> <span class="nt">--format</span><span class="o">=</span><span class="s1">'%(refname:short)'</span> refs/heads | <span class="nb">grep</span> <span class="nt">-v</span> main | <span class="k">while </span><span class="nv">IFS</span><span class="o">=</span> <span class="nb">read</span> <span class="nt">-r</span> branch<span class="p">;</span> <span class="k">do
    if</span> <span class="o">[[</span> <span class="si">$(</span>git log <span class="nt">-1</span> <span class="nt">--grep</span> <span class="s2">"</span><span class="nv">$branch</span><span class="s2">"</span><span class="si">)</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then
        </span><span class="nb">echo</span> <span class="s2">"git branch -D </span><span class="nv">$branch</span><span class="s2">"</span>
    <span class="k">fi
done</span>
</code></pre></div></div>

<p>So given a local branch with name <code class="language-plaintext highlighter-rouge">JIRA-banana</code>, and a commit with a 
message like <code class="language-plaintext highlighter-rouge">JIRA-banana fixed NPE in FooBar</code> which was rebased and merged
with main, so the local head commit(s) don’t match with what was merged,
this will show the branch as merged.</p>

<p>In a single line command:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git <span class="k">for</span><span class="nt">-each-ref</span> <span class="nt">--format</span><span class="o">=</span><span class="s1">'%(refname:short)'</span> refs/heads | <span class="nb">grep</span> <span class="nt">-v</span> main | <span class="k">while </span><span class="nv">IFS</span><span class="o">=</span> <span class="nb">read</span> <span class="nt">-r</span> branch<span class="p">;</span> <span class="k">do if</span> <span class="o">[[</span> <span class="si">$(</span>git log <span class="nt">-1</span> <span class="nt">--grep</span> <span class="s2">"</span><span class="nv">$branch</span><span class="s2">"</span><span class="si">)</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then </span><span class="nb">echo</span> <span class="s2">"git branch -D </span><span class="nv">$branch</span><span class="s2">"</span> <span class="p">;</span> <span class="k">fi</span> <span class="p">;</span> <span class="k">done</span>
</code></pre></div></div>

<p>Output:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git branch -D JIRA-banana
</code></pre></div></div>

<div>
    <a  title="Permanent link to ‘List (and delete) git branches that have been rebased and merged’"  href="https://martijndashorst.com/blog/2024/08/30/remove-rebased-branches">&nbsp;&#x260D;&nbsp;</a>
</div>
	]]></content>
    </entry>
    
    <entry>
        <id>tag:martijndashorst.com,2024-04-19:/blog/2024/04/19/htmx-jfall-2023-presentation-youtube</id>
        <title>Now available: HTMX: Web 1.0 with the benefits of Web 2.0 without the grift of Web 3.0-at JFall 2023</title>
        <summary type="html"><![CDATA[<p>The <a href="https://martijndashorst.com/blog/2023/11/09/jfall-htmx-presentation">HTMX presentation I gave at J-Fall 2023</a> is now available for wachting for all at Youtube.</p>]]></summary>
        <published>2024-04-19T00:00:00Z</published>
        <updated>2024-04-19T00:00:00Z</updated>
        <author>
            <name>Martijn Dashorst</name>
            <uri>https://martijndashorst.com</uri>
        </author>
        <link rel="alternate" type="text/html" href="https://martijndashorst.com/blog/2024/04/19/htmx-jfall-2023-presentation-youtube"/>
        <content type="html" xml:base="https://martijndashorst.com" xml:lang="en"><![CDATA[
<p>The <a href="https://martijndashorst.com/blog/2023/11/09/jfall-htmx-presentation">HTMX presentation I gave at J-Fall 2023</a> is now available for wachting for all at Youtube.</p>

<p>The video can be watched below, or when you follow <a href="https://youtu.be/0l6I0tA-Il4">this link</a>. Enjoy my Dunglish!</p>

<iframe width="560" height="315" src="https://www.youtube.com/embed/0l6I0tA-Il4?si=2mY9fvFvcd2VeSz4" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen=""></iframe>


<div>
    <a  title="Permanent link to ‘Now available: HTMX: Web 1.0 with the benefits of Web 2.0 without the grift of Web 3.0-at JFall 2023’"  href="https://martijndashorst.com/blog/2024/04/19/htmx-jfall-2023-presentation-youtube">&nbsp;&#x260D;&nbsp;</a>
</div>
	]]></content>
    </entry>
    
    <entry>
        <id>tag:martijndashorst.com,2023-11-09:/blog/2023/11/09/jfall-htmx-presentation</id>
        <title>HTMX: Web 1.0 with the benefits of Web 2.0 without the grift of Web 3.0-at JFall 2023</title>
        <summary type="html"><![CDATA[<p><a href="https://jfall.nl">JFall 2023</a> is a Dutch Java User Group 3-day conference packed into 1 day, and this year celebrated its 20th anniversary!</p>]]></summary>
        <published>2023-11-09T00:00:00Z</published>
        <updated>2023-11-09T00:00:00Z</updated>
        <author>
            <name>Martijn Dashorst</name>
            <uri>https://martijndashorst.com</uri>
        </author>
        <link rel="alternate" type="text/html" href="https://martijndashorst.com/blog/2023/11/09/jfall-htmx-presentation"/>
        <content type="html" xml:base="https://martijndashorst.com" xml:lang="en"><![CDATA[
<p><a href="https://jfall.nl">JFall 2023</a> is a Dutch Java User Group 3-day conference packed into 1 day, and this year celebrated its 20th anniversary!</p>

<p>I was honored to be able to present at the conference and my presentation “HTMX: Web 1.0 with the benefits of Web 2.0 without the grift of Web 3.0” was selected.
In this post I’m giving you the cliff notes of the presentation and the slides, as we eagerly await the upload of the recorded video.</p>

<p>These are <a href="https://www.slideshare.net/dashorst/htmx-web-10-with-the-benefits-of-web-20-without-the-grift-of-web-30">the slides</a>:</p>

<iframe src="https://www.slideshare.net/slideshow/embed_code/key/jsLxHdZbzkVfJU?hostedIn=slideshare&amp;page=upload" width="476" height="400" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"></iframe>

<h2 id="what-is-htmx">What is HTMX?</h2>

<p><a href="https://htmx.org">HTMX</a> is a client side javascript library that extends HTML using attributes to enable interactivity and dynamic web pages.</p>

<h2 id="why-does-htmx-exist">Why does HTMX exist?</h2>

<p>Current web architecture focusses on oodles of JavaScript and SPA’s to work around the limitations of HTML as a client side application platform:</p>

<ul>
  <li>HTML only provides GET and POST, and</li>
  <li>only <a> and &lt;form&gt; tags provide client-server communication</a></li>
</ul>

<p>Effectively HTML is stuck in 1995. SPA’s solve the “stuck in 1995” problem by working around HTML. HTMX solves the problem by extending HTML</p>

<h2 id="how-does-htmx-work">How does HTMX work?</h2>

<p>HTMX provides the following to extend HTML, augment the client-server communication and allow you to provide rich user experiences.</p>

<ul>
  <li>attributes on elements</li>
  <li>request and response headers to give server a way to respond to and direct HTMX</li>
  <li>classes for animations and indicators</li>
  <li>events for hooking into the various stages of HTMX and provide additional interactivity</li>
  <li>javascript functions for configuring HTMX and working with classes, finding and working with elements, and adding extensions</li>
  <li>extensions to provide more functionality like websockets, server-sent events and various DOM morphing algorithms</li>
</ul>

<p>In the presentation I gave some examples for each of these HTMX additions, and then I proceeded to give a live demo.</p>

<h2 id="a-live-demo">A live demo</h2>

<p>The live demo consisted of two parts:</p>
<ul>
  <li>HTMX core functionality <a href="https://github.com/dashorst/htmx-jfall">htmx-jfall</a></li>
  <li>A websocket multiplayer flag guessing game <a href="https://github.com/dashorst/funwithflags">Fun with Flags</a></li>
</ul>

<p>You can find the code at github (see the links).</p>

<h2 id="conclusions">Conclusions</h2>

<p>With HTMX a backend developer can now make HTML pages more dynamic without having to switch to a full client-side application build.
You just render out HTML and progressively enhance the application with HTMX tags and such to make a rich application.</p>

<p>I heartily recommend checking out HTMX and give it a 9/10.</p>


<div>
    <a  title="Permanent link to ‘HTMX: Web 1.0 with the benefits of Web 2.0 without the grift of Web 3.0-at JFall 2023’"  href="https://martijndashorst.com/blog/2023/11/09/jfall-htmx-presentation">&nbsp;&#x260D;&nbsp;</a>
</div>
	]]></content>
    </entry>
    
    <entry>
        <id>tag:martijndashorst.com,2023-10-29:/blog/2023/10/29/htmx-in-action</id>
        <title>HTMX in Action</title>
        <summary type="html"><![CDATA[<p>I’m becoming more and more a fan of htmx, and there’s a companion book written by the author(s) of htmx:</p>]]></summary>
        <published>2023-10-29T00:00:00Z</published>
        <updated>2023-10-29T00:00:00Z</updated>
        <author>
            <name>Martijn Dashorst</name>
            <uri>https://martijndashorst.com</uri>
        </author>
        <link rel="alternate" type="text/html" href="https://martijndashorst.com/blog/2023/10/29/htmx-in-action"/>
        <content type="html" xml:base="https://martijndashorst.com" xml:lang="en"><![CDATA[
<p>I’m becoming more and more a fan of htmx, and there’s a companion book written by the author(s) of htmx:</p>

<p><a href="https://hypermedia.systems">Hypermedia Systems</a></p>

<blockquote>
  <p>The revolutionary ideas that empowered the Web</p>

  <p>A simpler approach to building applications on the Web and beyond with htmx and Hyperview</p>

  <p>Enhancing web applications without using SPA frameworks</p>
</blockquote>

<div>
    <a  title="Permanent link to ‘HTMX in Action’"  href="https://martijndashorst.com/blog/2023/10/29/htmx-in-action">&nbsp;&#x260D;&nbsp;</a>
</div>
	]]></content>
    </entry>
    
    <entry>
        <id>tag:martijndashorst.com,2023-09-28:/blog/2023/09/28/fixing-eclipse-wont-start-macos</id>
        <title>Fixing Eclipse won&apos;t start issue on macOS</title>
        <summary type="html"><![CDATA[<p>Sometimes, when you update your Eclipse plugins, it won’t start after you’ve shut it down (e.g. after a reboot). This means that the system finds that the Eclipse application bundle has different cryptographic signature than when it was installed.</p>]]></summary>
        <published>2023-09-28T00:00:00Z</published>
        <updated>2023-09-28T00:00:00Z</updated>
        <author>
            <name>Martijn Dashorst</name>
            <uri>https://martijndashorst.com</uri>
        </author>
        <link rel="alternate" type="text/html" href="https://martijndashorst.com/blog/2023/09/28/fixing-eclipse-wont-start-macos"/>
        <content type="html" xml:base="https://martijndashorst.com" xml:lang="en"><![CDATA[
<p>Sometimes, when you update your Eclipse plugins, it won’t start after you’ve shut it down (e.g. after a reboot). 
This means that the system finds that the Eclipse application bundle has different cryptographic signature than when it was installed.</p>

<p>To check if the signature is (in)valid you can use this Terminal command:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>pkgutil <span class="nt">--check-signature</span> /Applications/Eclipse<span class="se">\ </span>2023.09.app 
Package <span class="s2">"Eclipse 2023.09"</span>:
   Status: package is invalid <span class="o">(</span>checksum did not verify<span class="o">)</span>
</code></pre></div></div>

<p>When the signature is invalid, you need to recalculate the signature:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>codesign <span class="nt">--force</span> <span class="nt">--deep</span> <span class="nt">--sign</span> - /Applications/Eclipse<span class="se">\ </span>2023.09.app 
/Applications/Eclipse 2023.09.app: replacing existing signature
</code></pre></div></div>

<p>And voilà! your Eclipse will start again.</p>

<div>
    <a  title="Permanent link to ‘Fixing Eclipse won&apos;t start issue on macOS’"  href="https://martijndashorst.com/blog/2023/09/28/fixing-eclipse-wont-start-macos">&nbsp;&#x260D;&nbsp;</a>
</div>
	]]></content>
    </entry>
    
    <entry>
        <id>tag:martijndashorst.com,2023-08-28:/blog/2023/08/28/react-communism-agile-scotsman</id>
        <title>React, communism, agile and being a Scotsman</title>
        <summary type="html"><![CDATA[<p><a href="https://www.youtube.com/clip/Ugkx8kvonWPJJvjcfIAOWjq6sdN4eeB6_ueu">The Primeagen</a>:</p>]]></summary>
        <published>2023-08-28T00:00:00Z</published>
        <updated>2023-08-28T00:00:00Z</updated>
        <author>
            <name>Martijn Dashorst</name>
            <uri>https://martijndashorst.com</uri>
        </author>
        <link rel="alternate" type="text/html" href="https://martijndashorst.com/blog/2023/08/28/react-communism-agile-scotsman"/>
        <content type="html" xml:base="https://martijndashorst.com" xml:lang="en"><![CDATA[
<p><a href="https://www.youtube.com/clip/Ugkx8kvonWPJJvjcfIAOWjq6sdN4eeB6_ueu">The Primeagen</a>:</p>

<blockquote>
  <p>If you use React right, it’s gonna work out… Just like communism, agile and being a Scotsman</p>
</blockquote>

<iframe width="560" height="315" src="https://www.youtube.com/embed/OXPoTD721qc?si=lPp2jKSA1bHxOlH5&amp;clip=Ugkx8kvonWPJJvjcfIAOWjq6sdN4eeB6_ueu&amp;clipt=EIvnSBiIz0k" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen=""></iframe>


<div>
    <a  title="Permanent link to ‘React, communism, agile and being a Scotsman’"  href="https://martijndashorst.com/blog/2023/08/28/react-communism-agile-scotsman">&nbsp;&#x260D;&nbsp;</a>
</div>
	]]></content>
    </entry>
    
    <entry>
        <id>tag:martijndashorst.com,2023-08-27:/blog/2023/08/27/htmx-quarkus-first-impressions</id>
        <title>HTMX and Quarkus First Impressions</title>
        <summary type="html"><![CDATA[<p>I’ve been eyeing <a href="https://htmx.org">HTMX</a> ever since I’ve laid my eyes on it, and already want to build applications using <a href="https://quarkus.io">Quarkus</a>.Fortunately €€€ dayjob provides the opportunity to combine both to build an internal tool to run several SQL scripts after one another.In this post I wanted to note my first impressions.</p>]]></summary>
        <published>2023-08-27T00:00:00Z</published>
        <updated>2023-08-27T00:00:00Z</updated>
        <author>
            <name>Martijn Dashorst</name>
            <uri>https://martijndashorst.com</uri>
        </author>
        <link rel="alternate" type="text/html" href="https://martijndashorst.com/blog/2023/08/27/htmx-quarkus-first-impressions"/>
        <content type="html" xml:base="https://martijndashorst.com" xml:lang="en"><![CDATA[
<p>I’ve been eyeing <a href="https://htmx.org">HTMX</a> ever since I’ve laid my eyes on it, and already want to build applications using <a href="https://quarkus.io">Quarkus</a>.
Fortunately €€€ dayjob provides the opportunity to combine both to build an internal tool to run several SQL scripts after one another.
In this post I wanted to note my first impressions.</p>

<p><img src="https://martijndashorst.com/uploads/htmx-meme.png" alt="HTMX meme" /></p>

<h3 id="what-is-htmx-in-a-nutshell">What is HTMX in a nutshell?</h3>

<p>It is a JavaScript library that enables <em>Hypertext As The Engine Of Application State</em> (HATEOAS) in the browser by using attributes to declaritively specify what actions need to be taken and which element needs to be replaced by the HTML response of the action.
HTMX issues mostly AJAX requests and integrates with the history API.
It is fully HTML driven, no additional JavaScript is necessary, only if you want pure clientside functionality.</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;div</span> <span class="na">hx-get=</span><span class="s">"/banana"</span> <span class="na">hx-target=</span><span class="s">"#strawberry"</span><span class="nt">&gt;</span>Click me<span class="nt">&lt;/div&gt;</span>

<span class="nt">&lt;div</span> <span class="na">id=</span><span class="s">"strawberry"</span><span class="nt">&gt;</span>gets replaced by the HTML that is returned after the AJAX GET<span class="nt">&lt;/div&gt;</span>
</code></pre></div></div>
<p>Clicking the <code class="language-plaintext highlighter-rouge">Click me</code> text inside the first <code class="language-plaintext highlighter-rouge">div</code> element will issue an AJAX GET request to the <code class="language-plaintext highlighter-rouge">/banana</code> endpoint on the server.
The request should respond with a HTML fragment that will replace the <code class="language-plaintext highlighter-rouge">strawberry</code> div.
HTMX takes care of all the plumbing.</p>

<h3 id="my-notes">My notes</h3>

<ul>
  <li>Quarkus: it is rather easy to get started and add new plugins</li>
  <li>For this project I needed Qute templates and JAX-RS (so rest-easy)</li>
  <li>Including HTMX is just using a <code class="language-plaintext highlighter-rouge">&lt;script&gt;</code> tag</li>
  <li>Using HTMX is just using the proper <code class="language-plaintext highlighter-rouge">hx-XYZ</code> attributes on your DOM elements</li>
  <li>Most uses for rich clients are present in the HTMX API: updating multiple elements in one go, events, history, etc.</li>
  <li>Rethinking how to do templating and setting up HTML endpoints for the UI is challenging coming from a <a href="https://wicket.apache.org">Wicket</a> history</li>
</ul>

<p>As you might know I have a <a href="https://wicketinaction.com">pretty strong Wicket background</a>. 
So the serverside rendering component of HTMX and low-JavaScript usage appeals to me considerably.
I have to re-learn some stuff to actually get good in the HTMX and HATEOAS mindset, and to combine multi-element updates instead of relying on full page refreshes (which HTMX takes good care of!)</p>

<p>I have created an already quite complicated UI with:</p>

<ul>
  <li>a sidebard menu containing our projects,</li>
  <li>a row of tabs containing the contents of each project,</li>
  <li>a list of (SQL) files and a SQL previewer,</li>
  <li>a previewer that syntax highlights the TSQL files</li>
  <li>a link to github to directly edit the SQL file</li>
</ul>

<p>And all these items are linked together already, with a minimum of Java code, HTML and no JavaScript of my own.</p>

<p>Tally for now:</p>
<ul>
  <li>94 lines of HTML templates</li>
  <li>173 lines of Java code (sloccount)</li>
  <li><a href="https://getbootstrap.com/docs/5.3/)https://getbootstrap.com/docs/5.3">bootstrap 5.3</a> (and bootstrap icons)</li>
  <li><a href="https://highlightjs.org">highlightjs</a> + highlight-tsql</li>
  <li><a href="https://htmx.org">HTMX</a></li>
</ul>

<h3 id="next-up">Next up</h3>

<ul>
  <li>securing the thing with OIDC + Topicus Keyhub</li>
  <li>connecting the project to a local git checkout of our project(s)</li>
  <li>making the scripts runnable against a database</li>
</ul>

<h3 id="in-conclusion">In conclusion</h3>

<p>The fun part when compared to writing Wicket pages is that you can easily edit the HTML templates to add functionality.
It is further enhanced by the quick reloading of my currently 3 Java classes by Quarkus’ development mode.</p>

<p>The hardest part for me is to figure out how to make this all maintainable and discoverable.
The Qute templating engine is nice, and Quarkus has some decent defaults, so probably I need to adhere to those standards more.</p>

<p>The next weeks will be fun and filled with learning!</p>


<div>
    <a  title="Permanent link to ‘HTMX and Quarkus First Impressions’"  href="https://martijndashorst.com/blog/2023/08/27/htmx-quarkus-first-impressions">&nbsp;&#x260D;&nbsp;</a>
</div>
	]]></content>
    </entry>
    
</feed>
