<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Jacob Quatier</title>
    <description>Jacob Quatier is a software engineer based in Portland, Oregon.
</description>
    <link>https://www.jacobquatier.com/</link>
    <atom:link href="https://www.jacobquatier.com/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Tue, 06 Oct 2026 03:04:24 +0000</pubDate>
    <lastBuildDate>Tue, 06 Oct 2026 03:04:24 +0000</lastBuildDate>
    <generator>Jekyll v3.10.0</generator>
    
      <item>
        <title>Squinch - Architecture Diagrams Your AI Agent Can Draw</title>
        <description>&lt;p&gt;Every project I’ve worked on has had The Diagram. You know the one. Somebody spent an afternoon lining up boxes in a drawing tool, it got pasted into a wiki, and six months later it’s wrong in three places and nobody remembers where the original file is. I’ve been that somebody more than once.&lt;/p&gt;

&lt;p&gt;There are a ton of tools out there for this already: drag-and-drop editors, text-based diagram languages, full-blown architecture modeling tools. I’ve used a lot of them, and they’re all good at what they do. But I always found myself looking for something else. I wanted the diagram to live in git next to the code. I wanted it to look like something I’d actually put in a design review. And lately I wanted my AI coding agent, which already knows the architecture, to just draw it for me. I never found one tool that did all of that, so I built it. Enter &lt;a href=&quot;https://squinch.cc&quot;&gt;Squinch&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;built-for-ai-agents-first&quot;&gt;Built for AI agents first&lt;/h3&gt;

&lt;p&gt;Most diagrams-as-code tools were designed for humans to write, and AI got bolted on later. Squinch went the other way around. It ships as a skill for your AI coding agent (Claude Code, Codex, Cursor, whatever you use), and the language was designed so an LLM can write it fluently. When something’s wrong, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;squinch check&lt;/code&gt; doesn’t just say “syntax error.” It tells you where the problem is, what’s wrong, and usually how to fix it (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;did you mean ...?&lt;/code&gt;), and it can do all that in JSON. So the agent writes the model, checks it, fixes what the checker flags, and renders it. In practice I describe the system in a paragraph and get back a diagram I don’t have to redraw.&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;center&quot; alt=&quot;A paragraph describing a products API on AWS is typed into a prompt box, and the finished architecture diagram rises underneath it&quot; src=&quot;/content/images/squinch/prompt.gif&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;one-model-every-altitude&quot;&gt;One model, every altitude&lt;/h3&gt;

&lt;p&gt;This is the part I’m most excited about. You write the model once, and every system automatically gets its own zoomable view. The landscape shows each system as a card, and clicking one opens up its internals while its neighbors stay on screen as muted context. You can also tag things (say &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#pci&lt;/code&gt;) and get a view that’s just the PCI stuff for an auditor. All the views come from the same source, so they can NOT disagree with each other.&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;center&quot; alt=&quot;Clicking a system card on a landscape diagram opens it into its internals, then the breadcrumb zooms back out&quot; src=&quot;/content/images/squinch/zoom.gif&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Here’s a small example:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-kotlin&quot; data-lang=&quot;kotlin&quot;&gt;&lt;span class=&quot;n&quot;&gt;system&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;orders&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Orders API&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;api&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;aws&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;api-gateway&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;API Gateway&quot;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;save&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;aws&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lambda&lt;/span&gt;      &lt;span class=&quot;s&quot;&gt;&quot;Save Order&quot;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;     &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;aws&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dynamodb&lt;/span&gt;    &lt;span class=&quot;s&quot;&gt;&quot;Orders Table&quot;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;datastore&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;notify&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;webhook&lt;/span&gt;     &lt;span class=&quot;s&quot;&gt;&quot;Notify Webhook&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;external&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;api&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;save&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;save&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;put item&quot;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;save&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;notify&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;order created&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;animate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;comet&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;img class=&quot;center&quot; alt=&quot;The rendered Orders API diagram: API Gateway calls a Save Order Lambda, which puts items in an Orders Table and calls an external Notify Webhook, with a dot animating along the webhook line&quot; src=&quot;/content/images/squinch/orders-api.svg&quot; /&gt;&lt;/p&gt;

&lt;p&gt;That’s it! No boxes to drag, you get real AWS icons, and that little dot riding the webhook line is just &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;animate: comet&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;it-actually-looks-good&quot;&gt;It actually looks good&lt;/h3&gt;

&lt;p&gt;I wanted these to look like something you’d be proud to put in front of people, not grey boxes with labels on them. Squinch ships with about 1,350 real vendor icons (AWS, Azure, Google Cloud, Kubernetes, plus a big set of product logos). Dark mode is designed rather than just inverted. You can export SVG, PNG, or one interactive HTML file with click-to-zoom and a presentation mode that works without a server.&lt;/p&gt;

&lt;h3 id=&quot;it-lives-in-git&quot;&gt;It lives in git&lt;/h3&gt;

&lt;p&gt;Rendering is deterministic, so the same input always produces the same output. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.squinch&lt;/code&gt; file sits next to the code it describes, and a GitHub Action fails the build when a committed diagram has gone stale. My favorite part is that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;squinch diff&lt;/code&gt; tells reviewers what changed in the architecture (“edge added: checkout → fraud”) instead of showing a thousand lines of SVG path data.&lt;/p&gt;

&lt;h3 id=&quot;why-squinch&quot;&gt;Why “Squinch”?&lt;/h3&gt;

&lt;p&gt;A squinch is the little corner arch that lets a round dome sit on a square room. It’s the piece of architecture that makes mismatched structures fit together, which felt about right. =)&lt;/p&gt;

&lt;h3 id=&quot;summary&quot;&gt;Summary&lt;/h3&gt;

&lt;p&gt;So yeah, if you’ve ever been stuck maintaining The Diagram, give it a try. It’s still pre-alpha, so expect some rough edges. Getting started is one command (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npx squinch skill&lt;/code&gt;), and then you just ask your AI agent for a diagram. Check out &lt;a href=&quot;https://squinch.cc&quot;&gt;squinch.cc&lt;/a&gt;, or try it in the &lt;a href=&quot;https://squinch.cc/playground/&quot;&gt;playground&lt;/a&gt; without installing anything. Enjoy!&lt;/p&gt;
</description>
        <pubDate>Sun, 04 Oct 2026 19:00:00 +0000</pubDate>
        <link>https://www.jacobquatier.com/squinch-ai-architecture-diagrams/</link>
        <guid isPermaLink="true">https://www.jacobquatier.com/squinch-ai-architecture-diagrams/</guid>
        
        
      </item>
    
      <item>
        <title>The Meter</title>
        <description>&lt;p&gt;The whole idea of this project was to create a giant meter to show website response time almost like a speedometer would. The result is something that’s both fun to watch and provides a meaningful ‘heartbeat’ of current status. After several revisions and different designs along the way, I ended up with what you see here.&lt;/p&gt;

&lt;h3 id=&quot;construction--design&quot;&gt;Construction &amp;amp; Design&lt;/h3&gt;

&lt;p&gt;The meter is carved using my CNC machine from 1/4” bi-color HDPE (12 inches square). This is a great material to cut signs or other carvings with because anything carved out is the alternate material color, so there’s no painting/masking/re-painting needed. The needle is cut from 1/8” orange acrylic which worked great for the speedometer theme. For mounting the micro servo, I designed a hole matching the shape of the outer plastic casing which the servo I chose had (see parts list for a link). I designed the whole thing using Inkscape and &lt;a href=&quot;http://www.easel.com/&quot;&gt;Easel&lt;/a&gt;, mainly because they are free and fairly easy to use. Check out my bill of materials if you are interested in using the same HDPE and acrylic.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.inventables.com/projects/website-response-time-meter&quot;&gt;View my design &amp;amp; bill of materials&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;center&quot; alt=&quot;The Meter Milling&quot; src=&quot;/content/images/meter2.jpg&quot; /&gt;
&lt;img class=&quot;center&quot; alt=&quot;The Meter Close-up&quot; src=&quot;/content/images/meter3.jpg&quot; /&gt;
&lt;img class=&quot;center&quot; alt=&quot;The Meter&quot; src=&quot;/content/images/meter.jpg&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;electronics&quot;&gt;Electronics&lt;/h3&gt;

&lt;p&gt;I decided to power the meter using the Arduino Uno microcontroller since it handles servo control really well. The Raspberry Pi would be another option, but I’ll detail the Arduino setup for now. My implementation also uses a few LED displays to display detailed metrics, but the servo is the main piece you need.
Here’s a quick parts list:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://amzn.to/2slSfsV&quot;&gt;Arduino UNO&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://amzn.to/2CZcB1c&quot;&gt;micro servo motor&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;2x &lt;a href=&quot;http://www.adafruit.com/products/1912&quot;&gt;Adafruit Quad Alphanumeric Display - Blue 0.54”&lt;/a&gt; (optional)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.adafruit.com/products/902&quot;&gt;Adafruit Bicolor LED Square Pixel Matrix&lt;/a&gt; (optional)&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://amzn.to/2D0U4l1&quot;&gt;misc jumper wires&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;screws, scrap wood for test cuts, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img alt=&quot;The Meter Animated&quot; src=&quot;/content/images/meter-sm.gif&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;code&quot;&gt;Code&lt;/h3&gt;

&lt;p&gt;Construction was by far the longest part of this project. The code ended up being pretty simple since it’s just rotating a servo using a PWM output and writing values to LED displays over i2c. The nice thing is that the implementation can be changed to support any kind of metric or API that is desired. For example, instead of web response time you could make a meter for monitoring CPU utilization on a server or even your own desktop. I’ve posted all of the code required to get this working, along with more detail about the implementation on GitHub under &lt;a href=&quot;https://github.com/jquatier/servometer&quot;&gt;servometer&lt;/a&gt;. Enjoy.&lt;/p&gt;
</description>
        <pubDate>Tue, 02 Dec 2014 04:12:00 +0000</pubDate>
        <link>https://www.jacobquatier.com/the-meter/</link>
        <guid isPermaLink="true">https://www.jacobquatier.com/the-meter/</guid>
        
        
      </item>
    
      <item>
        <title>Spring MVC Mapped Interceptors</title>
        <description>&lt;p&gt;Interceptors in Spring MVC are a great way to add logic that needs to execute for every request to your servlet. The nice thing is that you can have logic that executes BEFORE and/or AFTER the request is handled by your controller, which is done by overriding the preHandle and postHandle methods in the &lt;a href=&quot;http://static.springsource.org/spring/docs/3.2.x/javadoc-api/org/springframework/web/servlet/HandlerInterceptor.html&quot;&gt;HandlerInterceptor&lt;/a&gt; interface that Spring provides.&lt;/p&gt;

&lt;p&gt;The one problem in the past with using interceptors was that there wasn’t a good way to exclude them from running for certain requests. For example, you might have a specific service that doesn’t need to run that additional logic in your custom interceptor so it’s just adding unnecessary execution time.&lt;/p&gt;

&lt;p&gt;Enter Spring 3.2 and we now have a great way of selectively including or excluding interceptors from running based off a mapping system. It’s called Mapped Interceptors, and it uses Ant path matching to see if a request path matches the included or excluded paths. Check out the Spring &lt;a href=&quot;http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/mvc.html#mvc-config-interceptors&quot;&gt;documentation&lt;/a&gt; for more detail. Here’s an example:&lt;/p&gt;

&lt;p&gt;XML configuration:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-xml&quot; data-lang=&quot;xml&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;mvc:interceptors&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;mvc:interceptor&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;mvc:mapping&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;path=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/**&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;exclude-mapping&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;path=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/foo/**&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;bean&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;com.jacobquatier.MyCustomInterceptor&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;/mvc:interceptor&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/mvc:interceptors&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Java configuration:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;&lt;span class=&quot;nd&quot;&gt;@Configuration&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@EnableWebMvc&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MyWebConfig&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;WebMvcConfigurerAdapter&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;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;addInterceptors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;InterceptorRegistry&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;registry&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;registry&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;addInterceptor&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;nc&quot;&gt;MyCustomInterceptor&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;na&quot;&gt;addPathPatterns&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/**&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;na&quot;&gt;excludePathPatterns&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/foo/**&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;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Anyway, because the path matcher uses Ant paths, it’s pretty easy to include/exclude anything you want.&lt;/p&gt;

&lt;p&gt;One thing you might want to watch out for is that Spring automatically detects any beans of type MappedInterceptor and registers them in your servlet. So, if you have multiple servlets with some shared configuration/beans, any MappedInterceptor bean that’s sitting in the context will get picked up and be put in the list of interceptors that get run. This behavior can be overridden by subclassing the handler mapping and changing the detectMappedInterceptors method. See &lt;a href=&quot;http://static.springsource.org/spring/docs/3.2.x/javadoc-api/org/springframework/web/servlet/handler/AbstractHandlerMapping.html&quot;&gt;AbstractHandlerMapping&lt;/a&gt; for more information.&lt;/p&gt;
</description>
        <pubDate>Tue, 16 Jul 2013 05:38:00 +0000</pubDate>
        <link>https://www.jacobquatier.com/spring-mapped-interceptors/</link>
        <guid isPermaLink="true">https://www.jacobquatier.com/spring-mapped-interceptors/</guid>
        
        
      </item>
    
      <item>
        <title>Freemarker and Exception Logging</title>
        <description>&lt;p&gt;Freemarker is a pretty nice templating language for Java-based servlets, especially if you are looking for an alternative to JSP pages. One problem with it, or “feature” I should say, is that it puts a pretty large stack trace in your logs whenever it encounters an error rendering a template. In my travels, I’ve seen a single missing null-check fill up server logs rather quickly for pages that are hit often (especially if there is looping going on in the template). I decided it wasn’t really helping me at all to have these in the logs, so I wanted to turn them off, at least on the live site.&lt;/p&gt;

&lt;p&gt;Turns out all I needed to do was extend the FreemarkerConfigurer class that Spring MVC uses to instantiate the Freemarker view resolver. This is important because you need to set up the logger library before any of the Freemarker classes load up. Thankfully, there’s an afterPropertiesSet() method that you can override for this purpose. Here’s an example:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MyAwesomeFreemarkerConfigurer&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;FreeMarkerConfigurer&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;loggingEnabled&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&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;nd&quot;&gt;@Override&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;afterPropertiesSet&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;throws&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;IOException&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;TemplateException&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// disable freemarker logging if the bean is configured as such&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;loggingEnabled&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;resetFreemarkerLogging&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;na&quot;&gt;afterPropertiesSet&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;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;resetFreemarkerLogging&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;try&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;freemarker&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;Logger&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;selectLoggerLibrary&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Logger&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;LIBRARY_NONE&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;catch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;ClassNotFoundException&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&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;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Failed to disable Freemarker logging =(&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;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;setLoggingEnabled&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;loggingEnabled&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;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;loggingEnabled&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;loggingEnabled&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;That class will disable all Freemarker logging (Logger.LIBRARY_NONE). You’ll notice I added a property which allows me to enable/disable logging via bean configuration. This means I can turn logging off in the live site, but leave it on for test and development. You could also use this approach to set the logger library to whatever logging framework you use. By default, Freemarker will use the first logging library it finds, per the &lt;a href=&quot;http://freemarker.sourceforge.net/docs/pgui_misc_logging.html&quot;&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Anyway, depending on your situation you might not want logging turned off completely. But, in my case it was far too noisy to provide any value. The smallest template error made the logs a nightmare since the pages get hit so often. Template errors are easy to overlook (especially if they only happen when dynamic data is in a certain state), and I need my server logs readable at all times. Also, if a problem arises with a template, I can test it in an environment that has Freemarker logging turned on and I’ll see the stack trace. Hopefully by keeping logging enabled in test and dev, I get the best of both worlds. We’ll see! =)&lt;/p&gt;
</description>
        <pubDate>Thu, 09 May 2013 03:54:00 +0000</pubDate>
        <link>https://www.jacobquatier.com/freemarker-exception-logging/</link>
        <guid isPermaLink="true">https://www.jacobquatier.com/freemarker-exception-logging/</guid>
        
        
      </item>
    
      <item>
        <title>Hibernate Envers - Audit Logging Made Easy</title>
        <description>&lt;p&gt;One of the requirements for my most recent project was to provide a detailed audit trail for any changes made to my database entities through the administration panel. I needed to keep track of what was changed (at a field level) and who made the change. There are a ton of ways to do this, including triggers, plain old system logging, and homebrew audit tables. But, I decided to look around for something cooler than that. Enter Hibernate Envers. What’s nice about it is configuration is basically a one-liner (for the most part), and it plays nice with my existing all-annotations JPA2 Spring MVC project. All you need to do is mark your entities with the @Audited annotation, and it takes care of the rest for you. Here’s an example:&lt;/p&gt;

&lt;h3 id=&quot;maven-dependency-pomxml&quot;&gt;Maven dependency (pom.xml):&lt;/h3&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-xml&quot; data-lang=&quot;xml&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.hibernate&lt;span class=&quot;nt&quot;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;hibernate-envers&lt;span class=&quot;nt&quot;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;version&amp;gt;&lt;/span&gt;4.1.9.Final&lt;span class=&quot;nt&quot;&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;entity&quot;&gt;Entity:&lt;/h3&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;&lt;span class=&quot;nd&quot;&gt;@Audited&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Entity&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Table&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;PERSON&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;PersonEntity&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Serializable&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

  &lt;span class=&quot;nd&quot;&gt;@Id&lt;/span&gt;
  &lt;span class=&quot;nd&quot;&gt;@GeneratedValue&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;strategy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;GenerationType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;AUTO&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;nd&quot;&gt;@Column&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;ID&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Integer&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;nd&quot;&gt;@Column&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;FIRST_NAME&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&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;nd&quot;&gt;@Column&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;LAST_NAME&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&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;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;And, that’s it! So what does this do? Let’s look at the tables that Hibernate will generate:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-sql&quot; data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;k&quot;&gt;create&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;table&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PERSON_AUD&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;ID&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;REV&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;REVTYPE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;FIRST_NAME&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;varchar2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;LAST_NAME&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;varchar2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;primary&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ID&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;REV&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;create&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;table&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;REVINFO&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;REV&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;REVTSTMP&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;19&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;primary&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;REV&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;alter&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;table&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PERSON_AUD&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;constraint&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;FK_PERSON_AUD&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;-- I renamed the system generated name... ;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;foreign&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;REV&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;references&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;REVINFO&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Basically, with the default configuration, you end up with another table with the same name as your existing table but with “_AUD” appended on the end. You can also change the generated name of the tables if you want. It has the same fields as your entity table but adds a REV number to keep track of the revision, and a REVTYPE to indicate an addition, modification, or delete. Read more about this in the &lt;a href=&quot;http://docs.jboss.org/hibernate/envers/3.6/reference/en-US/html_single/#tables&quot;&gt;documentation&lt;/a&gt;. Each time any field is changed on one of your entities an entry will be written to this table saving the state, which allows you to easily see what changed between 2 revisions. Envers also includes utilities to query over these tables to find all the revisions for a certain entity.&lt;/p&gt;

&lt;h3 id=&quot;generating-schema-ddl&quot;&gt;Generating Schema DDL&lt;/h3&gt;

&lt;p&gt;By the way, if you are looking for an easy way to generate the DDL for your entities &lt;em&gt;AND&lt;/em&gt; your envers tables, here’s some code. I had trouble finding a Maven plugin that supported BOTH Hibernate 4 and Envers, so this is what I did:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;&lt;span class=&quot;nc&quot;&gt;Configuration&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;config&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;nc&quot;&gt;Configuration&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// don&apos;t forget to get the right dialect for Oracle, MySQL, etc&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setProperty&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;hibernate.dialect&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;org.hibernate.dialect.Oracle10gDialect&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;addAnnotatedClass&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;PersonEntity&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;nc&quot;&gt;SchemaExport&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;export&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;nc&quot;&gt;EnversSchemaGenerator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;export&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setOutputFile&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;person-schema.sql&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;export&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;execute&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&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;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&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;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;summary&quot;&gt;Summary&lt;/h3&gt;

&lt;p&gt;So yeah, Hibernate Envers is an awesome time-saver if you need an audit trail. Keep in mind that these tables can grow quickly in size if you have a lot of changes to your entities happening regularly. But otherwise, I’m really glad I found this since it was just what I needed. Enjoy!&lt;/p&gt;
</description>
        <pubDate>Sun, 21 Apr 2013 05:26:00 +0000</pubDate>
        <link>https://www.jacobquatier.com/hibernate-envers-audit-trail-made-easy/</link>
        <guid isPermaLink="true">https://www.jacobquatier.com/hibernate-envers-audit-trail-made-easy/</guid>
        
        
      </item>
    
      <item>
        <title>Facebook LIKE buttons without the count</title>
        <description>&lt;p&gt;&lt;img src=&quot;/content/images/facebook-like-button.jpg&quot; alt=&quot;Facebook Like Button&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I’m not a huge fan of putting Facebook LIKE buttons on everything, but there’s some cases where it makes sense. It’s also advantageous to use the code that Facebook provides for buttons rather than building your own, because it handles all the different states a user could be in (logged in, logged out, already liked, etc.). It allows users to like your content on Facebook without leaving your website, so that’s kind of nice as well.&lt;/p&gt;

&lt;p&gt;What is NOT nice is that if you use their button, they force you to show the number of likes. There isn’t a flag you can pass in (like Twitter has) to not show the count next to the button. Here’s a quick hack to hide the count by setting the width of the IFrame accordingly.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-css&quot; data-lang=&quot;css&quot;&gt;&lt;span class=&quot;c&quot;&gt;/* CSS Hack for hiding the LIKE count */&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;.fb-like&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;span&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;48px&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;!important&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;  
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;.fb-like&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;iframe&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;48px&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;!important&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;.fb-like&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;iframe&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;.fb_iframe_widget_lift&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;450px&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;!important&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;It’s important to note that the 3rd rule is to set the width correctly when the comment model window appears (Facebook allows you to comment on what you just liked). Without this, only the first 48 pixels of that modal would be visible.&lt;/p&gt;

&lt;p&gt;This will probably break at some point if Facebook decides to change their API like they often do, but this seems to work right now.&lt;/p&gt;
</description>
        <pubDate>Mon, 01 Apr 2013 07:22:00 +0000</pubDate>
        <link>https://www.jacobquatier.com/facebook-like-buttons-without-count/</link>
        <guid isPermaLink="true">https://www.jacobquatier.com/facebook-like-buttons-without-count/</guid>
        
        
      </item>
    
  </channel>
</rss>
