<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Committed Software</title>
    <description>The latest articles on DEV Community by Committed Software (@committedsw).</description>
    <link>https://dev.to/committedsw</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F107678%2F24a11ff1-9f60-4bb1-8cbf-0f97df86ac3e.jpg</url>
      <title>DEV Community: Committed Software</title>
      <link>https://dev.to/committedsw</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/committedsw"/>
    <language>en</language>
    <item>
      <title>Storybook Docs First Page</title>
      <dc:creator>Committed Software</dc:creator>
      <pubDate>Mon, 14 Oct 2019 00:00:00 +0000</pubDate>
      <link>https://dev.to/committedsw/storybook-docs-first-page-1ick</link>
      <guid>https://dev.to/committedsw/storybook-docs-first-page-1ick</guid>
      <description>&lt;p&gt;&lt;a href="///static/539f5c8478124e59686bba8183047688/0309e/storybook.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qq6mfMiy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://committed.software/static/539f5c8478124e59686bba8183047688/a8200/storybook.png" alt="storybook" title="storybook"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Storybook has been a great tool for helping the development and testing of our components. Now with the addition of the &lt;a href="https://medium.com/storybookjs/storybook-docspage-e185bc3622bf"&gt;DocsPage&lt;/a&gt; it will likely become our default platform for documentation and communication of our visual design libraries.&lt;/p&gt;

&lt;p&gt;However, one problem we have found is that there is no way to declare which page the documentation should open on. You can sort the stories and the first will be displayed. You can also add a parameter to the story metadata and use that for sorting.&lt;/p&gt;

&lt;p&gt;For &lt;code&gt;.mdx&lt;/code&gt; documentation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Meta&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Components|Button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;parameters&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;or for Component Story Format&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Components|Button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Then sort the stories in your &lt;code&gt;config.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;addParameters&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@storybook/react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;addParameters&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;storySort&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;kind&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;kind&lt;/span&gt;
        &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;But after sorting your desired first page may not be the first in the ordering. To set a specific first page we create our own simple addon. As it’s small, you can put it straight into the &lt;code&gt;addons.js&lt;/code&gt; file along with any other registered addons:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;STORIES_CONFIGURED&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@storybook/core-events&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;addonAPI&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@storybook/addons&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;addonAPI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;my-organisation/firstpage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;storybookAPI&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;storybookAPI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;STORIES_CONFIGURED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;story&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;storybookAPI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getUrlState&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/story/*&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;storybookAPI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;selectStory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Kind&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;story&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This is only triggered on load when the stories are configured. Also by testing the url for &lt;code&gt;/story/*&lt;/code&gt; we do not interrupt requests for a specific story or docs page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations
&lt;/h2&gt;

&lt;p&gt;This description applies to &lt;code&gt;v5.2&lt;/code&gt; upwards, though I think similar things can be done using &lt;code&gt;sortStoriesByKind&lt;/code&gt; for earlier versions. Also, if an incorrect story URL is entered then the first page by the ordering will be used. If this is a concern you can add into the addon:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;STORIES_CONFIGURED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;STORY_MISSING&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@storybook/core-events&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;addonAPI&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@storybook/addons&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;addonAPI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;my-organisation/firstpage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;storybookAPI&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;storybookAPI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;STORIES_CONFIGURED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;story&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;storybookAPI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getUrlState&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/story/*&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;storybookAPI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;selectStory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Kind&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;story&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;storybookAPI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;STORY_MISSING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;story&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;storybookAPI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;selectStory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Kind&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;story&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



</description>
      <category>storybook</category>
      <category>javascript</category>
      <category>testing</category>
    </item>
    <item>
      <title>Speedy Spotless</title>
      <dc:creator>Committed Software</dc:creator>
      <pubDate>Thu, 03 Oct 2019 10:17:27 +0000</pubDate>
      <link>https://dev.to/committedsw/speedy-spotless-4h0h</link>
      <guid>https://dev.to/committedsw/speedy-spotless-4h0h</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/commitd/speedy-spotless"&gt;Speedy Spotless&lt;/a&gt; is a Maven plugin for easy formatting of staged changes. It is inspired by &lt;a href="https://github.com/azz/pretty-quick"&gt;pretty-quick&lt;/a&gt; but for Java.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/diffplug/spotless"&gt;Spotless&lt;/a&gt; is a tool to automatically format your code. It can format in various languages in a multitude of different ways. Regularly running an automatic code formatter like Spotless is a great way to maintain a consistent code style and to keep changes readable. It is good practice to use a &lt;a href="https://www.atlassian.com/git/tutorials/git-hooks"&gt;Git hook&lt;/a&gt; to format new code as it is being committed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/diffplug/spotless/issues/178"&gt;Existing approaches&lt;/a&gt; for formatting staged changes don't address what to do for the formatting of partially staged files. If the formatter makes changes to the file it is no longer obvious what changes to include in the commit! Speedy Spotless will format such files, but will cancel the commit, allowing the developer to decide what to do instead of doing something that the developer may not have intended.&lt;/p&gt;

&lt;p&gt;Speedy Spotless is a drop in replacement for Spotless Maven Plugin and supports the same configuration options, but also includes the new goal &lt;code&gt;speedy-spotless:staged&lt;/code&gt; to trigger the formatting staged changes and &lt;code&gt;speedy-spotless:install-hooks&lt;/code&gt; that creates &amp;amp; installs the Git hook to format staged changes automatically. It will even preserve any existing hooks!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/commitd/speedy-spotless"&gt;Speedy Spotless on Github&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>java</category>
      <category>formatter</category>
      <category>spotless</category>
      <category>maven</category>
    </item>
    <item>
      <title>Vaadin Flow and Reactive Spring</title>
      <dc:creator>Committed Software</dc:creator>
      <pubDate>Sun, 23 Sep 2018 00:00:00 +0000</pubDate>
      <link>https://dev.to/committedsw/vaadin-flow-and-reactive-spring-2iik</link>
      <guid>https://dev.to/committedsw/vaadin-flow-and-reactive-spring-2iik</guid>
      <description>&lt;p&gt;&lt;a href="///static/philip-swinburn-60220-unsplash-9a57445ecc294e14d46690f9f649dd95-7a1db.jpg"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Id0XykWp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://committed.software/static/philip-swinburn-60220-unsplash-9a57445ecc294e14d46690f9f649dd95-f3a32.jpg" alt="philip swinburn 60220 unsplash"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Vaadin 11 and Spring Boot 2
&lt;/h1&gt;

&lt;p&gt;A couple of week back saw the &lt;a href="https://vaadin.com/blog/vaadin-11-is-now-available-with-gradle-support-and-new-components"&gt;release of Vaadin 11&lt;/a&gt; which builds on the recent major changes to &lt;a href="https://vaadin.com/blog/vaadin-10-is-out-"&gt;Vaadin 10&lt;/a&gt;. &lt;a href="https://vaadin.com/"&gt;Vaadin&lt;/a&gt; allows Java developers to build web user interfaces in Java with Java components.&lt;/p&gt;

&lt;p&gt;As we are heavy users of Java, and specifically Spring, Vaadin is an interesting technology for us. In this blog post, we will look at the use of some of the newer functionality of Spring Boot 2 with Vaadin.&lt;/p&gt;

&lt;p&gt;This isn’t an introduction or tutorial for Vaadin, they already have some great &lt;a href="https://vaadin.com/tutorials"&gt;resources&lt;/a&gt; and &lt;a href="https://vaadin.com/docs"&gt;documentation&lt;/a&gt; for that. We’ll cover some tips (and gotchas) when using Vaadin and Spring.&lt;/p&gt;

&lt;p&gt;Everything here works with Vaadin 10, which is the LTS version, but with Vaadin now following a 3-month release cycle the majority of developers will want to keep their apps up to date.&lt;/p&gt;

&lt;h2&gt;
  
  
  Spring and Vaadin
&lt;/h2&gt;

&lt;p&gt;Vaadin 10+ plays well with &lt;a href="https://spring.io/projects/spring-boot#learn"&gt;Spring Boot 2&lt;/a&gt; and has some specific annotations which can be used within components. This is covered in a whole chapter in the &lt;a href="https://vaadin.com/docs/v10/flow/spring/tutorial-spring-basic.html"&gt;use Flow with Spring&lt;/a&gt; documentation.&lt;/p&gt;

&lt;p&gt;We would highly recommend using Vaadin alongside Spring. If you are used to Vaadin, the Spring integration is very light but Spring will provide you with a considerable amount of additional engineering support:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Database access through with support for&lt;/li&gt;
&lt;li&gt;Access to caching locally and externally&lt;/li&gt;
&lt;li&gt;Authentication, including social sign on&lt;/li&gt;
&lt;li&gt;Messaging support&lt;/li&gt;
&lt;li&gt;External configuration mechanism&lt;/li&gt;
&lt;li&gt;Executable JAR and service wrappers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In short, combining Spring and Vaadin you have a complete stack before you’ve written any code yourself.&lt;/p&gt;

&lt;p&gt;If you are starting out with Vaadin they have a &lt;a href="https://vaadin.com/start"&gt;project starter&lt;/a&gt; for Spring &lt;a href="https://vaadin.com/start/latest/project-base-spring"&gt;Project Base with Spring&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you have a paid Vaadin subscription, they also have a full stack Vaadin Spring starter too.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Reactive Spring
&lt;/h2&gt;

&lt;p&gt;Spring Framework 5 and Spring Boot 2 offer the option to use the &lt;a href="https://spring.io/blog/2016/04/19/understanding-reactive-types"&gt;reactive types&lt;/a&gt; &lt;code&gt;Flux&lt;/code&gt; and &lt;code&gt;Mono&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Reactive types are a complex topic but consider them an improved, standardised and more flexible version of Java’s &lt;code&gt;Stream&lt;/code&gt; (now reactive &lt;code&gt;Flux&lt;/code&gt;) and &lt;code&gt;Optional&lt;/code&gt; (now reactive &lt;code&gt;Mono&lt;/code&gt;). Behind the scenes, they are designed for high throughput and non-blocking operations. Reactive types are an efficient and composable way to process data in applications.&lt;/p&gt;

&lt;p&gt;Reactive types provide flexibility on which thread events are published, processed and consumed. Like many UI frameworks, Vaadin enforces strict control over which thread can update a UI component.&lt;/p&gt;

&lt;p&gt;Here we have a counter of items, we can update by clicking the refresh button:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Text text = new Text("...");
Button button = new Button("Refresh", event -&amp;gt; {
  int count = 20;
  text.setValue(count + " items")
})
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;When the button is clicked, the event callback is run &lt;em&gt;in a manner that allows UI updates&lt;/em&gt; and the text value updated.&lt;/p&gt;

&lt;p&gt;So far, so un-reactive.&lt;/p&gt;

&lt;p&gt;Suppose we have a Reactive Spring Data Repository:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// The repository
public interface PersonRepository extends ReactiveCrudRepository&amp;lt;Person, String&amp;gt; {

}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;and use it in the following way&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PersonRepository repo = ... // Typically injected by Spring

Text text = new Text("...");
Button button = new Button("Refresh", event -&amp;gt; {

  // Ask for the count
  Mono&amp;lt;Long&amp;gt; mono = repo.count();

  // WARNING: DOESN'T WORK!
  mono.subscribe(count -&amp;gt; text.setValue(count + " items"));
})
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Here &lt;code&gt;subscribe&lt;/code&gt; will call the lambda (&lt;code&gt;count -&amp;gt; text.setValue&lt;/code&gt;) is called when then count operation is finished. This will happen asynchronously - the code above is basically just wiring an ‘on complete count’ callback. It will likely happen on the non-UI thread and hence without the proper UI locking that Vaadin requires. Clicking the button will cause an exception from Vaadin.&lt;/p&gt;

&lt;p&gt;You could &lt;code&gt;mono.block()&lt;/code&gt; in order to force waiting for the count, but that loses the benefits for reactive types. You don’t really want to force your UI to wait for long-running queries.&lt;/p&gt;

&lt;p&gt;To run code on a UI thread you can use the &lt;code&gt;UI.access()&lt;/code&gt; method. You can access the UI using the &lt;code&gt;getUI()&lt;/code&gt; method on a Vaadin &lt;code&gt;Component&lt;/code&gt; which returns an &lt;code&gt;Optional&lt;/code&gt;. Thus an implementation of the above would be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PersonRepository repo = ... // Auto wired / injected by Spring

Text text = new Text("...");
Button button = new Button("Refresh", event -&amp;gt; {
  Mono&amp;lt;Long&amp;gt; mono = repo.count();

  // In effect this says:
  // - when you get the count
  // - if you can get the UI
  // - schedule a ui update
  // - in that ui update, set the text value.
  mono.subscribe(count -&amp;gt; {
    getUI().ifPresent(ui -&amp;gt; {
      ui.access(() -&amp;gt; text.setValue(count + " items"));
    });
  }
})
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;That is quite a lot of code, and quite complex to read.&lt;/p&gt;

&lt;p&gt;Taking a step back, really what we want is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When the mono returns&lt;/li&gt;
&lt;li&gt;Convert to it a set of commands (&lt;code&gt;text.setValue&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Pass the commands to UI to execute&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This can be done more neatly as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;repository.count()
    .map(count -&amp;gt; () -&amp;gt; text.setValue(count + "items"))
    .subscribe(doInUi(getUi()));

// where
public static Consumer&amp;lt;Command&amp;gt; doInUi(Optional&amp;lt;Ui&amp;gt; ui) {
  return command -&amp;gt; ui.ifPresent(u -&amp;gt; u.access(command));
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You can make this nicer with Spring, by creating a &lt;code&gt;UiSupport&lt;/code&gt; component which you can inject into your components:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Component
@UIScope
public class UiSupport {

  private final UI ui;

  public UiSupport(@Inject UI ui) {
    this.ui = ui;
  }

  public Consumer&amp;lt;Command&amp;gt; doOnUi() {
    return command -&amp;gt; updateUi(command);
  }

  public void updateUi(Command command) {
    ui.access(command);
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Notice the component is scoped to the each individual Vaadin UI (&lt;code&gt;@UiScope&lt;/code&gt;) because we will need one &lt;code&gt;UiSupport&lt;/code&gt; per Vaadin UI (ie one for each user in each tab).&lt;/p&gt;

&lt;p&gt;So our callback becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Autowired
    public MyComponent(UiSupport uiSupport) {

      Button button = new Button("Refresh", event -&amp;gt; {
          repository.count()
            .map(count -&amp;gt; () -&amp;gt; text.setValue(count + "items"))
            .subscribe(uiSupport.doOnUi());
      });
      //...
    }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Or perhaps more cleanly out of the lambdas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Autowired
    public MyComponent(UiSupport uiSupport) {
      this.uiSupport = uiSupport;

      Button button = new Button("Refresh", event -&amp;gt; refreshData());
      //...
    }

    private void refreshData() {
        repository.count()
          .map(this::setTextValue)
          .subscribe(uiSupport.doOnUi());
    }

    private Command setTextValue(long count) {
      return () -&amp;gt; text.setValue(count + "items")
    }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Reactive repositories as a Data Provider
&lt;/h2&gt;

&lt;p&gt;Vaadin use DataProviders to provide the data items for tables, etc. If you are using Spring, you’ll often want this to be generated from a Spring Data Repository.&lt;/p&gt;

&lt;p&gt;You can neatly wrap a reactive repository to a &lt;code&gt;DataProvider&lt;/code&gt; using the &lt;code&gt;fromCallbacks&lt;/code&gt; method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class ReactiveDataProvider {

  public static &amp;lt;T&amp;gt; DataProvider&amp;lt;T,?&amp;gt; fromReactiveRepository(ReactiveCrudRepository&amp;lt;T, ?&amp;gt; repository) {
    return DataProvider.fromCallbacks(
        query -&amp;gt; repository.findAll()
            // Basic sorting will work if you implement Comparable&amp;lt;T&amp;gt; on your data item (T)
            // but it's better to so this in the database using Sort
            // which is more performant and flexible
            // .sort(query.getInMemorySorting())
            .skip(query.getOffset())
            .take(query.getLimit())
            .toStream(),
        query -&amp;gt; repository.count().map(Math::toIntExact).block()
    );
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The above doesn’t use the DataProvider query, so it’s a bit more effort if you want to access a filtered result set. For a simple, but flexible, approach to filtering look at the &lt;code&gt;QueryByExampleExecutor&amp;lt;T&amp;gt;&lt;/code&gt; which provides a neat way of passing a filter based on the data item class.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;ReactiveMongoRespository&lt;/code&gt; has query by example, so we can use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class ReactiveDataProvider {

  /// ...

  public static &amp;lt;T&amp;gt; DataProvider&amp;lt;T,Example&amp;lt;T&amp;gt;&amp;gt; fromReactiveMongoRepository(ReactiveMongoRepository&amp;lt;T, ?&amp;gt; repository) {
    return DataProvider.fromFilteringCallbacks(
        query -&amp;gt; 
            findByExample(repository, query.getFilter())
            .skip(query.getOffset())
            .take(query.getLimit())
            .toStream(),
        query -&amp;gt; countByExample(repository, query.getFilter())
            .map(Math::toIntExact).block()
    );
  }

  private static &amp;lt;T&amp;gt; Flux&amp;lt;T&amp;gt; findByExample(ReactiveMongoRepository&amp;lt;T,?&amp;gt; repository, Optional&amp;lt;Example&amp;lt;T&amp;gt;&amp;gt; filter) {
    if(filter.isPresent()) {
      return repository.findAll(filter.get());
    } else {
      return repository.findAll();
    }
  }

  private static &amp;lt;T&amp;gt; Mono&amp;lt;Long&amp;gt; countByExample(ReactiveMongoRepository&amp;lt;T,?&amp;gt; repository, Optional&amp;lt;Example&amp;lt;T&amp;gt;&amp;gt; filter) {
    if(filter.isPresent()) {
      return repository.count(filter.get());
    } else {
      return repository.count();
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You can use this in your components with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dataProvider = ReactiveDataProvider.fromReactiveMongoRepository(repository);
filteredDataProvider = dataProvider.withConfigurableFilter();

// You'd likely set this in response to user input but...
filteredDataProvider.setFilter(Example.of(new Person("hello")));
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;There’s &lt;a href="https://docs.spring.io/spring-data/mongodb/docs/current/reference/html/#query-by-example"&gt;a lot more you can do&lt;/a&gt; with &lt;code&gt;Example&lt;/code&gt; using &lt;code&gt;ExampleMatcher&lt;/code&gt;s.&lt;/p&gt;

&lt;h2&gt;
  
  
  Broadcaster and Spring application
&lt;/h2&gt;

&lt;p&gt;As Vaadin code exists on the server it has access to the full state of the application. For example, all the logged in users.&lt;/p&gt;

&lt;p&gt;So functionality such as broadcast messaging or shared state is easily implemented in Vaadin. The Vaadin documentation uses a &lt;a href="https://vaadin.com/docs/v10/flow/advanced/tutorial-push-broadcaster.html"&gt;broadcast pattern&lt;/a&gt; to achieve this.&lt;/p&gt;

&lt;p&gt;In Spring, we already have nice functionality for passing events around the application using &lt;code&gt;@EventListener&lt;/code&gt;. However, it seems that you can not use this within Vaadin components, see &lt;a href="https://github.com/vaadin/spring/issues/272"&gt;Github issue 272&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In order to bridge Spring events to Vaadin we use the same broadcaster pattern - combining broadcast via the registered listeners and Spring components:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// This is a unified broadcaster outputting to Spring and (registered) Vaadin components
public abstract class AbstractBroadcaster&amp;lt;T&amp;gt; {
  private Executor executor = Executors.newSingleThreadExecutor();

  private LinkedList&amp;lt;Consumer&amp;lt;T&amp;gt;&amp;gt; listeners = new LinkedList&amp;lt;&amp;gt;();

  @Autowired
  private ApplicationEventPublisher publisher;

  public synchronized BroadcastRegistration register(Consumer&amp;lt;T&amp;gt; listener) {
    listeners.add(listener);

    return () -&amp;gt; {
      synchronized (Broadcaster.class) {
        listeners.remove(listener);
      }
    };
  }

  public synchronized void broadcast(T message) {
    // Send message to Spring components
    publisher.publishEvent(message);

    // Send message to our listeners in Vaadin
    for (Consumer&amp;lt;T&amp;gt; listener : listeners) {
      executor.execute(() -&amp;gt; listener.accept(message));
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You can then create your own broadcaster for your specific event with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Service
public class PersonChangedBroadcaster extends AbstractBroadcaster&amp;lt;PersonsChangedEvent&amp;gt; {

}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You can now register a Vaadin route to respond to the event. Notice we register with the broadcaster &lt;code&gt;onAttach&lt;/code&gt; and deregister &lt;code&gt;onDetach&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Route
@Push
public class MainView extends VerticalLayout {

  private final VaadinFlux vf;
  private final PersonRepository repository;
  private final PersonChangedBroadcaster notifier;
  private final DataProvider&amp;lt;Person,Example&amp;lt;Person&amp;gt;&amp;gt; dataProvider;
  private BroadcastRegistration notifierBroadcastRegistration;

  public MainView(VaadinFlux vf,
      @Autowired PersonRepository repository, PersonChangedBroadcaster notifier) {
    this.template = template;
    this.vf = vf;
    this.repository = repository;
    this.notifier = notifier;

    dataProvider = ReactiveDataProvider.fromReactiveMongoRepository(repository);

    // Create components here...
  }

  private void refreshData() {
    // When we are prompted refresh the data
    vf.updateUi(() -&amp;gt; dataProvider.refreshAll());
  }

  @Override
  protected void onAttach(AttachEvent attachEvent) {
    super.onAttach(attachEvent);

    // Register for events as soon as we attach
    this.notifierBroadcastRegistration = notifier.register(p -&amp;gt; this.refreshData());
  }

  @Override
  protected void onDetach(DetachEvent detachEvent) {
    super.onDetach(detachEvent);

    // When we 'detach' we no longer want events any more
    if (notifierBroadcastRegistration != null) {
      notifierBroadcastRegistration.deregister();
      notifierBroadcastRegistration = null;
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Our MainView view will automatically update (thanks to &lt;code&gt;@Push&lt;/code&gt;) whenever a &lt;code&gt;PersonChangedEvent&lt;/code&gt; is sent.&lt;/p&gt;

&lt;p&gt;A typical use case, inside Spring would be to automatically refresh all users’ UI when a data item is added or deleted (by any user). In Spring Mongo we can take advantage of the &lt;code&gt;AbstractMongoEventListener&lt;/code&gt; to listen for save and delete functions. We can then push new events into our broadcaster:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Service
public class PersonChangedListener extends AbstractMongoEventListener&amp;lt;Person&amp;gt; {

  private final PersonChangedBroadcaster notifier;

  public PersonChangedListener(ApplicationEventPublisher publisher,
      PersonChangedBroadcaster notifier) {
    this.notifier = notifier;
  }

  @Override
  public void onAfterSave(AfterSaveEvent&amp;lt;Person&amp;gt; event) {
    super.onAfterSave(event);
    notifyListeners(new PersonsChangedEvent(event.getSource()));
  }

  @Override
  public void onAfterDelete(AfterDeleteEvent&amp;lt;Person&amp;gt; event) {
    super.onAfterDelete(event);
    notifyListeners(new PersonsChangedEvent(event.getSource()));
  }

  private void notifyListeners(PersonsChangedEvent event) {
    notifier.broadcast(event);
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Using Vaadin
&lt;/h2&gt;

&lt;p&gt;If, like us, you develop your Web UI with a framework such as React, the idea of moving back to Java might seem an odd step.&lt;/p&gt;

&lt;p&gt;Where we feel Vaadin really shines is to support our backend services. These don’t have consumer user interfaces, but they do benefit from management UIs. An example might be data microservice, where we offer an API to programmatically create, list or delete data, but we’d also like to provide a management UI to allow that to be easily entered by a system manager. We might also expose other functionality via the Vaadin UI such a data export and batch import, which aren’t part of the API.&lt;/p&gt;

&lt;p&gt;For these types of application, Vaadin allows us to quickly develop a UI which:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Has a simple unified build process for a service, since all code is compiled through Maven&lt;/li&gt;
&lt;li&gt;Is deployed as part of the service itself, integrated into a single JAR&lt;/li&gt;
&lt;li&gt;Takes advantage of the common Java code base (no duplication of code or opportunity for data transfer objects to diverge)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Outside that use case, Vaadin really shines where the server state is complex and needs to be shared. The above shows how in a few lines we can update all the users on important changes in state, triggered by the database. Thanks to Spring and Reactor we have non-blocking, performant code.&lt;/p&gt;

&lt;p&gt;Photo by &lt;a href="https://unsplash.com/photos/Z0tTnl_eOIo?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Philip Swinburn&lt;/a&gt; on &lt;a href="https://unsplash.com/search/photos/reindeer?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>vaadin</category>
      <category>spring</category>
      <category>reactive</category>
    </item>
    <item>
      <title>Hack: Accessing Time Machine backups</title>
      <dc:creator>Committed Software</dc:creator>
      <pubDate>Thu, 20 Sep 2018 00:00:00 +0000</pubDate>
      <link>https://dev.to/committedsw/hack-accessing-time-machine-backups-1m7n</link>
      <guid>https://dev.to/committedsw/hack-accessing-time-machine-backups-1m7n</guid>
      <description>&lt;p&gt;&lt;a href="///static/james-newcombe-350779-unsplash-3113aff4808b7b313d5c5777f499e9ba-7a1db.jpg"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rXEU2O0j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://committed.software/static/james-newcombe-350779-unsplash-3113aff4808b7b313d5c5777f499e9ba-f3a32.jpg" alt="james newcombe 350779 unsplash"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A natural choice for macOS backup is to use Time Machine to output to an external device. To protect the data, the backup disk is encrypted and each backup is encrypted independently. That’s all standard functionality for Time Machine.&lt;/p&gt;

&lt;p&gt;Time Machine works great when you wish to recover a deleted file or overwritten file. We don’t often see the need as we working in the cloud (versioning automatically on GDrive) or using Git (which is a time machine in its own right) but the safety net is reassuring.&lt;/p&gt;

&lt;p&gt;In the last week, we had reason to access a backup but the computer in question had been reformatted for a different purpose, we couldn’t use it to access its own backup.&lt;/p&gt;

&lt;h2&gt;
  
  
  What doesn’t work
&lt;/h2&gt;

&lt;p&gt;The theory is you can access another computer’s Time Machine by &lt;strong&gt;clicking on the Time Machine icon in the menu bar&lt;/strong&gt; and then &lt;strong&gt;holding down holding Option (alt)&lt;/strong&gt;. (You can add the Time Machine icon to the menu bar using System Preferences). When you press Option &lt;em&gt;‘Enter Time Machine’&lt;/em&gt; changes to &lt;em&gt;‘Browse other backup disks…’&lt;/em&gt; which prompts for a backup disk.&lt;/p&gt;

&lt;p&gt;Sadly, selecting the other machine’s Time machine backup doesn’t seem to work for us. It always displayed our current machine’s backup. A quick search shows others have seen the same problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Disk Utility to the rescue
&lt;/h2&gt;

&lt;p&gt;Access your backup server in Finder - it’ll be listed in the &lt;code&gt;Shared&lt;/code&gt; section in the Sidebar. You can log in (with your disk encryption password) and navigate to the folder where your backups are stored.&lt;/p&gt;

&lt;p&gt;They are &lt;code&gt;.sparsebundle&lt;/code&gt; files, in recent versions of Time Machine. If you haven’t been using encryption, you can probably review them just by right-clicking and selecting &lt;em&gt;‘Show Package Contents’&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;If you are using encryption, then &lt;em&gt;‘Show Package Content’&lt;/em&gt; issues an error box, stating &lt;em&gt;‘Device not found’&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Load up &lt;strong&gt;Disk Utility&lt;/strong&gt;. Then use the menu to &lt;strong&gt;File &amp;gt; Open Disk Image&lt;/strong&gt; and navigate to the backup you want. You should enter your backup encryption password when prompted. It’ll take a moment to think, but then your backup will be mounted and accessible in Finder.&lt;/p&gt;

&lt;p&gt;The backups are organised into folders which are timestamped &lt;em&gt;‘date and time of backup’&lt;/em&gt; and their content is &lt;em&gt;‘what has changed since the last backup’&lt;/em&gt;. It is not that easy to find the latest content of a folder, but that’s the way it is. Copy the files you want out of the Backup.&lt;/p&gt;

&lt;h3&gt;
  
  
  Warnings
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Don’t change or add files&lt;/strong&gt; in the backup. It’s probably fine but you want your backup to work. This is an emergency!&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Always unmount your backup volume&lt;/strong&gt; when you are done. Otherwise, next time to try to access it you may get an error saying it’s locked.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use at your own risk!&lt;/p&gt;

&lt;p&gt;Credit: Photo by &lt;a href="https://unsplash.com/photos/Ro7Rfs4Tb_I"&gt;James Newcombe&lt;/a&gt; on &lt;a href="https://unsplash.com/?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
      <category>macos</category>
    </item>
    <item>
      <title>Using SonarQube and GitHub without losing your comments</title>
      <dc:creator>Committed Software</dc:creator>
      <pubDate>Fri, 03 Aug 2018 17:00:00 +0000</pubDate>
      <link>https://dev.to/committedsw/using-sonarqube-and-github-without-losing-your-comments-2go4</link>
      <guid>https://dev.to/committedsw/using-sonarqube-and-github-without-losing-your-comments-2go4</guid>
      <description>&lt;p&gt;&lt;a href="/static/github-stickers-cover-0282251214cc1183d9920d1b0d567d70-e17b4.jpg"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcommitted.software%2Fstatic%2Fgithub-stickers-cover-0282251214cc1183d9920d1b0d567d70-f3a32.jpg" alt="github stickers cover"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you happen to use the official sonar-github plugin to integrate Sonar into your GitHub pull requests you may have found that the plugin has a tendency to delete any comments it considers stale. This is especially annoying when the Github account used for the integration is also a member of your team, causing many valuable review comments to disappear!&lt;/p&gt;

&lt;p&gt;While there exists an existing PR to fix this precise issue, the support for this Github Sonar plugin has dried up (with Sonar moving towards a &lt;a href="https://github.com/SonarSource/sonar-github/pull/30#issuecomment-349640582" rel="noopener noreferrer"&gt;new solution for its paid-for offerings&lt;/a&gt;). For this reason, we decided to fork the sonar-github project, applying the fix for this issue. &lt;a href="https://github.com/commitd/sonar-github/releases" rel="noopener noreferrer"&gt;Releases of our fork are available here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>codequality</category>
      <category>sonarqube</category>
      <category>github</category>
    </item>
    <item>
      <title>Cypress.io - A JavaScript E2E Testing Framework</title>
      <dc:creator>Committed Software</dc:creator>
      <pubDate>Wed, 09 May 2018 23:00:00 +0000</pubDate>
      <link>https://dev.to/committedsw/cypressio---a-javascript-e2e-testing-framework-5h2d</link>
      <guid>https://dev.to/committedsw/cypressio---a-javascript-e2e-testing-framework-5h2d</guid>
      <description>&lt;p&gt;&lt;a href="/static/cypress-logo-full-48359ea995d0302b2a703171a78c801f-8f9c4.png"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcommitted.software%2Fstatic%2Fcypress-logo-full-48359ea995d0302b2a703171a78c801f-8f9c4.png" alt="cypress logo full"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;End to end (E2E) testing is a crucial part of any development cycle and until now, E2E UI testing has been primarily done using &lt;a href="https://www.seleniumhq.org/projects/webdriver/" rel="noopener noreferrer"&gt;Selenium WebDriver&lt;/a&gt;. Now though, a new testing framework, &lt;a href="https://www.cypress.io/" rel="noopener noreferrer"&gt;Cypress&lt;/a&gt;, is available. It differs from Selenium and offers several extremely useful game-changing features, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Asynchronous DOM element finding&lt;/li&gt;
&lt;li&gt;Server stubbing&lt;/li&gt;
&lt;li&gt;‘Time Travel’ debugging&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Setup
&lt;/h3&gt;

&lt;p&gt;Setup could not be simpler - Cypress is just an npm package, and so can be installed as a package and run interactively with &lt;code&gt;cypress open&lt;/code&gt;, or run in headless mode with &lt;code&gt;cypress run&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Asynchronous by design
&lt;/h3&gt;

&lt;p&gt;Anyone who has any experience writing Selenium tests will likely know the pain of synchronisation: dealing with the problem of tests running before certain elements have loaded into the DOM. Cypress solves this by using JavaScript promises. Manually writing an implicit or explicit wait, as was the case in Selenium, is no longer needed as implicit waits are effectively built in.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;describe('a sample test', () =&amp;gt; {
  it('should do stuff', () =&amp;gt; {

    cy.visit(appUrl) // Go to appUrl

    cy.get('.some-button').click() // Wait for .some-button to be present, then click on it

    cy.get('.some-other-button', ($btn) =&amp;gt; {
      // do stuff with the element $btn
    })

    cy.get('.yet-another-button', ($btn) =&amp;gt; {
      // do stuff with the element $btn
    }, {timeout: 60000}) // If Cypress doesn't find the element within 60000 ms, then error
  })
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Server stubbing
&lt;/h3&gt;

&lt;p&gt;Cypress has built-in functionality to stub/mock any backend servers linked to the UI. This has 2 major advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We can remove any dependencies on a backend by stubbing responses for every request made to the API.&lt;/li&gt;
&lt;li&gt;We can mock some responses - for example, login attempts, or 3rd party APIs that we don’t want our tests to depend on.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;describe('another sample test', () =&amp;gt; {

  beforeEach(() =&amp;gt; {
    cy.server() // Enable response stubbing
    cy.route({
      method: 'GET', // when the app sends a GET request
      url: 'http://www.some-api.com/something', // to this URL
      response: {message: 'Some mocked message'} // then return this response
    })

    cy.visit(appUrl)
  })

  // Tests...
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Time travel debugging
&lt;/h3&gt;

&lt;p&gt;Even with a trivial setup and built-in support to tackle synchronisation issues, Cypress has another gem for developers. Interactive, ‘time travel’ debugging. In a simple UI, the user can see all the steps in the tests being run and see what happened before, during, and after each step.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcommitted.software%2Fcypress-debugging-c6efb7c87295a6da1d521b32dadf9b7f.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcommitted.software%2Fcypress-debugging-c6efb7c87295a6da1d521b32dadf9b7f.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Continuous Integration
&lt;/h3&gt;

&lt;p&gt;Continuous Integration can often be tricky when it comes to E2E testing. In terms of running Cypress tests, this is simple - it’s just an npm command. The potential difficulty comes in the form of running a UI (and maybe an API) as part of the pipeline. We achieved this by spinning up instances of the UI and backend as &lt;a href="https://www.docker.com/" rel="noopener noreferrer"&gt;Docker&lt;/a&gt; containers using &lt;a href="https://docs.docker.com/compose/" rel="noopener noreferrer"&gt;Docker Compose&lt;/a&gt;, although this is obviously dependant on a project’s infrastructure and deployment methodology.&lt;/p&gt;

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

&lt;p&gt;Cypress has amazing potential as a UI testing solution. Not only is it easy to get up and running, it also solves one of Selenium’s biggest headaches - synchronisation. By doing this using promises, getting used to this should be easy for most JavaScript developers. Time travel debugging allows for easy insight into where and why tests are failing, and the ability to stub part or all of the backend allows for testing just the UI, an entire system, or a mix of both.&lt;/p&gt;

</description>
      <category>cypress</category>
      <category>testing</category>
    </item>
    <item>
      <title>Conversational Bots With Dialogflow</title>
      <dc:creator>Committed Software</dc:creator>
      <pubDate>Fri, 13 Apr 2018 17:00:00 +0000</pubDate>
      <link>https://dev.to/committedsw/conversational-bots-with-dialogflow-25bf</link>
      <guid>https://dev.to/committedsw/conversational-bots-with-dialogflow-25bf</guid>
      <description>&lt;p&gt;&lt;a href="/static/google-home-mini-0f63541f5ca4f55b776e67ed87a255ce-be74e.jpeg"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcommitted.software%2Fstatic%2Fgoogle-home-mini-0f63541f5ca4f55b776e67ed87a255ce-f3a32.jpeg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Building Conversational Bots With Dialogflow
&lt;/h1&gt;

&lt;p&gt;Conversational bots are becoming increasingly popular, with AI assistants available on most mobile phones, devices like the Amazon Alexa and Google Home and in various chat applications like Slack and Facebook Messenger. However, developing conversational bots can produce a number of problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Speech recognition to understand a spoken user request.&lt;/li&gt;
&lt;li&gt;Extracting query parameters contained within a query.&lt;/li&gt;
&lt;li&gt;Understanding the intent of a query to determine the correct action.&lt;/li&gt;
&lt;li&gt;Generating an appropriate response for the query.&lt;/li&gt;
&lt;li&gt;Integration with a growing number of assistant devices or chat applications. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each platform usually has their own suggested approach for developers creating chatbots, for example Slack offers various APIs and suggests the use of JS libraries like &lt;a href="https://botkit.ai/" rel="noopener noreferrer"&gt;“Botkit”&lt;/a&gt;, whilst Amazon offer the &lt;a href="https://developer.amazon.com/alexa-skills-kit" rel="noopener noreferrer"&gt;“Alexa Skills Kit”&lt;/a&gt; and &lt;a href="https://aws.amazon.com/lambda/" rel="noopener noreferrer"&gt;“AWS Lambda functions”&lt;/a&gt;. Ideally, we don’t want to support multiple solutions for each device, so how can we write a conversational bot once whilst integrating with a variety of platforms?&lt;/p&gt;

&lt;h2&gt;
  
  
  Dialogflow
&lt;/h2&gt;

&lt;p&gt;Google’s Dialogflow platform provides us with a suitable solution; handling query parsing, parameter extraction, intent detection and offering easy integrations with a variety of common applications.&lt;/p&gt;

&lt;h3&gt;
  
  
  Intents
&lt;/h3&gt;

&lt;p&gt;Dialogflow allows us to define different Intents which it will match incoming queries to. We define examples of phrases that would trigger our intent and Dialogflow will use these to train a model used in query recognition. The more example queries provided, the more accurate the query recognition will be.&lt;/p&gt;

&lt;p&gt;We can also state the parameters that should be extracted from each request. For each parameter, we specify its name, type and default value. Dialogflow offers a number of existing types for common types like numbers, dates or locations whilst also allowing us to define our own entity types.&lt;/p&gt;

&lt;p&gt;&lt;a href="/static/Intent-3537221a7fcc2749e3efb7a61e238fb6-59a72.png"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcommitted.software%2Fstatic%2FIntent-3537221a7fcc2749e3efb7a61e238fb6-84ad3.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We state if each parameter is required, and we can also provide prompts to be used when a user does not provide all the required parameters. In the example above, the question regarding lunch requires a FoodType parameter.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;User: “Where should I go for lunch?”&lt;/p&gt;

&lt;p&gt;Bot: “Any preferences?”&lt;/p&gt;

&lt;p&gt;User: “A burger”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Dialogflow automatically handles these parameter filling exchanges, in a conversational manner utilising our provided prompts, before proceeding to build a response.&lt;/p&gt;

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

&lt;p&gt;Once a user’s Intent has been determined we need to provide a response for their request. Dialogflow allows us to provide basic text responses in the browser, with specific responses for different platforms like Google Assistant or Slack.&lt;/p&gt;

&lt;p&gt;&lt;a href="/static/Response-ab784c4e3c1f734a176c6a85119d5388-5082f.png"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcommitted.software%2Fstatic%2FResponse-ab784c4e3c1f734a176c6a85119d5388-84ad3.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, we probably want to provide a customised response, and for this Dialogflow offers integration with Firebase Cloud Functions. Once again it allows us to edit and deploy this function completely within the browser. Dialogflow provides us with a templated function to edit, in this function we write our request fulfilment code and provide Dialogflow with a map stating the functions to be called to handle each Intent.&lt;/p&gt;

&lt;p&gt;For each Intent handler, we can use the provided &lt;code&gt;request&lt;/code&gt; to extract specific parameters and build a custom response. We can also detect the request source, so that we can build a response specific to that platform, for example adding Cards to a Google Assistant response, or making use of Slack’s styled responses.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) =&amp;gt; {
  const agent = new WebhookClient({ request, response });

  function lunchHandler(agent) {
    var source = request.body.originalDetectIntentRequest ? request.body.originalDetectIntentRequest.source : undefined

    // Your code here - using request.body parameters to build a response

    switch(source){
        case 'slack': buildSlackResponse(agent); break;
        case 'google': buildGoogleAssistantResponse(agent); break;
        default: agent.add("Default response"); break;
    }

    // Add context for chained intents to use
    agent.setContext({ name: 'preference', lifespan: 2, parameters: { foodType: 'burger' }});
  }

  function buildSlackResponse(agent){
      // Building slack specific response
  }

  function buildGoogleAssistantResponse(agent){
      // Building Google Assistant cards
  }

  // Run the proper function handler based on the matched Dialogflow intent name
  let intentMap = new Map();
  intentMap.set('Lunch Intent', lunchHandler)
  agent.handleRequest(intentMap);
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We may want to make an asynchronous request from within our cloud function, calling an API or requesting data from a data store to populate a response. In this case, Dialogflow allows us to return a Promise from our intent handler function. Dialogflow will wait for the Promise to resolve before processing the agent response.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function lunchHandler(agent) {
    return Promise.resolve(someAsyncRequest()
      .then(function (res) {
        agent.add("Here is a service specific response")
      })
      .catch(function (err) {
        console.log(err.stack)
        agent.add('Sorry, the service is not available right now')
      })
    );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Integrations
&lt;/h3&gt;

&lt;p&gt;One of the main advantages of Dialogflow is its application integrations. Dialogflow offers simple integration with Google Assistant, Facebook Messenger, Slack, Twitter, Alexa, Skype and more. In most cases, these integrations are very simple to set up, with many being a case of activating the integration and providing a set of credentials required for the two services to communicate. In each case, Dialogflow provides a simple set of steps to follow to set up the integration.&lt;/p&gt;

&lt;p&gt;&lt;a href="/static/Facebook-aa46daefb118bde939fc7bdaff80c8f1-ed1e1.png"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcommitted.software%2Fstatic%2FFacebook-aa46daefb118bde939fc7bdaff80c8f1-84ad3.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once an integration is setup, any query requests from that platform are forwarded to Dialogflow for processing and results are returned, all requests from each platform are all handled by the same underlying service.&lt;/p&gt;

&lt;h3&gt;
  
  
  Wrapping Up
&lt;/h3&gt;

&lt;p&gt;Dialogflow is incredibly easy to use, conversational bots providing basic responses can be created entirely within the browser, without having to download or setup any development kits or having to write a single line of code. A user only requires any programming knowledge once they need to produce complex responses.&lt;/p&gt;

&lt;p&gt;Its many integrations truly seem to be its main advantage, allowing the developer to have one single service support a wide range of clients provides a maintainable solution. Every request is handled by the same parsing service and parameter extraction, leaving the developer to only be concerned with producing a suitable user response.&lt;/p&gt;

&lt;p&gt;As with most fits all solutions, Dialogflow does have its drawbacks. Many applications offer differing features within their chatbots, and supporting a large number of integrations may mean that some of these platform specific features cannot be taken advantage of. For example, at the moment of writing this, there are issues with the Slack integration and responding to direct &lt;a class="mentioned-user" href="https://dev.to/bot"&gt;@bot&lt;/a&gt; mentions.&lt;/p&gt;

&lt;p&gt;However, Dialogflow is constantly being updated and improved, new features are gradually being implemented and so these issues may be addressed over time.&lt;/p&gt;

&lt;p&gt;Credit: Blog photo by &lt;a href="https://unsplash.com/photos/d6dxQwmxV2Q?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;“Ben Kolde”&lt;/a&gt; on &lt;a href="https://unsplash.com/search/photos/google?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;“Unsplash”&lt;/a&gt;&lt;/p&gt;

</description>
      <category>bot</category>
      <category>dialogflow</category>
    </item>
    <item>
      <title>Jenkins Slack Notifications</title>
      <dc:creator>Committed Software</dc:creator>
      <pubDate>Sun, 14 Jan 2018 00:00:00 +0000</pubDate>
      <link>https://dev.to/committedsw/jenkins-slack-notifications-3mh4</link>
      <guid>https://dev.to/committedsw/jenkins-slack-notifications-3mh4</guid>
      <description>&lt;p&gt;&lt;a href="/static/slackNotifications-a661d0493d23b1574f3bf93fbf29bdc8-63613.png"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcommitted.software%2Fstatic%2FslackNotifications-a661d0493d23b1574f3bf93fbf29bdc8-84ad3.png" alt="slackNotifications"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To add a slack notification from our continuous integration builds on Jenkins Blue Ocean we use the &lt;a href="https://plugins.jenkins.io/slack" rel="noopener noreferrer"&gt;Slack Notification&lt;/a&gt; plugin. Adding a set of functions to the Jenkinsfile which is then called in the &lt;code&gt;post&lt;/code&gt; section of the pipeline. We use the git command to extract the committers name and the hash of the commit so we can link to the commit in bitbucket and add the author’s name if the build has failed or is unstable so it will be brought to their attention.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;pipeline&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; 
    &lt;span class="o"&gt;...&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;stages&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'env'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;steps&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;notifyStarted&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
      &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;...&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;post&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;success&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;notifySuccess&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;unstable&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;notifyUnstable&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;failure&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;notifyFailed&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;notifyBuild&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;buildStatus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'STARTED'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;colorCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'#5492f7'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;notify&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

  &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="n"&gt;project&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'projectName'&lt;/span&gt;
  &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="n"&gt;channel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"${project}"&lt;/span&gt;
  &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"https://bitbucket.org/committed/${project}/commits/"&lt;/span&gt; 

  &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="n"&gt;commit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sh&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;returnStdout:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;script:&lt;/span&gt; &lt;span class="s1"&gt;'git log -n 1 --format="%H"'&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;trim&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
  &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="n"&gt;link&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"${base}${commit}"&lt;/span&gt; 
  &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="n"&gt;shortCommit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;commit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;take&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sh&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;returnStdout:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;script:&lt;/span&gt; &lt;span class="s1"&gt;'git log -n 1 --format="%s"'&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;trim&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
  &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="n"&gt;subject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;${link}|${shortCommit}&amp;gt; ${title}"&lt;/span&gt; 

  &lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="n"&gt;summary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"${buildStatus}: Job &amp;lt;${env.RUN_DISPLAY_URL}|${env.JOB_NAME} [${env.BUILD_NUMBER}]&amp;gt;\n${subject} ${notify}"&lt;/span&gt;

  &lt;span class="n"&gt;slackSend&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;channel:&lt;/span&gt; &lt;span class="s2"&gt;"#${channel}"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;color:&lt;/span&gt; &lt;span class="n"&gt;colorCode&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;message:&lt;/span&gt; &lt;span class="n"&gt;summary&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

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

&lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;author&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;sh&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;returnStdout:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;script:&lt;/span&gt; &lt;span class="s1"&gt;'git log -n 1 --format="%an" | awk \'{print tolower($1);}\''&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;trim&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;notifyStarted&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;notifyBuild&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;notifySuccess&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;notifyBuild&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'SUCCESS'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'good'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;notifyUnstable&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;notifyBuild&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'UNSTABLE'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'warning'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"\nAuthor: @${author()} &amp;lt;${RUN_CHANGES_DISPLAY_URL}|Changelog&amp;gt;"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;notifyFailed&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;notifyBuild&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'FAILED'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'danger'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"\nAuthor: @${author()} &amp;lt;${RUN_CHANGES_DISPLAY_URL}|Changelog&amp;gt;"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>jenkins</category>
      <category>slack</category>
    </item>
    <item>
      <title>Debugging Elasticsearch Queries in Java: how to convert queries to JSON</title>
      <dc:creator>Committed Software</dc:creator>
      <pubDate>Fri, 03 Nov 2017 17:00:00 +0000</pubDate>
      <link>https://dev.to/committedsw/debugging-elasticsearch-queries-in-java-how-to-convert-queries-to-json-1f1f</link>
      <guid>https://dev.to/committedsw/debugging-elasticsearch-queries-in-java-how-to-convert-queries-to-json-1f1f</guid>
      <description>&lt;p&gt;&lt;a href="///static/Code-Data-Programming-Code-Computer-Programming-cc-zero-83e60fb3a72b66edc7930573fd279778-a09d4.jpg"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tkaH7usv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://committed.software/static/Code-Data-Programming-Code-Computer-Programming-cc-zero-83e60fb3a72b66edc7930573fd279778-f3a32.jpg" alt="Code Data Programming Code Computer Programming cc zero"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Elasticsearch has excellent documentation with detailed descriptions and plenty of examples. The &lt;a href="https://www.elastic.co/guide/en/elasticsearch/client/java-api/current/java-query-dsl.html"&gt;Elasticsearch Java API&lt;/a&gt; has handy builder classes accessible from &lt;code&gt;org.elasticsearch.index.query.QueryBuilders&lt;/code&gt; to craft queries and aggregations in an intuitive and fluent way that is idiomatic to Java.&lt;/p&gt;

&lt;p&gt;Unintuitively, however, &lt;code&gt;QueryBuilder&lt;/code&gt; and &lt;code&gt;AggregationBuilder&lt;/code&gt; subclasses do not implement &lt;code&gt;toString&lt;/code&gt;, making it harder to debug and analyze these Java calls than you would expect, as it is not always clear how they compare to the Elasticsearch-native JSON format used extensively in Elasticsearch’s documentation. This issue is compounded further when the construction of queries is out of your control!&lt;/p&gt;

&lt;p&gt;One way we could view our queries in JSON format is to enable elasticseach’s &lt;a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/index-modules-slowlog.html"&gt;Slow Log&lt;/a&gt;, but there is a simpler way, using the Java Elasticsearch API to achieve what we want:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import java.io.IOException;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.json.JsonXContent;

...

public static void toJSON(ToXContent queryBuilder) {
  try {
    XContentBuilder builder =
        queryBuilder.toXContent(JsonXContent.contentBuilder(), ToXContent.EMPTY_PARAMS);
    log.info(builder.string());
  } catch (IOException e) {
    log.error("Failed to log elasticsearch query", e);
  }
}

...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This can be used for classes implementing either &lt;code&gt;QueryBuilder&lt;/code&gt; or &lt;code&gt;AggregationBuilder&lt;/code&gt;, as both of these extend the &lt;code&gt;ToXContent&lt;/code&gt; interface.&lt;/p&gt;

&lt;p&gt;We can use the same approach when using Spring Data Elasticsearch by calling &lt;code&gt;NativeSearchQueryBuilder.getQuery()&lt;/code&gt;, &lt;code&gt;NativeSearchQueryBuilder.getFilter()&lt;/code&gt; or &lt;code&gt;NativeSearchQueryBuilder.getAggregations()&lt;/code&gt; and passing the resulting objects using the same approach.&lt;/p&gt;

&lt;p&gt;Now we can see the exact query that will be sent to Elasticsearch:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;{ "term" : { "user" : "Kimchy" } }&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If you are using &lt;a href="https://www.elastic.co/products/kibana"&gt;Kibana&lt;/a&gt; to view your indices, try copying &amp;amp; pasting your query across on the Discover page for further analysis.&lt;/p&gt;

</description>
      <category>elasticsearch</category>
      <category>java</category>
    </item>
    <item>
      <title>Docker in JUnit tests</title>
      <dc:creator>Committed Software</dc:creator>
      <pubDate>Mon, 23 Oct 2017 00:00:00 +0000</pubDate>
      <link>https://dev.to/committedsw/docker-in-junit-tests-4p4i</link>
      <guid>https://dev.to/committedsw/docker-in-junit-tests-4p4i</guid>
      <description>&lt;p&gt;&lt;a href="///static/testcontainers-3635f36b0d79fb640fb39747456f5f9a-748a9.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6hA0SUJY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://committed.software/static/testcontainers-3635f36b0d79fb640fb39747456f5f9a-84ad3.png" alt="testcontainers"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Unit testing in Java is made simple by libraries such as &lt;a href="http://junit.org/"&gt;JUnit&lt;/a&gt; and e.g. &lt;a href="http://site.mockito.org/"&gt;Mockito&lt;/a&gt;, but there’s not the same panacea for integration testing. Alongside your mocked out unit tests, integration tests are important to ensure the correct function of your software when accessing external services. Previously, we have taken different approaches to the problem, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Embedding the service&lt;/li&gt;
&lt;li&gt;Running the service&lt;/li&gt;
&lt;li&gt;Running a Docker container for the service&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Embedding the service can be hard (especially if it is not Java). Running them directly, or remotely, adds significant work to configure, maintain and make available for all developers and your continuous integration service. Running a Docker container for the service was our preferred method but setting them up locally and as part of the CI build seems out of sorts with the fundamental approach to testing. This has been a common and frustrating pain point for us.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test Containers
&lt;/h2&gt;

&lt;p&gt;We have recently switched to using &lt;a href="https://www.testcontainers.org/"&gt;TestContainers&lt;/a&gt; to solve this problem. TestContainers is an &lt;a href="https://github.com/testcontainers/testcontainers-java/blob/master/LICENSE"&gt;MIT&lt;/a&gt; licensed open source project for running a Docker container for a JUnit test.&lt;/p&gt;

&lt;h3&gt;
  
  
  Benefits
&lt;/h3&gt;

&lt;p&gt;This has a number of benefits over our previous approaches. First, we are running the tests against a real instance of the service, not some mocked or embedded version, which may behave differently. As the containers run just for the test they are isolated from other test and become much more reproducible. The setup and configuration are done in the test class, where they belong. It also allows you to easily repeat the test against different versions of the service allowing you to correctly determine a compatibility and check new versions of services do not require changes to your own code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use cases
&lt;/h3&gt;

&lt;p&gt;This technique for integration testing can easily be applied to multiple use cases, some of which have more specialised support:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.testcontainers.org/usage/database_containers.html"&gt;Databases&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Logging services&lt;/li&gt;
&lt;li&gt;Web services&lt;/li&gt;
&lt;li&gt;Complex &lt;a href="https://www.testcontainers.org/usage/docker_compose.html"&gt;multi-service&lt;/a&gt; interactions using &lt;a href="https://docs.docker.com/compose/"&gt;Docker Compose&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.testcontainers.org/usage/webdriver_containers.html"&gt;UI testing&lt;/a&gt; with &lt;a href="https://github.com/SeleniumHQ/docker-selenium"&gt;Selenium&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;

&lt;p&gt;The following example shows how to set up an integration test for Redis.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import org.junit.Rule;
import org.junit.Test;
import org.testcontainers.containers.GenericContainer;

import redis.clients.jedis.Jedis;

public class RedisIntegrationTest {

  private static final String DOCKER_IMAGE = "redis:3.2.9";

  private final Jedis jedis;

  @Rule // 1
  public static GenericContainer redis = new GenericContainer(DOCKER_IMAGE).withExposedPorts(6379); // 2, 3

    @Before
    public void setUp() throws Exception {
        Jedis jedis = new Jedis(redis.getContainerIpAddress(), redis.getMappedPort(6379)); // 4
    }

  @Test
  public void yourTest() {
    //Your test code here
  }

}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;@Rule&lt;/code&gt; Runs a new container for every test, you can change to &lt;code&gt;@ClassRule&lt;/code&gt; for a single container for the test class.&lt;/li&gt;
&lt;li&gt;It also supports the use of &lt;a href="https://www.testcontainers.org/usage/dockerfile.html"&gt;Dockerfiles&lt;/a&gt; or Docker Compose files for non-standard, of not published containers by using &lt;code&gt;DockerComposeContainer&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Other standard docker config like &lt;code&gt;.withVolume(), withEnv(), withCommand()&lt;/code&gt; are available.&lt;/li&gt;
&lt;li&gt;Obtain the configuration you need from the &lt;code&gt;GenericContainer&lt;/code&gt; object.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Disadvantages
&lt;/h3&gt;

&lt;p&gt;None! O.K. maybe there are some disadvantages, but we think they are well worth it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You need docker available to run the tests. (i.e. on your local device and on the CI server) but who doesn’t?&lt;/li&gt;
&lt;li&gt;You need to make docker available (which may require exposing the docker socket)&lt;/li&gt;
&lt;li&gt;You have to download the image but this is only needed once.&lt;/li&gt;
&lt;li&gt;Windows support is only in Alpha.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Credit: Image by &lt;a href="https://rnorth.org/"&gt;Richard North&lt;/a&gt;, TestContainers Project.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>testing</category>
      <category>java</category>
      <category>junit</category>
    </item>
    <item>
      <title>First impressions with GraphQL in Java</title>
      <dc:creator>Committed Software</dc:creator>
      <pubDate>Mon, 16 Oct 2017 12:40:00 +0000</pubDate>
      <link>https://dev.to/committedsw/first-impressions-with-graphql-in-java-5c82</link>
      <guid>https://dev.to/committedsw/first-impressions-with-graphql-in-java-5c82</guid>
      <description>&lt;p&gt;&lt;a href="///static/logo-aebeb4e70ae5145695bbb1e151e1fccf-f2200.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---xQjJzaA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://committed.software/static/logo-aebeb4e70ae5145695bbb1e151e1fccf-f2200.png" alt="GraphQL-Java"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://graphql.org/"&gt;GraphQL&lt;/a&gt; is an open query language for exposing data in a flexible way. It was developed by &lt;a href="https://code.facebook.com/projects/"&gt;Facebook&lt;/a&gt; and now in production use in many &lt;a href="http://graphql.org/users/"&gt;projects&lt;/a&gt;. The main concepts are that GraphQL describes the data available and then the consumer can ask for what they need. All using the same endpoint and language.&lt;/p&gt;

&lt;p&gt;We are investigating its use to expose natural language processing results to replace, or augment, &lt;a href="https://en.wikipedia.org/wiki/Representational_state_transfer"&gt;REST&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Java ecosystem
&lt;/h2&gt;

&lt;p&gt;GraphQL is programming language agnostic and different implementations exist in &lt;a href="http://graphql.org/code/#server-libraries"&gt;many languages&lt;/a&gt; for this project we are using Java and Spring Boot so the natural choice is &lt;a href="https://github.com/graphql-java/graphql-java"&gt;graphql-java&lt;/a&gt;. It may not be the only java implementation but it is certainly the most active at this time. This core project stays true to the specification and there are a number of supporting &lt;a href="https://github.com/graphql-java"&gt;projects&lt;/a&gt; to ease integration and use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Approach
&lt;/h2&gt;

&lt;p&gt;In GraphQL you need to declare your data schema so clients can introspect the system and query correctly. However, the schema needs to be an accurate representation of your underlying data classes. While you could create both of these things manually, generating one from the other will reduce effort and errors. One approach is to define your schema and generate the data classes. This approach is provided by &lt;a href="https://github.com/Distelli/graphql-apigen"&gt;graphql-apigen&lt;/a&gt; and &lt;a href="https://github.com/graphql-java/graphql-java-tools"&gt;graphql-java-tools&lt;/a&gt;. While this approach could be very useful if you have a new project with a strict schema specification, we already have data classes. Therefore, we take the classes-first approach and generate the schema. There is a &lt;a href="https://github.com/graphql-java/graphql-java-annotations"&gt;graphql-java-annotations&lt;/a&gt; project based on this approach, however, development of it seems to have stopped and the community seems to be moving towards &lt;a href="https://github.com/leangen/graphql-spqr"&gt;graphgql-spqr&lt;/a&gt; (pronounced “speaker”). It looks likely that this will become the official graphql-java class-first approach.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;

&lt;p&gt;It was very easy to get started using the &lt;a href="https://github.com/graphql-java/graphql-spring-boot"&gt;graphql-spring-boot&lt;/a&gt;. This gives:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A graphql-java servlet, to serve the schema, and accept GET and POST GraphQL requests&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://github.com/graphql/graphiql"&gt;GraphiQL UI&lt;/a&gt;, for writing and executing GraphQL queries against the published schema.&lt;/li&gt;
&lt;li&gt;
&lt;del&gt;grapghql-java-tools&lt;/del&gt; schema first&lt;/li&gt;
&lt;li&gt;
&lt;del&gt;graphql spring common&lt;/del&gt; class first&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We chose not to use the latter and added graphql-spqr simple by providing a &lt;code&gt;graphql.schema.GraphQLSchema&lt;/code&gt; Bean generated using graphql-spqr and annotations on &lt;code&gt;DemoService&lt;/code&gt; and the POJOs used.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package io.committed;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Controller;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

import graphql.schema.GraphQLSchema;
import io.committed.query.DemoService;
import io.leangen.graphql.GraphQLSchemaGenerator;

@Controller
@EnableAutoConfiguration
@ComponentScan
public class GrahpQLDemo {

  @Autowired
  DemoService demoService;

  @Bean
  GraphQLSchema schema() {
    return new GraphQLSchemaGenerator()
        .withOperationsFromSingleton(demoService)
        .generate();
  }

  public static void main(String[] args) throws Exception {
    SpringApplication.run(GrahpQLDemo.class, args);
  }

}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Getting going
&lt;/h2&gt;

&lt;p&gt;It was simple to add the graphql-spqr annotations to our existing JPA/MongoDB data access objects (DAO). In fact, if you are using the same names it is not even necessary as they will be picked up automatically. Alternatively, if you want to separate the DAO from the GraphQL definition you can define a set of data transfer objects (DTO) and use those. This may give you more flexibility if you can’t change your DAO layer. We exposed the types to the GraphQL by adding a root query method to each service i.e.:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package io.committed.query;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import io.committed.dao.repository.DemoRepository;
import io.committed.dto.Document;
import io.leangen.graphql.annotations.GraphQLQuery;

@Component
public class DocumentService {

  @Autowired
  DemoRepository repository;

  @GraphQLQuery(name = "allDocuments", description="Get all documents")
  public List&amp;lt;Document&amp;gt; getDocuments() {
    return repository.findAll();
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Arguments can be added to these methods for filtering, limiting, etc and if using Streams these can be returned directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@GraphQLQuery(name = "allDocuments", description="Get all documents")
  public Stream&amp;lt;Document&amp;gt; getDocuments(
      @GraphQLArgument(name = "limit", defaultValue = "0") int limit) {
    Stream&amp;lt;Document&amp;gt; stream = repository.streamAll();
    if (limit &amp;gt; 0) {
      stream = stream.limit(limit);
    }

    return stream;
  }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Similarly, we can get a specific document by id, and directly return an &lt;code&gt;Optional&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@GraphQLQuery(name = "document")
  public Optional&amp;lt;Document&amp;gt; getDocument(@GraphQLArgument(name = "id") String id) {
    return repository.findById(id);
  }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In GraphQL the client asks explicitly for what data the result should contain. This does not have to be restricted to the fields of your data objects, methods can also be used to provide calculated results, here is a trivial example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package io.committed.dto;

import io.leangen.graphql.annotations.GraphQLId;
import io.leangen.graphql.annotations.GraphQLQuery;
import lombok.Data;

@Data
public class Document {

  @GraphQLId
  private String id;
  private String content;

  @GraphQLQuery(name = "length")
  public int length() {
    return content.length();
  }

}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This will expose a &lt;code&gt;length&lt;/code&gt; field on the &lt;code&gt;Document&lt;/code&gt; class. This method is only called if requested by the query so the client does not have to pay the penalty for any calculations that they do not need. Such methods also allow the client to save on data transfer by getting the server to do the calculations and only transferring the result.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting graphing
&lt;/h2&gt;

&lt;p&gt;The real power of GraphQL comes from the ability to traverse data type by their joining properties. For example, if I have Entities extracted from a Document then I want to be able to query for the entities contained in a document. If these are already stored in your Document object this is trivial, however, they may be stored in a different table or collection in your database. To embed entities in the document we add the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@GraphQLQuery(name = "entities")
  public Stream&amp;lt;Entity&amp;gt; getByDocument(@GraphQLContext Document document) {
    return repository.getByDocumentId(document.getId());
  }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;where the &lt;code&gt;@GraphQLContext&lt;/code&gt; annotation provides the linking logic to build the schema.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting querying
&lt;/h2&gt;

&lt;p&gt;You can query using the GraphiQL UI hosted on &lt;code&gt;/graphiql&lt;/code&gt; or send HTTP requests to &lt;code&gt;/graphql&lt;/code&gt; and get the schema from &lt;code&gt;/schema.json&lt;/code&gt;, I’m sure all these are configurable too. You can also use the GraphQL internally, for example by creating a &lt;code&gt;QueryService&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package io.committed.query;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import graphql.ExecutionResult;
import graphql.GraphQL;
import graphql.schema.GraphQLSchema;

@Service
public class QueryService {

  private final GraphQL graphQL;

  @Autowired
  public QueryService(GraphQLSchema graphQLSchema) {
    graphQL = GraphQL.newGraphQL(graphQLSchema).build();
  }

  public ExecutionResult query(String query) {
    return graphQL.execute(query);
  }

}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Or by exposing the &lt;code&gt;GraphQL&lt;/code&gt; object as a bean.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting better
&lt;/h2&gt;

&lt;p&gt;We were able to get a quick GraphQL endpoint up and running in less that a day on our existing DAO objects providing a powerful querying mechanism for clients. During this investigation, we uncovered and reported a bug in graphql-spqr and got a rapid response from the &lt;a href="https://github.com/kaqqao"&gt;author&lt;/a&gt;. It looks likely that this ecosystem will develop fast, out suggestions for improvements to graphql-spqr are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ability to ignore certain fields&lt;/li&gt;
&lt;li&gt;Out of the box support for limiting and filtering&lt;/li&gt;
&lt;li&gt;Support for graphql-java v5&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Overall, this is a very promising route for rapid integration of GraphQL into an existing spring-boot server.&lt;/p&gt;

</description>
      <category>java</category>
      <category>graphql</category>
    </item>
    <item>
      <title>React Router Redux Authenticated Container</title>
      <dc:creator>Committed Software</dc:creator>
      <pubDate>Mon, 22 Aug 2016 15:23:00 +0000</pubDate>
      <link>https://dev.to/committedsw/react-router-redux-authenticated-container-26na</link>
      <guid>https://dev.to/committedsw/react-router-redux-authenticated-container-26na</guid>
      <description>&lt;p&gt;Separate authentication from your Components with a dedicated authentication component.&lt;/p&gt;

&lt;p&gt;When writing &lt;a href="https://facebook.github.io/react/"&gt;React&lt;/a&gt; applications with &lt;a href="https://github.com/reactjs/redux"&gt;Redux&lt;/a&gt; and &lt;a href="https://github.com/reactjs/react-router-redux"&gt;react-router-redux&lt;/a&gt; some routes in your application may require an authenticated user and others not. To separate the authentication concern we use a specific container that checks for the authentication and before rendering the child. If the authentication fails then you can respond by display an error or more likely redirect to login.&lt;/p&gt;

&lt;h2&gt;
  
  
  Route
&lt;/h2&gt;

&lt;p&gt;To simplify the main render method we use a function to wrap the child in an &lt;code&gt;AuthenticatedComponent&lt;/code&gt;, so it is clear in your main render method which parts of your application are protected.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ReactDOM.render(
  &amp;lt;Provider store={store}&amp;gt;
    &amp;lt;Router history={history}&amp;gt;
      &amp;lt;Route path="/" component={AppParent}&amp;gt;
        &amp;lt;Route path="login" component={LoginContainer}/&amp;gt;
        &amp;lt;Route path="logout" component={LogoutContainer}/&amp;gt;
        &amp;lt;Route path="about" component={AboutPage}/&amp;gt;
        &amp;lt;Route path="help" component={HelpPage}/&amp;gt;
        &amp;lt;Route path="user" component={requireAuth(UserContainer)}/&amp;gt;
        &amp;lt;Route path="admin" component={requireAuth(AdminContainer)}/&amp;gt;
        &amp;lt;Route path="main" component={requireAuth(MainContainer)}&amp;gt;
          &amp;lt;Route path="one" component={FirstPage}/&amp;gt;
          &amp;lt;Route path="two" component={SecondPage}/&amp;gt;
        &amp;lt;/Route&amp;gt;
      &amp;lt;/Route&amp;gt;
    &amp;lt;/Router&amp;gt;
  &amp;lt;/Provider&amp;gt;,
  document.getElementById('app')
)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Authenticated Component
&lt;/h2&gt;

&lt;p&gt;We then implement the &lt;code&gt;requireAuth&lt;/code&gt; function as follows. You may need to change the detail of the auth check depending on your authentication actions and you can make the &lt;code&gt;authFailed&lt;/code&gt; function do whatever you like, in this example we redirect to login with the path so we can redirect back after a successful login.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { Component, PropTypes } from 'react'
import { connect } from 'react-redux'
import { push } from 'react-router-redux'

export function requireAuth(ChildComponent) {

  class AuthenticatedComponent extends Component {

    componentWillMount() {
      this.checkAuth(this.props.isAuthenticated);
    }

    componentWillReceiveProps(nextProps) {
      this.checkAuth(nextProps.isAuthenticated);
    }

    checkAuth(isAuthenticated) {
      if (!isAuthenticated) {
        this.props.authFailed();
      }
    }

    render() {
      return (
        &amp;lt;div&amp;gt;
         { this.props.isAuthenticated === true ?  
           &amp;lt;ChildComponent { ...this.props } /&amp;gt; : null }
        &amp;lt;/div&amp;gt;
      )

    }
  }

  const mapStateToProps = (state) =&amp;gt; ({
    auth: state.auth,
    isAuthenticated: state.auth.login.isAuthenticated,
  });

  const mapDispatchToProps = (dispatch, ownProps) =&amp;gt; {
    return {
      authFailed: () =&amp;gt; {
        let location = ownProps.location
        let redirect = encodeURIComponent(location.pathname + location.search)
        dispatch(push(`/login?next=${redirect}`))
      },
    }
  }

  return connect(mapStateToProps, mapDispatchToProps)(AuthenticatedComponent);

}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The auth details can be useful for the child components, say to show the username but not all children are likely to need it. A good way to do this is to make it a context object for the children. This can be done by adding the following to the class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class AuthenticatedComponent extends Component {

  \\...

  static childContextTypes = {
    auth: PropTypes.object.isRequired
  }

  getChildContext() {
    return {
      auth: this.props.auth
    }
  }

  \\...
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



</description>
      <category>react</category>
      <category>redux</category>
    </item>
  </channel>
</rss>
