<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title>Craig Burke</title>
		<description></description>		
		<link>http://www.craigburke.com</link>
		<atom:link href="http://www.craigburke.com/feed.xml" rel="self" type="application/rss+xml" />
		
			<item>
				<title>Groovy Document Builder - MPL Edition</title>
				<description>&lt;p&gt;&lt;strong&gt;With the latest release of the &lt;a href=&quot;https://github.com/craigburke/document-builder&quot;&gt;Groovy Document Builder&lt;/a&gt;, the entire project (including the PDF builder) are now available under the MPL2 license.&lt;/strong&gt; 
I’ve removed iText as a dependency and am now using PdfBox for the Pdf generation so that everyone can use this with the far more permissive MPL2 license (instead of AGPL).&lt;/p&gt;

&lt;p&gt;Here’s an updated example using the latest version:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;example.groovy&lt;/strong&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-groovy&quot; data-lang=&quot;groovy&quot;&gt;&lt;span class=&quot;nd&quot;&gt;@Grab&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;group&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'com.craigburke.document'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'pdf'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'0.2.4'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Grab&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;group&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'com.craigburke.document'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'word'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'0.2.4'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;com.craigburke.document.builder.PdfDocumentBuilder&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;com.craigburke.document.builder.WordDocumentBuilder&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;com.craigburke.document.core.Align&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;builders&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;PdfDocumentBuilder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'example.pdf'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)),&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;WordDocumentBuilder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'example.docx'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RAINBOW_COLORS&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'#FF0000'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'#FF7F00'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'#FFFF00'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'#00FF00'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'#0000FF'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'#4B0082'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'#8B00FF'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GROOVY_IMAGE_URL&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'http://www.craigburke.com/images/posts/groovy-logo.png'&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;groovyImageData&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;URL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GROOVY_IMAGE_URL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;bytes&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;builders&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;create&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; 
		&lt;span class=&quot;n&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;font:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;family:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Helvetica'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;size:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;14&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;pt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;margin:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;top:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.75&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;inches&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;paragraph&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Groovy Document Builder v.0.2.4&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;font:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;color:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'#990000'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;size:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;22&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;pt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;paragraph&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;font&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;42&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;pt&lt;/span&gt;
            &lt;span class=&quot;s2&quot;&gt;&quot;Hello Woooorld!!!!!&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;toUpperCase&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;eachWithIndex&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;letter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;font&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;color&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RAINBOW_COLORS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RAINBOW_COLORS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;letter&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;font&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;--&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;lineBreak&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Current font size is ${font.size}pt&quot;&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;paragraph&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Back to default font and aligned to the right&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;align:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Align&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;RIGHT&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;paragraph&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;margin:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;left:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.25&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;inches&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;right:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;inch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;top:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.25&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;inches&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;bottom:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.25&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;inches&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;font&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;family:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Times-Roman'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;bold:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;italic:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;color:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'#333333'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;A paragraph with a different font and margins&quot;&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;paragraph&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;align:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Align&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;CENTER&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;data:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;groovyImageData&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;width:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;250&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;px&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;height:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;125&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;px&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;lineBreak&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Figure 1: Groovy Logo&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;font:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;italic:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;size:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;pt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;paragraph&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Suddenly, a table...&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;font:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;size:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;22&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;pt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;])&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;table&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;width:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;inches&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;padding:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;px&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;border:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;size:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;px&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;color:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'#990000'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;cell&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Left Aligned&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;width:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.5&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;inches&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;align:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Align&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;LEFT&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;cell&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Center Aligned&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;width:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;inches&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;align:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Align&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;CENTER&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;cell&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;align:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Align&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;RIGHT&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Right Aligned&quot;&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This will render a Word and Pdf document that looks like this:
&lt;img src=&quot;/images/posts/groovy-document-builder-2.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;PdfBox works great but it’s extremely low level. When rendering the paragraphs and tables I have to do all the work of breaking up lines,
positioning the text on the page, and drawing the lines of the table borders.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;While the test coverage is looking much better now, given how much more complex the builder is I anticipate there being some edge cases in
rendering both paragraphs and tables that I missed. If you run into any issues, please &lt;a href=&quot;https://github.com/craigburke/document-builder/issues&quot;&gt;raise an issue&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I’ll start planning the next release (0.3) soon, which should include at very least headers and footers. Feel free to offer up any suggestions or 
feedback on how things look like so far either on the &lt;a href=&quot;https://github.com/craigburke/document-builder&quot;&gt;project page&lt;/a&gt; or on twitter (&lt;a href=&quot;https://twitter.com/craigburke1&quot;&gt;@craigburke1&lt;/a&gt;).&lt;/p&gt;
</description>
				<pubDate>Mon, 02 Mar 2015 00:00:00 +0000</pubDate>
				<link>http://www.craigburke.com/2015/03/02/groovy-document-builder-mpl-edition.html</link>
				<guid isPermaLink="true">http://www.craigburke.com/2015/03/02/groovy-document-builder-mpl-edition.html</guid>
			</item>
		
			<item>
				<title>Monthly Book Roundup (December 2014)</title>
				<description>&lt;p&gt;I’m more than a little late writing my last roundup for 2014 but it includes an awesome Spring Boot book and an extremely comprehensive book about iText.&lt;/p&gt;

&lt;dl class=&quot;books&quot;&gt;

  &lt;dt&gt;
	&lt;a href=&quot;https://www.packtpub.com/application-development/learning-spring-boot&quot;&gt;
		&lt;img src=&quot;/images/books/learning-spring-boot.jpg&quot; /&gt;
	&lt;/a&gt;
  &lt;/dt&gt;
  &lt;dd&gt;

    &lt;h4&gt;&lt;a href=&quot;https://www.packtpub.com/application-development/learning-spring-boot&quot;&gt;Learning Spring Boot&lt;/a&gt;&lt;/h4&gt;
  	&lt;p&gt;
		As I'm developing more and more in Spring Boot, this book has been absolutely indespensible to me. It's very well written and examples 
		are very practical and well explained. I especially liked how code is introduced with detailed explanation of the important lines. 
	&lt;/p&gt;
		
	&lt;p&gt;
		While most of the book is written using Java, Groovy gets some love in the first chapter and it made for a very pleasant introduction.
		I really enjoyed this book and I've referred back to it often since finishing it.
	&lt;/p&gt;
	
	&lt;p&gt;&lt;strong&gt;This book does an outstanding job of demystifying Spring Boot and all the magic that goes along with it. I very highly recommend it.&lt;/strong&gt;&lt;/p&gt;
	
	
  &lt;/dd&gt;

  &lt;dt&gt;
	&lt;a href=&quot;http://itextpdf.com/book/&quot;&gt;
		&lt;img src=&quot;/images/books/itext.jpg&quot; /&gt;
	&lt;/a&gt;
  &lt;/dt&gt;
  &lt;dd&gt;
    	&lt;h4&gt;&lt;a href=&quot;http://itextpdf.com/book/&quot;&gt;iText In Action&lt;/a&gt;&lt;/h4&gt;
       
	   	&lt;p&gt;
			This book is incredibly comprehensive, filled with tons of examples. After reading it, I was surprised at exactly how low level the pdf format is and 
			how much the iText library does to create a really nice abstraction over that. The later chapters really dig into the more advanced aspects of creating
			pdfs.
		&lt;/p&gt;
	   
		&lt;p&gt;
			I started reading this book after I began working on my &lt;a href=&quot;https://github.com/craigburke/document-builder&quot;&gt;Groovy Document Builder&lt;/a&gt; and the lessons learned
			from it have been really invaluable. 
		&lt;/p&gt;
		&lt;p&gt;
			&lt;strong&gt;While I'm transitioning away from iText for that particular project, I think this book is definitely worth a look if you're working with iText or 
				simply want more insight about the pdf format.&lt;/strong&gt;
		&lt;/p&gt;
  &lt;/dd&gt;

&lt;/dl&gt;
</description>
				<pubDate>Wed, 11 Feb 2015 00:00:00 +0000</pubDate>
				<link>http://www.craigburke.com/2015/02/11/monthly-book-roundup-december.html</link>
				<guid isPermaLink="true">http://www.craigburke.com/2015/02/11/monthly-book-roundup-december.html</guid>
			</item>
		
			<item>
				<title>Groovy Document Builder</title>
				<description>&lt;p&gt;While there are lots of extremely capable Java libraries for generating different kinds of documents (iText, Apache POI, etc), it’s 
not always easy to use these libraries. It’s for that reason that I decided to leverage Groovy’s excellent support for building DSLs to
create the &lt;a href=&quot;https://github.com/craigburke/document-builder&quot;&gt;Groovy Document Builder&lt;/a&gt; in order to simplify this.&lt;/p&gt;

&lt;p&gt;The best way to illustrate how it works is probably with an example&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;example.groovy&lt;/strong&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-groovy&quot; data-lang=&quot;groovy&quot;&gt;&lt;span class=&quot;nd&quot;&gt;@Grab&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;group&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'com.craigburke.document'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'pdf'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'0.1.6'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Grab&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;group&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'com.craigburke.document'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'word'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'0.1.6'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;com.craigburke.document.builder.PdfDocumentBuilder&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;com.craigburke.document.builder.WordDocumentBuilder&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;builders&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;PdfDocumentBuilder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'example.pdf'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)),&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;WordDocumentBuilder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'example.docx'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)),&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RAINBOW_COLORS&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'#FF0000'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'#FF7F00'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'#FFFF00'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'#00FF00'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'#0000FF'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'#4B0082'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'#8B00FF'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GROOVY_IMAGE_URL&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'http://www.craigburke.com/images/posts/groovy-logo.png'&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;groovyImageData&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;URL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GROOVY_IMAGE_URL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;bytes&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;builders&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;create&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;font:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;family:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Helvetica'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;size:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;14&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;pt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;margin:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;top:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.75&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;inches&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;paragraph&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Groovy Document Builder&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;font:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;size:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;22&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;pt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;paragraph&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;font&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;42&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;pt&lt;/span&gt;
            &lt;span class=&quot;s2&quot;&gt;&quot;Hello Woooorld!!!!!&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;toUpperCase&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;eachWithIndex&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;letter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;font&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;--&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;font&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;color&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RAINBOW_COLORS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RAINBOW_COLORS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;letter&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;lineBreak&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Current font size is ${font.size}pt&quot;&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;paragraph&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Font size is back to 14pt now with the default black font&quot;&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;paragraph&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;margin:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;left:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.25&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;inches&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;right:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;inch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;top:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.25&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;inches&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;bottom:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.25&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;inches&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;font&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;family:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Times-Roman'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;bold:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;italic:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;color:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'#333333'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;A paragraph with a different font and margins&quot;&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;paragraph&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;margin:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;left:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;inch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;data:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;groovyImageData&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;width:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;250&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;px&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;height:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;125&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;px&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;lineBreak&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Figure 1: Groovy Logo&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;font:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;italic:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;size:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;pt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;paragraph&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Suddenly, a table...&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;font:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;size:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;22&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;pt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;margin:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;bottom:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.25&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;inches&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;])&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;table&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;width:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;inches&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;cell&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Cell 1&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;width:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;inch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;cell&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Cell 2&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;width:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;inches&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;cell&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;width:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;inches&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Cell 3&quot;&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;After running&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-groovy&quot; data-lang=&quot;groovy&quot;&gt;&lt;span class=&quot;n&quot;&gt;groovy&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;example&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;groovy&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;both a Word document and a PDF fille will be created that look something like this:
&lt;img src=&quot;/images/posts/groovy-document-builder-1.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;A couple things to note about the code above:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Both builders use completely different libraries (iText for pdf and Apache POI for Word) but I can hide those differences thanks to Groovy’s amazing builder support.&lt;/li&gt;
  &lt;li&gt;Typically you wouldn’t grab the bytes of an image from a URL like I did here. Something like &lt;strong&gt;byte[] groovyImageData = new File(‘groovy.png’).bytes&lt;/strong&gt; would be more typical. I did it this way so the example could be completely self contained.&lt;/li&gt;
  &lt;li&gt;The properties like margins, font sizes, widths, etc all expect a value in points. Since options like margins are better expressed in inches you can use values like 2.inches or 1.inch and the 
conversion to points will be done for you.&lt;/li&gt;
  &lt;li&gt;Font options are inherited and properties be overriden at any level without impacting the rest of the document.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I think this is a really good start for this project and it meets the needs for several projects I’m working on right now, but there’s a lot I’d like to add to this such as lists, links, page headers, page footers, and sections. 
Documentation is clearly lacking at this point and I’d like to beef up the test suite as well. 
I’m also toying around with the idea of generating simpler document types like Markdown or AsciiDoc.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The current DSL or the future plans for this project are all very fluid right now. If you’d like to give feedback or make suggestions you can add it as an issue on the 
&lt;a href=&quot;https://github.com/craigburke/document-builder&quot;&gt;Groovy Document Builder project page&lt;/a&gt; or you can just send me a tweet &lt;a href=&quot;https://twitter.com/craigburke1&quot;&gt;@craigburke1&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

</description>
				<pubDate>Thu, 22 Jan 2015 00:00:00 +0000</pubDate>
				<link>http://www.craigburke.com/2015/01/22/groovy-document-builder.html</link>
				<guid isPermaLink="true">http://www.craigburke.com/2015/01/22/groovy-document-builder.html</guid>
			</item>
		
			<item>
				<title>Monthly Book Roundup (November 2014)</title>
				<description>&lt;p&gt;This month’s books include a great book about functional programming in Java 8 and a book about Groovy DSLs.&lt;/p&gt;

&lt;dl class=&quot;books&quot;&gt;

  &lt;dt&gt;
	&lt;a href=&quot;https://pragprog.com/book/vsjava8/functional-programming-in-java&quot;&gt;
		&lt;img src=&quot;/images/books/functional-java.jpg&quot; /&gt;
	&lt;/a&gt;
  &lt;/dt&gt;
  &lt;dd&gt;

    &lt;h4&gt;&lt;a href=&quot;https://pragprog.com/book/vsjava8/functional-programming-in-java&quot;&gt;Functional Programming in Java&lt;/a&gt;&lt;/h4&gt;
  	&lt;p&gt;First, I just want to say that I think this book was very good and extremely well written. So the following criticisms are directed at the Java language and not the book itself which I thoroughly enjoyed.&lt;/p&gt; 

  	&lt;p&gt;The hardest part about reading this book for me was the fact that I had to stop myself from mentally rewriting the examples in Groovy. The fact that Venkat (the author) used the same example for tail recursion in his excellent &lt;em&gt;Programming Groovy 2&lt;/em&gt; book certainly didn't help me to not make those comparisons.&lt;/p&gt;

  	&lt;p&gt;&lt;strong&gt;The functional programming additions in Java 8 are really exciting, but Groovy did it all first and in my opinion they still do it much better. If though you're interested in Java 8 lambdas and functional programming then this is an outstanding book and well worth reading.&lt;/strong&gt;&lt;/p&gt;

  &lt;/dd&gt;

  &lt;dt&gt;
	&lt;a href=&quot;https://www.packtpub.com/application-development/groovy-domain-specific-languages&quot;&gt;
		&lt;img src=&quot;/images/books/groovy-dsl.png&quot; /&gt;
	&lt;/a&gt;
  &lt;/dt&gt;
  &lt;dd&gt;
    	&lt;h4&gt;&lt;a href=&quot;https://www.packtpub.com/application-development/groovy-domain-specific-languages&quot;&gt;Groovy for Domain-Specific Languages&lt;/a&gt;&lt;/h4&gt;
       
		&lt;p&gt;While this book was fairly well written, I was overall disappointed by this one. First of all, it does deal with an older version of Groovy (1.6) so it doesn't touch on some of newer Groovy improvements related to DSLs.&lt;/p&gt;
		
		&lt;p&gt;The other major issue with this book is that there are quite a few errors in the code that make the examples very difficult to follow at times (ruining what would have been a really good example of implementing a rules engine in Chapter 8).&lt;/p&gt;

		&lt;p&gt;Despite my issues with the rest of the book, Chapters 6 and 7 were actually really solid and gave some useful insights by looking at existing Groovy DSLs and explaining how to implement your own builder.&lt;strong&gt; If you do decide to read this book to help you design your own DSL, I would stick to Chapters 6 and 7 and avoid the rest.&lt;/strong&gt;&lt;/p&gt;

  &lt;/dd&gt;

&lt;/dl&gt;
</description>
				<pubDate>Wed, 03 Dec 2014 00:00:00 +0000</pubDate>
				<link>http://www.craigburke.com/2014/12/03/monthly-book-roundup-november.html</link>
				<guid isPermaLink="true">http://www.craigburke.com/2014/12/03/monthly-book-roundup-november.html</guid>
			</item>
		
			<item>
				<title>AngularJS Grails Template - Part 2: Advanced Customization</title>
				<description>&lt;p&gt;This post is a followup to &lt;a href=&quot;/2014/11/17/angular-grails-template-1.html&quot;&gt;Part 1 - Getting Started,&lt;/a&gt; so if you haven’t already created an application using the Angular Grails Lazybones template, you should probably start there.&lt;/p&gt;

&lt;p&gt;Now I’m going talk about the ways you can further customize and tailor the Angular modules that the lazybones template generates.&lt;/p&gt;

&lt;h4 id=&quot;project-template&quot;&gt;Project Template&lt;/h4&gt;

&lt;p&gt;Whenever you run the &lt;strong&gt;lazybones generate module&lt;/strong&gt; command, it references the files found in &lt;strong&gt;src/templates/angular/crud&lt;/strong&gt; in your main project to build out your new module:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/angular-grails-lazybones-2-1.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The files here mirror your project structure, so you have fine grain control over what files are created and where they ultimately end up.&lt;/p&gt;

&lt;p&gt;Any files with a &lt;strong&gt;.gtpl&lt;/strong&gt; extension will be processed by the Groovy’s &lt;a href=&quot;http://groovy.codehaus.org/api/groovy/text/SimpleTemplateEngine.html&quot;&gt;SimpleTemplateEngine&lt;/a&gt; so the rules about escaping characters apply here.&lt;/p&gt;

&lt;p&gt;You can use the variables &lt;strong&gt;DOLLAR_SIGN,&lt;/strong&gt; &lt;strong&gt;TAB,&lt;/strong&gt; and &lt;strong&gt;NEWLINE&lt;/strong&gt; within your template files so to add those characters without having to worry about escaping them.&lt;/p&gt;

&lt;h4 id=&quot;path-variables&quot;&gt;Path Variables&lt;/h4&gt;

&lt;p&gt;You’ll notice in the screenshot above, that certain folder and file names have values like &lt;strong&gt;_resourceName_&lt;/strong&gt; or &lt;strong&gt;_groupPath_.&lt;/strong&gt; These refer to values that allow you to have more control over the destination of your template files. Note the use of the underscores surrounding the variable names in the file/folder names.&lt;/p&gt;

&lt;p&gt;Here’s a list of the variables that can be used to help build the paths within your project:&lt;/p&gt;

&lt;table class=&quot;table&quot;&gt;
&lt;thead&gt;
	&lt;tr&gt;
		&lt;th&gt;Variable&lt;/th&gt;
		&lt;th&gt;Description&lt;/th&gt;
		&lt;th&gt;Example&lt;/th&gt;
	&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;	
	&lt;tr&gt;
		&lt;td&gt;&lt;strong&gt;groupPath&lt;/strong&gt;&lt;/td&gt;
		&lt;td&gt;Java source path based on your project group&lt;/td&gt;
		&lt;td&gt;&lt;strong&gt;com/craigburke/angular&lt;/strong&gt; (for group com.craigburke.angular)&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;&lt;strong&gt;resourceName&lt;/strong&gt;&lt;/td&gt;
		&lt;td&gt;The domain class name&lt;/td&gt;
		&lt;td&gt;&lt;strong&gt;Employee&lt;/strong&gt;&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;&lt;strong&gt;moduleName&lt;/strong&gt;&lt;/td&gt;
		&lt;td&gt;the angular module name&lt;/td&gt;
		&lt;td&gt;&lt;strong&gt;exampleApp.employee&lt;/strong&gt;&lt;/td&gt;
	&lt;/tr&gt;

	&lt;tr&gt;
		&lt;td&gt;&lt;strong&gt;modulePath&lt;/strong&gt;&lt;/td&gt;
		&lt;td&gt;Path based on angular module name&lt;/td&gt;
		&lt;td&gt;&lt;strong&gt;example-app/employee&lt;/strong&gt; (for module exampleApp.employee)&lt;/td&gt;
	&lt;/tr&gt;
&lt;/tbody&gt;	
&lt;/table&gt;

&lt;h4 id=&quot;domain-properties&quot;&gt;Domain properties&lt;/h4&gt;

&lt;p&gt;In addition to the path variables above, a map of variable for each domain property are add as a variable &lt;strong&gt;properties&lt;/strong&gt;&lt;/p&gt;

&lt;table class=&quot;table&quot;&gt;
&lt;thead&gt;
	&lt;tr&gt;
		&lt;th&gt;Variable&lt;/th&gt;
		&lt;th&gt;Description&lt;/th&gt;
		&lt;th&gt;Example&lt;/th&gt;
	&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;	
	&lt;tr&gt;
		&lt;td&gt;&lt;strong&gt;name&lt;/strong&gt;&lt;/td&gt;
		&lt;td&gt;The property name&lt;/td&gt;
		&lt;td&gt;&lt;strong&gt;birthDate&lt;/strong&gt;&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;&lt;strong&gt;label&lt;/strong&gt;&lt;/td&gt;
		&lt;td&gt;The natural name based on the property name&lt;/td&gt;
		&lt;td&gt;&lt;strong&gt;Birth Date&lt;/strong&gt;&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;&lt;strong&gt;type&lt;/strong&gt;&lt;/td&gt;
		&lt;td&gt;The class of the property&lt;/td&gt;
		&lt;td&gt;&lt;strong&gt;java.util.Date&lt;/strong&gt;&lt;/td&gt;
	&lt;/tr&gt;

	&lt;tr&gt;
		&lt;td&gt;&lt;strong&gt;domainClass&lt;/strong&gt;&lt;/td&gt;
		&lt;td&gt;Boolean indicating whether the property is a domain class&lt;/td&gt;
		&lt;td&gt;&lt;strong&gt;false&lt;/strong&gt;&lt;/td&gt;
	&lt;/tr&gt;

	&lt;tr&gt;
		&lt;td&gt;&lt;strong&gt;constraints&lt;/strong&gt;&lt;/td&gt;
		&lt;td&gt;A map of the constaints for the property&lt;/td&gt;
		&lt;td&gt;&lt;strong&gt;[required: true, nullable: false]&lt;/strong&gt;&lt;/td&gt;
	&lt;/tr&gt;
&lt;/tbody&gt;	
&lt;/table&gt;

&lt;p&gt;So given our example domain class Employee:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-groovy&quot; data-lang=&quot;groovy&quot;&gt;&lt;span class=&quot;kn&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;com.craigburke&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Employee&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;firstName&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lastName&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Date&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;birthDate&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;BigDecimal&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;salary&lt;/span&gt;

	&lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;constraints&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;maxSize:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;128&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;lastName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;masSize:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;256&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;birthDate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;required:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;nullable:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
	
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The &lt;strong&gt;properties&lt;/strong&gt; variable would have this value within your templates&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-groovy&quot; data-lang=&quot;groovy&quot;&gt;&lt;span class=&quot;k&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;properties&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;
	&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'firstName'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;label:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'First Name'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;domainClass:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;constraints:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;required:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;nullable:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;maxSize:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;128&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;],&lt;/span&gt;
	&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'lastName'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;label:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Last Name'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;domainClass:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;constraints:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;required:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;nullable:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;maxSize:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;256&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;],&lt;/span&gt;
	&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'birthDate'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;label:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Birth Date'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;domainClass:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;constraints:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;required:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;nullable:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;],&lt;/span&gt;
	&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'salary'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;label:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Salary'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BigDecimal&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;domainClass:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;constraints:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;required:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;nullable:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This takes into account the Grails default of properties being required and non-nullable when determining the constraints.&lt;/p&gt;

&lt;h4 id=&quot;renderutil-class&quot;&gt;RenderUtil Class&lt;/h4&gt;

&lt;p&gt;The RenderUtil class is an easy way to expose new methods or properties to your templates. You can also override any of the variables listed above if you’d like.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Any property or closure assigned to the util map within this file will be available within your templates.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As an example, here’s how I could expose a new method called &lt;strong&gt;renderPanel&lt;/strong&gt; within my templates:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;src/templates/angular/RenderUtil.groovy&lt;/strong&gt;&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-groovy&quot; data-lang=&quot;groovy&quot;&gt;&lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;util&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[:]&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;util&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;renderPanel&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; 
	&lt;span class=&quot;s2&quot;&gt;&quot;&quot;&quot;&amp;lt;div class=&quot;panel panel-default&quot;&amp;gt;
	  &amp;lt;div class=&quot;panel-body&quot;&amp;gt;
	    ${text}
	  &amp;lt;/div&amp;gt;
	&amp;lt;/div&amp;gt;&quot;&quot;&quot;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;util&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;These added properties or methods can be used in any of the files found in your template folder (not just HTML files). The HTML files are just where I found these additional methods most useful (using them almost like Grails TagLibs).&lt;/p&gt;

&lt;h4 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h4&gt;

&lt;p&gt;I wanted to provide a good starter project for anyone looking to use Grails and AngularJS together but I also wanted to make it easy to configure any aspect of the project.&lt;/p&gt;

&lt;p&gt;I’m looking forward to hearing how people are making use of this or if anyone has suggestions. &lt;strong&gt;I’m going to use this template extensively in my own work and will continue to work actively on it, so as always feedback is definitely welcome.&lt;/strong&gt;&lt;/p&gt;

</description>
				<pubDate>Mon, 24 Nov 2014 00:00:00 +0000</pubDate>
				<link>http://www.craigburke.com/2014/11/24/angular-grails-template-2.html</link>
				<guid isPermaLink="true">http://www.craigburke.com/2014/11/24/angular-grails-template-2.html</guid>
			</item>
		
			<item>
				<title>AngularJS Grails Template - Part 1: Getting Started</title>
				<description>&lt;p&gt;The goal of the &lt;a href=&quot;https://github.com/craigburke/lazybones-angular-grails&quot;&gt;Angular Grails Lazybones Project&lt;/a&gt; was to create a simple starting point for people who wanted to use AngularJS and Grails together. This allows you to setup an Grails project and generate AngularJS CRUD applications from your domain classes.&lt;/p&gt;

&lt;h4 id=&quot;creating-a-new-project&quot;&gt;Creating a New Project&lt;/h4&gt;
&lt;p&gt;First we need to make sure we have lazybones installed. The easiest way to do this is through &lt;a href=&quot;http://gvmtool.net/&quot;&gt;GVM&lt;/a&gt; like so:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;gvm &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;lazybones&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Then we can easily create our new web app:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;lazybones create angular-grails example-app&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;After running this command you’ll be asked a series of questions about your project. Here’s what the questions look like, with responses I’ve entered for an example application:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;table class=&quot;rouge-table&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class=&quot;gutter gl&quot;&gt;&lt;pre class=&quot;lineno&quot;&gt;1
2
3
4
5
6
&lt;/pre&gt;&lt;/td&gt;&lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;go&quot;&gt;Define the name for your project [angular-grails]: example-app
Defined the version of AngularJS you want in your project [1.3]: 1.3   
Define value for your main AngularJS module [myApp]: exampleApp
Define the value for your application group [com.company]: com.craigburke
Define value for your application 'version' [0.1]: 1.0
Define the name for your war file [ROOT.war]: my-app.war&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;When selecting the AngularJS version (question 2), you can opt for either AngularJS 1.2 or 1.3. &lt;strong&gt;If you need to support an older version of Internet Explorer(IE) such as IE 8 or below, you should choose AngularJS 1.2. The 1.3 version does not support IE 8 and below.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After answering these questions you should then have a new Grails project in the folder you specified (example-app in this case) with some goodies like Bootstrap, Angular UI and Font Awesome already included. As we’ll see later, there’s also a lazybones subtemplate (located in the .lazybones folder) that will help you create new Angular modules.&lt;/p&gt;

&lt;p&gt;One other way that this project is different from a standard Grails project is that it makes use of &lt;a href=&quot;https://github.com/grails/grails-gradle-plugin&quot;&gt;Grails Gradle plugin&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;By using the Gradle Grails plugin here we can run JavaScript and Groovy tests with a single command and also not have to worry about installing all the testing dependencies that are needed (Karma, Jasmine, PhantomJS, etc).&lt;/strong&gt;&lt;/p&gt;

&lt;h4 id=&quot;adding-a-domain-class&quot;&gt;Adding a Domain Class&lt;/h4&gt;

&lt;p&gt;Once we’ve created our project, the next step is to add a domain class in the usual &lt;strong&gt;grails-app/domain&lt;/strong&gt; location. Here’s an Employee domain class I’ll use for this example:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;grails-app/domain/com/craigburke/Employee.groovy&lt;/strong&gt;&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-groovy&quot; data-lang=&quot;groovy&quot;&gt;&lt;span class=&quot;kn&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;com.craigburke&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Employee&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;firstName&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lastName&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Date&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;birthDate&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;BigDecimal&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;salary&lt;/span&gt;

	&lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;constraints&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;birthDate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;required:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h4 id=&quot;generating-a-crud-angularjs-module&quot;&gt;Generating a CRUD AngularJS Module&lt;/h4&gt;

&lt;p&gt;Now that we have the domain class to use as our base, we can generate an AngularJS CRUD module to get us started by running the following with the project folder:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;lazybones generate module &lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;We’ll then be prompted to answer some questions about our new module:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-console&quot; data-lang=&quot;console&quot;&gt;&lt;span class=&quot;go&quot;&gt;Define the name for your new module [myModule]: employee
Define the name of the domain class [Foo]: Employee
Your Angular app (exampleApp.employee) has been created
URL: /employee&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now we can run our app to take a look at our new module&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;gradlew run&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;If we browse to &lt;strong&gt;http://localhost:8080/example-app/employee&lt;/strong&gt; we should see something like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/angular-grails-lazybones-1-1.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We’ve got a paged list of employees that we can add to (as well as edit and delete), we can also filter the list on based on the four properties found in the domain class. Awesome!&lt;/p&gt;

&lt;h4 id=&quot;project-stucture&quot;&gt;Project stucture&lt;/h4&gt;

&lt;p&gt;Next we’ll take a look at exactly what the lazybones generate command actually added to our project. First lets take a look at the relevant parts of our &lt;strong&gt;grails-app/conf/UrlMappings.groovy&lt;/strong&gt; file:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-groovy&quot; data-lang=&quot;groovy&quot;&gt;&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;UrlMappings&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

	&lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mappings&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;s1&quot;&gt;'/employee'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;view:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'employee'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;s1&quot;&gt;'/api/employee'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;resources:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'employee'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
	&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Here we see that two mappings have been created one for the REST actions &lt;strong&gt;/api/employee&lt;/strong&gt; and one that links to a new view that was created.&lt;/p&gt;

&lt;p&gt;Now we’ll look at the &lt;strong&gt;EmployeeController&lt;/strong&gt; that was generated which handles all those REST requests:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;grails-app/controllers/com/craigburke/EmployeeController.groovy&lt;/strong&gt;&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-groovy&quot; data-lang=&quot;groovy&quot;&gt;&lt;span class=&quot;kn&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;com.craigburke&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;com.craigburke.Employee&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;EmployeeController&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PagedRestfulController&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;EmployeeController&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Employee&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The &lt;strong&gt;PagedRestfulController&lt;/strong&gt; is very similar to the default &lt;strong&gt;RestfulController&lt;/strong&gt; that’s part of Grails with some additional support for filtering and paging.&lt;/p&gt;

&lt;p&gt;Here’s what the &lt;strong&gt;employee.gsp&lt;/strong&gt; view looks like:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;grails-app/views/employee.gsp&lt;/strong&gt;&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;meta&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;layout&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;content=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;main&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;asset:javascript&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;example-app/employee/module&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;

&lt;span class=&quot;nt&quot;&gt;&amp;lt;body&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;ng-app=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;exampleApp.employee&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;

&lt;span class=&quot;nt&quot;&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This view is very simple because it’s just the entry point of our AngularJS app. All the relevant JavaScript and angular templates are found in &lt;strong&gt;/grails-app/assets/javascripts/example-app/employee.&lt;/strong&gt; Here’s what the structure of our new AngularJS module looks like:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/angular-grails-lazybones-1-2.png&quot; /&gt;&lt;/p&gt;

&lt;h4 id=&quot;tests&quot;&gt;Tests&lt;/h4&gt;

&lt;p&gt;The lazybones generate command also added some tests for our new module. There are Geb/Spock functional tests as well as AngularJS Jasmine unit tests as seen below:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/angular-grails-lazybones-1-3.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This tests may fail depending on your specific constraints, but should serve as a good starting point. To run all the tests you use this command:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;gradlew &lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;If you want to run only the Jasmine unit tests you can run this command:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;gradlew jasmineRun&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Alternatively you can run your Jasmine tests in watch mode so they are run everytime your source changes:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;gradlew jasmineWatch&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;These Gradle tasks are setup so that all the dependencies are downloaded and resolved for you. The only thing you need to have install is the JDK.&lt;/p&gt;

&lt;h4 id=&quot;paging-and-filtering&quot;&gt;Paging and Filtering&lt;/h4&gt;

&lt;p&gt;The default filtering works well for simple cases but you’ll likely want to override this method to have a bit more control over what is filtered.&lt;/p&gt;

&lt;p&gt;For example if I wanted to add just a simple box that searches both first name and last name I would override the &lt;strong&gt;loadPagedResults&lt;/strong&gt; method in my &lt;strong&gt;EmployeeController&lt;/strong&gt; like so:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;grails-app/controllers/com/craigburke/EmployeeController.groovy&lt;/strong&gt;&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-groovy&quot; data-lang=&quot;groovy&quot;&gt;&lt;span class=&quot;kn&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;com.craigburke&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;grails.gorm.PagedResultList&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;com.craigburke.Employee&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;EmployeeController&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PagedRestfulController&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;EmployeeController&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Employee&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
	
    &lt;span class=&quot;nd&quot;&gt;@Override&lt;/span&gt;
      &lt;span class=&quot;kd&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PagedResultList&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;loadPagedResults&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;filter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;filter&lt;/span&gt;

          &lt;span class=&quot;n&quot;&gt;resource&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;createCriteria&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;max:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;offset:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
              &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;search&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
				  &lt;span class=&quot;n&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                  	&lt;span class=&quot;n&quot;&gt;ilike&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'firstName'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;${filter.search}%&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
                  	&lt;span class=&quot;n&quot;&gt;ilike&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'lastName'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;${filter.search}%&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;				  
				  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
              &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
              &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;sort&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                  &lt;span class=&quot;n&quot;&gt;order&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;sort&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
              &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
          &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
	
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The relevant part of the HTML in my &lt;strong&gt;/grails-app/assets/javascripts/example-app/employee/templates/list.tpl.html&lt;/strong&gt; file would then be simplified to this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;panel panel-default&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;panel-heading&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;h3&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;panel-title&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;i&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;fa fa-filter&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/i&amp;gt;&lt;/span&gt; Filter List&lt;span class=&quot;nt&quot;&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;panel-body&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
	  &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;row&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
		  &lt;span class=&quot;nt&quot;&gt;&amp;lt;form&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;form&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
			  &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;form-group col-md-2&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
				  &lt;span class=&quot;nt&quot;&gt;&amp;lt;label&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;for=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;filter.search&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Name Search&lt;span class=&quot;nt&quot;&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
				  &lt;span class=&quot;nt&quot;&gt;&amp;lt;input&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;text&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'form-control'&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;ng-model=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;ctrl.filter.search&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;ng-model-options=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{ debounce: 300 }&quot;&lt;/span&gt;  &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    		  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
		  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
	  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
 &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
 &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h4 id=&quot;json-response&quot;&gt;JSON Response&lt;/h4&gt;

&lt;p&gt;When you generate a new CRUD module, a custom JSON marshaller is created for your domain class and added to to the &lt;strong&gt;CustomMarshallerRegistrar&lt;/strong&gt; class.&lt;/p&gt;

&lt;p&gt;Here’s an example of what the default marshaller for the Employee class would look like:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;src/groovy/com/craigburke/CustomMarshallerRegistrar.groovy&lt;/strong&gt;&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-groovy&quot; data-lang=&quot;groovy&quot;&gt;&lt;span class=&quot;kn&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;com.craigburke&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;grails.converters.JSON&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CustomMarshallerRegistrar&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

	&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;registerMarshallers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;registerObjectMarshaller&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;com&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;craigburke&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;Employee&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;kt&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[:]&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'id'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'firstName'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;firstName&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'lastName'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;lastName&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'birthDate'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;birthDate&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'salary'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;salary&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'toText'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
			&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;map&lt;/span&gt; 
		&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; 
	&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;By default it includes all the fields from the Employee domain class in addition to a &lt;strong&gt;toText&lt;/strong&gt; property that is set to the value of the toString method.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If, for example, you wanted to remove salary property from the default JSON response, just remove that line from here.&lt;/strong&gt; This will mean though, that you’ll need to modify your Angular Templates to remove the references to salary as well. In this case, the templates would be located within the
&lt;strong&gt;grails-app/assets/javascripts/example-app/employee/templates&lt;/strong&gt; folder.&lt;/p&gt;

&lt;h4 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h4&gt;

&lt;p&gt;As you can see, this template allows you to quickly get started building an AngularJS application in Grails.&lt;/p&gt;

&lt;p&gt;The template was designed to be highly customizable and there are lots of ways to customize and modify your app and the modules you can generate. I go into more detail on the more advanced customization in &lt;a href=&quot;/2014/11/24/angular-grails-template-2.html&quot;&gt;Part 2: Advanced Customization&lt;/a&gt;.&lt;/p&gt;
</description>
				<pubDate>Mon, 17 Nov 2014 00:00:00 +0000</pubDate>
				<link>http://www.craigburke.com/2014/11/17/angular-grails-template-1.html</link>
				<guid isPermaLink="true">http://www.craigburke.com/2014/11/17/angular-grails-template-1.html</guid>
			</item>
		
			<item>
				<title>Monthly Book Roundup (October 2014)</title>
				<description>&lt;p&gt;This month’s books include another excellent Groovy book and a solid overview of Spring Framework 4.&lt;/p&gt;

&lt;dl class=&quot;books&quot;&gt;

  &lt;dt&gt;
	&lt;a href=&quot;https://pragprog.com/book/vslg2/programming-groovy-2&quot;&gt;
		&lt;img src=&quot;/images/books/programming-groovy-2.jpg&quot; /&gt;
	&lt;/a&gt;
  &lt;/dt&gt;
  &lt;dd&gt;

    &lt;h4&gt;&lt;a href=&quot;https://pragprog.com/book/vslg2/programming-groovy-2&quot;&gt;Programming Groovy 2&lt;/a&gt;&lt;/h4&gt;
  &lt;p&gt;I absolutely loved this book. Venkat is an excellent writer and the examples he gave were fantastic.&lt;/p&gt; 

  &lt;p&gt;One of the best parts of this book is the emphasis on pitfalls for those coming from a more traditional Java background. There are some subtleties of language I learned here that I was previously unaware of.&lt;/p&gt;

  &lt;p&gt;
	  &lt;strong&gt;This book goes pretty deep and the meta programming sections were especially good and thorough. This book is highly recommended for people looking to get a better overall understanding of the Groovy language.&lt;/strong&gt;
  &lt;/p&gt;

  &lt;/dd&gt;


  &lt;dt&gt;
	&lt;a href=&quot;http://www.apress.com/9781430265320&quot;&gt;
		&lt;img src=&quot;/images/books/introducing-spring.jpg&quot; /&gt;
	&lt;/a&gt;
  &lt;/dt&gt;
  &lt;dd&gt;
    	&lt;h4&gt;&lt;a href=&quot;http://www.apress.com/9781430265320&quot;&gt;Introducing Spring Framework: A Primer&lt;/a&gt;&lt;/h4&gt;
       
		&lt;p&gt;This was a pretty nice (albeit basic) overview of the Spring Framework. In addition to talking about the core framework, this book also discussed a few of the offered extensions (Spring Social, Spring Data, Spring AMQP) which was actually pretty interesting.&lt;/p&gt;

		&lt;p&gt;I would have liked to have seen a little more detail (especially in the parts about Groovy and Spring Boot), but it was all well written.&lt;/p&gt;

		&lt;p&gt;&lt;strong&gt;This book is geared more toward Spring beginners, but it served as a nice refresher for me while aquainting me more with some of newer features of the framework.&lt;/strong&gt;&lt;/p&gt;

  &lt;/dd&gt;

&lt;/dl&gt;
</description>
				<pubDate>Wed, 12 Nov 2014 00:00:00 +0000</pubDate>
				<link>http://www.craigburke.com/2014/11/12/monthly-book-roundup-october.html</link>
				<guid isPermaLink="true">http://www.craigburke.com/2014/11/12/monthly-book-roundup-october.html</guid>
			</item>
		
			<item>
				<title>Monthly Book Roundup (September 2014)</title>
				<description>&lt;p&gt;This month includes the two books from mrhaki’s Goodness Notebooks bundle (Groovy and Grails)&lt;/p&gt;

&lt;dl class=&quot;books&quot;&gt;

  &lt;dt&gt;
	&lt;a href=&quot;https://leanpub.com/groovy-goodness-notebook&quot;&gt;
		&lt;img src=&quot;/images/books/groovy-goodness.jpg&quot; /&gt;
	&lt;/a&gt;
  &lt;/dt&gt;
  &lt;dd&gt;

    &lt;h4&gt;&lt;a href=&quot;https://leanpub.com/groovy-goodness-notebook&quot;&gt;Groovy Goodness Notebook&lt;/a&gt;&lt;/h4&gt;
   &lt;p&gt;Since this book was simply a collection of Groovy related blog posts from mrhaki, I was initially concerned about how well this book would flow. My fear turned out to be completely unfounded though since this book was extremely well organized and a joy to read.&lt;/p&gt;

   &lt;p&gt;This book is pretty hefty and full of some very useful tips along with some examples that might be a bit less practical but are nonetheless explained very clearly and absolutely push your understanding of the Groovy language.&lt;/p&gt;

   &lt;p&gt;&lt;strong&gt;Mrhaki is a very clever guy and it’s facinating to see his solutions to both common and uncommon problems using the Groovy language.&lt;/strong&gt;&lt;/p&gt;

  &lt;/dd&gt;


  &lt;dt&gt;
	&lt;a href=&quot;https://leanpub.com/grails-goodness-notebook&quot;&gt;
		&lt;img src=&quot;/images/books/grails-goodness.png&quot; /&gt;
	&lt;/a&gt;
  &lt;/dt&gt;
  &lt;dd&gt;
    	&lt;h4&gt;&lt;a href=&quot;https://leanpub.com/grails-goodness-notebook&quot;&gt;Grails Goodness Notebook&lt;/a&gt;&lt;/h4&gt;
       
	   &lt;p&gt;This book was much shorter than the Groovy book above, but I had the same “huh, I never thought of doing something like that” reaction to many of these tips.&lt;/p&gt;

	   &lt;p&gt;Some of the tips relate specifically to older versions of Grails but there’s still plenty of good stuff here.&lt;/p&gt;

	   &lt;p&gt;This book, like the Groovy goodness book above, is very written and extremely easy to read with very clear examples. &lt;strong&gt;I very highly recommend getting this as part of the Goodness bundle so you can read both of these excellent books.&lt;/strong&gt;&lt;/p&gt;
    
	&amp;lt;/p&amp;gt;
  &lt;/dd&gt;

&lt;/dl&gt;
</description>
				<pubDate>Fri, 10 Oct 2014 00:00:00 +0000</pubDate>
				<link>http://www.craigburke.com/2014/10/10/monthly-book-roundup-september.html</link>
				<guid isPermaLink="true">http://www.craigburke.com/2014/10/10/monthly-book-roundup-september.html</guid>
			</item>
		
			<item>
				<title>Monthly Book Roundup (August 2014)</title>
				<description>&lt;p&gt;This month was a JavaScript focused one that includes two absolutely outstanding books.&lt;/p&gt;

&lt;dl class=&quot;books&quot;&gt;

  &lt;dt&gt;
	&lt;a href=&quot;http://www.manning.com/resig/&quot;&gt;
		&lt;img src=&quot;/images/books/javascript-ninja.jpg&quot; /&gt;
	&lt;/a&gt;
  &lt;/dt&gt;
  &lt;dd&gt;

    &lt;h4&gt;&lt;a href=&quot;http://www.manning.com/resig/&quot;&gt;Secrets of the JavaScript Ninja&lt;/a&gt;&lt;/h4&gt;
    &lt;p&gt;
        &lt;strong&gt;This is an amazingly good book. 
        It explained some of the more complex aspects of JavaScript (like scope, closures, and function invocation) in such a clear way. It 
        definitely provided me with plenty of insight about the language and some powerful tools and strategies to use.
        &lt;/strong&gt;
    &lt;/p&gt;
    
    &lt;p&gt; 
        A common refrain for the book was also &quot;this would be really straightforward, but IE...&quot; and it really gave me a window into 
        how difficult a task developing jQuery was for John Resig (one of the authors). It was really interesting seeing how jQuery
        and other libraries dealt with some of the browser JavaScript inconsistencies.
    &lt;/p&gt;

    &lt;p&gt;
        There are some pretty advanced examples within this book but they tend to be broken down and explained really well. 
        I don't know if it'll qualify you to be a JavaScript ninja, but it certainly will give you plenty of idea and tools to use in your development.
    &lt;/p&gt;

  &lt;/dd&gt;


  &lt;dt&gt;
	&lt;a href=&quot;http://shop.oreilly.com/product/0636920033486.do&quot;&gt;
		&lt;img src=&quot;/images/books/angularjs-up-and-running.gif&quot; /&gt;
	&lt;/a&gt;
  &lt;/dt&gt;
  &lt;dd&gt;
    	&lt;h4&gt;&lt;a href=&quot;http://shop.oreilly.com/product/0636920033486.do&quot;&gt;AngularJS Up &amp;amp; Running&lt;/a&gt;&lt;/h4&gt;
        &lt;p&gt;&lt;strong&gt;
            This is hands down the best AngularJS book I've read and one I'd definitely recommend for 
            people new to AngularJS or those with more experience. 
        &lt;/strong&gt;&lt;/p&gt;
    
        &lt;p&gt;
            It references a really recent version of AngularJS (1.2.19) and talked about some features I really wasn't aware of. 
            The style of the code is also consistent with Todd Motto's &lt;a href=&quot;http://toddmotto.com/opinionated-angular-js-styleguide-for-teams/&quot;&gt;
            Opinionated AngularJS styleguide for teams
            &lt;/a&gt;, so this is a book that really reflects a lot of current AngularJS best practices.
        &lt;/p&gt;
        
        &lt;p&gt;
            This book is written by the same authors of the original O'Reilly AngularJS book, but this book fills in a lot of gaps 
            left in that book. I thought it was a nice touch to have a separate chapter on testing for controllers, services and directives
            right after they are introduced. That makes more sense to me than just having a huge chapter on testing stuck at the end of the book.
        &lt;/p&gt;
        
        &lt;p&gt;&lt;strong&gt;I highly recommend this book to anyone doing (or interested in doing) AngularJS development.&lt;/strong&gt;&lt;/p&gt;
    
	&amp;lt;/p&amp;gt;
  &lt;/dd&gt;

&lt;/dl&gt;
</description>
				<pubDate>Fri, 05 Sep 2014 00:00:00 +0000</pubDate>
				<link>http://www.craigburke.com/2014/09/05/monthly-book-roundup-august.html</link>
				<guid isPermaLink="true">http://www.craigburke.com/2014/09/05/monthly-book-roundup-august.html</guid>
			</item>
		
			<item>
				<title>Testing with AngularJS, Grails and Gradle</title>
				<description>&lt;p&gt;One of the open questions I had with my &lt;a href=&quot;http://angular-grails.interwebs.io/&quot;&gt;Angular Grails project&lt;/a&gt; was how testing was going to work and I came up with
a solution that I’m pretty satisified with.&lt;/p&gt;

&lt;p&gt;I decided to stick with Spock and Geb for the server side and end-to-end testing. Geb works great and there’s 
no compelling reason I could see to use anything else (like Protractor).&lt;/p&gt;

&lt;p&gt;As for my AngularJS unit/integration tests I went with Jasmine. 
The issue though was that I wanted to be able to run all my tests together. 
I also didn’t want to have to worry about everyone on my team installing Node and all the necessary Node dependencies (Karma, Jasmine, etc)
just to run the JavaScript tests.&lt;/p&gt;

&lt;p&gt;After seeing John Engelman’s &lt;a href=&quot;https://www.youtube.com/watch?v=YoaZrHE4CSk&quot;&gt;Building A Full Application Stack With Gradle&lt;/a&gt; (watch it if you haven’t), 
where he talked about both the &lt;a href=&quot;https://github.com/grails/grails-gradle-plugin&quot;&gt;Grails Gradle plugin&lt;/a&gt; and the 
&lt;a href=&quot;https://github.com/srs/gradle-node-plugin&quot;&gt;Gradle Node plugin&lt;/a&gt;, I figured I could use both of these plugins to help with this.&lt;/p&gt;

&lt;p&gt;Here’s a portion of my current  &lt;a href=&quot;https://github.com/craigburke/angular-grails/blob/master/build.gradle&quot;&gt;build.gradle&lt;/a&gt; file:&lt;/p&gt;

&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;project&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;ext&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;jasmineDependencies&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'karma'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'karma-jasmine'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'karma-chrome-launcher'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;karmaExec&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'node_modules/karma/bin/karma'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;karmaConfig&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'test/js/karma.conf.js'&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;setupJasmine&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NpmTask&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;outputs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;dir&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'node_modules'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'install'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;jasmineDependencies&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;jasmineRun&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NodeTask&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;dependsOn:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'setupJasmine'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;script&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;karmaExec&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'start'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;karmaConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'--single-run'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;jasmineWatch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;type:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NodeTask&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;dependsOn:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'setupJasmine'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;script&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;karmaExec&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'start'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;karmaConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;dependsOn&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;jasmineRun&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;So now I can run all my tests (Groovy and JavaScript) in my project with this:&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;./gradlew &lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If Node isn’t installed the Node Gradle plugin will install it for me. The &lt;strong&gt;setupJasmine&lt;/strong&gt; task also downloads all the dependencies I need.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I can run all my tests with one command and all I need is to have the JVM installed. Awesome!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I can run the Jasmine tests by themselves too:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;./gradlew jasmineRun
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I can also run these tests in watch mode (where tests are automatically rerun everytime your source changes). Very 
useful during active development:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;./gradlew jasmineWatch
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;You can find the full &lt;a href=&quot;https://github.com/craigburke/angular-grails/blob/master/build.gradle&quot;&gt;build.gradle&lt;/a&gt; file I’m using up on the &lt;a href=&quot;https://github.com/craigburke/angular-grails/&quot;&gt;Angular Grails project page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The Gradle Grails plugin seems to work great, but if you’re a little hesitant to so radically change your build process
you should checkout: &lt;a href=&quot;http://www.objectpartners.com/2014/08/19/add-javascript-unit-tests-and-run-them-with-grails-test-app/&quot;&gt;Add Javascript unit tests and run them with “grails test-app”&lt;/a&gt;.&lt;/p&gt;
</description>
				<pubDate>Thu, 04 Sep 2014 00:00:00 +0000</pubDate>
				<link>http://www.craigburke.com/2014/09/04/testing-with-angularjs-grails-gradle.html</link>
				<guid isPermaLink="true">http://www.craigburke.com/2014/09/04/testing-with-angularjs-grails-gradle.html</guid>
			</item>
		
	</channel>
</rss>
