I think this is pretty cool. But thi s is my first Hibernate/Struts project so feel free to critique away... or to suggest somewhere else this should be posted. Or maybe this is a well-known pattern already?
The Problem:
A typical project will have some text strings that are entered using HTML <input> form fields and then written to a database using Hibernate via a framework such as Struts. The maximum string length may be specified in the HTML (<input maxlength=...), in the DDL, in the xxx.hbm.xml, and possibly in a validation rule. Using XDoclet and hbm2ddl, and no Struts length validation rule, the size is in both the XDoclet comments and in the HTML.
It is easy to make the error of changing a constant in only one of the two places. This may not show up as a problem until a user enters a long string and sees an exception if the database field is smaller.
Wouldn't it be nice to specify each property length in just one place?
The Solution:
This assumes Struts, but may be adaptable for other purposes.
The length is in the XDoclet annotation only:
Code:
/**
* @hibernate.property
* length="40"
* non-null="true"
*/
public String getCountry() { ...
This generates XML as usual (or you may handcode the XML, depending on your methodology):
Code:
<property
name="country"
type="java.lang.String"
column="country"
length="40" />
Now, use a simple stylesheet (size.xsl) to generate a resource properties file from the XML:
Code:
<?xml version='1.0'?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text" encoding="utf-8"/>
<xsl:template match="class">
<xsl:for-each select="property">
size.<xsl:value-of select='@name'/>=<xsl:value-of select='@length'/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Ant has XSLT support built-in so it is easy to generate the .properties file as part of the build:
Code:
<target name="xsl" depends="xdoclet">
<xslt basedir="build/xdoclet/" destdir="build/"
includes="*.hbm.xml" style="size.xsl">
<mapper type="glob" from="*.hbm.xml" to="*.properties"/>
</xslt>
</target>
Then in Struts, add all the generated .properties files (aka bundles), one for each class, in struts-config.xml:
Code:
<message-resources key="class1" parameter="Class1" null="false"/>
<message-resources key="class2" parameter="Class2" null="false"/>
In the JSP page, set a variable to the property name (e.g. ${field.name}), then using that extract the size from the appropriate message resource bundle:
Code:
<c:set var="s">
<bean:message key="size.${field.name}" bundle="class1" />
</c:set>
<html:text property="${field.name}" size="${s}" maxlength="${s}" />
(Am I correct that JSTL's <fmt:message> won't accept an expression? That's why I used <bean:message>.)
Works for me! I hope someone finds this useful.