<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Gorilla Logic Blogs &#187; Jerry Andrews</title>
	<atom:link href="http://blog.gorillalogic.com/category/jerry-andrews/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.gorillalogic.com</link>
	<description>Gorillas reflect on software development.</description>
	<lastBuildDate>Fri, 09 Dec 2011 19:21:12 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Java Components and Package Visibility</title>
		<link>http://blog.gorillalogic.com/2011/06/01/java-components-and-package-visibility/</link>
		<comments>http://blog.gorillalogic.com/2011/06/01/java-components-and-package-visibility/#comments</comments>
		<pubDate>Thu, 02 Jun 2011 02:11:00 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Jerry Andrews]]></category>

		<guid isPermaLink="false">tag:blogger.com,1999:blog-2731245157941249406.post-789844401751661272</guid>
		<description><![CDATA[I have a recurring problem: I want to build a component within a large application.  Here's an example: I want to synchronize QuickBooks Invoices with my application's invoices.  The component API produces and consumes application invoices, sales reps,...]]></description>
			<content:encoded><![CDATA[<div>I have a recurring problem: I want to build a component within a large application.  Here&#8217;s an example: I want to synchronize QuickBooks Invoices with my application&#8217;s invoices.  The component API produces and consumes application invoices, sales reps, accounts, and customers, but the internals of the sync task are very complicated, involving 3rd-party Invoices, maps to interface invoice-like objects, synchronizers, etc.  The main app has no need to know most of this stuff.</div>
<div></div>
<div>Java provides no mechanism to build a subclass structure for my sync component&#8211;I must either build the whole thing in a single package containing hundreds of package-scoped objects, or I must build public objects visible to the rest of my app so my component can have an internal package structure which models its behavior.</div>
<div></div>
<div>What I really need is a visibility modifier making classes only visible to their sub-packages.</div>
<p><a name='more'></a>
<div>I want my component to have a well-defined interface, and I want to be able to structure its internals cleanly. The component is complex, so it needs large-scale internal structure. My component wants to consume and emit objects key to the application&#8211;typically important domain objects&#8211;so it has a few dependencies outside of its package, and it&#8217;s thus not a true component. Java gives me a small number of very heavy-weight ways to do this: write an EJB, write a web service, write a domain VO package and a set of dependent packages.  All these approaches are hard to back-fit into existing projects, and tend to require a full app-server to implement. All I really needs is some kind if hierarchical visibility within the package structure, but instead, I have to deploy a huge heavyweight thingy to get what should be easilly done, done.</div>
<div></div>
<div>Java needs package-level visibility declarations.  By that I mean: we need to be able to say &#8220;this class is visible to this package and sub-packages&#8221;.  Alternately: this package is visible to sub-packages except when classes are defined as public.  Either way, I&#8217;d get the ability to define a component within a package, within the context of an enterprise app, and without the heavyweight behavior that comes with EJBs and web services and other large-scale things.</div>
<div></div>
<div>Bottom line: I want to build large-scale apps with small-scale tools. Give me that, and I can do a lot with not much memory and not much CPU.</div>
<div></div>
<div>Is it time for a JSR on visibility?</div>
<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2731245157941249406-789844401751661272?l=execdesign.blogspot.com' alt='' /></div>
]]></content:encoded>
			<wfw:commentRss>http://blog.gorillalogic.com/2011/06/01/java-components-and-package-visibility/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Creating Healthy Craftsmen</title>
		<link>http://blog.gorillalogic.com/2011/01/18/creating-healthy-craftsmen/</link>
		<comments>http://blog.gorillalogic.com/2011/01/18/creating-healthy-craftsmen/#comments</comments>
		<pubDate>Tue, 18 Jan 2011 17:56:00 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Jerry Andrews]]></category>

		<guid isPermaLink="false">tag:blogger.com,1999:blog-2731245157941249406.post-6750652575565984015</guid>
		<description><![CDATA[There's been a healthy debate over on the software craftsmanship mailing list about what craftsmanship means in the context of software development. I've been a proponent of, among other things, some set of standards by which a practitioner's capabilit...]]></description>
			<content:encoded><![CDATA[<p>There&#8217;s been a healthy debate over on the software craftsmanship mailing list about what craftsmanship means in the context of software development. I&#8217;ve been a proponent of, among other things, some set of standards by which a practitioner&#8217;s capabilities can be measured. That&#8217;s been unpopular, as you might imagine.<br /><a name='more'></a><br />George Dinwiddie (<a href="http://blog.gdinwiddie.com/">http://blog.gdinwiddie.com</a>) has written a bit about what he believes. I respect and agree with most of his conclusions, but I do disagree with his attitude on measuring developer&#8217;s capabilities. I don&#8217;t want to pick on George, but his are the most recent articles I&#8217;ve read on this topic (<a href="http://blog.gdinwiddie.com/2011/01/15/software-craftsmanship/">http://blog.gdinwiddie.com/2011/01/15/software-craftsmanship/</a>,&nbsp;<a href="http://blog.gdinwiddie.com/2011/01/17/trades-crafts-and-certification/">http://blog.gdinwiddie.com/2011/01/17/trades-crafts-and-certification/</a>), and they make the same mistakes I see everywhere when discussing performance tests. &nbsp;To wit:<br />
<blockquote>G&#8212;- is a certified tradesman. &nbsp;G&#8212;- did horrible work. &nbsp;G&#8212;&#8211;&#8217;s work was certified acceptable by a third party, also certified. &nbsp;Therefore certification doesn&#8217;t guarantee excellent (or &#8220;craftsmanlike&#8221;) work.</p></blockquote>
<p>Now here&#8217;s the fallacies in that argument:</p>
<ol>
<li>Certification, by itself, only guarantees that, at least at one point in time, the practitioner knew how to do excellent work (or at least, work up to the level of the certification standard). &nbsp;It doesn&#8217;t mean (s)he will always do it.</li>
<li>One (or two, or ten) examples where certification doesn&#8217;t do what it was intended to do doesn&#8217;t mean that certification never works, or even that it seldom works.</li>
<li>The certification in question when this sort of argument is made seldom, if ever, covers the issues of craftsmanship under discussion.</li>
<li>A certified individual, like most people, may not do the same level of work every day. &nbsp;Even master craftsmen have bad days or weeks or even years. In trade work, unfortunately, you can&#8217;t always throw it out and fix it; there are schedules to meet.</li>
</ol>
<p>So that particular argument is terminally flawed, and shouldn&#8217;t be made at all. &nbsp;To amplify a bit:</p>
<div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;">I have contended and continue to contend that <b>one key enabler</b> of good craftsmanship is the ability to measure a practitioner&#8217;s skill. &nbsp;I contend that what you can&#8217;t measure, you don&#8217;t understand. &nbsp;I support both objective and subjective measurement tools&#8211;because in complex situations, it&#8217;s generally not practical to make measurements purely objective. I don&#8217;t believe we, as programmers, have such a measure. There are some certifications. &nbsp;I&#8217;ve looked at the requirements for some of them&#8211;and they&#8217;re often quite good. &nbsp;Sadly, they tend to be product-specific.</div>
<p>I&#8217;d be the last to contend that certification is the <i>only</i>&nbsp;ingredient of a healthy craftsmanship movement or in developing excellent programmers. &nbsp;It&#8217;s simply one tool&#8211;a way to measure oneself both for one&#8217;s own edification, and to help others gauge your breadth of knowledge. I think it&#8217;s a particularly important tool&#8211;a pillar, if you will, along with other pillars, such as the community of like-minded individuals against whom you measure yourself, and who can comment on your work.</p>
<p>I think it&#8217;s important to review what certification means. It usually means &#8220;at some point in time, this individual knew and could put into practice certain tools, rules, and practices which, by this certification, we have verified&#8221;. &nbsp;Usually the certification standard is generated by people who really know the subject, and are qualified to determine what parts of the subject are key to being effective. Certification doesn&#8217;t say anything about a practitioner&#8217;s willingness to apply what (s)he knows&#8211;that&#8217;s a different problem, solved in different ways (e.g. establishing and maintaining a reputation, publishing your work for review, etc.).</p>
<p>What I&#8217;d really like to see is some kind of actual data comparing the performance of programmers (or plumbers, or electricians) who are certified in some way to those who aren&#8217;t certified, on tasks related to the certification. I see a lot of opinions (mine included) bandied about without actual, real, verifiable data. One of the things that makes DeMarco and Lister (Peopleware) compelling reading is that they provide actual data. Real studies with results that aren&#8217;t anecdotal. They&#8217;re not just voicing &#8220;opinions developed over years of practice&#8221;&#8211;they (and we) should be conducting actual experiments to verify our theories.</p>
<p>Craftsmanship, in my mind, requires:</p>
<ul>
<li>an attitude that it&#8217;s worthwhile to create excellent work, to provide the necessary stimulus,</li>
<li>access to people who can teach and/or materials from which a practitioner can learn what that means and how to accomplish it, to provide the necessary knowledge and experience,</li>
<li>some standard ways to measure a practitioner&#8217;s progress from neophyte to mastery, to provide a mechanism for the practitioner to understand where (s)he is and where (s)he needs to go, and</li>
<li>some mechanism for displaying the practitioner&#8217;s achievements, so that mastery carries real benefits in the working world, thereby incenting mastery in others, and helping people outside the craft or trade to select workers appropriate for their tasks.</li>
</ul>
<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2731245157941249406-6750652575565984015?l=execdesign.blogspot.com' alt='' /></div>
]]></content:encoded>
			<wfw:commentRss>http://blog.gorillalogic.com/2011/01/18/creating-healthy-craftsmen/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Documentation in the wild</title>
		<link>http://blog.gorillalogic.com/2011/01/12/documentation-in-the-wild/</link>
		<comments>http://blog.gorillalogic.com/2011/01/12/documentation-in-the-wild/#comments</comments>
		<pubDate>Wed, 12 Jan 2011 18:46:00 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Jerry Andrews]]></category>

		<guid isPermaLink="false">tag:blogger.com,1999:blog-2731245157941249406.post-3011176565269541619</guid>
		<description><![CDATA[I just started a new project. &#160;I has no documentation except the code.In this particular project, this is generally a Good Thing--the code in question is clear, well written, and (ahem) completely without comments. &#160;I'm not having a lot of tr...]]></description>
			<content:encoded><![CDATA[<p>I just started a new project. &nbsp;I has no documentation except the code.</p>
<p>In this particular project, this is generally a Good Thing&#8211;the code in question is clear, well written, and (ahem) completely without comments. &nbsp;I&#8217;m not having a lot of trouble understanding it, overall, because it really is very good code. &nbsp;But&#8230; I&#8217;ve spent 2 days trying to figure out how one important feature works.</p>
<p><a href="http://thedailywtf.com/Articles/Documentation-Done-Right.aspx">http://thedailywtf.com/Articles/Documentation-Done-Right.aspx</a></p>
<p>&#8216;Nuff said.
<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2731245157941249406-3011176565269541619?l=execdesign.blogspot.com' alt='' /></div>
]]></content:encoded>
			<wfw:commentRss>http://blog.gorillalogic.com/2011/01/12/documentation-in-the-wild/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Kanban in IT</title>
		<link>http://blog.gorillalogic.com/2010/10/27/kanban-in-it/</link>
		<comments>http://blog.gorillalogic.com/2010/10/27/kanban-in-it/#comments</comments>
		<pubDate>Wed, 27 Oct 2010 15:51:00 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Jerry Andrews]]></category>

		<guid isPermaLink="false">tag:blogger.com,1999:blog-2731245157941249406.post-3498887163581922695</guid>
		<description><![CDATA[Here's a nice series of articles on using Kanban in an IT setting. I found it interesting because it shows not only what they did, but how their process evolved over time in several settings.&#160;http://blogs.lessthandot.com/index.php/ITProfessionals/...]]></description>
			<content:encoded><![CDATA[<p>Here&#8217;s a nice series of articles on using Kanban in an IT setting. I found it interesting because it shows not only what they did, but how their process evolved over time in several settings.&nbsp;<a href="http://blogs.lessthandot.com/index.php/ITProfessionals/ITProcesses/applying-kanban-to-it-processes-part-1">http://blogs.lessthandot.com/index.php/ITProfessionals/ITProcesses/applying-kanban-to-it-processes-part-1</a>
<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2731245157941249406-3498887163581922695?l=execdesign.blogspot.com' alt='' /></div>
]]></content:encoded>
			<wfw:commentRss>http://blog.gorillalogic.com/2010/10/27/kanban-in-it/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Sucking Less: Checking In More Often</title>
		<link>http://blog.gorillalogic.com/2010/03/20/sucking-less-checking-in-more-often/</link>
		<comments>http://blog.gorillalogic.com/2010/03/20/sucking-less-checking-in-more-often/#comments</comments>
		<pubDate>Sat, 20 Mar 2010 21:07:00 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Jerry Andrews]]></category>

		<guid isPermaLink="false">tag:blogger.com,1999:blog-2731245157941249406.post-4165590103859773602</guid>
		<description><![CDATA[I'm fairly fearless when coding, which means that about once a week, I delete a huge chunk of something I should've kept, or change something into something unrecognizable, thereby inadvertently breaking a dozen unit tests. When I discover the problem,...]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m fairly fearless when coding, which means that about once a week, I delete a huge chunk of something I should&#8217;ve kept, or change something into something unrecognizable, thereby inadvertently breaking a dozen unit tests. When I discover the problem, usually about 4 hours later, I no longer have any idea what I did that made the bad thing happen. Then I spend another 2 or 3 hours figuring out what I broke and fixing it. &nbsp;Ugly.</p>
<p>On my personal projects, I check in code every time I get a unit test working. My checkins are something like 15-20 minutes apart. &nbsp;On projects I get paid for, though, checking in means running the whole unit test suite, and that can take 10 minutes (on a good project) or 2 hours (on a bad one)&#8211;so I don&#8217;t do it very often. That&#8217;s when I get into trouble. &nbsp;I&#8217;ve been meaning to solve that problem for some time, and Joel Spolsky&#8217;s blog topic last Wednesday (<a href="http://www.joelonsoftware.com/">Joel on Software</a>) finally kicked me in the pants. &nbsp;It took 15 minutes to solve the problem; here&#8217;s how I did it.</p>
<p><a name='more'></a>
<p>The new breed of source code control systems, distributed systems like Git and Mercurial, have had my attention for awhile, as I usually work with a team that&#8217;s spread out geographically. &nbsp;I regularly need to share code that&#8217;s not quite ready to be delivered with another developer, and that developer is very likely in a different city. &nbsp;Typically we&#8217;re reduced to emailing files to each other. A distributed SCC system would resolve this, as we could sync changes between our personal development&nbsp;repositories, but I assumed setting up and learning a new SCC would be painful, as it has been in the past, so I never got around to it. &nbsp;Joel&#8217;s article on Mercurial, however, got me to thinking about it seriously, and since I had a few hours on my hands, I figured I&#8217;d give it a try. &nbsp;What I didn&#8217;t expect was that I&#8217;d be up and functional in 10 minutes.</p>
<p>I downloaded Mercurial and installed it on my main dev box, which is a Windows laptop (I know, I suck). That took about 2 minutes, including googling for the Mercurial web site (<a href="http://mercurial.selenic.com/">http://mercurial.selenic.com/</a>). Then I changed to the main development directory of my current project, and typed (per Joel&#8217;s tutorial at&nbsp;<a href="http://hginit.com/">http://hginit.com/</a>):<br /><span class="Apple-style-span" style="font-size: small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">hg init</span></span><br /><span class="Apple-style-span" style="font-size: small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">hg add</span></span></p>
<p>The first impressive thing is these commands &#8216;just worked&#8217;. &nbsp;The second is that&#8217;s all that&#8217;s required to set up a local repository and add an entire project to it. Really. I&#8217;m <i>so</i>&nbsp;psyched!</p>
<p>The &#8220;add&#8221; command was naive, because it added <i>everything</i>, including build output and subversion control directories (**/.svn/**). &nbsp;I spent the next 10 minutes reverting my add, (&#8220;<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: small;">hg revert &#8211;all</span></span>&#8220;), then building an &#8220;ignore&#8221; file, then adding again, and finally committing. &nbsp;To shorten your search (Mercurial has great documentation, by the way&#8211;it only took me a few minutes to figure this stuff out), here&#8217;s what I ended up doing.</p>
<p>1. I created an .hhrc file in my home directory (C:\Documents and Settings\Jerry) with the following content:</p>
<p><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: small;">[ui]</span></span><br /><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: small;">username=jerry</span></span><br /><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: small;">editor=C:/bin/vim/vim71/gvim</span></span></p>
<p>The &#8220;username&#8221; entry preempts a request by the &#8220;commit&#8221; command for a username, and I prefer vi to the default editor, which is notepad.</p>
<p>2. In the root of my project directory, I created a .hgignore file with the following content:</p>
<p><span class="Apple-style-span" style="font-size: small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">syntax: glob</span></span><br /><span class="Apple-style-span" style="font-size: small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">.svn</span></span><br /><span class="Apple-style-span" style="font-size: small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">*.class</span></span><br /><span class="Apple-style-span" style="font-size: small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">*.log</span></span><br /><span class="Apple-style-span" style="font-size: small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">.hgignore</span></span><br /><span class="Apple-style-span" style="font-size: small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">antbuild/*</span></span><br /><span class="Apple-style-span" style="font-size: small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">build.properties</span></span></p>
<p>This tells Mercurial to ignore all files or directories named .svn (which is where subversion stores its status), all .class and .log files, the .hgignore file itself, the build.properties file, and anything in the antbuild directory (or its subdirectories). Mercurial ignore files support at least 3 different syntaxes for specifying files; the documentation is available on the Mercurial wiki and it&#8217;s quite complete.</p>
<p>Finally:</p>
<p><span class="Apple-style-span" style="font-size: small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">hg add</span></span><br /><span class="Apple-style-span" style="font-size: small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">hg commit</span></span></p>
<p>Now I&#8217;m in a position to check in locally every few minutes, but when I have a small feature complete, I can deliver via svn to the project&#8217;s repository. &nbsp;That&#8217;s right: I&#8217;m using Mercurial locally, and SVN for the project.</p>
<p>On my next project, I hope to have a chance to specify that the whole team uses Mercurial for the whole project; working with another programmer who&#8217;s not physically nearby just got a whole lot easier; we can exchange our updates directly with Mercurial, then push them up to a central repository independently. Sweet!
<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2731245157941249406-4165590103859773602?l=execdesign.blogspot.com' alt='' /></div>
]]></content:encoded>
			<wfw:commentRss>http://blog.gorillalogic.com/2010/03/20/sucking-less-checking-in-more-often/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Annotating Custom Types in Hibernate</title>
		<link>http://blog.gorillalogic.com/2010/03/03/annotating-custom-types-in-hibernate/</link>
		<comments>http://blog.gorillalogic.com/2010/03/03/annotating-custom-types-in-hibernate/#comments</comments>
		<pubDate>Wed, 03 Mar 2010 18:00:00 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Jerry Andrews]]></category>

		<guid isPermaLink="false">tag:blogger.com,1999:blog-2731245157941249406.post-1372983217889567300</guid>
		<description><![CDATA[Hibernate has a lot of nice features, and it's pretty well documented, but a recent need to add a simple custom type to an existing mapping left me flailing around for documentation on exactly how to do it. I wanted to do it with annotations, not by up...]]></description>
			<content:encoded><![CDATA[<p>Hibernate has a lot of nice features, and it&#8217;s pretty well documented, but a recent need to add a simple custom type to an existing mapping left me flailing around for documentation on exactly how to do it. I wanted to do it with annotations, not by updating the Hibernate configuration (that approach <i>is</i>&nbsp;well-documented). Here&#8217;s how it&#8217;s done.</p>
<p><a name='more'></a>Two new classes are needed. &nbsp;You can do it with one (and the Hibernate examples do it that way), but they really have different functions, so I coded them separately.</p>
<p>The first is the class you want to use for the column. &nbsp;In my case, I needed a Date with no milliseconds, which is a thin wrapper over java.util.Date. &nbsp;Here&#8217;s my class:</p>
<p><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;">/**</span></span><br /><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;">&nbsp;* Oracle stores dates in DATE columns down to the second; Java stores them to the millisecond.</span></span><br /><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;">&nbsp;* This occasionally can confuse Hibernate as to what data are stale. &nbsp;This class slices off</span></span><br /><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;">&nbsp;* any milliseconds which might be present in its representation.</span></span><br /><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;">&nbsp;*/</span></span><br /><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;">public class DateNoMs extends java.util.Date {</span></span><br /><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;">&nbsp;&nbsp; &nbsp;private static final long serialVersionUID = 1L;</span></span><br /><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"><br /></span></span><br /><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;">&nbsp;&nbsp; &nbsp;/** @see java.util.Date()&nbsp;*/</span></span><br /><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;">&nbsp;&nbsp; &nbsp;public&nbsp;DateNoMs() {</span></span><br /><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;super();</span></span><br /><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;long t = getTime();</span></span><br /><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;setTime(t &#8211; t%1000);</span></span><br /><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;">&nbsp;&nbsp; &nbsp;}</span></span><br /><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"><br /></span></span><br /><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;">&nbsp;&nbsp; &nbsp;/** @see java.util.Date(long)&nbsp;*/</span></span><br /><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;">&nbsp;&nbsp; &nbsp;public&nbsp;DateNoMs(long time) {</span></span><br /><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;super(time &#8211; time%1000);</span></span><br /><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;">&nbsp;&nbsp; &nbsp;}</span></span><br /><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;">&nbsp;&nbsp; &nbsp;</span></span><br /><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;">&nbsp;&nbsp; &nbsp;/**</span></span><br /><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;">&nbsp;&nbsp; &nbsp; * @param value</span></span><br /><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;">&nbsp;&nbsp; &nbsp; */</span></span><br /><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;">&nbsp;&nbsp; &nbsp;public&nbsp;DateNoMs(Date value) {</span></span><br /><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;long t = value.getTime();</span></span><br /><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;setTime(t &#8211; t%1000);</span></span><br /><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;">&nbsp;&nbsp; &nbsp;}</span></span><br /><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"><br /></span></span><br /><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;">&nbsp;&nbsp; &nbsp;/** @see java.util.Date#setTime(long) &nbsp; &nbsp; */</span></span><br /><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;">&nbsp;&nbsp; &nbsp;@Override</span></span><br /><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;">&nbsp;&nbsp; &nbsp;public void setTime(long time) {</span></span><br /><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;super.setTime(time &#8211; time%1000);</span></span><br /><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;">&nbsp;&nbsp; &nbsp;}</span></span><br /><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;">}</span></span>
<div></div>
<div>Straightforward, right? &nbsp;Now, in my class, I have a field mapping:</div>
<div></div>
<div>
<div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;">&nbsp;&nbsp; &nbsp;@Column(name = &#8220;PAYMENT_DATE&#8221;)</span></span></div>
<div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;">&nbsp;&nbsp; &nbsp;private&nbsp;DateNoMs&nbsp;m_paymentDate;</span></span></div>
<div></div>
<div>Of course, this won&#8217;t run&#8211;Hibernate will gag on the mapping, because it doesn&#8217;t know how to map a JDBC DATE column to a DateNoMs&#8211;as one would expect. &nbsp;There are two things we need at this point: first, an object which Hibernate can use to transform JDBC DATE into a DateNoMs, and an annotation pointing to that &#8220;Factory&#8221;. &nbsp;The factory class is produced by implementing (in the simplest case) org.hibernate.usertype.UserType. Documentation in this interface is pretty thin, but there are good examples available in the Hibernate distribution. Here&#8217;s my implementation. &nbsp;I&#8217;m greatly helped by the fact that my class (DateNoMs) is very close to java.util.Date, and java.sql.Date extends java.util.Date.</div>
<div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Times New Roman';"><span class="Apple-style-span" style="font-size: medium;"><br /></span></span></span></span></div>
<div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">/**</span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;* Map &#8220;things&#8221; (currently Oracle Date columns) to the DateNoMs.</span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;*/</span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">public class&nbsp;DateNoMsType implements UserType {</span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><br /></span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp;/** @see org.hibernate.usertype.UserType#assemble(java.io.Serializable, Object) &nbsp; &nbsp; */</span></span></div>
<div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">&nbsp;&nbsp; &nbsp;public Object assemble(Serializable cached, @SuppressWarnings(&#8220;unused&#8221;) Object owner) {</span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;return cached;</span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp;}</span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><br /></span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp;/** @see org.hibernate.usertype.UserType#deepCopy(Object) &nbsp; &nbsp; */</span></span></div>
<div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">&nbsp;&nbsp; &nbsp;public Object deepCopy(Object value) {</span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;if (value==null)</span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return null;</span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;if (! (value instanceof java.util.Date))</span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;throw new UnsupportedOperationException(&#8220;can&#8217;t convert &#8220;+value.getClass());</span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;return new&nbsp;DateNoMs((java.util.Date)value);</span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp;}</span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><br /></span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp;/** @see org.hibernate.usertype.UserType#disassemble(Object) &nbsp; &nbsp; */</span></span></div>
<div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">&nbsp;&nbsp; &nbsp;public Serializable disassemble(Object value) throws HibernateException {</span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;if (! (value instanceof java.util.Date))</span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;throw new UnsupportedOperationException(&#8220;can&#8217;t convert &#8220;+value.getClass());</span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><br /></span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;return new&nbsp;DateNoMs((java.util.Date)value);</span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp;}</span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><br /></span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp;/** @see org.hibernate.usertype.UserType#equals(Object, Object) &nbsp; &nbsp; */</span></span></div>
<div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">&nbsp;&nbsp; &nbsp;public boolean equals(Object x, Object y) throws HibernateException {</span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;return x.equals(y);</span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp;}</span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><br /></span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp;/** @see org.hibernate.usertype.UserType#hashCode(Object) &nbsp; &nbsp; */</span></span></div>
<div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">&nbsp;&nbsp; &nbsp;public int hashCode(Object value) throws HibernateException {</span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;return value.hashCode();</span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp;}</span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><br /></span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp;/** @see org.hibernate.usertype.UserType#isMutable() &nbsp; &nbsp; */</span></span></div>
<div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">&nbsp;&nbsp; &nbsp;public boolean isMutable() {</span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;return true;</span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp;}</span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><br /></span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp;/** @see org.hibernate.usertype.UserType#nullSafeGet(java.sql.ResultSet, String[], Object) &nbsp; &nbsp; */</span></span></div>
<div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">&nbsp;&nbsp; &nbsp;public Object nullSafeGet(ResultSet rs, String[] names, @SuppressWarnings(&#8220;unused&#8221;) Object owner)</span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;throws HibernateException, SQLException {</span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;// assume that we only map to one column, so there&#8217;s only one column name</span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;java.sql.Date value = rs.getDate( names[0] );</span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;if (value==null)</span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return null;</span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;return new&nbsp;DateNoMs(value.getTime());</span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp;}</span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><br /></span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp;/** @see org.hibernate.usertype.UserType#nullSafeSet(java.sql.PreparedStatement, Object, int) &nbsp; &nbsp; */</span></span></div>
<div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">&nbsp;&nbsp; &nbsp;public void nullSafeSet(PreparedStatement stmt, Object value, int index)</span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;throws HibernateException, SQLException {</span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;if (value==null) {</span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;stmt.setNull(index, Types.DATE);</span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return;</span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;}</span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><br /></span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;if (! (value instanceof java.util.Date))</span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;throw new UnsupportedOperationException(&#8220;can&#8217;t convert &#8220;+value.getClass());</span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><br /></span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;stmt.setDate( index, new java.sql.Date( ((java.util.Date)value).getTime()) );</span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp;}</span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><br /></span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp;/** @see org.hibernate.usertype.UserType#replace(Object, Object, Object) &nbsp; &nbsp; */</span></span></div>
<div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">&nbsp;&nbsp; &nbsp;public Object replace(Object original,&nbsp;</span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;@SuppressWarnings(&#8220;unused&#8221;) Object target, @SuppressWarnings(&#8220;unused&#8221;) Object owner) &nbsp;{</span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;return original;</span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp;}</span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><br /></span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp;/** @see org.hibernate.usertype.UserType#returnedClass() &nbsp; &nbsp; */</span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp;@SuppressWarnings(&#8220;unchecked&#8221;)</span></span></div>
<div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">&nbsp;&nbsp; &nbsp;public Class returnedClass() {</span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;return&nbsp;DateNoMs.class;</span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp;}</span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><br /></span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp;/** @see org.hibernate.usertype.UserType#sqlTypes() &nbsp; &nbsp; */</span></span></div>
<div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">&nbsp;&nbsp; &nbsp;public int[] sqlTypes() {</span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;return new int[] {Types.DATE};</span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">&nbsp;&nbsp; &nbsp;}</span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><br /></span></span></div>
<div><span class="Apple-style-span" style="font-size: x-small;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">}</span></span></div>
<div></div>
<div>The core of this class is the two methods which get and set values associated with my new type: nullSafeSet and nullSafeGet. &nbsp;One key thing to note is that nullSafeGet is supplied with a list of all the column names mapped to the custom datatype in the current query. &nbsp;In my case, there&#8217;s only one, but in complex cases, you can map multiple columns to one object (there are examples in the Hibernate documentation).</div>
<div></div>
<div>The final piece of the puzzle is the annotation which tells Hibernate to use the new &#8220;Type&#8221; class to generate objects of your custom type by adding a new @Type annotation to the column:</div>
<div></div>
<div>
<div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;">&nbsp;&nbsp; &nbsp;@Type(type=&#8221;com.gorillalogic.type.DateNoMsType&#8221;)</span></span></div>
<div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;">&nbsp;&nbsp; &nbsp;@Column(name = &#8220;PAYMENT_DATE&#8221;)</span></span></div>
<div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;">&nbsp;&nbsp; &nbsp;private&nbsp;DateNoMs&nbsp;m_paymentDate;</span></span></div>
<div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"><br /></span></span></div>
</div>
<div>The @Type annotation needs a full path to the class that implements the userType interface; this is the factory for producing the target type of the mapped column.</div>
<div></div>
<div>If you&#8217;re going to use your new type in a lot of places, you can shorten the @Type annotation by doing a typedef; you can place this in package-info.java in any package you like (I put mine in the same package as the UserType class). &nbsp;Here&#8217;s the line for the type defined above:</div>
<div></div>
<div>
<div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;">@TypeDefs(</span></span></div>
<div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;">&nbsp;&nbsp;{</span></span></div>
<div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"></span></span><span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"></span></span></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;">&nbsp;&nbsp; &nbsp;@TypeDef(name = &#8220;dateNoMs&#8221;,&nbsp;typeClass =&nbsp;com.gorillalogic.type.DateNoMsType.class</span></span></div>
<div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"></span></span><span class="Apple-tab-span" style="white-space: pre;"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"></span></span></span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;">&nbsp;&nbsp;})&nbsp;package com.gorillalogic.type;</span></span></div>
<div></div>
<div>Now my column annotation can look like this:</div>
<div></div>
<div>
<div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;">&nbsp;&nbsp; &nbsp;@Type(type=&#8221;dateNoMsType&#8221;)</span></span></div>
<div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;">&nbsp;&nbsp; &nbsp;@Column(name = &#8220;PAYMENT_DATE&#8221;)</span></span></div>
<div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;">&nbsp;&nbsp; &nbsp;private&nbsp;DateNoMs&nbsp;m_paymentDate;</span></span></div>
<div><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><span class="Apple-style-span" style="font-size: x-small;"><br /></span></span></div>
<div>That should be enough to get you started.&nbsp;</div>
</div>
</div>
</div>
</div>
<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2731245157941249406-1372983217889567300?l=execdesign.blogspot.com' alt='' /></div>
]]></content:encoded>
			<wfw:commentRss>http://blog.gorillalogic.com/2010/03/03/annotating-custom-types-in-hibernate/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>java.util.DuctTape</title>
		<link>http://blog.gorillalogic.com/2010/02/21/java-util-ducttape/</link>
		<comments>http://blog.gorillalogic.com/2010/02/21/java-util-ducttape/#comments</comments>
		<pubDate>Sun, 21 Feb 2010 18:00:00 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Jerry Andrews]]></category>

		<guid isPermaLink="false">tag:blogger.com,1999:blog-2731245157941249406.post-4087528071421994905</guid>
		<description><![CDATA[OverviewThe proposed class, java.util.DuctTape, is designed as a general purpose fix for a variety of commonly-observed situations in production code.  It serves as a temporary patch until a permanent solution is developed and deployed.FeaturesDuctTape...]]></description>
			<content:encoded><![CDATA[<p><b>Overview<br /></b><br />The proposed class, java.util.DuctTape, is designed as a general purpose fix for a variety of commonly-observed situations in production code.  It serves as a temporary patch until a permanent solution is developed and deployed.<br /><a name='more'></a><br /><b>Features<br /></b><br />DuctTape has the following features:
<ol>
<li>Transform any internal data representation into any external representation without creating dependencies on either side.</li>
<li>Transform any component interface into the interface required by any caller, again without creating dependencies.</li>
<li>Perform branches into any point in existing code, and returns from any point in existing code, allowing for maximal reuse without recoding where logic already exists to perform some function.</li>
<li>Intercept attempted calls to any unimplemented method and send an email request to support to perform the operation manually</li>
</ol>
<p><b>Discussion<br /></b><br />The utility of a properly-executed DuctTape implementation seems obvious. Once code is in production, users inevitably find edge and corner cases (and sometimes whole use cases) not anticipated by the requirements, design, implementation, or QA teams. The lead time required to implement these cases is often not available; a quick-and-dirty DuctTape-based solution is required to keep things running smoothly.  A standard DuctTape implementation is far preferable to the hacks commonly used to hold things together until the next point release.</p>
<p>We urge immediate action on this by the developer community.</p>
<div><b>Acknowledgement</b>
<div></div>
<div>Thanks to <a href="http://eldoradosoftware.blogspot.com/">Bob Hedlund</a> for the original DuctTape class concept. Thanks to the TCAS team for suggestions on the feature list.</div>
</div>
<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2731245157941249406-4087528071421994905?l=execdesign.blogspot.com' alt='' /></div>
]]></content:encoded>
			<wfw:commentRss>http://blog.gorillalogic.com/2010/02/21/java-util-ducttape/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Database/Code impedance mismatch</title>
		<link>http://blog.gorillalogic.com/2010/02/17/databasecode-impedance-mismatch/</link>
		<comments>http://blog.gorillalogic.com/2010/02/17/databasecode-impedance-mismatch/#comments</comments>
		<pubDate>Wed, 17 Feb 2010 19:02:00 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Jerry Andrews]]></category>

		<guid isPermaLink="false">tag:blogger.com,1999:blog-2731245157941249406.post-2766792186649739643</guid>
		<description><![CDATA[I love natural keys in database design.  You have to pay attention, though: the natural impedance mismatch between a programming language representation and the database representation of the key can bite you.Consider an object whose primary key might ...]]></description>
			<content:encoded><![CDATA[<p>I love natural keys in database design.  You have to pay attention, though: the natural impedance mismatch between a programming language representation and the database representation of the key can bite you.</p>
<p>Consider an object whose primary key might contain a date&#8211;say, a change log record. Oracle and DB2 both store a DATE as a time containing year, month, day, hours, minutes, and seconds.  No timezone.  The natural mapping for a Java tool like Hibernate is to map to a java.util.Date, which stores the Date as a time in milliseconds since the epoch GMT, and then maps it to whatever timezone is set on the machine where the code is running for display and conversion.</p>
<p>Now consider what might happen (especially if our change log record is attached to some parent object);</p>
<ol>
<li>We create and save the object; it is persisted. The local cached copy contains a non-zero value for milliseconds, but the database has truncated the milliseconds value and saved it.</li>
<li>Later on in the code somewhere, we have reason to save the object again, perhaps as part of some collection operation.</li>
<li>Hibernate looks in its cache, compares it with the database, and notes that the values of the Date don&#8217;t match&#8211;so it tries to save the value again.</li>
<li>The database dutifully tosses out the spare milliseconds, and bam! we have an attempt to re-insert an existing record, so it throws an exception.</li>
</ol>
<p>This is all terribly confusing to the programmer, who, inspecting the objects in question, sees no difference between what&#8217;s in the database and what&#8217;s in her code, especially since the default display characteristics of her database browser and her debugger don&#8217;t show the milliseconds.
<p>The easy fix in this case is to declare a class which matches the database representation&#8211;in this case, a good choice would be to declare a new class which truncates the milliseconds.  A modest example is shown below:</p>
<pre>/*** Public Domain; use or extend at will.*/import java.util.Date;

public class DbDate extends Date {/** increment if you change the state model     */private static final long serialVersionUID = 1L;

/** @see java.util.Date#Date() */public DbDate() {    long t = getTime();    setTime(t - t%1000);}

/** @see java.util.Date#Date(long) */public DbDate(long t) {    super(t - t%1000);}

/** @see java.util.Date#setTime(long)     */@Overridepublic void setTime(long time) {    super.setTime(time - time%1000);}}</pre>
<p>Also note that if you declared the database column as a TIMESTAMP, the Java and database representations more-or-less match&#8211;avoiding, in this case, this kind of problem. Note that Oracle doesn&#8217;t support TIMESTAMP_WITH_TIMEZONE in a primary key, and DB2 doesn&#8217;t implement TIMESTAMP_WITH_TIMEZONE at all&#8211;as of the last time I had access to DB2.</p>
<p>Dealing with timezones is another topic entirely&#8211;one which I&#8217;ll take up in a future post.</p>
<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2731245157941249406-2766792186649739643?l=execdesign.blogspot.com' alt='' /></div>
]]></content:encoded>
			<wfw:commentRss>http://blog.gorillalogic.com/2010/02/17/databasecode-impedance-mismatch/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Limiting Irreversibility</title>
		<link>http://blog.gorillalogic.com/2010/02/14/limiting-irreversibility/</link>
		<comments>http://blog.gorillalogic.com/2010/02/14/limiting-irreversibility/#comments</comments>
		<pubDate>Sun, 14 Feb 2010 18:00:00 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Jerry Andrews]]></category>

		<guid isPermaLink="false">tag:blogger.com,1999:blog-2731245157941249406.post-5030876561998397578</guid>
		<description><![CDATA[This afternoon I was reading Martin Fowler's commentary on architecture: http://www.martinfowler.com/ieeeSoftware/whoNeedsArchitect.pdf, and ran across the following:At a fascinating talk at the XP 2002 conference (http://martinfowler.com/articles/xp20...]]></description>
			<content:encoded><![CDATA[<p>This afternoon I was reading Martin Fowler&#8217;s commentary on architecture: <a href="http://www.martinfowler.com/ieeeSoftware/whoNeedsArchitect.pdf">http://www.martinfowler.com/ieeeSoftware/whoNeedsArchitect.pdf</a>, and ran across the following:
<div></div>
<div style="padding: 0px 0px 6px 2em;">At a fascinating talk at the XP 2002 conference (http://martinfowler.com/articles/xp2002.html), Enrico Zaninotto, an economist, analyzed the underlying thinking behind agile ideas in manufacturing and software development. One aspect I found particularly interesting was his comment that irreversibility was one of the prime drivers of complexity. He saw agile methods, in manufacturing and software development, as a shift that seeks to contain complexity by reducing irreversibility—as opposed to tackling other complexitydrivers. I think that one of an architect’s most important tasks is to remove architecture by finding ways to eliminate irreversibility in software designs.</div>
<div></div>
<div>I think he&#8217;s absolutely on the mark with this&#8211;in fact, I think it illuminates one of the two or three key roles of architecture in system implementation. If the architect focuses on helping to define approaches which are hard to change once the system &#8220;complexifies&#8221;, and in helping developers write solid code that can easily be modified when needs change, (s)he goes a long, long way towards making the system flexible and maintainable.</div>
<div></div>
<div>Note that there&#8217;s two architectural roles there: (1) helping to make key decisions early, and (2) mentoring developers around those decisions.</div>
<div></div>
<div>On most of the dev teams I&#8217;ve worked with, the first set of decisions is made by proposal and refinement&#8211;one of us proposes an overall approach, and the rest of us point out tweaks or whole new approaches until the whole thing gels in everyone&#8217;s mind.  It seems to work, if everyone is engaged. Some architects would prefer to &#8220;rule by fiat&#8221;, but I&#8217;ve found that generally results in systems which can&#8217;t be maintained or in far more work than is needed.  It&#8217;s very hard to get key decisions right by yourself. To illustrate: I once proposed a relatively modest refactoring in a large thorny user interface, to separate business logic from display logic and generally make it easier to maintain.  The reigning architect decided we needed a complete rewrite, in direct opposition to the opinion of everyone else on the team.  Nobody objected strongly, though everyone quietly agreed that a rewrite probably wasn&#8217;t needed&#8211;it&#8217;s lot more fun to write new code than to modify old. Nobody asked what the minimum effort needed to meet the requirements was. About two years and a couple million dollars later, the new system is, indeed, quite a bit better-structured than the old one. It&#8217;s not clear if the new UI will produce allow faster, cleaner updates than the old one&#8211;but it sure cost a lot to build: about twice the initial estimate, and about 6 times the original proposal. (By the way: the rewrite is considered a success by all involved.  See &#8220;<a href="http://thedailywtf.com/Articles/What_Could_Possibly_Be_Worse_Than_Failure_0x3f_.aspx">What Could Possibly Be Worse Than Failure?</a>&#8221; by Alex Papadimoulis.)</div>
<div></div>
<div>A second role implied in minimizing irreversibility is &#8220;mentor&#8221;.  Writing good code is hard; writing well-structured code without someone to bounce your design off of is doubly hard.  I spend a lot of time talking with the members of my teams, trying to make sure we have a design that&#8217;s flexible and understandable. A lot of what we think of as &#8220;architecture&#8221; starts out as a small feature being implemented by a relatively junior developer.  I try to make sure (s)he has someone to work with in the early stages of that work, or at least a trial design to start from.</div>
<div></div>
<div>I love Martin Fowler&#8217;s writing: he always gives me something good to think about.</div>
<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2731245157941249406-5030876561998397578?l=execdesign.blogspot.com' alt='' /></div>
]]></content:encoded>
			<wfw:commentRss>http://blog.gorillalogic.com/2010/02/14/limiting-irreversibility/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SEMAT and development principles</title>
		<link>http://blog.gorillalogic.com/2010/02/03/semat-and-development-principles/</link>
		<comments>http://blog.gorillalogic.com/2010/02/03/semat-and-development-principles/#comments</comments>
		<pubDate>Wed, 03 Feb 2010 18:00:00 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Jerry Andrews]]></category>

		<guid isPermaLink="false">tag:blogger.com,1999:blog-2731245157941249406.post-1196235921399575870</guid>
		<description><![CDATA[My first reaction to SEMAT was--is this practical?  But as I've thought about it more, I've decided there are some principles of good software design and implementation they can probably agree upon and illuminate.For context: I spent 15 years as a prac...]]></description>
			<content:encoded><![CDATA[<div>My first reaction to <a href="http://www.semat.org/">SEMAT </a>was&#8211;is this practical?  But as I&#8217;ve thought about it more, I&#8217;ve decided there are some principles of good software design and implementation they can probably agree upon and illuminate.</div>
<div></div>
<div>For context: I spent 15 years as a practicing nuclear engineer before becoming a practicing software developer.</div>
<div></div>
<div>&#8220;Engineering practice&#8221;, as I found it in the field, is often as arbitrary as &#8220;software development practice&#8221;.  What is &#8220;good&#8221; is measured first by &#8220;what works&#8221;, second by &#8220;what&#8217;s elegant&#8221;, and finally by &#8220;what&#8217;s inexpensive&#8221;, and is judged primarily by senior practitioners working against their own experience rather than some set of objective standards (though those exist as well). In hardware engineering, the time lapse between design review and implementation is quite often very long (especially large-scale design, e.g. power plants, where I worked).  As a result, feedback loops are even longer and harder to manage. What dominates in the large scale seems to be &#8220;what worked&#8221;&#8211;and just as often, &#8220;what failed&#8221;.</div>
<div></div>
<div>This seems to me to be exactly the type of thing we&#8217;re developing now as developers&#8211;we now have lots of categories of languages for solving different types of problems and we&#8217;re developing solid tools and techniques for measuring performance, managing projects, and closing the loop between design and implementation. The world for software developers is a FAR less arbitrary place, and has far more development of tools and techniques, than in 1976 when I started coding.</div>
<div></div>
<div>The body of common practice is regularly changing in hardware engineering, as analysis tools get better.  When I graduated, one of my first tasks required a stress analysis, which I did with a calculator by hand.  These days, an engineer would set that up in a desktop finite-element analysis program with a nice UI, and he&#8217;d get a better answer in less time.  The principles are the same, though: determine, through an understanding of material behavior and machine design, what a specific application required of the machine and what combination of off-the-shelf components and custom machining could be used to implement that application.  It&#8217;s very much what I do today: I pick off-the-shelf components and custom components to create a design to meet certain requirements.</div>
<div></div>
<div>Can we, as a group, specify some of the principles on which those decisions get made?  I suspect we can.  While I&#8217;m only really fluent in one sub-part of OO design, I know of a few; consider the SOLID principles in OO design, various common design patterns, and the corpus of tools and techniques in Knuth&#8217;s &#8220;The Art of Computer Programming&#8221;.</div>
<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2731245157941249406-1196235921399575870?l=execdesign.blogspot.com' alt='' /></div>
]]></content:encoded>
			<wfw:commentRss>http://blog.gorillalogic.com/2010/02/03/semat-and-development-principles/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

