<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title><![CDATA[Take the First Step]]></title>
  <subtitle><![CDATA[Dwight Shih's Soap Box on the Internet Commons]]></subtitle>
  <link href="/atom.xml" rel="self"/>
  <link href="https://ideoplex.com/"/>
  <updated>2017-09-17T21:37:34.000Z</updated>
  <id>https://ideoplex.com/</id>
  
  <author>
    <name><![CDATA[Dwight Shih]]></name>
    
  </author>
  
  <generator uri="http://hexo.io/">Hexo</generator>
  
  <entry>
    <title><![CDATA[Spring Configuration and Profiles]]></title>
    <link href="https://ideoplex.com/2017/09/17/spring-configuration-and-profiles/"/>
    <id>https://ideoplex.com/2017/09/17/spring-configuration-and-profiles/</id>
    <published>2017-09-17T21:35:17.000Z</published>
    <updated>2017-09-17T21:37:34.000Z</updated>
    <content type="html"><![CDATA[<p>Spring supports profile specific application properties via a file naming convention:</p>
<ul>
<li>Profile specific application properties outside your jar (application-{profile}.properties or application-{profile}.yml)</li>
<li>Profile specific application properties packaged in your jar (application-{profile}.properties or application-{profile}.yml)</li>
</ul>
<p>If you’re using YAML, then you can also use profile documents inside the YAML file.
Let’s take a closer look using the CommandLineRunner from last week’s post <a href="https://ideoplex.com/2017/09/10/externalized-configuration-in-spring/">Externalized Configuration in Spring</a></p>
<pre><code>@SpringBootApplication
public class Application implements CommandLineRunner {

    @Value("${myApp.name}")
    private String name;
    @Value("${myApp.primary}")
    private String primary = "foo";
    @Value("${myApp.secondary}")
    private String secondary = "foo";

    private static final Logger log = LoggerFactory.getLogger(Application.class);

    public static void main(String[] args) throws Exception {
        final SpringApplication app = new SpringApplicationBuilder(Application.class)
            .properties("spring.config.name=myApp")
            .build();
        app.run();
    }

    public void run(String ... strings)
        throws Exception
    {
        log.warn("name\t {}", name);
        log.warn("primary\t {}", primary);
        log.warn("secondary\t {}", secondary);
    }
}
</code></pre>

<p>A YAML file is actually a sequence of documents separated by --- lines,
and Spring parses each document separately to a flattened map.
If a YAML document contains a <strong>spring.profiles</strong> key,
then that <a href="https://docs.spring.io/spring-boot/docs/current/reference/html/howto-properties-and-configuration.html#howto-change-configuration-depending-on-the-environment" target="_blank" rel="external">value controls whether that document is included in the final merge.</a></p>
<p>Let’s take a look at an example.
Here is the file packaged in my jar:</p>
<pre><code>myApp:
  name:         Package Default
  primary:      Package Default
  secondary:    Package Default

---
spring.profiles: one

myApp:
  name:         Package 1

---
spring.profiles: two

myApp:
  name:         Package 22
  primary:      Package 22

---
spring.profiles: three

myApp:
  primary:      Package 333
  secondary:    Package 333
</code></pre>

<p>With no active profile, we get the values from the first document.</p>
<pre><code>$ java -jar target/application-config-0.1.0.jar
WARN  [main]  name       Package Default
WARN  [main]  primary    Package Default
WARN  [main]  secondary  Package Default
</code></pre>

<p>Set <strong>one</strong> as the active profile,
to merge the first document with the document containing <strong>spring.profiles: one</strong>:</p>
<pre><code>$ (export SPRING_PROFILES_ACTIVE=one ; java -jar target/application-config-0.1.0.jar)
WARN  [main]  name       Package 1
WARN  [main]  primary    Package Default
WARN  [main]  secondary  Package Default
</code></pre>

<p>Set <strong>two,three</strong> as the active profiles,
to merge the first document with the documents containing <strong>spring.profiles: two</strong>, <strong>spring.profiles: three</strong>:</p>
<pre><code>$ (export SPRING_PROFILES_ACTIVE=two,three ; java -jar target/application-config-0.1.0.jar)
WARN  [main]  name       Package 22
WARN  [main]  primary    Package 333
WARN  [main]  secondary  Package 333
</code></pre>

<p>And finally, add a local myApp.yml that sets the active profile.
The merge order is:</p>
<ol>
<li>packaged default document</li>
<li>local default document</li>
<li>active profile document</li>
</ol>
<pre><code>$ cat myApp.yml
spring.profiles.active: one

myApp:
    name:       Local
    secondary:  Local
$ java -jar target/application-config-0.1.0.jar
WARN  [main]  name       Package 1
WARN  [main]  primary    Package Default
WARN  [main]  secondary  Local
</code></pre>
]]></content>
    <summary type="html">
    <![CDATA[<p>Spring supports profile specific application properties via a file naming convention:</p>
<ul>
<li>Profile specific application propertie]]>
    </summary>
    
      <category term="java" scheme="https://ideoplex.com/tags/java/"/>
    
      <category term="spring" scheme="https://ideoplex.com/tags/spring/"/>
    
      <category term="technology" scheme="https://ideoplex.com/categories/technology/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[Externalized Configuration in Spring]]></title>
    <link href="https://ideoplex.com/2017/09/10/externalized-configuration-in-spring/"/>
    <id>https://ideoplex.com/2017/09/10/externalized-configuration-in-spring/</id>
    <published>2017-09-10T21:46:13.000Z</published>
    <updated>2017-09-10T21:53:54.000Z</updated>
    <content type="html"><![CDATA[<p>Spring comes with excellent support for <a href="https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html" target="_blank" rel="external">externalized configuration</a>.
This allows you to have sensible defaults checked into your source code repository,
while providing a plethora of options for setting properties that shouldn’t be checked in (account credentials)
or
can’t be checked in (specification of active profiles):</p>
<ul>
<li>…</li>
<li>OS environment variables</li>
<li>Profile specific application properties outside your jar (application-{profile}.properties or application-{profile}.yml)</li>
<li>Profile specific application properties packaged in your jar (application-{profile}.properties or application-{profile}.yml)</li>
<li>Application properties outside your jar (application.properties or application.yml)</li>
<li>Application properties packaged in your jar (application.properties or application.yml)</li>
<li>…</li>
</ul>
<p>But if you’re deploying to an application server, then there is a little tweak that you’ll need to keep in your back pocket - changing the spring.config.name from application to something else in code.
This will let you add a centralized configuration directory to your application server classpath for all your deployed web applications,
where setting spring.config.name by environment variable, command line options or JNDI don’t work).</p>
<p>Personally, I like using the org.springframework.boot.builder.SpringApplicationBuilder to change the spring.config.name to myApp:</p>
<pre><code>app = new SpringApplicationBuilder(Application.class)
    .properties("spring.config.name=myApp")
    .build()
    .run();
</code></pre>

<p>But, it can can also be done with the standard org.springframework.boot.SpringConfiguration.</p>
<pre><code>app = new SpringApplication(Application.class);
Properties props = new Properties();
props.setProperty("spring.config.name","myApp");
app.setDefaultProperties(props);
app.run();
</code></pre>

<p>It is also possible to externalize the configuration with org.springframework.context.annotation.PropertySource,
but this forgoes some application properties magic:</p>
<ul>
<li>PropertySource does not support YAML</li>
<li>PropertySource does not have profile support</li>
<li>You override properties with application properties while you define all properties with PropertySource (application properties uses the <strong>value</strong> from the file with the highest priority, while PropertySource uses the <strong>file</strong> with the highest priority).</li>
<li>Maven plugin adds the project.build.directory to the application properties search list (spring.config.location), where developers can easily specify values while keeping them out of source control.</li>
</ul>
]]></content>
    <summary type="html">
    <![CDATA[<p>Spring comes with excellent support for <a href="https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-co]]>
    </summary>
    
      <category term="java" scheme="https://ideoplex.com/tags/java/"/>
    
      <category term="spring" scheme="https://ideoplex.com/tags/spring/"/>
    
      <category term="technology" scheme="https://ideoplex.com/categories/technology/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[Goodbye Harold]]></title>
    <link href="https://ideoplex.com/2016/06/26/goodbye-harold/"/>
    <id>https://ideoplex.com/2016/06/26/goodbye-harold/</id>
    <published>2016-06-26T18:44:09.000Z</published>
    <updated>2016-06-26T20:19:16.000Z</updated>
    <content type="html"><![CDATA[<p>Appointment TV may be dead,
but <a href="http://www.imdb.com/title/tt1839578/" target="_blank" rel="external">Person of Interest</a>
was the next best thing - a show worthy of an HD recording.
Harold Finch, the “Man in the Suit” and the Machine finished their five year run in style.
Harold has started a new life with Grace,
John gave his life to save the world
and
the Machine was re-born.
In a world without Samaritan,
who knows what the Machine will do.</p>
<p>CBS has given me back 22 hours a year.
I’d rather spend those 22 hours with the Machine.</p>
]]></content>
    <summary type="html">
    <![CDATA[<p>Appointment TV may be dead,
but <a href="http://www.imdb.com/title/tt1839578/" target="_blank" rel="external">Person of Interest</a>
was ]]>
    </summary>
    
      <category term="culture" scheme="https://ideoplex.com/tags/culture/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[This One's for Pat]]></title>
    <link href="https://ideoplex.com/2016/02/14/this-ones-for-pat/"/>
    <id>https://ideoplex.com/2016/02/14/this-ones-for-pat/</id>
    <published>2016-02-14T16:57:06.000Z</published>
    <updated>2016-03-26T21:01:15.000Z</updated>
    <content type="html"><![CDATA[<p>Two years ago I was cautiously optimistic.
The Seahawks had a great defense,
the Broncos had an great offense
and
I was looking forward to a great Super Bowl.
That lead to a beat down as painful to watch as the
<a href="https://en.wikipedia.org/wiki/Super_Bowl_XXIV" target="_blank" rel="external">Super Bowl XXIV</a> thrashing.</p>
<p>This year I was guardedly pessimistic.
All season long I had been saying that the Broncos didn’t need Peyton Manning at
the height of his powers - they just needed Peyton to play at a replacement
level and the defense could do the rest.
Unfortunately,
Peyton wasn’t able to play at a replacement level.
The result was a game in which Denver never trailed,
but kept me on the edge of my seat most of the game.</p>
<p>After obsessively reviewing the post game analysis, I subscribe to the theory
that the Carolina coaching staff let their team down while the Denver staff
understood how to the Broncos could/would win.
With the Broncos unlikely to put together a long TD drive,
it was imperative that the Panthers manage field position and not give the
Broncos a short field.
Instead the Panthers gave up a defensive touchdown on their second position
and the Broncos were on their way.</p>
<blockquote><p>I really think Carolina’s coaches didn’t appreciate the kind of game they were in, and it led to handing the Broncos their best chance to win the game. If Rivera and Co. had approached it with the sort of thinking that goes along with trying to win a game 16-13 or 13-9, all sorts of things might have been different. In particular, if Carolina approaches the game with the 1st principal being giving the Broncos zero chance to get a turnover on a very short field, the game might turn out different.</p>
<footer><strong>Will Allen</strong><cite><a href="http://www.footballoutsiders.com/audibles/2016/audibles-line-super-bowl-50?page=1#comment-1021506" target="_blank" rel="external">www.footballoutsiders.com/audibles/2016/audibles-line-super-bowl-50?page=1#comment-1021506</a></cite></footer></blockquote>]]></content>
    <summary type="html">
    <![CDATA[<p>Two years ago I was cautiously optimistic.
The Seahawks had a great defense,
the Broncos had an great offense
and
I was looking forward t]]>
    </summary>
    
      <category term="football" scheme="https://ideoplex.com/tags/football/"/>
    
      <category term="my teams" scheme="https://ideoplex.com/tags/my-teams/"/>
    
      <category term="sports" scheme="https://ideoplex.com/categories/sports/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[Stanford 4 - Clemson 0]]></title>
    <link href="https://ideoplex.com/2015/12/13/stanford-4-clemson-0/"/>
    <id>https://ideoplex.com/2015/12/13/stanford-4-clemson-0/</id>
    <published>2015-12-13T21:57:02.000Z</published>
    <updated>2016-02-13T19:21:43.000Z</updated>
    <content type="html"><![CDATA[<p>Congratulations to the <a href="http://www.gostanford.com/ViewArticle.dbml?DB_OEM_ID=30600&amp;ATCLID=210582192" target="_blank" rel="external">National Champion Stanford Cardinal</a> for their first NCAA men’s soccer championship.</p>
<p>I was prepared for a defensive game when both both semi-final games went to
penalty kicks after playing to 0-0 draws.
But Jordan Morris scored for Stanford just 87 seconds into the final and the
Cardinal never looked back.</p>
]]></content>
    <summary type="html">
    <![CDATA[<p>Congratulations to the <a href="http://www.gostanford.com/ViewArticle.dbml?DB_OEM_ID=30600&amp;ATCLID=210582192" target="_blank" rel="ext]]>
    </summary>
    
      <category term="my teams" scheme="https://ideoplex.com/tags/my-teams/"/>
    
      <category term="soccer" scheme="https://ideoplex.com/tags/soccer/"/>
    
      <category term="sports" scheme="https://ideoplex.com/categories/sports/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[Gouging is not a Sustainable Advantage]]></title>
    <link href="https://ideoplex.com/2015/11/15/gouging-not-a-sustainable-advantage/"/>
    <id>https://ideoplex.com/2015/11/15/gouging-not-a-sustainable-advantage/</id>
    <published>2015-11-15T19:48:14.000Z</published>
    <updated>2015-11-15T19:56:37.000Z</updated>
    <content type="html"><![CDATA[<p>Gouging your customers may be legal.
It may even be moral.
But I’m happy to see that it is not a sustainable business advantage.
And the sooner that investors realize that gouging your customers makes your
<a href="http://www.nytimes.com/2015/11/13/business/huge-valeant-stake-exposes-rift-at-sequoia-fund.html?_r=0" target="_blank" rel="external">business strategy unsustainable</a>,
the sooner this kind of behavior will end.</p>
]]></content>
    <summary type="html">
    <![CDATA[<p>Gouging your customers may be legal.
It may even be moral.
But I’m happy to see that it is not a sustainable business advantage.
And the ]]>
    </summary>
    
      <category term="business" scheme="https://ideoplex.com/tags/business/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[Theme and Site Update]]></title>
    <link href="https://ideoplex.com/2015/11/15/theme-site-update/"/>
    <id>https://ideoplex.com/2015/11/15/theme-site-update/</id>
    <published>2015-11-15T19:22:21.000Z</published>
    <updated>2015-11-15T19:59:02.000Z</updated>
    <content type="html"><![CDATA[<p>Website viewers may notice a couple of site changes.</p>
<ol>
<li>My tag cloud is now shown at the bottom of the front page.</li>
<li>The main menu links to “Home”, “Technology Category”, “Sports Category”, and “Java Tag”.</li>
</ol>
<p>I thought that my front page ended a bit abruptly
after removing the ability to page through the entire weblog.
The tag cloud provides some guidance in exploring my back catalog
and is enabled by the latest update to my
<a href="https://github.com/ideoplex/hexo-theme-landscape/commit/ce3fd448252320d4c40c102ff0d729d0e945a72d" target="_blank" rel="external">hexo-theme-landscape work branch</a>.</p>
<p>It’s feels odd, not having a link to my Java Tutorials.
Getting my <a href="/2003/06/24/dmoz-update/">tutorial page on DMOZ</a> was a big step 12 years ago.
It was a strong effort back then,
but I let it wither on the vine.
Now it is time to move on.</p>
]]></content>
    <summary type="html">
    <![CDATA[<p>Website viewers may notice a couple of site changes.</p>
<ol>
<li>My tag cloud is now shown at the bottom of the front page.</li>
<li>The]]>
    </summary>
    
      <category term="colophon" scheme="https://ideoplex.com/tags/colophon/"/>
    
      <category term="hexo" scheme="https://ideoplex.com/tags/hexo/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[CloudFront Checkpoint/Hexo Theme Update]]></title>
    <link href="https://ideoplex.com/2015/11/08/cloudfront-checkpoint-hexo-theme-update/"/>
    <id>https://ideoplex.com/2015/11/08/cloudfront-checkpoint-hexo-theme-update/</id>
    <published>2015-11-08T21:31:44.000Z</published>
    <updated>2015-11-08T23:15:45.000Z</updated>
    <content type="html"><![CDATA[<p><a href="https://aws.amazon.com/cloudfront/" target="_blank" rel="external">CloudFront</a> is looking good.
My added bandwidth cost is about $.20 a month - a very cost effective way to
add SSL to my S3 hosted weblog.
There is one financial gotcha - the first 1000 URL invalidations are free,
but it is $.005 per invalidation after that.
I blew through my free invalidations when I added SSL and
regenerated every page last month.
I think 1000 free invalidations a month would be ample for most people,
but not for me.</p>
<p>I have almost 900 total posts.
That means I invalidate about 90 URLs with every post (10 posts per page).
Or about 10 posts a month,
unless I’m willing to pay.
I don’t think anyone really wants to page through my entire weblog.
And I already updated my archive (<a href="/archives/2015/">2015</a>), category
(<a href="/categories/technology/">technology</a>), and tag (<a href="/tags/java/">java</a>) pages
to present a single page of titles last year.
So I’ve updated the hexo landscape theme to only generate the first index page.</p>
<p>My fork of
<a href="https://github.com/ideoplex/hexo-theme-landscape" target="_blank" rel="external">hexo-theme-landscape</a> is on
github.
<a href="/">Take the First Step</a> uses the work branch.
I <a href="https://git-scm.com/docs/git-cherry-pick" target="_blank" rel="external">cherry-pick</a> commits from work to
master so that I can generate clean pull requests from master.</p>
]]></content>
    <summary type="html">
    <![CDATA[<p><a href="https://aws.amazon.com/cloudfront/" target="_blank" rel="external">CloudFront</a> is looking good.
My added bandwidth cost is ab]]>
    </summary>
    
      <category term="colophon" scheme="https://ideoplex.com/tags/colophon/"/>
    
      <category term="hexo" scheme="https://ideoplex.com/tags/hexo/"/>
    
      <category term="hosting" scheme="https://ideoplex.com/tags/hosting/"/>
    
      <category term="technology" scheme="https://ideoplex.com/categories/technology/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[Cucumber-java and TestNG]]></title>
    <link href="https://ideoplex.com/2015/11/03/cucumber-java-and-testng/"/>
    <id>https://ideoplex.com/2015/11/03/cucumber-java-and-testng/</id>
    <published>2015-11-04T01:59:09.000Z</published>
    <updated>2015-11-11T11:29:09.000Z</updated>
    <content type="html"><![CDATA[<p>With the addition
of my <a href="/2015/11/01/jersey-client-with-gson/">jersey client tests</a>, I thought I was
ready to add cucumber support to my project.
I was wrong.
The documentation on using Cucumber and TestNG is a bit sparse
and I was getting a bit flustered on where to put the feature definition file.</p>
<p>It turns out that I was making a mountain out of a mole hill.
If you put the feature file in the wrong place,
then cucumber will tell you where it was looking.</p>
<figure class="highlight groovy"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">$ mvn clean test -q -Dskip=client,browser</span><br><span class="line"></span><br><span class="line">-------------------------------------------------------</span><br><span class="line"> T E S T S</span><br><span class="line">-------------------------------------------------------</span><br><span class="line">Running TestSuite</span><br><span class="line">Configuring TestNG <span class="string">with:</span> TestNG652Configurator</span><br><span class="line">No features found at [<span class="string">classpath:</span>com<span class="regexp">/ideoplex/</span>tutorial]</span><br><span class="line"></span><br><span class="line"><span class="number">0</span> Scenarios</span><br><span class="line"><span class="number">0</span> Steps</span><br><span class="line"><span class="number">0</span>m0<span class="number">.000</span>s</span><br><span class="line"></span><br><span class="line">Tests <span class="string">run:</span> <span class="number">4</span>, <span class="string">Failures:</span> <span class="number">0</span>, <span class="string">Errors:</span> <span class="number">0</span>, <span class="string">Skipped:</span> <span class="number">0</span>, Time <span class="string">elapsed:</span> <span class="number">1.806</span> sec - <span class="keyword">in</span> TestSuite</span><br><span class="line"></span><br><span class="line"><span class="string">Results :</span></span><br><span class="line"></span><br><span class="line">Tests <span class="string">run:</span> <span class="number">4</span>, <span class="string">Failures:</span> <span class="number">0</span>, <span class="string">Errors:</span> <span class="number">0</span>, <span class="string">Skipped:</span> <span class="number">0</span></span><br></pre></td></tr></table></figure>
<a id="more"></a>
<p>So here’s the <strong>CucumberTest</strong> implementation of AbstractTestNGCucumberTests that
does the work.</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.ideoplex.tutorial;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> cucumber.api.CucumberOptions;</span><br><span class="line"><span class="keyword">import</span> cucumber.api.testng.AbstractTestNGCucumberTests;</span><br><span class="line"></span><br><span class="line"><span class="annotation">@CucumberOptions</span>(plugin = &#123;<span class="string">"json:target/cucumber-report.json"</span>,</span><br><span class="line">                           <span class="string">"html:target/cucumber-report"</span>&#125;)</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">CucumberTest</span> <span class="keyword">extends</span> <span class="title">AbstractTestNGCucumberTests</span></span><br><span class="line"></span>&#123;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>Here’s the feature file,
placed in <em>src/test/resources/com/ideoplex/tutorial</em>
to match the package path of <strong>CucumberTest</strong>.</p>
<figure class="highlight http"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">Feature</span>: <span class="string">User Management</span></span><br><span class="line"></span><br><span class="line"><span class="vbnet">Scenario: Add <span class="keyword">New</span> Email</span><br><span class="line">  Given prospective user <span class="keyword">with</span> email <span class="string">"user@example.com"</span> pre-exists</span><br><span class="line">   <span class="keyword">And</span>  email <span class="string">"user@example.com"</span> <span class="keyword">is</span> <span class="keyword">not</span> pre-registered</span><br><span class="line">  <span class="keyword">When</span>  user submits add <span class="string">"user@example.com"</span> form</span><br><span class="line">  <span class="keyword">Then</span>  email <span class="string">"user@example.com"</span> <span class="keyword">is</span> registered</span><br><span class="line"></span><br><span class="line">Scenario: Reject Duplicate Email</span><br><span class="line">  Given prospective user <span class="keyword">with</span> email <span class="string">"user@example.com"</span> pre-exists</span><br><span class="line">   <span class="keyword">And</span>  email <span class="string">"user@example.com"</span> <span class="keyword">is</span> pre-registered</span><br><span class="line">  <span class="keyword">When</span>  user submits add <span class="string">"user@example.com"</span> form</span><br><span class="line">  <span class="keyword">Then</span>  duplicate email <span class="string">"user@example.com"</span> <span class="keyword">error</span> <span class="keyword">is</span> thrown</span></span><br></pre></td></tr></table></figure>
<p>And the updates to the pom.xml to include the cucumber dependencies.</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="title">version</span>&gt;</span>$&#123;jersey.client.version&#125;<span class="tag">&lt;/<span class="title">version</span>&gt;</span></span><br><span class="line">           <span class="tag">&lt;<span class="title">scope</span>&gt;</span>test<span class="tag">&lt;/<span class="title">scope</span>&gt;</span></span><br><span class="line">         <span class="tag">&lt;/<span class="title">dependency</span>&gt;</span></span><br><span class="line">+        <span class="tag">&lt;<span class="title">dependency</span>&gt;</span></span><br><span class="line">+          <span class="tag">&lt;<span class="title">groupId</span>&gt;</span>info.cukes<span class="tag">&lt;/<span class="title">groupId</span>&gt;</span></span><br><span class="line">+          <span class="tag">&lt;<span class="title">artifactId</span>&gt;</span>cucumber-java<span class="tag">&lt;/<span class="title">artifactId</span>&gt;</span></span><br><span class="line">+          <span class="tag">&lt;<span class="title">version</span>&gt;</span>$&#123;cukes.version&#125;<span class="tag">&lt;/<span class="title">version</span>&gt;</span></span><br><span class="line">+          <span class="tag">&lt;<span class="title">scope</span>&gt;</span>test<span class="tag">&lt;/<span class="title">scope</span>&gt;</span></span><br><span class="line">+        <span class="tag">&lt;/<span class="title">dependency</span>&gt;</span></span><br><span class="line">+        <span class="tag">&lt;<span class="title">dependency</span>&gt;</span></span><br><span class="line">+          <span class="tag">&lt;<span class="title">groupId</span>&gt;</span>info.cukes<span class="tag">&lt;/<span class="title">groupId</span>&gt;</span></span><br><span class="line">+          <span class="tag">&lt;<span class="title">artifactId</span>&gt;</span>cucumber-testng<span class="tag">&lt;/<span class="title">artifactId</span>&gt;</span></span><br><span class="line">+          <span class="tag">&lt;<span class="title">version</span>&gt;</span>$&#123;cukes.version&#125;<span class="tag">&lt;/<span class="title">version</span>&gt;</span></span><br><span class="line">+          <span class="tag">&lt;<span class="title">scope</span>&gt;</span>test<span class="tag">&lt;/<span class="title">scope</span>&gt;</span></span><br><span class="line">+        <span class="tag">&lt;/<span class="title">dependency</span>&gt;</span></span><br><span class="line">     <span class="tag">&lt;/<span class="title">dependencies</span>&gt;</span></span><br><span class="line">     <span class="tag">&lt;<span class="title">properties</span>&gt;</span></span><br><span class="line">         <span class="tag">&lt;<span class="title">jersey.version</span>&gt;</span>2.12<span class="tag">&lt;/<span class="title">jersey.version</span>&gt;</span></span><br><span class="line"> @@ -138,6 +150,7 @@</span><br><span class="line">         <span class="tag">&lt;<span class="title">testng.version</span>&gt;</span>6.9.4<span class="tag">&lt;/<span class="title">testng.version</span>&gt;</span></span><br><span class="line">         <span class="tag">&lt;<span class="title">selenium.version</span>&gt;</span>2.45.0<span class="tag">&lt;/<span class="title">selenium.version</span>&gt;</span></span><br><span class="line">         <span class="tag">&lt;<span class="title">surefire.version</span>&gt;</span>2.18.1<span class="tag">&lt;/<span class="title">surefire.version</span>&gt;</span></span><br><span class="line">+        <span class="tag">&lt;<span class="title">cukes.version</span>&gt;</span>1.2.4<span class="tag">&lt;/<span class="title">cukes.version</span>&gt;</span></span><br><span class="line">         <span class="tag">&lt;<span class="title">skip</span>&gt;</span><span class="tag">&lt;/<span class="title">skip</span>&gt;</span></span><br><span class="line">     <span class="tag">&lt;/<span class="title">properties</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;/<span class="title">project</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>This version of
<a href="https://github.com/ideoplex/jersey-gson/commit/5695d15c0b070432a872ab814eb9a943dac62bb2" target="_blank" rel="external">Jersey, Gson and DataTables</a>
is on my github work branch.
Normally I link to the master branch,
but this feature is still half baked.</p>
<p><em>01 Nov <a href="/2015/11/01/jersey-client-with-gson/">Jersey Client with Gson</a></em></p>
]]></content>
    <summary type="html">
    <![CDATA[<p>With the addition
of my <a href="/2015/11/01/jersey-client-with-gson/">jersey client tests</a>, I thought I was
ready to add cucumber support to my project.
I was wrong.
The documentation on using Cucumber and TestNG is a bit sparse
and I was getting a bit flustered on where to put the feature definition file.</p>
<p>It turns out that I was making a mountain out of a mole hill.
If you put the feature file in the wrong place,
then cucumber will tell you where it was looking.</p>
<figure class="highlight groovy"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">$ mvn clean test -q -Dskip=client,browser</span><br><span class="line"></span><br><span class="line">-------------------------------------------------------</span><br><span class="line"> T E S T S</span><br><span class="line">-------------------------------------------------------</span><br><span class="line">Running TestSuite</span><br><span class="line">Configuring TestNG <span class="string">with:</span> TestNG652Configurator</span><br><span class="line">No features found at [<span class="string">classpath:</span>com<span class="regexp">/ideoplex/</span>tutorial]</span><br><span class="line"></span><br><span class="line"><span class="number">0</span> Scenarios</span><br><span class="line"><span class="number">0</span> Steps</span><br><span class="line"><span class="number">0</span>m0<span class="number">.000</span>s</span><br><span class="line"></span><br><span class="line">Tests <span class="string">run:</span> <span class="number">4</span>, <span class="string">Failures:</span> <span class="number">0</span>, <span class="string">Errors:</span> <span class="number">0</span>, <span class="string">Skipped:</span> <span class="number">0</span>, Time <span class="string">elapsed:</span> <span class="number">1.806</span> sec - <span class="keyword">in</span> TestSuite</span><br><span class="line"></span><br><span class="line"><span class="string">Results :</span></span><br><span class="line"></span><br><span class="line">Tests <span class="string">run:</span> <span class="number">4</span>, <span class="string">Failures:</span> <span class="number">0</span>, <span class="string">Errors:</span> <span class="number">0</span>, <span class="string">Skipped:</span> <span class="number">0</span></span><br></pre></td></tr></table></figure>]]>
    
    </summary>
    
      <category term="java" scheme="https://ideoplex.com/tags/java/"/>
    
      <category term="testing" scheme="https://ideoplex.com/tags/testing/"/>
    
      <category term="technology" scheme="https://ideoplex.com/categories/technology/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[Jersey Client with Gson]]></title>
    <link href="https://ideoplex.com/2015/11/01/jersey-client-with-gson/"/>
    <id>https://ideoplex.com/2015/11/01/jersey-client-with-gson/</id>
    <published>2015-11-01T19:49:23.000Z</published>
    <updated>2015-11-11T11:29:09.000Z</updated>
    <content type="html"><![CDATA[<p>It doesn’t make sense to have full test coverage of the <a href="https://github.com/ideoplex/jersey-gson" target="_blank" rel="external">jersey-gson</a> project
in <a href="/2015/06/21/jquery-ajax-and-selenium/">selenium</a>.
Let’s fill in the gaps with some jersey-client unit tests.</p>
<p>First,
we need a UserMap deserializer to mirror the existing serializer.
The existing serializer sends the UserMap as an object whose value is an Array of rows
(this simplifies interaction with the DataTables front end).
We deserialize the UserMap by iterating through the array,
turning each row into a User object,
and adding each User object to the Map.</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">...</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">UserMapUnmarshall</span> <span class="keyword">implements</span> <span class="title">JsonDeserializer</span>&lt;<span class="title">UserMap</span>&gt; </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> Gson gson = <span class="keyword">new</span> Gson();</span><br><span class="line"></span><br><span class="line">    <span class="annotation">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> UserMap <span class="title">deserialize</span><span class="params">(JsonElement mapFormat, Type typeOfSrc, JsonDeserializationContext context)</span> </span>&#123;</span><br><span class="line">        Iterator&lt;JsonElement&gt;  iterate = mapFormat.getAsJsonObject()</span><br><span class="line">            .get(<span class="string">"data"</span>)</span><br><span class="line">            .getAsJsonArray()</span><br><span class="line">            .iterator();</span><br><span class="line"></span><br><span class="line">        UserMap  users = <span class="keyword">new</span> UserMap();</span><br><span class="line">        <span class="keyword">while</span>( iterate.hasNext() ) &#123;</span><br><span class="line">            JsonObject user     = ((JsonElement) iterate.next()).getAsJsonObject();</span><br><span class="line">            String     email    = user.get(<span class="string">"email"</span>).getAsString();</span><br><span class="line">            User       add      = <span class="keyword">new</span> User();</span><br><span class="line">            add.setEmail( email );</span><br><span class="line">            add.setSurname( user.get(<span class="string">"surname"</span>).getAsString() );</span><br><span class="line">            add.setGivenName( user.get(<span class="string">"givenName"</span>).getAsString() );</span><br><span class="line">            users.put( email, add );</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> users;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<a id="more"></a>
<p>Next,
we need to register the new UserMapUnmarshall class for use by the GsonReader class -
just as we registered the UserMapMarshall class for the GsonWriter class.</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line">diff --git a/src/main/java/com/ideoplex/tutorial/GsonReader.java b/src/main/java/com/ideoplex/tutorial/GsonReader.java</span><br><span class="line">index <span class="number">144f</span>bde..<span class="number">4e117</span>cc <span class="number">100644</span></span><br><span class="line">--- a/src/main/java/com/ideoplex/tutorial/GsonReader.java</span><br><span class="line">+++ b/src/main/java/com/ideoplex/tutorial/GsonReader.java</span><br><span class="line">@@ -<span class="number">28</span>,<span class="number">12</span> +<span class="number">28</span>,<span class="number">16</span> @@ <span class="keyword">import</span> javax.ws.rs.core.MultivaluedMap;</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"> <span class="keyword">import</span> com.google.gson.Gson;</span><br><span class="line">+<span class="keyword">import</span> com.google.gson.GsonBuilder;</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"> <span class="annotation">@Provider</span></span><br><span class="line"> <span class="annotation">@Consumes</span>(MediaType.APPLICATION_JSON)</span><br><span class="line"> <span class="annotation">@Singleton</span></span><br><span class="line"> <span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">GsonReader</span>&lt;<span class="title">T</span>&gt; <span class="keyword">implements</span> <span class="title">MessageBodyReader</span>&lt;<span class="title">T</span>&gt; </span>&#123;</span><br><span class="line">+    <span class="keyword">protected</span> <span class="keyword">static</span> Gson gson = <span class="keyword">new</span> GsonBuilder()</span><br><span class="line">+        .registerTypeAdapter(UserMap.class,<span class="keyword">new</span> UserMapUnmarshall())</span><br><span class="line">+        .create();</span><br><span class="line">  </span><br><span class="line">     <span class="annotation">@Override</span></span><br><span class="line">     <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">isReadable</span><span class="params">(Class&lt;?&gt; type, Type genericType,</span><br><span class="line">@@ -<span class="number">46</span>,<span class="number">8</span> +<span class="number">50</span>,<span class="number">7</span> @@ <span class="keyword">public</span> class GsonReader&lt;T&gt; implements MessageBodyReader&lt;T&gt; &#123;</span><br><span class="line">             Annotation[] antns, MediaType mt,</span><br><span class="line">             MultivaluedMap&lt;String, String&gt; mm, InputStream in)</span></span><br><span class="line">             <span class="keyword">throws</span> IOException, WebApplicationException </span>&#123;</span><br><span class="line">-        Gson g = <span class="keyword">new</span> Gson();</span><br><span class="line">-        <span class="keyword">return</span> g.fromJson(_convertStreamToString(in), type);</span><br><span class="line">+        <span class="keyword">return</span> gson.fromJson(_convertStreamToString(in), type);</span><br><span class="line">     &#125;</span><br><span class="line">  </span><br><span class="line">     <span class="function"><span class="keyword">private</span> String <span class="title">_convertStreamToString</span><span class="params">(InputStream inputStream)</span></span></span><br></pre></td></tr></table></figure>
<p>Let’s complete our suite of server services by adding a method to get a single user and a method to delete a user.
The new feature in this code is the use of the PathParam annotation to extract values from the request path.
And the remainder of the new code builds on features that we’ve used before. </p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line">diff --git a/src/main/java/com/ideoplex/tutorial/MyResource.java b/src/main/java/com/ideoplex/tutorial/MyResource.java</span><br><span class="line">index a69c8ac..<span class="number">6</span>ef69fb <span class="number">100644</span></span><br><span class="line">--- a/src/main/java/com/ideoplex/tutorial/MyResource.java</span><br><span class="line">+++ b/src/main/java/com/ideoplex/tutorial/MyResource.java</span><br><span class="line">@@ -<span class="number">1</span>,<span class="number">8</span> +<span class="number">1</span>,<span class="number">10</span> @@</span><br><span class="line"> <span class="keyword">package</span> com.ideoplex.tutorial;</span><br><span class="line"> </span><br><span class="line">+<span class="keyword">import</span> javax.ws.rs.DELETE;</span><br><span class="line"> <span class="keyword">import</span> javax.ws.rs.GET;</span><br><span class="line"> <span class="keyword">import</span> javax.ws.rs.POST;</span><br><span class="line"> <span class="keyword">import</span> javax.ws.rs.Path;</span><br><span class="line">+<span class="keyword">import</span> javax.ws.rs.PathParam;</span><br><span class="line"> <span class="keyword">import</span> javax.ws.rs.QueryParam;</span><br><span class="line"> <span class="keyword">import</span> javax.ws.rs.Consumes;</span><br><span class="line"> <span class="keyword">import</span> javax.ws.rs.Produces;</span><br><span class="line">@@ -<span class="number">61</span>,<span class="number">6</span> +<span class="number">63</span>,<span class="number">32</span> @@ <span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MyResource</span> </span>&#123;</span><br><span class="line">         <span class="keyword">return</span> user;</span><br><span class="line">     &#125;</span><br><span class="line"> </span><br><span class="line">+    <span class="annotation">@GET</span></span><br><span class="line">+    <span class="annotation">@Path</span>(<span class="string">"user/get/&#123;email&#125;"</span>)</span><br><span class="line">+    <span class="annotation">@Produces</span>(MediaType.APPLICATION_JSON)</span><br><span class="line">+    <span class="function"><span class="keyword">public</span> User <span class="title">getUser</span><span class="params">(@PathParam(<span class="string">"email"</span>)</span> String email) </span>&#123;</span><br><span class="line">+        User  rVal   = users.get(email);</span><br><span class="line">+        <span class="keyword">if</span> ( rVal == <span class="keyword">null</span> ) &#123;</span><br><span class="line">+            <span class="keyword">throw</span> <span class="keyword">new</span> WebApplicationException(Response</span><br><span class="line">+                                              .status(Response.Status.NOT_FOUND)</span><br><span class="line">+                                              .build());</span><br><span class="line">+        &#125;</span><br><span class="line">+        <span class="keyword">return</span> rVal;</span><br><span class="line">+    &#125;</span><br><span class="line">+</span><br><span class="line">+    <span class="annotation">@DELETE</span></span><br><span class="line">+    <span class="annotation">@Path</span>(<span class="string">"user/delete/&#123;email&#125;"</span>)</span><br><span class="line">+    <span class="annotation">@Produces</span>(MediaType.APPLICATION_JSON)</span><br><span class="line">+    <span class="function"><span class="keyword">public</span> User <span class="title">deleteUser</span><span class="params">(@PathParam(<span class="string">"email"</span>)</span> String email) </span>&#123;</span><br><span class="line">+        User  rVal   = users.remove(email);</span><br><span class="line">+        <span class="keyword">if</span> ( rVal == <span class="keyword">null</span> ) &#123;</span><br><span class="line">+            <span class="keyword">throw</span> <span class="keyword">new</span> WebApplicationException(Response</span><br><span class="line">+                                              .status(Response.Status.NOT_FOUND)</span><br><span class="line">+                                              .build());</span><br><span class="line">+        &#125;</span><br><span class="line">+        <span class="keyword">return</span> rVal;</span><br><span class="line">+    &#125;</span><br><span class="line">+</span><br><span class="line">     <span class="annotation">@POST</span></span><br><span class="line">     <span class="annotation">@Path</span>(<span class="string">"user/post"</span>)</span><br><span class="line">     <span class="annotation">@Consumes</span>(MediaType.APPLICATION_JSON)</span><br></pre></td></tr></table></figure>
<p>Now we can add a set of jersey client unit tests to exercise our server methods.
I’ve split the code into multiple blocks for for clarity.
The first block of code registers the GsonReader and GsonWriter classes for use by the client
(explicit registration is not needed on the server because the automated server scan searches for the annotated classes).</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">Client          client;</span><br><span class="line">WebResource     resource;</span><br><span class="line">ClientResponse  response;</span><br><span class="line"></span><br><span class="line">&#123;</span><br><span class="line">    ClientConfig config = <span class="keyword">new</span> DefaultClientConfig();</span><br><span class="line">    config.getClasses().add(GsonReader.class);</span><br><span class="line">    config.getClasses().add(GsonWriter.class);</span><br><span class="line"></span><br><span class="line">    client   = Client.create(config);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>Execute a GET with an email path parameter:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">System.out.println(<span class="string">"Verify that "</span> + email + <span class="string">" is not available yet"</span>);</span><br><span class="line">resource  = client.resource( url + <span class="string">"/get/"</span> + email );</span><br><span class="line">response  = resource.accept(MediaType.APPLICATION_JSON)</span><br><span class="line">    .get(ClientResponse.class);</span><br><span class="line"><span class="keyword">assert</span>( response.getStatus() == <span class="number">404</span> );</span><br></pre></td></tr></table></figure>
<p>Execute a POST, submitting a User object and parsing the User object from the response.</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">System.out.println(<span class="string">"Verify that user/post on "</span> + email + <span class="string">" succeeds"</span>);</span><br><span class="line">resource  = client.resource( url + <span class="string">"/post"</span> );</span><br><span class="line">response  = resource.accept(MediaType.APPLICATION_JSON)</span><br><span class="line">    .type(MediaType.APPLICATION_JSON)</span><br><span class="line">    .post(ClientResponse.class,sample);</span><br><span class="line"><span class="keyword">assert</span>( response.getStatus() == <span class="number">200</span> );</span><br><span class="line">User  rVal  = response.getEntity(User.class);</span><br><span class="line"><span class="keyword">assert</span>( email.equals(rVal.getEmail()) );</span><br></pre></td></tr></table></figure>
<p>Execute a GET, parsing the UserMap object from the response.</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">System.out.println(<span class="string">"Verify that "</span> + email + <span class="string">" is in the userMap"</span>);</span><br><span class="line">resource  = client.resource( url + <span class="string">"/map"</span> );</span><br><span class="line">response  = resource.accept(MediaType.APPLICATION_JSON)</span><br><span class="line">    .get(ClientResponse.class);</span><br><span class="line"><span class="keyword">assert</span>( response.getStatus() == <span class="number">200</span> );</span><br><span class="line">UserMap  rVal  = response.getEntity(UserMap.class);</span><br><span class="line"><span class="keyword">assert</span>( rVal != <span class="keyword">null</span> );</span><br><span class="line">User     look   = rVal.get(email);</span><br><span class="line"><span class="keyword">assert</span>( look != <span class="keyword">null</span> );</span><br></pre></td></tr></table></figure>
<p>Execute a DELETE, parsing the User object from the response.</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">System.out.println(<span class="string">"Verify that delete on "</span> + email + <span class="string">" succeeds"</span>);</span><br><span class="line">resource  = client.resource( url + <span class="string">"/delete/"</span> + email );</span><br><span class="line">response  = resource.accept(MediaType.APPLICATION_JSON)</span><br><span class="line">    .delete(ClientResponse.class);</span><br><span class="line"><span class="keyword">assert</span>( response.getStatus() == <span class="number">200</span> );</span><br><span class="line">User  rVal  = response.getEntity(User.class);</span><br><span class="line"><span class="keyword">assert</span>( email.equals(rVal.getEmail()) );</span><br></pre></td></tr></table></figure>
<p>And finally,
a small change to the BrowserTest test annotation to insure out new client tests run before the selenium tests.</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">diff --git a/src/test/java/com/ideoplex/tutorial/BrowserTest.java b/src/test/java/com/ideoplex/tutorial/BrowserTest.java</span><br><span class="line">index bac07fb..f70c161 <span class="number">100644</span></span><br><span class="line">--- a/src/test/java/com/ideoplex/tutorial/BrowserTest.java</span><br><span class="line">+++ b/src/test/java/com/ideoplex/tutorial/BrowserTest.java</span><br><span class="line">@@ -<span class="number">76</span>,<span class="number">7</span> +<span class="number">76</span>,<span class="number">7</span> @@ <span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">BrowserTest</span> </span>&#123;</span><br><span class="line">     &#125;</span><br><span class="line"> </span><br><span class="line">     <span class="annotation">@Parameters</span>(&#123;<span class="string">"browser"</span>,<span class="string">"baseurl"</span>,<span class="string">"waitajax"</span>&#125;)</span><br><span class="line">-    <span class="annotation">@Test</span>(invocationCount = <span class="number">2</span>, groups=<span class="string">"browser"</span>)</span><br><span class="line">+    <span class="annotation">@Test</span>(invocationCount = <span class="number">2</span>, dependsOnGroups=<span class="string">"client"</span>, groups=<span class="string">"browser"</span>)</span><br><span class="line">     <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">userCreate</span><span class="params">( String browser, String baseurl, String waitajax )</span></span><br><span class="line">     </span>&#123;</span><br><span class="line">         WebDriver driver = <span class="string">"chrome"</span>.equalsIgnoreCase(browser)</span><br></pre></td></tr></table></figure>
<p>The full source for this version of <a href="https://github.com/ideoplex/jersey-gson/commit/5fd91650b576838127c5dbe96bb1096e7095bb86" target="_blank" rel="external">Jersey, Gson and Datatables</a> is on github.
BTW, I’m using jersey-client 1.18 for expediency,
I’ll update this for 2.x in the near future.</p>
<p><em>31 Oct
<a href="/2015/10/31/jersey-gson-content-type-woes/">jersey-gson Content-Type Woes</a></em><br>
<em>03 Nov <a href="/2015/11/03/cucumber-java-and-testng/">Cucumber-java and TestNG</a></em></p>
]]></content>
    <summary type="html">
    <![CDATA[<p>It doesn’t make sense to have full test coverage of the <a href="https://github.com/ideoplex/jersey-gson">jersey-gson</a> project
in <a href="/2015/06/21/jquery-ajax-and-selenium/">selenium</a>.
Let’s fill in the gaps with some jersey-client unit tests.</p>
<p>First,
we need a UserMap deserializer to mirror the existing serializer.
The existing serializer sends the UserMap as an object whose value is an Array of rows
(this simplifies interaction with the DataTables front end).
We deserialize the UserMap by iterating through the array,
turning each row into a User object,
and adding each User object to the Map.</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">...</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">UserMapUnmarshall</span> <span class="keyword">implements</span> <span class="title">JsonDeserializer</span>&lt;<span class="title">UserMap</span>&gt; </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> Gson gson = <span class="keyword">new</span> Gson();</span><br><span class="line"></span><br><span class="line">    <span class="annotation">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> UserMap <span class="title">deserialize</span><span class="params">(JsonElement mapFormat, Type typeOfSrc, JsonDeserializationContext context)</span> </span>&#123;</span><br><span class="line">        Iterator&lt;JsonElement&gt;  iterate = mapFormat.getAsJsonObject()</span><br><span class="line">            .get(<span class="string">"data"</span>)</span><br><span class="line">            .getAsJsonArray()</span><br><span class="line">            .iterator();</span><br><span class="line"></span><br><span class="line">        UserMap  users = <span class="keyword">new</span> UserMap();</span><br><span class="line">        <span class="keyword">while</span>( iterate.hasNext() ) &#123;</span><br><span class="line">            JsonObject user     = ((JsonElement) iterate.next()).getAsJsonObject();</span><br><span class="line">            String     email    = user.get(<span class="string">"email"</span>).getAsString();</span><br><span class="line">            User       add      = <span class="keyword">new</span> User();</span><br><span class="line">            add.setEmail( email );</span><br><span class="line">            add.setSurname( user.get(<span class="string">"surname"</span>).getAsString() );</span><br><span class="line">            add.setGivenName( user.get(<span class="string">"givenName"</span>).getAsString() );</span><br><span class="line">            users.put( email, add );</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> users;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]>
    
    </summary>
    
      <category term="gson" scheme="https://ideoplex.com/tags/gson/"/>
    
      <category term="java" scheme="https://ideoplex.com/tags/java/"/>
    
      <category term="technology" scheme="https://ideoplex.com/categories/technology/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[jersey-gson Content-Type Woes]]></title>
    <link href="https://ideoplex.com/2015/10/31/jersey-gson-content-type-woes/"/>
    <id>https://ideoplex.com/2015/10/31/jersey-gson-content-type-woes/</id>
    <published>2015-10-31T18:36:59.000Z</published>
    <updated>2015-11-11T11:29:09.000Z</updated>
    <content type="html"><![CDATA[<p>Another update to my <a href="https://github.com/ideoplex/jersey-gson/commit/e7bfbd4837a02d451a93bff640639be7b7028972" target="_blank" rel="external">jersey-gson</a> project today.
I was trying to add some jersey-client unit tests to the project,
but I just couldn’t get the GsonReader and GsonWriter classes to work on the client.
The tests worked with manually generated JSON,
but failed with automatically generated JSON.</p>
<p>I tried adding a LoggingFilter to examine the actual request being sent to the server,
but nothing jumped out at me.
Then I added <a href="http://fiddler.wikidot.com/mono" target="_blank" rel="external">Mono Fiddler</a> as a debugging
<a href="http://stackoverflow.com/a/16232381" target="_blank" rel="external">proxy server</a> and I saw it.</p>
<blockquote><p>The request succeeded with “Content-Type: application/json”<br>
The request failed with “Content-Type: application/json; charset=UTF-8”</p>
</blockquote>
<p>A quick change to GsonWriter and my client requests started working.
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">diff --git a/src/main/java/com/ideoplex/tutorial/GsonWriter.java b/src/main/java/com/ideoplex/tutorial/GsonWriter.java</span><br><span class="line">index <span class="number">9</span>ef181d..<span class="number">95</span>a12c3 <span class="number">100644</span></span><br><span class="line">--- a/src/main/java/com/ideoplex/tutorial/GsonWriter.java</span><br><span class="line">+++ b/src/main/java/com/ideoplex/tutorial/GsonWriter.java</span><br><span class="line">@@ -<span class="number">42</span>,<span class="number">7</span> +<span class="number">42</span>,<span class="number">6</span> @@ <span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">GsonWriter</span>&lt;<span class="title">T</span>&gt; <span class="keyword">implements</span> <span class="title">MessageBodyWriter</span>&lt;<span class="title">T</span>&gt; </span>&#123;</span><br><span class="line">             MultivaluedMap&lt;String, Object&gt; httpHeaders,</span><br><span class="line">             OutputStream entityStream)</span><br><span class="line">             <span class="keyword">throws</span> IOException, WebApplicationException &#123;</span><br><span class="line">-        httpHeaders.get(<span class="string">"Content-Type"</span>).add(<span class="string">"charset=UTF-8"</span>);</span><br><span class="line">         entityStream.write(gson.toJson(t).getBytes(<span class="string">"UTF-8"</span>));</span><br><span class="line">     &#125;</span><br></pre></td></tr></table></figure></p>
<p>Of course, code changes always cascade.
Now my selenium browser tests were failing.
A little exploration in the browser developer tools
revealed that JSON.parse was the culprit.
Another code update and the tests were succeeding.</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line">diff --git a/src/main/webapp/index.html b/src/main/webapp/index.html</span><br><span class="line">index <span class="number">9568</span>c94..f147ace <span class="number">100644</span></span><br><span class="line">--- a/src/main/webapp/index.html</span><br><span class="line">+++ b/src/main/webapp/index.html</span><br><span class="line">@@ -<span class="number">134</span>,<span class="number">13</span> +<span class="number">134</span>,<span class="number">13</span> @@</span><br><span class="line">          type:        <span class="string">"POST"</span>,</span><br><span class="line">          url:         <span class="string">"webapi/myresource/user/post"</span>,</span><br><span class="line">          data:        <span class="built_in">JSON</span>.stringify(json),</span><br><span class="line">-         contentType: <span class="string">"application/json; charset=utf-8"</span>,</span><br><span class="line">+         contentType: <span class="string">"application/json"</span>,</span><br><span class="line">          error:       <span class="function"><span class="keyword">function</span>(<span class="params">xhr,status,error</span>) </span>&#123;</span><br><span class="line">            bootbox.alert(xhr.responseText);</span><br><span class="line">          &#125;,</span><br><span class="line">          success:     <span class="function"><span class="keyword">function</span>(<span class="params">data,status,xhr</span>)</span>&#123;</span><br><span class="line">            form[<span class="number">0</span>].reset();</span><br><span class="line">-           $(<span class="string">'#users'</span>).DataTable().row.add(<span class="built_in">JSON</span>.parse(data)).draw(<span class="literal">false</span>);</span><br><span class="line">+           $(<span class="string">'#users'</span>).DataTable().row.add(data).draw(<span class="literal">false</span>);</span><br><span class="line">          &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">      &#125;</span><br><span class="line">@@ -<span class="number">151</span>,<span class="number">14</span> +<span class="number">151</span>,<span class="number">14</span> @@</span><br><span class="line">          type:        <span class="string">"POST"</span>,</span><br><span class="line">          url:         <span class="string">"webapi/myresource/user/edit"</span>,</span><br><span class="line">          data:        <span class="built_in">JSON</span>.stringify(json),</span><br><span class="line">-         contentType: <span class="string">"application/json; charset=utf-8"</span>,</span><br><span class="line">+         contentType: <span class="string">"application/json"</span>,</span><br><span class="line">          error:       <span class="function"><span class="keyword">function</span>(<span class="params">xhr,status,error</span>) </span>&#123;</span><br><span class="line">            bootbox.alert(xhr.responseText);</span><br><span class="line">            $(<span class="string">'#users tbody tr.selected'</span>).removeClass(<span class="string">'selected'</span>);</span><br><span class="line">          &#125;,</span><br><span class="line">          success:     <span class="function"><span class="keyword">function</span>(<span class="params">data,status,xhr</span>)</span>&#123;</span><br><span class="line">            form[<span class="number">0</span>].reset();</span><br><span class="line">-           $(<span class="string">'#users'</span>).DataTable().row(<span class="string">'.selected'</span>).data(<span class="built_in">JSON</span>.parse(data)).draw(<span class="literal">false</span>);</span><br><span class="line">+           $(<span class="string">'#users'</span>).DataTable().row(<span class="string">'.selected'</span>).data(data).draw(<span class="literal">false</span>);</span><br><span class="line">            $(<span class="string">'#users tbody tr.selected'</span>).removeClass(<span class="string">'selected'</span>);</span><br><span class="line">          &#125;</span><br><span class="line">        &#125;);</span><br></pre></td></tr></table></figure>
<p><em>25 Oct
<a href="/2015/10/25/autostart-jetty-in-maven/">Autostart Jetty in Maven</a></em><br>
<em>01 Nov
<a href="/2015/11/01/jersey-client-with-gson/">Jersey Client with Gson</a></em></p>
]]></content>
    <summary type="html">
    <![CDATA[<p>Another update to my <a href="https://github.com/ideoplex/jersey-gson/commit/e7bfbd4837a02d451a93bff640639be7b7028972" target="_blank" re]]>
    </summary>
    
      <category term="gson" scheme="https://ideoplex.com/tags/gson/"/>
    
      <category term="java" scheme="https://ideoplex.com/tags/java/"/>
    
      <category term="technology" scheme="https://ideoplex.com/categories/technology/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[Autostart Jetty in Maven]]></title>
    <link href="https://ideoplex.com/2015/10/25/autostart-jetty-in-maven/"/>
    <id>https://ideoplex.com/2015/10/25/autostart-jetty-in-maven/</id>
    <published>2015-10-26T00:12:43.000Z</published>
    <updated>2015-11-11T11:29:09.000Z</updated>
    <content type="html"><![CDATA[<p>I’ve made some administrative updates to my
<a href="https://github.com/ideoplex/jersey-gson/commit/6c3509c0e1a4470c426be53df460bffea6f04a47" target="_blank" rel="external">jersey-gson</a> project.</p>
<p>First, I’ve updated the pom.xml to automatically start the application in
jetty during the maven process-test-classes phase and to automatically stop the
jetty instance during the maven install phase.
This insures that the webapp will be running and available in the maven test,
integration-test and verify phases.</p>
<figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">diff --git a/pom.xml b/pom.xml&#10;index 318325d..47b6a2c 100644&#10;--- a/pom.xml&#10;+++ b/pom.xml&#10;@@ -47,6 +47,22 @@&#10;               &#60;groupId&#62;org.eclipse.jetty&#60;/groupId&#62;&#10;               &#60;artifactId&#62;jetty-maven-plugin&#60;/artifactId&#62;&#10;               &#60;version&#62;$&#123;jetty.version&#125;&#60;/version&#62;&#10;+              &#60;executions&#62;&#10;+                &#60;execution&#62;&#10;+                  &#60;id&#62;start-jetty&#60;/id&#62;&#10;+                  &#60;phase&#62;process-test-classes&#60;/phase&#62;&#10;+                  &#60;goals&#62;&#10;+                    &#60;goal&#62;start&#60;/goal&#62;&#10;+                  &#60;/goals&#62;&#10;+                &#60;/execution&#62;&#10;+                &#60;execution&#62;&#10;+                  &#60;id&#62;stop-jetty&#60;/id&#62;&#10;+                  &#60;phase&#62;install&#60;/phase&#62;&#10;+                  &#60;goals&#62;&#10;+                    &#60;goal&#62;stop&#60;/goal&#62;&#10;+                  &#60;/goals&#62;&#10;+                &#60;/execution&#62;&#10;+              &#60;/executions&#62;&#10;             &#60;/plugin&#62;&#10; &#10;             &#60;plugin&#62;</span><br></pre></td></tr></table></figure>
<a id="more"></a>
<p>With this change, it is no longer necessary to start jetty via “mvn jetty:run”
before executing the Selenium tests.
I’ve also changed the name of the class running the Selenium tests from
SetupTest to BrowserTest and made some minor updates:</p>
<ol>
<li>Added the invocationCount=2 to the userCreate @Test annotation to
automatically run the test twice. The first invocation demonstrates the
behavior when the user does not pre-exist and the second demonstrates
behavior when the user does exist.</li>
<li>Added the groups=”browser” to the userCreate @Test annotation.</li>
<li>Moved the Thread.sleep invocation to a new method. This method is annotated
to depend on the “browser” group so that it runs after the userCreate method.</li>
</ol>
<figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ diff -U2 SetupTest.java BrowserTest.java&#10;--- SetupTest.java&#9;2015-10-25 18:20:28.031091530 -0400&#10;+++ BrowserTest.java&#9;2015-10-25 18:21:37.855086967 -0400&#10;@@ -17,5 +17,5 @@&#10; &#10; &#10;-public class SetupTest &#123;&#10;+public class BrowserTest &#123;&#10; &#10;     protected boolean ajaxWait = false;&#10;@@ -77,7 +77,6 @@&#10; &#10;     @Parameters(&#123;&#34;browser&#34;,&#34;baseurl&#34;,&#34;waitajax&#34;&#125;)&#10;-    @Test&#10;+    @Test(invocationCount = 2, groups=&#34;browser&#34;)&#10;     public void userCreate( String browser, String baseurl, String waitajax )&#10;-        throws Exception&#10;     &#123;&#10;         WebDriver driver = &#34;chrome&#34;.equalsIgnoreCase(browser)&#10;@@ -92,7 +91,14 @@&#10;         addUsers(driver);&#10; &#10;-        Thread.sleep(10000);&#10;         driver.quit();&#10;     &#125;&#10; &#10;+    @Test(dependsOnGroups = &#34;browser&#34;)&#10;+    public void pause()&#10;+        throws Exception&#10;+    &#123;&#10;+        System.out.println(&#34;Sleeping&#34;);&#10;+        Thread.sleep(10000);&#10;+    &#125;&#10;+&#10; &#125;</span><br></pre></td></tr></table></figure>
<p>With this change, the “mvn test” output looks like this:</p>
<figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ mvn test&#10;[INFO] Scanning for projects...&#10; ...&#10;[INFO] jetty-9.3.0.M2&#10;[INFO] Started o.e.j.m.p.JettyWebAppContext@1813f3e9&#123;/,file:///Projects/webapp/jersey-gson/src/main/webapp/,AVAILABLE&#125;&#123;file:///Projects/webapp/jersey-gson/src/main/webapp/&#125;&#10;[INFO] Started ServerConnector@806996&#123;HTTP/1.1,[http/1.1]&#125;&#123;0.0.0.0:8080&#125;&#10;[INFO] Started @3741ms&#10;[INFO] Started Jetty Server&#10;[INFO] &#10;[INFO] --- maven-surefire-plugin:2.18.1:test (default-test) @ jersey-gson ---&#10;[INFO] Surefire report directory: /Projects/webapp/jersey-gson/target/surefire-reports&#10;&#10;-------------------------------------------------------&#10; T E S T S&#10;-------------------------------------------------------&#10;Running com.ideoplex.tutorial.BrowserTest&#10;Configuring TestNG with: TestNG652Configurator&#10;Compare george@example.com to No data available in table&#10;Compare john@example.com to No matching records found&#10;Compare thomas@example.com to No matching records found&#10;Compare james@example.com to No matching records found&#10;Compare james2@example.com to No matching records found&#10;Compare john2@example.com to No matching records found&#10;Compare andrew@example.com to No matching records found&#10;Compare martin@example.com to No matching records found&#10;Compare william@example.com to No matching records found&#10;Compare john3@example.com to No matching records found&#10;Compare james3@example.com to No matching records found&#10;Compare zachary@example.com to No matching records found&#10;Compare millard@example.com to No matching records found&#10;Compare abraham@example.com to No matching records found&#10;Compare george@example.com to george@example.com&#10;Compare john@example.com to john@example.com&#10;Compare thomas@example.com to thomas@example.com&#10;Compare james@example.com to james@example.com&#10;Compare james2@example.com to james2@example.com&#10;Compare john2@example.com to john2@example.com&#10;Compare andrew@example.com to andrew@example.com&#10;Compare martin@example.com to martin@example.com&#10;Compare william@example.com to william@example.com&#10;Compare john3@example.com to john3@example.com&#10;Compare james3@example.com to james3@example.com&#10;Compare zachary@example.com to zachary@example.com&#10;Compare millard@example.com to millard@example.com&#10;Compare abraham@example.com to abraham@example.com&#10;Sleeping&#10;Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 59.271 sec - in com.ideoplex.tutorial.BrowserTest&#10;&#10;Results :&#10;&#10;Tests run: 3, Failures: 0, Errors: 0, Skipped: 0&#10;&#10;[INFO] ------------------------------------------------------------------------&#10;[INFO] BUILD SUCCESS&#10;[INFO] ------------------------------------------------------------------------&#10;[INFO] Total time: 01:02 min&#10;[INFO] Finished at: 2015-10-25T20:06:20-04:00&#10;[INFO] Final Memory: 24M/285M&#10;[INFO] ------------------------------------------------------------------------</span><br></pre></td></tr></table></figure>
<p><em>16 Aug
<a href="/2015/08/16/datatables-bootstrap-and-text-overflow/">DataTables, Bootstrap and Text Overflow</a></em><br>
<em>31 Oct <a href="/2015/10/31/jersey-gson-content-type-woes/">jersey-gson Content-Type Woes</a></em></p>
]]></content>
    <summary type="html">
    <![CDATA[<p>I’ve made some administrative updates to my
<a href="https://github.com/ideoplex/jersey-gson/commit/6c3509c0e1a4470c426be53df460bffea6f04a47">jersey-gson</a> project.</p>
<p>First, I’ve updated the pom.xml to automatically start the application in
jetty during the maven process-test-classes phase and to automatically stop the
jetty instance during the maven install phase.
This insures that the webapp will be running and available in the maven test,
integration-test and verify phases.</p>
<figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">diff --git a/pom.xml b/pom.xml&#10;index 318325d..47b6a2c 100644&#10;--- a/pom.xml&#10;+++ b/pom.xml&#10;@@ -47,6 +47,22 @@&#10;               &#60;groupId&#62;org.eclipse.jetty&#60;/groupId&#62;&#10;               &#60;artifactId&#62;jetty-maven-plugin&#60;/artifactId&#62;&#10;               &#60;version&#62;$&#123;jetty.version&#125;&#60;/version&#62;&#10;+              &#60;executions&#62;&#10;+                &#60;execution&#62;&#10;+                  &#60;id&#62;start-jetty&#60;/id&#62;&#10;+                  &#60;phase&#62;process-test-classes&#60;/phase&#62;&#10;+                  &#60;goals&#62;&#10;+                    &#60;goal&#62;start&#60;/goal&#62;&#10;+                  &#60;/goals&#62;&#10;+                &#60;/execution&#62;&#10;+                &#60;execution&#62;&#10;+                  &#60;id&#62;stop-jetty&#60;/id&#62;&#10;+                  &#60;phase&#62;install&#60;/phase&#62;&#10;+                  &#60;goals&#62;&#10;+                    &#60;goal&#62;stop&#60;/goal&#62;&#10;+                  &#60;/goals&#62;&#10;+                &#60;/execution&#62;&#10;+              &#60;/executions&#62;&#10;             &#60;/plugin&#62;&#10; &#10;             &#60;plugin&#62;</span><br></pre></td></tr></table></figure>]]>
    
    </summary>
    
      <category term="maven" scheme="https://ideoplex.com/tags/maven/"/>
    
      <category term="technology" scheme="https://ideoplex.com/categories/technology/"/>
    
  </entry>
  
</feed>
