Jekyll2023-04-18T04:21:19+00:00https://jsedano.dev/feed.xmljsedano.devthis is my personal dev blog. hope you find something of interest here. I post about software development.juan sedanoPlain Thymeleaf2023-04-17T06:00:00+00:002023-04-17T06:00:00+00:00https://jsedano.dev/java/thymeleaf/2023/04/17/plain-thymeleaf<p><code class="language-plaintext highlighter-rouge">Thymeleaf</code> is an HTML (<a href="https://www.thymeleaf.org/doc/tutorials/3.1/usingthymeleaf.html#what-kind-of-templates-can-thymeleaf-process">and more</a>) template engine for Java. This is the core in action with nothing else.</p>
<p>You can find the complete code for this here: <a href="https://github.com/jsedano/examples/tree/main/only-thymeleaf">only-thymeleaf</a>.</p>
<p>All of this is just putting into a project what has being posted in this <a href="https://stackoverflow.com/a/71995574/1845671">stackoverflow answer</a> which in turn was found on this <a href="https://github.com/thymeleaf/thymeleaf/issues/561#issuecomment-490648829">comment on github</a>.</p>
<p>We begin by getting only the core jar for Thymeleaf (the latest one at the time this post was written).</p>
<p><a href="https://github.com/jsedano/examples/blob/main/only-thymeleaf/pom.xml">pom.xml</a></p>
<figure class="highlight"><pre><code class="language-xml" data-lang="xml"><span class="nt"><dependency></span>
<span class="nt"><groupId></span>org.thymeleaf<span class="nt"></groupId></span>
<span class="nt"><artifactId></span>thymeleaf<span class="nt"></artifactId></span>
<span class="nt"><version></span>3.1.1.RELEASE<span class="nt"></version></span>
<span class="nt"></dependency></span></code></pre></figure>
<p>Then we create our <code class="language-plaintext highlighter-rouge">template</code> inside resources on a directory apptly named <code class="language-plaintext highlighter-rouge">templates</code>.</p>
<p><a href="https://github.com/jsedano/examples/blob/main/only-thymeleaf/src/main/resources/templates/index.html">src/main/resources/templates/index.html</a></p>
<figure class="highlight"><pre><code class="language-html" data-lang="html"><span class="cp"><!DOCTYPE html></span>
<span class="nt"><html</span> <span class="na">lang=</span><span class="s">"en"</span> <span class="na">xmlns:th=</span><span class="s">"http://www.thymeleaf.org"</span><span class="nt">></span>
<span class="nt"><head></span>
<span class="nt"><meta</span> <span class="na">charset=</span><span class="s">"UTF-8"</span><span class="nt">></span>
<span class="nt"><title></span>Thymeleaf hello world<span class="nt"></title></span>
<span class="nt"></head></span>
<span class="nt"><body></span>
<span class="nt"><p></span>First name: <span class="nt"><span</span> <span class="na">th:text=</span><span class="s">"${first_name}?: '(no first name specified)'"</span><span class="nt">/></span>.<span class="nt"></p></span>
<span class="nt"><p></span>Last name: <span class="nt"><span</span> <span class="na">th:text=</span><span class="s">"${last_name}?: '(no last name specified)'"</span><span class="nt">/></span>.<span class="nt"></p></span>
<span class="nt"></body></span>
<span class="nt"></html></span></code></pre></figure>
<p>Inside the <code class="language-plaintext highlighter-rouge">span tag</code> we have <code class="language-plaintext highlighter-rouge">th</code> which is how all data attributes starts on Thymeleaf, you can see that it’s declared as a namespace definition above on the html tag. We are also using a variable expression <code class="language-plaintext highlighter-rouge">${}</code> with an Elvis operator <code class="language-plaintext highlighter-rouge">?:</code> which is an special operator that only returns it’s value when the evaluated expression returns null, which means if <code class="language-plaintext highlighter-rouge">first_name</code> is null then <code class="language-plaintext highlighter-rouge">(no first name specified)</code> will be returned.</p>
<p>Now to bring it all together:
<a href="https://github.com/jsedano/examples/blob/main/only-thymeleaf/src/main/java/dev/jsedano/examples/onlythymeleaf/Main.java">src/main/java/dev/jsedano/examples/onlythymeleaf/Main.java</a></p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="kt">var</span> <span class="n">resolver</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ClassLoaderTemplateResolver</span><span class="o">();</span>
<span class="n">resolver</span><span class="o">.</span><span class="na">setTemplateMode</span><span class="o">(</span><span class="nc">TemplateMode</span><span class="o">.</span><span class="na">HTML</span><span class="o">);</span>
<span class="n">resolver</span><span class="o">.</span><span class="na">setCharacterEncoding</span><span class="o">(</span><span class="s">"UTF-8"</span><span class="o">);</span>
<span class="n">resolver</span><span class="o">.</span><span class="na">setPrefix</span><span class="o">(</span><span class="s">"/templates/"</span><span class="o">);</span>
<span class="n">resolver</span><span class="o">.</span><span class="na">setSuffix</span><span class="o">(</span><span class="s">".html"</span><span class="o">);</span></code></pre></figure>
<p>Since we are not using Spring or nothing to helps us with dependency injection we will create objects the traditional way, setting up the prefix for where the templates will be stored and the suffix for them.</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="kt">var</span> <span class="n">context</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Context</span><span class="o">();</span>
<span class="k">if</span> <span class="o">(</span><span class="n">args</span><span class="o">.</span><span class="na">length</span> <span class="o">!=</span> <span class="mi">0</span><span class="o">)</span> <span class="o">{</span>
<span class="n">context</span><span class="o">.</span><span class="na">setVariable</span><span class="o">(</span><span class="s">"first_name"</span><span class="o">,</span> <span class="n">args</span><span class="o">[</span><span class="mi">0</span><span class="o">]);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">args</span><span class="o">.</span><span class="na">length</span> <span class="o">></span> <span class="mi">1</span><span class="o">)</span> <span class="o">{</span>
<span class="n">context</span><span class="o">.</span><span class="na">setVariable</span><span class="o">(</span><span class="s">"last_name"</span><span class="o">,</span> <span class="n">args</span><span class="o">[</span><span class="mi">1</span><span class="o">]);</span>
<span class="o">}</span>
<span class="o">}</span></code></pre></figure>
<p>This will be the context which will hold the objects that Thymeleaf will use to generate the html.</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="kt">var</span> <span class="n">templateEngine</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">TemplateEngine</span><span class="o">();</span>
<span class="n">templateEngine</span><span class="o">.</span><span class="na">setTemplateResolver</span><span class="o">(</span><span class="n">resolver</span><span class="o">);</span>
<span class="kt">var</span> <span class="n">result</span> <span class="o">=</span> <span class="n">templateEngine</span><span class="o">.</span><span class="na">process</span><span class="o">(</span><span class="s">"index"</span><span class="o">,</span> <span class="n">context</span><span class="o">);</span>
<span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">result</span><span class="o">);</span></code></pre></figure>
<p>Here we create a <code class="language-plaintext highlighter-rouge">TemplateEngine</code> object and pass the <code class="language-plaintext highlighter-rouge">resolver</code>, then we call <code class="language-plaintext highlighter-rouge">process</code> on the <code class="language-plaintext highlighter-rouge">templateEngine</code> object with the name of the template and the context we created above.</p>
<p>We can create our fat jar running <code class="language-plaintext highlighter-rouge">mvn verify</code> and then call it with <code class="language-plaintext highlighter-rouge">java -jar ./target/only-thymeleaf-1.0-jar-with-dependencies.jar</code> to print the result of the template processing, if we send variables when we executed we can see how they get replace:</p>
<figure class="highlight"><pre><code class="language-text" data-lang="text">only-thymeleaf % java -jar ./target/only-thyme leaf-1.0-jar-with-dependencies.jar
SLF4J: No SLF4J providers were found.
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See https://www.slf4j.org/codes.html#noProviders for further details.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Thymeleaf hello world</title>
</head>
<body>
<p>First name: <span>(no first name specified)</span>.</p>
<p>Last name: <span>(no last name specified)</span>.</p>
</body>
</html>
only-thymeleaf % java -jar ./target/only-thymeleaf-1.0-jar-with-dependencies.jar juan sedano
SLF4J: No SLF4J providers were found.
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See https://www.slf4j.org/codes.html#noProviders for further details.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Thymeleaf hello world</title>
</head>
<body>
<p>First name: <span>juan</span>.</p>
<p>Last name: <span>sedano</span>.</p>
</body>
</html></code></pre></figure>
<p>For more information on Thymeleaf you can go directly to the <a href="https://www.thymeleaf.org/doc/tutorials/3.1/usingthymeleaf.html">thymeleaf docs</a>.</p>
<p>Download the complete code for this here: <a href="https://github.com/jsedano/examples/tree/main/only-thymeleaf">only-thymeleaf</a>.</p>juan sedanoThymeleaf is an HTML (and more) template engine for Java. This is the core in action with nothing else.Lissajous curve Java2022-10-28T06:00:00+00:002022-10-28T06:00:00+00:00https://jsedano.dev/java/2022/10/28/lissajous-curve-java<p>Just a Lissajous curve on Java displayed on a JFrame.</p>
<p>You can find the complete code for this here: <a href="https://github.com/jsedano/examples/blob/main/java-snippets/Lissajous.java">Lissajous.java</a>.</p>
<p>First of all, the code is a complete rip-off from <a href="https://www.gopl.io">The Go Programming Language</a> book, specifically from this <a href="https://github.com/adonovan/gopl.io/blob/master/ch1/lissajous/main.go">code from chapter 1</a>.</p>
<p>I won’t even pretend to understand the maths on this one, so lets just dive into the code, first we initialize our window:</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="kt">int</span> <span class="n">size</span> <span class="o">=</span> <span class="mi">100</span><span class="o">;</span>
<span class="nc">JFrame</span> <span class="n">frame</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">JFrame</span><span class="o">(</span><span class="s">"Lissajous"</span><span class="o">);</span>
<span class="n">frame</span><span class="o">.</span><span class="na">setDefaultCloseOperation</span><span class="o">(</span><span class="nc">JFrame</span><span class="o">.</span><span class="na">EXIT_ON_CLOSE</span><span class="o">);</span>
<span class="nc">JPanel</span> <span class="n">panel</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">JPanel</span><span class="o">();</span>
<span class="n">panel</span><span class="o">.</span><span class="na">setPreferredSize</span><span class="o">(</span><span class="k">new</span> <span class="nc">Dimension</span><span class="o">(</span><span class="mi">2</span><span class="o">*</span><span class="n">size</span><span class="o">+</span><span class="mi">1</span><span class="o">,</span> <span class="mi">2</span><span class="o">*</span><span class="n">size</span><span class="o">+</span><span class="mi">1</span><span class="o">));</span>
<span class="n">frame</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="n">panel</span><span class="o">);</span>
<span class="n">frame</span><span class="o">.</span><span class="na">pack</span><span class="o">();</span>
<span class="n">frame</span><span class="o">.</span><span class="na">setResizable</span><span class="o">(</span><span class="kc">false</span><span class="o">);</span>
<span class="n">frame</span><span class="o">.</span><span class="na">setLocationRelativeTo</span><span class="o">(</span><span class="kc">null</span><span class="o">);</span>
<span class="n">frame</span><span class="o">.</span><span class="na">setVisible</span><span class="o">(</span><span class="kc">true</span><span class="o">);</span></code></pre></figure>
<p>With that we have a non resizable JFrame on the middle of the screen, that terminates the program when closed which contains a JPanel where we can draw, in order to do so we only need the Graphics from the JPanel:</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="nc">Graphics</span> <span class="n">g</span> <span class="o">=</span> <span class="n">panel</span><span class="o">.</span><span class="na">getGraphics</span><span class="o">();</span></code></pre></figure>
<p>Then we start shamelessly translating the Go code from the link above to Java:</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="kt">double</span> <span class="n">cycles</span> <span class="o">=</span> <span class="mi">5</span><span class="o">;</span>
<span class="kt">double</span> <span class="n">angularResolution</span> <span class="o">=</span> <span class="mf">0.001</span><span class="o">;</span>
<span class="kt">long</span> <span class="n">delay</span> <span class="o">=</span> <span class="mi">80</span><span class="o">;</span>
<span class="kt">int</span> <span class="n">frames</span> <span class="o">=</span> <span class="mi">64</span><span class="o">;</span>
<span class="k">for</span><span class="o">(;;){</span>
<span class="kt">double</span> <span class="n">frequency</span> <span class="o">=</span> <span class="nc">Math</span><span class="o">.</span><span class="na">random</span><span class="o">()</span> <span class="o">*</span> <span class="mf">3.0</span><span class="o">;</span>
<span class="kt">float</span> <span class="n">phase</span> <span class="o">=</span> <span class="mf">0.0f</span><span class="o">;</span>
<span class="k">for</span><span class="o">(</span> <span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span> <span class="n">i</span> <span class="o"><</span> <span class="n">frames</span><span class="o">;</span> <span class="n">i</span><span class="o">++)</span> <span class="o">{</span>
<span class="n">g</span><span class="o">.</span><span class="na">setColor</span><span class="o">(</span><span class="nc">Color</span><span class="o">.</span><span class="na">BLACK</span><span class="o">);</span>
<span class="n">g</span><span class="o">.</span><span class="na">fillRect</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span><span class="mi">0</span><span class="o">,</span> <span class="n">panel</span><span class="o">.</span><span class="na">getWidth</span><span class="o">(),</span> <span class="n">panel</span><span class="o">.</span><span class="na">getHeight</span><span class="o">());</span>
<span class="n">g</span><span class="o">.</span><span class="na">setColor</span><span class="o">(</span><span class="nc">Color</span><span class="o">.</span><span class="na">GREEN</span><span class="o">);</span>
<span class="k">for</span><span class="o">(</span><span class="kt">double</span> <span class="n">t</span> <span class="o">=</span> <span class="mf">0.0</span><span class="o">;</span> <span class="n">t</span> <span class="o"><</span> <span class="n">cycles</span><span class="o">*</span><span class="mi">2</span><span class="o">*</span><span class="nc">Math</span><span class="o">.</span><span class="na">PI</span><span class="o">;</span> <span class="n">t</span><span class="o">+=</span> <span class="n">angularResolution</span><span class="o">){</span>
<span class="kt">double</span> <span class="n">x</span> <span class="o">=</span> <span class="nc">Math</span><span class="o">.</span><span class="na">sin</span><span class="o">(</span><span class="n">t</span><span class="o">);</span>
<span class="kt">double</span> <span class="n">y</span> <span class="o">=</span> <span class="nc">Math</span><span class="o">.</span><span class="na">sin</span><span class="o">(</span><span class="n">t</span> <span class="o">*</span> <span class="n">frequency</span> <span class="o">+</span> <span class="n">phase</span><span class="o">);</span>
<span class="n">g</span><span class="o">.</span><span class="na">drawRect</span><span class="o">(</span> <span class="o">(</span><span class="n">size</span> <span class="o">+</span> <span class="o">(</span><span class="kt">int</span><span class="o">)(</span><span class="n">x</span><span class="o">*</span><span class="n">size</span><span class="o">+</span><span class="mf">0.5</span><span class="o">)),</span> <span class="o">(</span><span class="n">size</span> <span class="o">+</span> <span class="o">(</span><span class="kt">int</span><span class="o">)(</span><span class="n">y</span><span class="o">*</span><span class="n">size</span><span class="o">+</span><span class="mf">0.5</span><span class="o">)),</span><span class="mi">1</span><span class="o">,</span><span class="mi">1</span><span class="o">);</span>
<span class="o">}</span>
<span class="n">phase</span> <span class="o">+=</span> <span class="mf">0.1</span><span class="o">;</span>
<span class="nc">Thread</span><span class="o">.</span><span class="na">sleep</span><span class="o">(</span><span class="n">delay</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span></code></pre></figure>
<p>Since its a single file, if we have Java 11 or above we can run it without compiling with:</p>
<figure class="highlight"><pre><code class="language-shell" data-lang="shell">java Lissajous.java</code></pre></figure>
<p>And we should see this:</p>
<div style="text-align: center;">
<a href="/assets/images/lissajous-curve-java/lissajous-curve-java.gif">
<img src="/assets/images/lissajous-curve-java/lissajous-curve-java.gif" alt="lissajous-curve-java" width="350" height="350" />
</a>
</div>
<p><br /></p>
<p>Download the complete code for this here: <a href="https://github.com/jsedano/examples/blob/main/java-snippets/Lissajous.java">Lissajous.java</a>.</p>juan sedanoJust a Lissajous curve on Java displayed on a JFrame.Java Redis pub/sub example with Jedis2022-09-19T06:00:00+00:002022-09-19T06:00:00+00:00https://jsedano.dev/java,/redis/2022/09/19/java-redis-pub-sub-example<p>This is a Redis pub/sub example written in Java using Jedis.</p>
<ul>
<li>You can find the complete code for this here: <a href="https://github.com/jsedano/examples/tree/main/redis-pub-sub">Java Redis pub/sub example</a>.</li>
<li>For more neat stuff that Redis can do look here: <a href="/redis/2022/09/17/redis-2022.html">Redis 2022</a>.</li>
</ul>
<h3 id="prerequisites">Prerequisites</h3>
<ul>
<li><a href="https://github.com/jsedano/examples/tree/main/redis-pub-sub">Download the code</a></li>
<li>Have an instance of <a href="https://redis.io/docs/stack/get-started/install/docker/">redis-stack</a> running.</li>
<li>Apache Maven 3.8.6</li>
<li>Java 17</li>
</ul>
<h3 id="libraries-used">Libraries used</h3>
<p>We are only using <a href="https://github.com/redis/jedis">jedis</a> in order to keep the example simple.</p>
<h3 id="redis-commands-used">Redis Commands used</h3>
<h4 id="subscribe">subscribe</h4>
<p>this is used in order to subscribe to one or more channels:</p>
<figure class="highlight"><pre><code class="language-shell" data-lang="shell">subscribe channel1 channel2... channelN</code></pre></figure>
<h4 id="unsubscribe">unsubscribe</h4>
<p>unsubscribe current client to one or more channels:</p>
<figure class="highlight"><pre><code class="language-shell" data-lang="shell">unsubscribe channel1 channel2... channelN</code></pre></figure>
<h4 id="psubscribe">psubscribe</h4>
<p>instead of subscribing to a channel, this allows you to subscribe to one of more patterns:</p>
<figure class="highlight"><pre><code class="language-shell" data-lang="shell">psubscribe pattern1 pattern2... patternN</code></pre></figure>
<p>for example if you subscribe to <code class="language-plaintext highlighter-rouge">foo*</code> it means that you will get the messages meant for all the channels that start with <code class="language-plaintext highlighter-rouge">foo</code>.</p>
<h4 id="punsubscribe">punsubscribe</h4>
<p>unsubscribe from one or more patterns:</p>
<figure class="highlight"><pre><code class="language-shell" data-lang="shell">punsubscribe pattern1 pattern2... patternN</code></pre></figure>
<h4 id="publish">publish</h4>
<p>publish sends a message to connected clients, returns the number of clients that got the message.</p>
<figure class="highlight"><pre><code class="language-shell" data-lang="shell">publish aChannel <span class="s1">'some message'</span></code></pre></figure>
<h4 id="ping">ping</h4>
<p>sends a ping from a client to the server, optionally you can send a message and the ping will echo it.</p>
<figure class="highlight"><pre><code class="language-shell" data-lang="shell">ping</code></pre></figure>
<p>or</p>
<figure class="highlight"><pre><code class="language-shell" data-lang="shell">ping a message</code></pre></figure>
<h3 id="code-walkthrough">Code walkthrough</h3>
<p>We need to extend <code class="language-plaintext highlighter-rouge">JedisPubSub</code> in order to give our client functionality.</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="kn">import</span> <span class="nn">redis.clients.jedis.JedisPubSub</span><span class="o">;</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">LogPubSub</span> <span class="kd">extends</span> <span class="nc">JedisPubSub</span> <span class="o">{</span></code></pre></figure>
<p>To keep this example simple we are only going to add very basic functionality, in order to know which client is the one that got the message we are adding a name field.</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"> <span class="kd">private</span> <span class="nc">String</span> <span class="n">name</span><span class="o">;</span>
<span class="kd">public</span> <span class="nf">LogPubSub</span><span class="o">(</span><span class="nc">String</span> <span class="n">name</span><span class="o">)</span> <span class="o">{</span>
<span class="k">this</span><span class="o">.</span><span class="na">name</span> <span class="o">=</span> <span class="n">name</span><span class="o">;</span>
<span class="o">}</span></code></pre></figure>
<p>For <code class="language-plaintext highlighter-rouge">subscribe</code>, <code class="language-plaintext highlighter-rouge">unsubscribe</code>, <code class="language-plaintext highlighter-rouge">psubscribe</code>, <code class="language-plaintext highlighter-rouge">punsubscribe</code> and <code class="language-plaintext highlighter-rouge">pong</code> (which is the one that a successful ping triggers) we only print the information:</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"> <span class="kd">public</span> <span class="kt">void</span> <span class="nf">onSubscribe</span><span class="o">(</span><span class="nc">String</span> <span class="n">channel</span><span class="o">,</span> <span class="kt">int</span> <span class="n">subscribedChannels</span><span class="o">)</span> <span class="o">{</span>
<span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">printf</span><span class="o">(</span>
<span class="s">"name: %s method: %s channel: %s subscribedChannels: %d\n"</span><span class="o">,</span>
<span class="n">name</span><span class="o">,</span> <span class="s">"onSubscribe"</span><span class="o">,</span> <span class="n">channel</span><span class="o">,</span> <span class="n">subscribedChannels</span><span class="o">);</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">onUnsubscribe</span><span class="o">(</span><span class="nc">String</span> <span class="n">channel</span><span class="o">,</span> <span class="kt">int</span> <span class="n">subscribedChannels</span><span class="o">)</span> <span class="o">{</span>
<span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">printf</span><span class="o">(</span>
<span class="s">"name: %s method: %s channel: %s subscribedChannels: %d\n"</span><span class="o">,</span>
<span class="n">name</span><span class="o">,</span> <span class="s">"onUnsubscribe"</span><span class="o">,</span> <span class="n">channel</span><span class="o">,</span> <span class="n">subscribedChannels</span><span class="o">);</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">onPUnsubscribe</span><span class="o">(</span><span class="nc">String</span> <span class="n">pattern</span><span class="o">,</span> <span class="kt">int</span> <span class="n">subscribedChannels</span><span class="o">)</span> <span class="o">{</span>
<span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">printf</span><span class="o">(</span>
<span class="s">"name: %s method: %s patten: %s subscribedChannels: %d\n"</span><span class="o">,</span>
<span class="n">name</span><span class="o">,</span> <span class="s">"onPUnsubscribe"</span><span class="o">,</span> <span class="n">pattern</span><span class="o">,</span> <span class="n">subscribedChannels</span><span class="o">);</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">onPSubscribe</span><span class="o">(</span><span class="nc">String</span> <span class="n">pattern</span><span class="o">,</span> <span class="kt">int</span> <span class="n">subscribedChannels</span><span class="o">)</span> <span class="o">{</span>
<span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">printf</span><span class="o">(</span>
<span class="s">"name: %s method: %s patten: %s subscribedChannels: %d\n"</span><span class="o">,</span>
<span class="n">name</span><span class="o">,</span> <span class="s">"onPSubscribe"</span><span class="o">,</span> <span class="n">pattern</span><span class="o">,</span> <span class="n">subscribedChannels</span><span class="o">);</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">onPong</span><span class="o">(</span><span class="nc">String</span> <span class="n">message</span><span class="o">)</span> <span class="o">{</span>
<span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">printf</span><span class="o">(</span><span class="s">"name: %s method: %s message: %s\n"</span><span class="o">,</span> <span class="n">name</span><span class="o">,</span> <span class="s">"onPong"</span><span class="o">,</span> <span class="n">message</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span></code></pre></figure>
<p>When receiving a message in the client apart from printing the information if the message is a ping then we will do a <code class="language-plaintext highlighter-rouge">ping</code>.
If receiving the String “exit” we will unsubscribe from that channel or pattern (in the case of client subscribed using psubscribe).</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"> <span class="kd">public</span> <span class="kt">void</span> <span class="nf">onMessage</span><span class="o">(</span><span class="nc">String</span> <span class="n">channel</span><span class="o">,</span> <span class="nc">String</span> <span class="n">message</span><span class="o">)</span> <span class="o">{</span>
<span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">printf</span><span class="o">(</span>
<span class="s">"name: %s method: %s channel: %s message: %s\n"</span><span class="o">,</span> <span class="n">name</span><span class="o">,</span> <span class="s">"onMessage"</span><span class="o">,</span> <span class="n">channel</span><span class="o">,</span> <span class="n">message</span><span class="o">);</span>
<span class="k">switch</span> <span class="o">(</span><span class="n">message</span><span class="o">)</span> <span class="o">{</span>
<span class="k">case</span> <span class="s">"ping"</span><span class="o">:</span>
<span class="k">this</span><span class="o">.</span><span class="na">ping</span><span class="o">();</span>
<span class="k">break</span><span class="o">;</span>
<span class="k">case</span> <span class="s">"exit"</span><span class="o">:</span>
<span class="k">this</span><span class="o">.</span><span class="na">unsubscribe</span><span class="o">(</span><span class="n">channel</span><span class="o">);</span>
<span class="k">break</span><span class="o">;</span>
<span class="k">default</span><span class="o">:</span>
<span class="k">if</span> <span class="o">(</span><span class="n">message</span><span class="o">.</span><span class="na">indexOf</span><span class="o">(</span><span class="s">"ping"</span><span class="o">)</span> <span class="o">==</span> <span class="mi">0</span> <span class="o">&&</span> <span class="n">message</span><span class="o">.</span><span class="na">indexOf</span><span class="o">(</span><span class="s">" "</span><span class="o">)</span> <span class="o">==</span> <span class="mi">4</span><span class="o">)</span> <span class="o">{</span>
<span class="k">this</span><span class="o">.</span><span class="na">ping</span><span class="o">(</span><span class="n">message</span><span class="o">.</span><span class="na">substring</span><span class="o">(</span><span class="mi">5</span><span class="o">));</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">onPMessage</span><span class="o">(</span><span class="nc">String</span> <span class="n">pattern</span><span class="o">,</span> <span class="nc">String</span> <span class="n">channel</span><span class="o">,</span> <span class="nc">String</span> <span class="n">message</span><span class="o">)</span> <span class="o">{</span>
<span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">printf</span><span class="o">(</span>
<span class="s">"name: %s method: %s pattern: %s channel: %s message: %s\n"</span><span class="o">,</span>
<span class="n">name</span><span class="o">,</span> <span class="s">"onPMessage"</span><span class="o">,</span> <span class="n">pattern</span><span class="o">,</span> <span class="n">channel</span><span class="o">,</span> <span class="n">message</span><span class="o">);</span>
<span class="k">switch</span> <span class="o">(</span><span class="n">message</span><span class="o">)</span> <span class="o">{</span>
<span class="k">case</span> <span class="s">"ping"</span><span class="o">:</span>
<span class="k">this</span><span class="o">.</span><span class="na">ping</span><span class="o">();</span>
<span class="k">break</span><span class="o">;</span>
<span class="k">case</span> <span class="s">"exit"</span><span class="o">:</span>
<span class="k">this</span><span class="o">.</span><span class="na">punsubscribe</span><span class="o">(</span><span class="n">pattern</span><span class="o">);</span>
<span class="k">break</span><span class="o">;</span>
<span class="k">default</span><span class="o">:</span>
<span class="k">if</span> <span class="o">(</span><span class="n">message</span><span class="o">.</span><span class="na">indexOf</span><span class="o">(</span><span class="s">"ping"</span><span class="o">)</span> <span class="o">==</span> <span class="mi">0</span> <span class="o">&&</span> <span class="n">message</span><span class="o">.</span><span class="na">indexOf</span><span class="o">(</span><span class="s">" "</span><span class="o">)</span> <span class="o">==</span> <span class="mi">4</span><span class="o">)</span> <span class="o">{</span>
<span class="k">this</span><span class="o">.</span><span class="na">ping</span><span class="o">(</span><span class="n">message</span><span class="o">.</span><span class="na">substring</span><span class="o">(</span><span class="mi">5</span><span class="o">));</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">}</span></code></pre></figure>
<p>Then we only need to make a <code class="language-plaintext highlighter-rouge">JedisPooled</code> connection and used it to subscribe to a channel or pattern:</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="nc">JedisPooled</span> <span class="n">jedis</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">JedisPooled</span><span class="o">(</span><span class="s">"localhost"</span><span class="o">,</span> <span class="mi">6379</span><span class="o">);</span>
<span class="nc">ExecutorService</span> <span class="n">executor</span> <span class="o">=</span> <span class="nc">Executors</span><span class="o">.</span><span class="na">newFixedThreadPool</span><span class="o">(</span><span class="mi">4</span><span class="o">);</span>
<span class="n">executor</span><span class="o">.</span><span class="na">execute</span><span class="o">(()</span> <span class="o">-></span> <span class="n">jedis</span><span class="o">.</span><span class="na">subscribe</span><span class="o">(</span><span class="k">new</span> <span class="nc">LogPubSub</span><span class="o">(</span><span class="s">"onlyOne"</span><span class="o">),</span> <span class="s">"dev.one"</span><span class="o">));</span>
<span class="n">executor</span><span class="o">.</span><span class="na">execute</span><span class="o">(()</span> <span class="o">-></span> <span class="n">jedis</span><span class="o">.</span><span class="na">subscribe</span><span class="o">(</span><span class="k">new</span> <span class="nc">LogPubSub</span><span class="o">(</span><span class="s">"oneAndTwo"</span><span class="o">),</span> <span class="s">"dev.one"</span><span class="o">,</span> <span class="s">"dev.two"</span><span class="o">));</span>
<span class="n">executor</span><span class="o">.</span><span class="na">execute</span><span class="o">(()</span> <span class="o">-></span> <span class="n">jedis</span><span class="o">.</span><span class="na">psubscribe</span><span class="o">(</span><span class="k">new</span> <span class="nc">LogPubSub</span><span class="o">(</span><span class="s">"pattern"</span><span class="o">),</span> <span class="s">"dev.*"</span><span class="o">));</span></code></pre></figure>
<p>We need to run the subscribe and psubscribe on a thread since those are blocking operations.</p>
<p>In this example we are creating three clients, which we will identify as “onlyOne”, “oneAndTwo” and “pattern”, this doesn’t mean anything to redis, but it will be easier for us to keep track of whats happening.</p>
<ul>
<li>“onlyOne” is subscribed to channel “dev.one”.</li>
<li>“oneAndTwo” is subscribed to channels “dev.one” and “dev.two”.</li>
<li>“pattern” is subscribed to the pattern “dev.*”.</li>
</ul>
<p>With this we could send messages using publish on our <a href="https://redis.io/docs/stack/insight/">RedisInsight CLI</a> which should be running on http://localhost:8001/redis-stack/browser if we installed the <a href="https://redis.io/docs/stack/get-started/install/docker/">redis-stack</a>.</p>
<p>But we will also send messages using jedis.</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="nc">String</span> <span class="n">message</span> <span class="o">=</span> <span class="s">""</span><span class="o">;</span>
<span class="k">try</span> <span class="o">(</span><span class="nc">BufferedReader</span> <span class="n">br</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">BufferedReader</span><span class="o">(</span><span class="k">new</span> <span class="nc">InputStreamReader</span><span class="o">(</span><span class="nc">System</span><span class="o">.</span><span class="na">in</span><span class="o">)))</span> <span class="o">{</span>
<span class="k">do</span> <span class="o">{</span>
<span class="n">message</span> <span class="o">=</span> <span class="n">br</span><span class="o">.</span><span class="na">readLine</span><span class="o">();</span>
<span class="kt">int</span> <span class="n">firstSpace</span> <span class="o">=</span> <span class="n">message</span><span class="o">.</span><span class="na">indexOf</span><span class="o">(</span><span class="sc">' '</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">firstSpace</span> <span class="o">></span> <span class="mi">1</span><span class="o">)</span> <span class="o">{</span>
<span class="n">jedis</span><span class="o">.</span><span class="na">publish</span><span class="o">(</span><span class="n">message</span><span class="o">.</span><span class="na">substring</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="n">firstSpace</span><span class="o">),</span> <span class="n">message</span><span class="o">.</span><span class="na">substring</span><span class="o">(</span><span class="n">firstSpace</span> <span class="o">+</span> <span class="mi">1</span><span class="o">));</span>
<span class="o">}</span>
<span class="o">}</span> <span class="k">while</span> <span class="o">(!</span><span class="s">"close"</span><span class="o">.</span><span class="na">equals</span><span class="o">(</span><span class="n">message</span><span class="o">));</span>
<span class="n">jedis</span><span class="o">.</span><span class="na">close</span><span class="o">();</span>
<span class="nc">System</span><span class="o">.</span><span class="na">exit</span><span class="o">(</span><span class="mi">0</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="k">throw</span> <span class="k">new</span> <span class="nf">RuntimeException</span><span class="o">(</span><span class="n">e</span><span class="o">);</span>
<span class="o">}</span></code></pre></figure>
<p>For building the code run <code class="language-plaintext highlighter-rouge">mvn package</code> and a far jar will be generated on target and then you can run it like so <code class="language-plaintext highlighter-rouge">java -jar RedisPubSub-1.0.jar</code>.</p>
<p>Example run:</p>
<figure class="highlight"><pre><code class="language-shell" data-lang="shell">... target % java <span class="nt">-jar</span> RedisPubSub-1.0.jar
SLF4J: Failed to load class <span class="s2">"org.slf4j.impl.StaticLoggerBinder"</span><span class="nb">.</span>
SLF4J: Defaulting to no-operation <span class="o">(</span>NOP<span class="o">)</span> logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder <span class="k">for </span>further details.
name: pattern method: onPSubscribe patten: dev.<span class="k">*</span> subscribedChannels: 1
name: oneAndTwo method: onSubscribe channel: dev.one subscribedChannels: 1
name: oneAndTwo method: onSubscribe channel: dev.two subscribedChannels: 2
dev.one hello
name: pattern method: onPMessage pattern: dev.<span class="k">*</span> channel: dev.one message: hello
name: oneAndTwo method: onMessage channel: dev.one message: hello
dev.five hello to you
name: pattern method: onPMessage pattern: dev.<span class="k">*</span> channel: dev.five message: hello to you
dev.two also to you
name: pattern method: onPMessage pattern: dev.<span class="k">*</span> channel: dev.two message: also to you
name: oneAndTwo method: onMessage channel: dev.two message: also to you
dev.six <span class="nb">exit
</span>name: pattern method: onPMessage pattern: dev.<span class="k">*</span> channel: dev.six message: <span class="nb">exit
</span>name: pattern method: onPUnsubscribe patten: dev.<span class="k">*</span> subscribedChannels: 0
dev.two <span class="nb">exit
</span>name: oneAndTwo method: onMessage channel: dev.two message: <span class="nb">exit
</span>name: oneAndTwo method: onUnsubscribe channel: dev.two subscribedChannels: 1
dev.one ping say my name
name: oneAndTwo method: onMessage channel: dev.one message: ping say my name
name: oneAndTwo method: onPong message: say my name
dev.two are you alive?
dev.five no one is listening here
dev.one this one is alive
name: oneAndTwo method: onMessage channel: dev.one message: this one is alive
dev.one <span class="nb">exit
</span>name: oneAndTwo method: onMessage channel: dev.one message: <span class="nb">exit
</span>name: oneAndTwo method: onUnsubscribe channel: dev.one subscribedChannels: 0
dev.one not anymore
close
... target %</code></pre></figure>
<p>Download the complete code for this here: <a href="https://github.com/jsedano/examples/tree/main/redis-pub-sub">Java Redis pub/sub example</a>.</p>juan sedanoThis is a Redis pub/sub example written in Java using Jedis.Redis 20222022-09-17T06:00:00+00:002022-09-17T06:00:00+00:00https://jsedano.dev/redis/2022/09/17/redis-2022<p>What is Redis (Remote Dictionary Server) on 2022. What can we do with it. How to scale. How to run it on the cloud.</p>
<h2 id="what-is-redis">What is Redis?</h2>
<p>Redis is a key value store, just like a hash table. It can be used in-memory as cache and data will not be persisted or it can persist the data and be use as data storage. <a href="https://redis.io/docs/data-types/tutorial/#keys">Keys</a> can have a length to up to 512 MB.</p>
<p>It can also be used as a <a href="https://redis.com/solutions/use-cases/messaging/">message queue / message broker.</a></p>
<h2 id="supported-data-types">Supported data types</h2>
<p>Redis supports several data types</p>
<table>
<thead>
<tr>
<th>Type</th>
<th>Max Size</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><a href="https://redis.io/docs/data-types/tutorial/#strings">Strings</a></td>
<td>512 MB</td>
<td>Bytes, text, serialized objects, binary arrays</td>
</tr>
<tr>
<td><a href="https://redis.io/docs/data-types/lists/">Lists</a></td>
<td>2^32 - 1 (4,294,967,295) elements.</td>
<td>Linked list of Redis Strings</td>
</tr>
<tr>
<td><a href="https://redis.io/docs/data-types/sets/">Sets</a></td>
<td>2^32 - 1 (4,294,967,295) members.</td>
<td>Unordered unique Redis Strings</td>
</tr>
<tr>
<td><a href="https://redis.io/docs/data-types/sorted-sets/">Sorted Sets</a></td>
<td>Not specified</td>
<td>Every String has also an integer weight that you must set up</td>
</tr>
<tr>
<td><a href="https://redis.io/docs/data-types/hashes/">Hashes</a></td>
<td>4,294,967,295 (2^32 - 1) field-value pairs</td>
<td>Hash table</td>
</tr>
<tr>
<td><a href="https://redis.io/docs/data-types/streams/">Streams</a></td>
<td>Not specified</td>
<td>Used to track real time events and allows consumers and consumer groups to read them</td>
</tr>
</tbody>
</table>
<h3 id="special-use-cases-types">Special use cases types</h3>
<ul>
<li><a href="https://redis.io/docs/data-types/geospatial/">Geospatial</a></li>
</ul>
<p>Allows to store coordinates and perform operations such as finding the closest one.</p>
<ul>
<li><a href="https://redis.io/docs/data-types/geospatial/">HyperLogLog</a></li>
</ul>
<p>Not gonna even try to summarize this one, <a href="http://antirez.com/news/75">read this instead.</a></p>
<ul>
<li><a href="https://redis.io/docs/data-types/geospatial/">Bitmaps</a></li>
</ul>
<p>Use a String like a bit vector, allows performing bitwise operations.</p>
<ul>
<li><a href="https://redis.io/docs/data-types/geospatial/">Bitfields</a></li>
</ul>
<p>Allows storing, atomic read, write and read operations for 1 bit unsigned integers to 63 signed bit integers.</p>
<h2 id="additional-support">Additional support</h2>
<h3 id="redisjson"><a href="https://redis.io/docs/stack/json/">RedisJSON</a></h3>
<p>Adds facilities to store json documents and adds operations to be able to access / update fields using <a href="https://goessner.net/articles/JsonPath/">JSONPath</a>.</p>
<h3 id="redisgraph"><a href="https://redis.io/docs/stack/graph/">RedisGraph</a></h3>
<p>A graph database.</p>
<h3 id="redistimeseries"><a href="https://redis.io/docs/stack/timeseries/">RedisTimeSeries</a></h3>
<p>Module that adds a time series data structure to Redis, allowing querying by start / end time.</p>
<h3 id="redisbloom"><a href="https://redis.io/docs/stack/bloom/">RedisBloom</a></h3>
<p>Probabilistic data structures.</p>
<h3 id="redisinsight"><a href="https://redis.io/docs/stack/insight/">RedisInsight</a></h3>
<p>Visual support that helps optimizing your stuff on Redis.</p>
<h2 id="message-queues-with-redis-pubsub"><a href="https://redis.io/docs/manual/pubsub/">Message queues with Redis Pub/Sub</a></h2>
<p>We can use Redis to create channels, send messages to the channels and have subscribers that recive the message.</p>
<h2 id="redis-on-the-cloud">Redis on the cloud</h2>
<h3 id="redis-cloud">redis cloud</h3>
<p>We can use a hosted service using the offer from Redis on <a href="https://redis.com/try-free/">Redis Cloud</a>.</p>
<p>Or you can install it following <a href="https://developer.redis.com/create/from-source/">guides detailed here.</a></p>
<h3 id="aws"><a href="https://aws.amazon.com/redis/">aws</a></h3>
<p>AWS only supports Redis as an in memmory database, but you could try to install it on a service like EC2 and put a separate storage to persist.</p>
<h3 id="gcp"><a href="https://cloud.google.com/memorystore/docs/redis/redis-overview">gcp</a></h3>
<p>Google cloud platform currently does not suppert persisting the data out of the box.</p>
<h3 id="azure"><a href="https://azure.microsoft.com/en-us/products/cache/">azure</a></h3>
<p>Apparently you can persist using out of the box redis services on azure, but they dont recomend it.</p>
<h2 id="scalabity">Scalabity</h2>
<p>You can scale horizontally using <a href="https://redis.io/docs/manual/scaling/">Redis Cluster</a> where you have a master that replicates the information between replicas, but it doesn’t guarantees that you are not going to lose data, if you are unlucky that a replica is randomly selected as master and then it goes down before propagating the changes, it can lose data, unless you configure it so that the master has to acknowledge having replicated the information, but then you have to accept a hit on your performance.</p>
<h2 id="security"><a href="https://redis.io/docs/manual/security/">Security</a></h2>
<p>Redis recomends that redis is only used on trusted environments where only trusted clients can access it.</p>juan sedanoWhat is Redis (Remote Dictionary Server) on 2022. What can we do with it. How to scale. How to run it on the cloud.A custom annotation to apply currying in Java2022-06-26T06:00:00+00:002022-06-26T06:00:00+00:00https://jsedano.dev/java/2022/06/26/a-custom-annotation-to-apply-currying-in-java<p>I created a custom annotation in order to apply currying to a method or constructor.</p>
<p>You can find the complete code for this here: <a href="https://github.com/jsedano/curry">curry</a>.</p>
<p>For more information on currying check this <a href="/java/2022/06/13/currying-in-java.html">post</a> and for a background
on annotations in Java check this <a href="/java/2022/06/18/java-annotations.html">one</a>.</p>
<p>First we create the annotation:</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="nd">@Retention</span><span class="o">(</span><span class="nc">RetentionPolicy</span><span class="o">.</span><span class="na">SOURCE</span><span class="o">)</span>
<span class="nd">@Target</span><span class="o">({</span><span class="nc">ElementType</span><span class="o">.</span><span class="na">METHOD</span><span class="o">,</span> <span class="nc">ElementType</span><span class="o">.</span><span class="na">CONSTRUCTOR</span><span class="o">})</span>
<span class="kd">public</span> <span class="nd">@interface</span> <span class="nc">Curry</span> <span class="o">{}</span></code></pre></figure>
<p>We only need the annotation to be processed and then discarded (we don’t need to
have it available at run time or recorded on the .class) so we use <code class="language-plaintext highlighter-rouge">@Retention(RetentionPolicy.SOURCE)</code>.</p>
<p>This annotation will only be used on methods and constructors so we set those as the Target
on <code class="language-plaintext highlighter-rouge">@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})</code>.</p>
<p>Then we create a processor for the annotation:</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="nd">@SupportedAnnotationTypes</span><span class="o">(</span><span class="s">"dev.jsedano.curry.annotation.Curry"</span><span class="o">)</span>
<span class="nd">@SupportedSourceVersion</span><span class="o">(</span><span class="nc">SourceVersion</span><span class="o">.</span><span class="na">RELEASE_17</span><span class="o">)</span>
<span class="nd">@AutoService</span><span class="o">(</span><span class="nc">Processor</span><span class="o">.</span><span class="na">class</span><span class="o">)</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">CurryProcessor</span> <span class="kd">extends</span> <span class="nc">AbstractProcessor</span> <span class="o">{</span></code></pre></figure>
<p>Using <code class="language-plaintext highlighter-rouge">@SupportedAnnotationTypes("dev.jsedano.curry.annotation.Curry")</code> we say that
this processor will only look for that particular annotation.</p>
<p><code class="language-plaintext highlighter-rouge">@SupportedSourceVersion(SourceVersion.RELEASE_17)</code> here we are saying the Java version supported.</p>
<p>The last one is pretty interesting, <code class="language-plaintext highlighter-rouge">@AutoService(Processor.class)</code> is from a Google
library called <a href="https://github.com/google/auto/tree/master/service">auto-service</a>. In order for the Java compiler to use a
processor the class needs to be declared inside the jar on the <code class="language-plaintext highlighter-rouge">META-INF/services</code>
directory on the <code class="language-plaintext highlighter-rouge">javax.annotation.processing.Processor</code> file, the auto-service library
does that for you.</p>
<p>Then we need to implement the <code class="language-plaintext highlighter-rouge">process</code> method on out custom processor.</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">process</span><span class="o">(</span><span class="nc">Set</span><span class="o"><?</span> <span class="kd">extends</span> <span class="nc">TypeElement</span><span class="o">></span> <span class="n">annotations</span><span class="o">,</span> <span class="nc">RoundEnvironment</span> <span class="n">roundEnv</span><span class="o">)</span> <span class="o">{</span></code></pre></figure>
<p>Inside our class we get the <code class="language-plaintext highlighter-rouge">processingEnv</code> object that provides us with functionality
such as <code class="language-plaintext highlighter-rouge">getMessager()</code> that we use to print a warning message on compile time when
the @Curry annotation is used on a method with 1 or more than 10 parameters:</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="n">otherMethods</span><span class="o">.</span><span class="na">stream</span><span class="o">()</span>
<span class="o">.</span><span class="na">forEach</span><span class="o">(</span>
<span class="n">e</span> <span class="o">-></span>
<span class="n">processingEnv</span>
<span class="o">.</span><span class="na">getMessager</span><span class="o">()</span>
<span class="o">.</span><span class="na">printMessage</span><span class="o">(</span>
<span class="nc">Diagnostic</span><span class="o">.</span><span class="na">Kind</span><span class="o">.</span><span class="na">MANDATORY_WARNING</span><span class="o">,</span>
<span class="s">"incorrect number of parameters, allowed only between 2 and 1O, will not generate code for this one"</span><span class="o">,</span>
<span class="n">e</span><span class="o">));</span></code></pre></figure>
<p>We also have this one <code class="language-plaintext highlighter-rouge">getFiler()</code> which allows us to create Java source files:</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="nc">JavaFileObject</span> <span class="n">builderFile</span> <span class="o">=</span> <span class="n">processingEnv</span><span class="o">.</span><span class="na">getFiler</span><span class="o">().</span><span class="na">createSourceFile</span><span class="o">(</span><span class="n">builderClassName</span><span class="o">);</span></code></pre></figure>
<p>On the <a href="https://github.com/jsedano/curry/tree/main/tests">tests</a> module of the project we declare some methods with the @Curry annotation, for example this constructor:</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="nd">@Curry</span>
<span class="kd">public</span> <span class="nf">AnnotatedClass</span><span class="o">(</span>
<span class="kt">boolean</span> <span class="n">aBoolean</span><span class="o">,</span> <span class="nc">List</span><span class="o"><</span><span class="nc">String</span><span class="o">></span> <span class="n">aStringList</span><span class="o">,</span> <span class="kt">int</span> <span class="n">aNumber</span><span class="o">,</span> <span class="kt">char</span> <span class="n">aChar</span><span class="o">,</span> <span class="kt">float</span> <span class="n">aFloat</span><span class="o">)</span> <span class="o">{</span>
<span class="k">this</span><span class="o">.</span><span class="na">aBoolean</span> <span class="o">=</span> <span class="n">aBoolean</span><span class="o">;</span>
<span class="k">this</span><span class="o">.</span><span class="na">aStringList</span> <span class="o">=</span> <span class="n">aStringList</span><span class="o">;</span>
<span class="k">this</span><span class="o">.</span><span class="na">aNumber</span> <span class="o">=</span> <span class="n">aNumber</span><span class="o">;</span>
<span class="k">this</span><span class="o">.</span><span class="na">aChar</span> <span class="o">=</span> <span class="n">aChar</span><span class="o">;</span>
<span class="k">this</span><span class="o">.</span><span class="na">aFloat</span> <span class="o">=</span> <span class="n">aFloat</span><span class="o">;</span>
<span class="o">}</span></code></pre></figure>
<p>After running <code class="language-plaintext highlighter-rouge">mvn clean verify</code> on the parent module we can see the autogenerated code under <code class="language-plaintext highlighter-rouge">target/generated-sources/annotations/dev.jsedano.curry.tests</code>:</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="kd">public</span> <span class="kd">static</span> <span class="n">java</span><span class="o">.</span><span class="na">util</span><span class="o">.</span><span class="na">function</span><span class="o">.</span><span class="na">Function</span><span class="o"><</span><span class="n">java</span><span class="o">.</span><span class="na">lang</span><span class="o">.</span><span class="na">Boolean</span><span class="o">,</span><span class="n">java</span><span class="o">.</span><span class="na">util</span><span class="o">.</span><span class="na">function</span><span class="o">.</span><span class="na">Function</span><span class="o"><</span><span class="n">java</span><span class="o">.</span><span class="na">util</span><span class="o">.</span><span class="na">List</span><span class="o"><</span><span class="n">java</span><span class="o">.</span><span class="na">lang</span><span class="o">.</span><span class="na">String</span><span class="o">>,</span><span class="n">java</span><span class="o">.</span><span class="na">util</span><span class="o">.</span><span class="na">function</span><span class="o">.</span><span class="na">Function</span><span class="o"><</span><span class="n">java</span><span class="o">.</span><span class="na">lang</span><span class="o">.</span><span class="na">Integer</span><span class="o">,</span><span class="n">java</span><span class="o">.</span><span class="na">util</span><span class="o">.</span><span class="na">function</span><span class="o">.</span><span class="na">Function</span><span class="o"><</span><span class="n">java</span><span class="o">.</span><span class="na">lang</span><span class="o">.</span><span class="na">Character</span><span class="o">,</span><span class="n">java</span><span class="o">.</span><span class="na">util</span><span class="o">.</span><span class="na">function</span><span class="o">.</span><span class="na">Function</span><span class="o"><</span><span class="n">java</span><span class="o">.</span><span class="na">lang</span><span class="o">.</span><span class="na">Float</span><span class="o">,</span><span class="n">dev</span><span class="o">.</span><span class="na">jsedano</span><span class="o">.</span><span class="na">curry</span><span class="o">.</span><span class="na">tests</span><span class="o">.</span><span class="na">AnnotatedClass</span><span class="o">>>>>></span> <span class="nf">pentaConstructor</span><span class="o">(</span><span class="n">dev</span><span class="o">.</span><span class="na">jsedano</span><span class="o">.</span><span class="na">curry</span><span class="o">.</span><span class="na">util</span><span class="o">.</span><span class="na">function</span><span class="o">.</span><span class="na">PentaFunction</span><span class="o"><</span><span class="n">java</span><span class="o">.</span><span class="na">lang</span><span class="o">.</span><span class="na">Boolean</span><span class="o">,</span><span class="n">java</span><span class="o">.</span><span class="na">util</span><span class="o">.</span><span class="na">List</span><span class="o"><</span><span class="n">java</span><span class="o">.</span><span class="na">lang</span><span class="o">.</span><span class="na">String</span><span class="o">>,</span><span class="n">java</span><span class="o">.</span><span class="na">lang</span><span class="o">.</span><span class="na">Integer</span><span class="o">,</span><span class="n">java</span><span class="o">.</span><span class="na">lang</span><span class="o">.</span><span class="na">Character</span><span class="o">,</span><span class="n">java</span><span class="o">.</span><span class="na">lang</span><span class="o">.</span><span class="na">Float</span><span class="o">,</span><span class="n">dev</span><span class="o">.</span><span class="na">jsedano</span><span class="o">.</span><span class="na">curry</span><span class="o">.</span><span class="na">tests</span><span class="o">.</span><span class="na">AnnotatedClass</span><span class="o">></span> <span class="n">function</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">v0</span><span class="o">-></span><span class="n">v1</span><span class="o">-></span><span class="n">v2</span><span class="o">-></span><span class="n">v3</span><span class="o">-></span><span class="n">v4</span><span class="o">-></span> <span class="n">function</span><span class="o">.</span><span class="na">apply</span><span class="o">(</span><span class="n">v0</span><span class="o">,</span><span class="n">v1</span><span class="o">,</span><span class="n">v2</span><span class="o">,</span><span class="n">v3</span><span class="o">,</span><span class="n">v4</span><span class="o">);</span>
<span class="o">}</span></code></pre></figure>
<p>It is not pretty looking, but we can use it to then curry the five parameter constructor
of the example class:</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="kt">var</span> <span class="n">pentaConstructor</span> <span class="o">=</span> <span class="nc">AnnotatedClassCurryer</span><span class="o">.</span><span class="na">pentaConstructor</span><span class="o">(</span><span class="nl">AnnotatedClass:</span><span class="o">:</span><span class="k">new</span><span class="o">);</span></code></pre></figure>
<p>You can see another example <a href="https://github.com/jsedano/examples/blob/main/curry-examples/src/main/java/dev/jsedano/curry/examples/WgetVersion2.java">here</a>, but if you want to compile it
you need to do <code class="language-plaintext highlighter-rouge">mvn clean install</code> on the curryer module of <a href="https://github.com/jsedano/curry">curry</a>.</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="nd">@Curry</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="nc">String</span> <span class="nf">wget</span><span class="o">(</span>
<span class="kt">int</span> <span class="n">connectionTimeout</span><span class="o">,</span>
<span class="kt">int</span> <span class="n">readTimeout</span><span class="o">,</span>
<span class="kt">boolean</span> <span class="n">followRedirects</span><span class="o">,</span>
<span class="nc">String</span> <span class="n">requestMethod</span><span class="o">,</span>
<span class="nc">String</span> <span class="n">address</span><span class="o">)</span> <span class="o">{</span>
<span class="k">try</span> <span class="o">{</span>
<span class="no">URL</span> <span class="n">url</span> <span class="o">=</span> <span class="k">new</span> <span class="no">URL</span><span class="o">(</span><span class="n">address</span><span class="o">);</span>
<span class="nc">HttpURLConnection</span> <span class="n">con</span> <span class="o">=</span> <span class="o">(</span><span class="nc">HttpURLConnection</span><span class="o">)</span> <span class="n">url</span><span class="o">.</span><span class="na">openConnection</span><span class="o">();</span>
<span class="n">con</span><span class="o">.</span><span class="na">setRequestMethod</span><span class="o">(</span><span class="n">requestMethod</span><span class="o">);</span>
<span class="n">con</span><span class="o">.</span><span class="na">setConnectTimeout</span><span class="o">(</span><span class="n">connectionTimeout</span><span class="o">);</span>
<span class="n">con</span><span class="o">.</span><span class="na">setReadTimeout</span><span class="o">(</span><span class="n">readTimeout</span><span class="o">);</span>
<span class="n">con</span><span class="o">.</span><span class="na">setInstanceFollowRedirects</span><span class="o">(</span><span class="n">followRedirects</span><span class="o">);</span>
<span class="nc">BufferedReader</span> <span class="n">in</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">BufferedReader</span><span class="o">(</span><span class="k">new</span> <span class="nc">InputStreamReader</span><span class="o">(</span><span class="n">con</span><span class="o">.</span><span class="na">getInputStream</span><span class="o">()));</span>
<span class="nc">String</span> <span class="n">inputLine</span><span class="o">;</span>
<span class="nc">StringBuffer</span> <span class="n">content</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">StringBuffer</span><span class="o">();</span>
<span class="k">while</span> <span class="o">((</span><span class="n">inputLine</span> <span class="o">=</span> <span class="n">in</span><span class="o">.</span><span class="na">readLine</span><span class="o">())</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="n">content</span><span class="o">.</span><span class="na">append</span><span class="o">(</span><span class="n">inputLine</span><span class="o">);</span>
<span class="o">}</span>
<span class="n">in</span><span class="o">.</span><span class="na">close</span><span class="o">();</span>
<span class="k">return</span> <span class="n">address</span> <span class="o">+</span> <span class="s">" "</span> <span class="o">+</span> <span class="n">content</span><span class="o">.</span><span class="na">toString</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="nc">StringWriter</span> <span class="n">sw</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">StringWriter</span><span class="o">();</span>
<span class="nc">PrintWriter</span> <span class="n">pw</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">PrintWriter</span><span class="o">(</span><span class="n">sw</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="n">pw</span><span class="o">);</span>
<span class="nc">String</span> <span class="n">stackTrace</span> <span class="o">=</span> <span class="n">sw</span><span class="o">.</span><span class="na">toString</span><span class="o">();</span>
<span class="k">return</span> <span class="n">address</span> <span class="o">+</span> <span class="s">" "</span> <span class="o">+</span> <span class="n">stackTrace</span><span class="o">.</span><span class="na">substring</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="n">stackTrace</span><span class="o">.</span><span class="na">indexOf</span><span class="o">(</span><span class="s">"\n"</span><span class="o">));</span>
<span class="o">}</span>
<span class="o">}</span></code></pre></figure>
<p>Then we can set the values we need in a curried way and use it:</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">main</span><span class="o">(</span><span class="nc">String</span><span class="o">[]</span> <span class="n">args</span><span class="o">)</span> <span class="o">{</span>
<span class="kt">var</span> <span class="n">get</span> <span class="o">=</span>
<span class="nc">WgetVersion2Curryer</span><span class="o">.</span><span class="na">wget</span><span class="o">(</span><span class="nl">WgetVersion2:</span><span class="o">:</span><span class="n">wget</span><span class="o">)</span>
<span class="o">.</span><span class="na">apply</span><span class="o">(</span><span class="mi">100</span><span class="o">)</span>
<span class="o">.</span><span class="na">apply</span><span class="o">(</span><span class="mi">100</span><span class="o">)</span>
<span class="o">.</span><span class="na">apply</span><span class="o">(</span><span class="kc">false</span><span class="o">)</span>
<span class="o">.</span><span class="na">apply</span><span class="o">(</span><span class="s">"GET"</span><span class="o">);</span>
<span class="nc">List</span><span class="o">.</span><span class="na">of</span><span class="o">(</span>
<span class="s">"https://www.google.com"</span><span class="o">,</span>
<span class="s">"https://www.wikipedia.org"</span><span class="o">,</span>
<span class="s">"asdf"</span><span class="o">,</span>
<span class="s">"https://docs.oracle.com/javase/10/docs/api/java/net/package-summary.html"</span><span class="o">,</span>
<span class="s">"https://jsedano.dev"</span><span class="o">,</span>
<span class="s">"https://raw.githubusercontent.com/center-key/clabe-validator/main/clabe.ts"</span><span class="o">)</span>
<span class="o">.</span><span class="na">parallelStream</span><span class="o">()</span>
<span class="o">.</span><span class="na">map</span><span class="o">(</span><span class="n">get</span><span class="o">)</span>
<span class="o">.</span><span class="na">forEach</span><span class="o">(</span><span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">::</span><span class="n">println</span><span class="o">);</span>
<span class="o">}</span></code></pre></figure>
<p>Download the complete code from this post here: <a href="https://github.com/jsedano/curry">curry</a>.</p>juan sedanoI created a custom annotation in order to apply currying to a method or constructor.Java @Annotations2022-06-18T06:00:00+00:002022-06-18T06:00:00+00:00https://jsedano.dev/java/2022/06/18/java-annotations<p>If you have been using Java for about a week (probably even less) chances are you have already seen some annotations.
Let’s review some stuff about them.</p>
<p>As explained on <a href="[https://docs.oracle.com/javase/tutorial/java/annotations/]">https://docs.oracle.com/javase/tutorial/java/annotations/</a> we can use annotations to:</p>
<ul>
<li><strong>Give information to the compiler</strong>: so we can detect errors or even suppress warnings.</li>
<li><strong>Compile-time and deployment-time processing</strong>: we can generate code, xml files and so on.</li>
<li><strong>Runtime processing</strong>: some annotations can be reviewed at runtime (using reflection).</li>
</ul>
<p>Annotations can be used anywhere you use a type.</p>
<p>One interesting fact is that annotations can potentially generate code, but they <strong>can not modify it</strong>.
If you use tools like <a href="[https://projectlombok.org]">lombok</a> you know that they actually modify the code, but they usually achieve this by
accessing internal libraries.</p>
<p>Annotations are defined with the <strong>@interface</strong> keyword like so:</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="kd">public</span> <span class="nd">@interface</span> <span class="nc">Version</span> <span class="o">{</span>
<span class="kt">int</span> <span class="nf">mayor</span><span class="o">();</span>
<span class="kt">int</span> <span class="nf">minor</span><span class="o">();</span>
<span class="o">}</span></code></pre></figure>
<p>They can receive any primitive types, enums, other annotations and arrays of those previously mentioned. Let’s define an enum:</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="kd">public</span> <span class="kd">enum</span> <span class="nc">Usage</span> <span class="o">{</span>
<span class="no">UTILITY</span><span class="o">,</span>
<span class="no">DTO</span><span class="o">,</span>
<span class="no">DAO</span><span class="o">,</span>
<span class="no">SERVICE</span>
<span class="o">}</span></code></pre></figure>
<p>Then let’s create another annotation:</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="kd">public</span> <span class="nd">@interface</span> <span class="nc">Info</span> <span class="o">{</span>
<span class="nc">String</span><span class="o">[]</span> <span class="nf">authors</span><span class="o">();</span>
<span class="nc">Usage</span> <span class="nf">usage</span><span class="o">();</span>
<span class="nc">Version</span> <span class="nf">version</span><span class="o">();</span>
<span class="o">}</span></code></pre></figure>
<p>Now we use it:</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="nd">@Info</span><span class="o">(</span>
<span class="n">authors</span> <span class="o">=</span> <span class="o">{</span><span class="s">"jsedano"</span><span class="o">,</span> <span class="s">"weirderror"</span><span class="o">},</span>
<span class="n">usage</span> <span class="o">=</span> <span class="nc">Usage</span><span class="o">.</span><span class="na">UTILITY</span><span class="o">,</span>
<span class="n">version</span> <span class="o">=</span> <span class="nd">@Version</span><span class="o">(</span><span class="n">mayor</span> <span class="o">=</span> <span class="mi">1</span><span class="o">,</span> <span class="n">minor</span> <span class="o">=</span> <span class="mi">0</span><span class="o">))</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">VeryUtil</span> <span class="o">{}</span></code></pre></figure>
<p>You can specify if the annotation needs to be retained by the virtual machine at run time
or not; or even if they are to be discarded by the compiler. This is achieved by using a <code class="language-plaintext highlighter-rouge">meta-annotation</code>,
meta-annotations are annotations that are applied to another annotations.</p>
<p>You can also define where the annotation can be used, for example in methods, in constructors and so on.</p>
<p>Let’s look at how the <strong>@Override</strong> annotation is defined (@Override is a predefined annotation that is use to
mark methods that are using method overriding):</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="nd">@Target</span><span class="o">(</span><span class="nc">ElementType</span><span class="o">.</span><span class="na">METHOD</span><span class="o">)</span>
<span class="nd">@Retention</span><span class="o">(</span><span class="nc">RetentionPolicy</span><span class="o">.</span><span class="na">SOURCE</span><span class="o">)</span>
<span class="kd">public</span> <span class="nd">@interface</span> <span class="nc">Override</span> <span class="o">{</span>
<span class="o">}</span></code></pre></figure>
<p>As you can see the meta-annotation <strong>@Target</strong> is used to say that this particular annotation can only be used
above a method declaration and the <strong>@Retention</strong> annotation is saying that this annotation will not be recorded in
the class file and will not be available at runtime.</p>
<p>In order to actually define functionality for an annotation type we need to implement an <a href="/java/2022/06/26/a-custom-annotation-to-apply-currying-in-java.html">AbstractProcessor</a>.</p>juan sedanoIf you have been using Java for about a week (probably even less) chances are you have already seen some annotations. Let’s review some stuff about them.Currying in Java2022-06-13T06:00:00+00:002022-06-13T06:00:00+00:00https://jsedano.dev/java/2022/06/13/currying-in-java<p>Let’s see some examples of how to achieve currying in Java.</p>
<p>You can find the complete code for this here: <a href="https://github.com/jsedano/examples/blob/main/java-snippets/curry_example.jsh">curry_example.jsh</a>.</p>
<p>Currying is taking a function with <code class="language-plaintext highlighter-rouge">n</code> parameters and returning a function with one parameter that returns a function with one parameter until you reach the <code class="language-plaintext highlighter-rouge">n</code> parameters of the original function and then you get the result.</p>
<p>The following method gets the curried version of a method with the signature:</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="kt">int</span> <span class="nf">methodName</span><span class="o">(</span><span class="kt">int</span> <span class="n">a</span><span class="o">,</span> <span class="kt">int</span> <span class="n">b</span><span class="o">)</span></code></pre></figure>
<p>And returns the curried version:</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="kd">public</span> <span class="kd">static</span> <span class="nc">Function</span><span class="o"><</span><span class="nc">Integer</span><span class="o">,</span> <span class="nc">Function</span><span class="o"><</span><span class="nc">Integer</span><span class="o">,</span> <span class="nc">Integer</span><span class="o">>></span> <span class="nf">toCurry</span><span class="o">(</span>
<span class="nc">BiFunction</span><span class="o"><</span><span class="nc">Integer</span><span class="o">,</span> <span class="nc">Integer</span><span class="o">,</span> <span class="nc">Integer</span><span class="o">></span> <span class="n">function</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">v</span> <span class="o">-></span> <span class="n">v1</span> <span class="o">-></span> <span class="n">function</span><span class="o">.</span><span class="na">apply</span><span class="o">(</span><span class="n">v</span><span class="o">,</span> <span class="n">v1</span><span class="o">);</span>
<span class="o">}</span></code></pre></figure>
<p>Then we can use it to get curried versions of such methods:</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="kt">var</span> <span class="n">curriedAdd</span> <span class="o">=</span> <span class="n">toCurry</span><span class="o">(</span><span class="nl">Math:</span><span class="o">:</span><span class="n">addExact</span><span class="o">);</span>
<span class="kt">var</span> <span class="n">curriedMultiply</span> <span class="o">=</span> <span class="n">toCurry</span><span class="o">(</span><span class="nl">Math:</span><span class="o">:</span><span class="n">multiplyExact</span><span class="o">);</span></code></pre></figure>
<p>And use them like this:</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">format</span><span class="o">(</span><span class="s">"curriedAdd(2)(10): %d\n"</span><span class="o">,</span><span class="n">curriedAdd</span><span class="o">.</span><span class="na">apply</span><span class="o">(</span><span class="mi">2</span><span class="o">).</span><span class="na">apply</span><span class="o">(</span><span class="mi">10</span><span class="o">));</span>
<span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">format</span><span class="o">(</span><span class="s">"curriedMultiply(2)(10): %d\n"</span><span class="o">,</span><span class="n">curriedMultiply</span><span class="o">.</span><span class="na">apply</span><span class="o">(</span><span class="mi">2</span><span class="o">).</span><span class="na">apply</span><span class="o">(</span><span class="mi">10</span><span class="o">));</span></code></pre></figure>
<p>In the following example we use the curried versions to first add 1 and then multiply by 2 all the elements of a stream</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="kt">var</span> <span class="n">add1</span> <span class="o">=</span> <span class="n">toCurry</span><span class="o">(</span><span class="nl">Math:</span><span class="o">:</span><span class="n">addExact</span><span class="o">).</span><span class="na">apply</span><span class="o">(</span><span class="mi">1</span><span class="o">);</span>
<span class="kt">var</span> <span class="n">multiplyBy2</span> <span class="o">=</span> <span class="n">toCurry</span><span class="o">(</span><span class="nl">Math:</span><span class="o">:</span><span class="n">multiplyExact</span><span class="o">).</span><span class="na">apply</span><span class="o">(</span><span class="mi">2</span><span class="o">);</span>
<span class="nc">List</span><span class="o">.</span><span class="na">of</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="mi">1</span><span class="o">,</span> <span class="mi">2</span><span class="o">,</span> <span class="mi">3</span><span class="o">,</span> <span class="mi">4</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="n">add1</span><span class="o">).</span><span class="na">map</span><span class="o">(</span><span class="n">multiplyBy2</span><span class="o">).</span><span class="na">forEach</span><span class="o">(</span><span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">::</span><span class="n">println</span><span class="o">);</span></code></pre></figure>
<p>We can use currying as a form of <code class="language-plaintext highlighter-rouge">partial application</code>, imagine we have the following method:</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="kd">public</span> <span class="kd">static</span> <span class="nc">String</span> <span class="nf">wget</span><span class="o">(</span>
<span class="kt">int</span> <span class="n">connectionTimeout</span><span class="o">,</span>
<span class="kt">int</span> <span class="n">readTimeout</span><span class="o">,</span>
<span class="kt">boolean</span> <span class="n">followRedirects</span><span class="o">,</span>
<span class="nc">String</span> <span class="n">requestMethod</span><span class="o">,</span>
<span class="nc">String</span> <span class="n">address</span><span class="o">)</span> <span class="o">{</span>
<span class="k">try</span> <span class="o">{</span>
<span class="no">URL</span> <span class="n">url</span> <span class="o">=</span> <span class="k">new</span> <span class="no">URL</span><span class="o">(</span><span class="n">address</span><span class="o">);</span>
<span class="nc">HttpURLConnection</span> <span class="n">con</span> <span class="o">=</span> <span class="o">(</span><span class="nc">HttpURLConnection</span><span class="o">)</span> <span class="n">url</span><span class="o">.</span><span class="na">openConnection</span><span class="o">();</span>
<span class="n">con</span><span class="o">.</span><span class="na">setRequestMethod</span><span class="o">(</span><span class="n">requestMethod</span><span class="o">);</span>
<span class="n">con</span><span class="o">.</span><span class="na">setConnectTimeout</span><span class="o">(</span><span class="n">connectionTimeout</span><span class="o">);</span>
<span class="n">con</span><span class="o">.</span><span class="na">setReadTimeout</span><span class="o">(</span><span class="n">readTimeout</span><span class="o">);</span>
<span class="n">con</span><span class="o">.</span><span class="na">setInstanceFollowRedirects</span><span class="o">(</span><span class="n">followRedirects</span><span class="o">);</span>
<span class="k">return</span> <span class="n">address</span> <span class="o">+</span> <span class="s">" "</span> <span class="o">+</span> <span class="n">con</span><span class="o">.</span><span class="na">getResponseCode</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="nc">StringWriter</span> <span class="n">sw</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">StringWriter</span><span class="o">();</span>
<span class="nc">PrintWriter</span> <span class="n">pw</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">PrintWriter</span><span class="o">(</span><span class="n">sw</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="n">pw</span><span class="o">);</span>
<span class="nc">String</span> <span class="n">stackTrace</span> <span class="o">=</span> <span class="n">sw</span><span class="o">.</span><span class="na">toString</span><span class="o">();</span>
<span class="k">return</span> <span class="n">address</span> <span class="o">+</span> <span class="s">" "</span> <span class="o">+</span> <span class="n">stackTrace</span><span class="o">.</span><span class="na">substring</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="n">stackTrace</span><span class="o">.</span><span class="na">indexOf</span><span class="o">(</span><span class="s">"\n"</span><span class="o">));</span>
<span class="o">}</span>
<span class="o">}</span></code></pre></figure>
<p>This method returns the <code class="language-plaintext highlighter-rouge">http status</code> or part of the exception if any was thrown.</p>
<p>If we use it like that we would have to be setting all the parameters everytime we want to use the function, but if we have a curried version:</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="kd">public</span> <span class="kd">static</span> <span class="nc">Function</span><span class="o"><</span><span class="nc">Integer</span><span class="o">,</span> <span class="nc">Function</span><span class="o"><</span><span class="nc">Boolean</span><span class="o">,</span> <span class="nc">Function</span><span class="o"><</span><span class="nc">String</span><span class="o">,</span> <span class="nc">Function</span><span class="o"><</span><span class="nc">String</span><span class="o">,</span> <span class="nc">String</span><span class="o">>>>></span>
<span class="nf">cwget</span><span class="o">(</span><span class="kt">int</span> <span class="n">v</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">v1</span> <span class="o">-></span> <span class="n">v2</span> <span class="o">-></span> <span class="n">v3</span> <span class="o">-></span> <span class="n">v4</span> <span class="o">-></span> <span class="n">wget</span><span class="o">(</span><span class="n">v</span><span class="o">,</span> <span class="n">v1</span><span class="o">,</span> <span class="n">v2</span><span class="o">,</span> <span class="n">v3</span><span class="o">,</span> <span class="n">v4</span><span class="o">);</span>
<span class="o">}</span></code></pre></figure>
<p>We could then set the parameters we have:</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="kt">var</span> <span class="n">get</span> <span class="o">=</span> <span class="n">cwget</span><span class="o">(</span><span class="mi">100</span><span class="o">).</span><span class="na">apply</span><span class="o">(</span><span class="mi">100</span><span class="o">).</span><span class="na">apply</span><span class="o">(</span><span class="kc">false</span><span class="o">).</span><span class="na">apply</span><span class="o">(</span><span class="s">"GET"</span><span class="o">);</span></code></pre></figure>
<p>And then just fill the renaming parameter when using the function:</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="nc">List</span><span class="o">.</span><span class="na">of</span><span class="o">(</span>
<span class="s">"https://www.google.com"</span><span class="o">,</span>
<span class="s">"https://www.wikipedia.org"</span><span class="o">,</span>
<span class="s">"asdf"</span><span class="o">,</span>
<span class="s">"https://docs.oracle.com/javase/10/docs/api/java/net/package-summary.html"</span><span class="o">,</span>
<span class="s">"https://jsedano.dev"</span><span class="o">,</span>
<span class="s">"https://raw.githubusercontent.com/center-key/clabe-validator/main/clabe.ts"</span><span class="o">)</span>
<span class="o">.</span><span class="na">parallelStream</span><span class="o">()</span>
<span class="o">.</span><span class="na">map</span><span class="o">(</span><span class="n">get</span><span class="o">)</span>
<span class="o">.</span><span class="na">forEach</span><span class="o">(</span><span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">::</span><span class="n">println</span><span class="o">);</span></code></pre></figure>
<p>Download the complete code from this post here: <a href="https://github.com/jsedano/examples/blob/main/java-snippets/curry_example.jsh">curry_example.jsh</a>.</p>juan sedanoLet’s see some examples of how to achieve currying in Java.Remove duplicates in unordered array with Java using streams2022-05-28T06:00:00+00:002022-05-28T06:00:00+00:00https://jsedano.dev/java/2022/05/28/remove-duplicates-in-unordered-array<p>Heres how to remove duplicates from an unordered primitive int array on Java using streams.</p>
<p>You can find the complete code for this here: <a href="https://github.com/jsedano/examples/blob/main/java-snippets/remove_dupes_unordered_the_smart_way.jsh">remove_dupes_unordered_the_smart_way.jsh</a>.</p>
<p>Consider the following straight forward problem, you receive a primitive int array and you need to return a new array only containing the unique elements.</p>
<p>Because we are using <code class="language-plaintext highlighter-rouge">streams</code> since 2014 and we know that a <code class="language-plaintext highlighter-rouge">Set</code> does not accept duplicates, we only need to collect the array into a set and back into an array.</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="kt">int</span><span class="o">[]</span> <span class="nf">removeDupes</span><span class="o">(</span><span class="kt">int</span> <span class="n">arr</span><span class="o">[])</span> <span class="o">{</span>
<span class="k">return</span> <span class="nc">Arrays</span><span class="o">.</span><span class="na">stream</span><span class="o">(</span><span class="n">arr</span><span class="o">)</span>
<span class="o">.</span><span class="na">boxed</span><span class="o">()</span>
<span class="o">.</span><span class="na">collect</span><span class="o">(</span><span class="nc">Collectors</span><span class="o">.</span><span class="na">toSet</span><span class="o">()).</span><span class="na">stream</span><span class="o">()</span>
<span class="o">.</span><span class="na">mapToInt</span><span class="o">(</span><span class="nl">Integer:</span><span class="o">:</span><span class="n">intValue</span><span class="o">).</span><span class="na">toArray</span><span class="o">();</span>
<span class="o">}</span></code></pre></figure>
<p>The <code class="language-plaintext highlighter-rouge">boxed</code> method just returns an Integer stream instead of a primitive one.</p>
<p>Download the complete code from this post here: <a href="https://github.com/jsedano/examples/blob/main/java-snippets/remove_dupes_unordered_the_smart_way.jsh">remove_dupes_unordered_the_smart_way.jsh</a>.</p>juan sedanoHeres how to remove duplicates from an unordered primitive int array on Java using streams.Remove duplicates in ordered array Java2021-07-05T06:00:00+00:002021-07-05T06:00:00+00:00https://jsedano.dev/java/2021/07/05/remove-duplicates-in-ordered-array<p>Heres how to remove duplicates from an ordered primitive int array on Java.</p>
<p>You can find the complete code for this here: <a href="https://github.com/jsedano/examples/blob/main/java-snippets/remove_dupes.jsh">remove_dupes.jsh</a>.</p>
<p>Consider the following problem, you have to remove the duplicates from an ordered integer array <code class="language-plaintext highlighter-rouge">in place</code>.
Since you cant actually change the length of a primitive array in java without declaring a new one, you will return the new length the array would have without the duplicates.</p>
<p>In order to solve this in O(n) time and O(1) space we are going to use a <code class="language-plaintext highlighter-rouge">two pointer technique</code>.
We will have <code class="language-plaintext highlighter-rouge">j</code> that will increase by one in every iteration and <code class="language-plaintext highlighter-rouge">i</code> which will increase only if its different from the value which j points to, ignoring every duplicate found.</p>
<p>This doesn’t account for a null, or less than a lenght 2 array (in which case we could start j at 0).</p>
<p>The pre-increment could be less readable but just remember that <code class="language-plaintext highlighter-rouge">++variable</code> means we are increasing first and then using the variable.</p>
<figure class="highlight"><pre><code class="language-java" data-lang="java"><span class="kt">int</span> <span class="nf">removeDupes</span><span class="o">(</span><span class="kt">int</span> <span class="n">arr</span><span class="o">[])</span> <span class="o">{</span>
<span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span>
<span class="k">for</span><span class="o">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">1</span><span class="o">;</span> <span class="n">j</span> <span class="o"><</span> <span class="n">arr</span><span class="o">.</span><span class="na">length</span><span class="o">;</span> <span class="n">j</span><span class="o">++)</span> <span class="o">{</span>
<span class="k">if</span><span class="o">(</span><span class="n">arr</span><span class="o">[</span><span class="n">i</span><span class="o">]</span> <span class="o">!=</span> <span class="n">arr</span><span class="o">[</span><span class="n">j</span><span class="o">])</span> <span class="o">{</span>
<span class="n">arr</span><span class="o">[++</span><span class="n">i</span><span class="o">]</span> <span class="o">=</span> <span class="n">arr</span><span class="o">[</span><span class="n">j</span><span class="o">];</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="k">return</span> <span class="o">++</span><span class="n">i</span><span class="o">;</span>
<span class="o">}</span></code></pre></figure>
<p>Download the complete code from this post here: <a href="https://github.com/jsedano/examples/blob/main/java-snippets/remove_dupes.jsh">remove_dupes.jsh</a>.</p>juan sedanoHeres how to remove duplicates from an ordered primitive int array on Java.Quick test2021-06-21T06:00:00+00:002021-06-21T06:00:00+00:00https://jsedano.dev/random/2021/06/21/quick-test<p>Juat checking if I can post directly from GitHub.</p>
<p>I guess its possible.</p>juan sedanoJuat checking if I can post directly from GitHub.