Author: buildbot
Date: Thu Nov 27 03:21:29 2014
New Revision: 930714
Log:
Production update by buildbot for tapestry
Modified:
websites/production/tapestry/content/cache/main.pageCache
websites/production/tapestry/content/using-beaneditform-to-create-user-forms.data/address-v3.png
websites/production/tapestry/content/using-beaneditform-to-create-user-forms.data/address-v5.png
websites/production/tapestry/content/using-beaneditform-to-create-user-forms.data/address-v6.png
websites/production/tapestry/content/using-beaneditform-to-create-user-forms.data/address-v7.png
websites/production/tapestry/content/using-beaneditform-to-create-user-forms.data/address-v8.png
websites/production/tapestry/content/using-beaneditform-to-create-user-forms.html
Modified: websites/production/tapestry/content/cache/main.pageCache
==============================================================================
Binary files - no diff available.
Modified:
websites/production/tapestry/content/using-beaneditform-to-create-user-forms.data/address-v3.png
==============================================================================
Binary files - no diff available.
Modified:
websites/production/tapestry/content/using-beaneditform-to-create-user-forms.data/address-v5.png
==============================================================================
Binary files - no diff available.
Modified:
websites/production/tapestry/content/using-beaneditform-to-create-user-forms.data/address-v6.png
==============================================================================
Binary files - no diff available.
Modified:
websites/production/tapestry/content/using-beaneditform-to-create-user-forms.data/address-v7.png
==============================================================================
Binary files - no diff available.
Modified:
websites/production/tapestry/content/using-beaneditform-to-create-user-forms.data/address-v8.png
==============================================================================
Binary files - no diff available.
Modified:
websites/production/tapestry/content/using-beaneditform-to-create-user-forms.html
==============================================================================
---
websites/production/tapestry/content/using-beaneditform-to-create-user-forms.html
(original)
+++
websites/production/tapestry/content/using-beaneditform-to-create-user-forms.html
Thu Nov 27 03:21:29 2014
@@ -137,52 +137,53 @@ public class CreateAddress
<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[ @Property
private Address address;
]]></script>
-</div></div><p>When you refresh the page, you may see the warning like the
following at the top of the page:</p><p><img class="confluence-embedded-image"
src="https://cwiki.apache.org/confluence/download/attachments/23340431/hmac-warning.png?version=2&modificationDate=1416883285600&api=v2"
data-image-src="/confluence/download/attachments/23340431/hmac-warning.png?version=2&modificationDate=1416883285600&api=v2"></p><p>If
you see that, it means you need to invent an HMAC passphrase for your app.
Just edit your AppModule.java class (in your services package), adding a couple
of lines to the contributeApplicationDefaults method like the
following:</p><div class="code panel pdl" style="border-width: 1px;"><div
class="codeContent panelContent pdl">
+</div></div><p>When you refresh the page, you may see the warning like the
following at the top of the page:</p><p><img class="confluence-embedded-image"
src="https://cwiki.apache.org/confluence/download/attachments/23340431/hmac-warning.png?version=2&modificationDate=1416883285000&api=v2"
data-image-src="/confluence/download/attachments/23340431/hmac-warning.png?version=2&modificationDate=1416883285000&api=v2"></p><p>If
you see that, it means you need to invent an HMAC passphrase for your app.
Just edit your AppModule.java class (in your services package), adding a couple
of lines to the contributeApplicationDefaults method like the
following:</p><div class="code panel pdl" style="border-width: 1px;"><div
class="codeContent panelContent pdl">
<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[ // Set the HMAC pass phrase to secure
object data serialized to client
configuration.add(SymbolConstants.HMAC_PASSPHRASE,
"");]]></script>
-</div></div><p>but, instead of an empty string, insert a long, <strong>random
string of characters</strong> (like a very long and complex password, at least
30 characters) that you keep private.</p><p>After you do that, stop the app and
restart it, and click on the Create new address link again, and you'll see
something like this:</p><p><img class="confluence-embedded-image"
src="https://cwiki.apache.org/confluence/download/attachments/23340431/create-address-initial.png?version=2&modificationDate=1416884366039&api=v2"
data-image-src="/confluence/download/attachments/23340431/create-address-initial.png?version=2&modificationDate=1416884366039&api=v2"></p><p>Tapestry
has done quite a bit of work here. It has created a form that includes a field
for each property. Further, it has seen that the honorific property is an
enumerated type, and presented that as a drop-down list.</p><p>In addition,
Tapestry has converted the property names ("city", "email", "firstName") to u
ser presentable labels ("City", "Email", "First Name"). In fact, these are
<label> elements, so clicking a label with the mouse will move the input
cursor into the corresponding field.</p><p>This is an awesome start; it's a
presentable interface, quite nice in fact for a few minute's work. But it's far
from perfect; let's get started with some customizations.</p><h1
id="UsingBeanEditFormToCreateUserForms-ChangingFieldOrder">Changing Field
Order</h1><p>The BeanEditForm must guess at the right order to present the
fields; for public fields, they end up in alphabetical order. For standard
JavaBeans properties, the BeanEditForm default is in the order in which the
getter methods are defined in the class (it uses line number information, if
available).</p><p>A better order for these fields is the order in which they
are defined in the Address
class:</p><ul><li>honorific</li><li>firstName</li><li>lastName</li><li>street1</li><li>street2</li><li>city</li><li>state</li><li>zip</li><li
>email</li><li>phone</li></ul><p>We can accomplish this by using the
><code>reorder</code> parameter of the BeanEditForm component, which is a
>comma separated list of property (or public field) names:</p><div class="code
>panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl"
>style="border-bottom-width: 1px;"><b>CreateAddress.tml
>(partial)</b></div><div class="codeContent panelContent pdl">
+</div></div><p>but, instead of an empty string, insert a long, <strong>random
string of characters</strong> (like a very long and complex password, at least
30 characters) that you keep private.</p><p>After you do that, stop the app and
restart it, and click on the Create new address link again, and you'll see
something like this:</p><p><img class="confluence-embedded-image"
src="https://cwiki.apache.org/confluence/download/attachments/23340431/create-address-initial.png?version=2&modificationDate=1416884366000&api=v2"
data-image-src="/confluence/download/attachments/23340431/create-address-initial.png?version=2&modificationDate=1416884366000&api=v2"></p><p>Tapestry
has done quite a bit of work here. It has created a form that includes a field
for each property. Further, it has seen that the honorific property is an
enumerated type, and presented that as a drop-down list.</p><p>In addition,
Tapestry has converted the property names ("city", "email", "firstName") to u
ser presentable labels ("City", "Email", "First Name"). In fact, these are
<label> elements, so clicking a label with the mouse will move the input
cursor into the corresponding field.</p><p>This is an awesome start; it's a
presentable interface, quite nice in fact for a few minute's work. But it's far
from perfect; let's get started with some customizations.</p><h1
id="UsingBeanEditFormToCreateUserForms-ChangingFieldOrder">Changing Field
Order</h1><p>The BeanEditForm must guess at the right order to present the
fields; for public fields, they end up in alphabetical order. For standard
JavaBeans properties, the BeanEditForm default is in the order in which the
getter methods are defined in the class (it uses line number information, if
available).</p><p>A better order for these fields is the order in which they
are defined in the Address
class:</p><ul><li>honorific</li><li>firstName</li><li>lastName</li><li>street1</li><li>street2</li><li>city</li><li>state</li><li>zip</li><li
>email</li><li>phone</li></ul><p>We can accomplish this by using the
><code>reorder</code> parameter of the BeanEditForm component, which is a
>comma separated list of property (or public field) names:</p><div class="code
>panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl"
>style="border-bottom-width: 1px;"><b>CreateAddress.tml
>(partial)</b></div><div class="codeContent panelContent pdl">
<script class="theme: Default; brush: xml; gutter: false"
type="syntaxhighlighter"><![CDATA[ <t:beaneditform
object="address"
reorder="honorific,firstName,lastName,street1,street2,city,state,zip,email,phone"
/>
]]></script>
-</div></div><p><img class="confluence-embedded-image"
src="https://cwiki.apache.org/confluence/download/attachments/23340431/create-address-reordered.png?version=2&modificationDate=1416884592822&api=v2"
data-image-src="/confluence/download/attachments/23340431/create-address-reordered.png?version=2&modificationDate=1416884592822&api=v2"></p><h3
id="UsingBeanEditFormToCreateUserForms-Customizinglabels">Customizing
labels</h3><p>Tapestry makes it pretty easy to customize the labels used on the
fields. It's just a matter of creating a <em>message catalog</em> for the
page.</p><p>In Tapestry, every page and component may have its own message
catalog. This is a standard Java properties file, and it is named the same as
the page or component class, with a ".properties" extension. A message catalog
consists of a series of lines, each line is a message key and a message value
separated with an equals sign.</p><p>All it takes is to create a message entry
with a particular nam
e: the name of the property suffixed with "-label". As elsewhere, Tapestry is
forgiving of case.</p><div class="preformatted panel" style="border-width:
1px;"><div class="preformattedHeader panelHeader" style="border-bottom-width:
1px;"><b>src/main/resources/com/example/tutorial/pages/address/CreateAddress.properties</b></div><div
class="preformattedContent panelContent">
+</div></div><p><img class="confluence-embedded-image"
src="https://cwiki.apache.org/confluence/download/attachments/23340431/create-address-reordered.png?version=2&modificationDate=1416884592000&api=v2"
data-image-src="/confluence/download/attachments/23340431/create-address-reordered.png?version=2&modificationDate=1416884592000&api=v2"></p><h3
id="UsingBeanEditFormToCreateUserForms-Customizinglabels">Customizing
labels</h3><p>Tapestry makes it pretty easy to customize the labels used on the
fields. It's just a matter of creating a <em>message catalog</em> for the
page.</p><p>In Tapestry, every page and component may have its own message
catalog. This is a standard Java properties file, and it is named the same as
the page or component class, with a ".properties" extension. A message catalog
consists of a series of lines, each line is a message key and a message value
separated with an equals sign.</p><p>All it takes is to create a message entry
with a particular nam
e: the name of the property suffixed with "-label". As elsewhere, Tapestry is
forgiving of case.</p><div class="preformatted panel" style="border-width:
1px;"><div class="preformattedHeader panelHeader" style="border-bottom-width:
1px;"><b>src/main/resources/com/example/tutorial/pages/address/CreateAddress.properties</b></div><div
class="preformattedContent panelContent">
<pre>street1-label=Street 1
street2-label=Street 2
email-label=E-Mail
zip-label=Zip Code
phone-label=Phone Number</pre>
-</div></div><p>Since this is a <em>new</em> file (and not a change to an
existing file), you may have to restart Jetty to force Tapestry to pick up the
change.</p><p><img class="confluence-embedded-image
confluence-content-image-border" width="700"
src="https://cwiki.apache.org/confluence/download/attachments/23340431/address-v3.png?version=1&modificationDate=1286782418000&api=v2"
data-image-src="/confluence/download/attachments/23340431/address-v3.png?version=1&modificationDate=1286782418000&api=v2"><br
clear="none"> Create Address form with field labels corrected</p><p>We can
also customize the options in the drop down list. All we have to do is add some
more entries to the message catalog matching the enum names to the desired
labels. Update CreateAddress.properties and add:</p><div class="preformatted
panel" style="border-width: 1px;"><div class="preformattedContent panelContent">
+</div></div><p>Since this is a <em>new</em> file (and not a change to an
existing file), you may have to restart Jetty to force Tapestry to pick up the
change.</p><p><img class="confluence-embedded-image
confluence-content-image-border"
src="https://cwiki.apache.org/confluence/download/attachments/23340431/address-v3.png?version=2&modificationDate=1417055915528&api=v2"
data-image-src="/confluence/download/attachments/23340431/address-v3.png?version=2&modificationDate=1417055915528&api=v2"></p><p>We
can also customize the options in the drop down list. All we have to do is add
some more entries to the message catalog matching the enum names to the desired
labels. Update CreateAddress.properties and add:</p><div class="preformatted
panel" style="border-width: 1px;"><div class="preformattedContent panelContent">
<pre>MR=Mr.
MRS=Mrs.
DR=Dr.
</pre>
</div></div><p>Notice that we don't have to include an option for MISS,
because that is converted to "Miss" anyway. You might just want to include it
for sake of consistency ... the point is, each option label is searched for
separately.</p><p>Lastly, the default label on the submit button is
"Create/Update" (BeanEditForm doesn't know how it is being used). Let's change
that to "Create Address".</p><p>That button is a component within the
BeanEditForm component. It's not a property, so we can't just put a message
into the message catalog, the way we can with the fields. Fortunately, the
BeanEditForm component includes a parameter expressly for re-labeling the
button. Simply change the CreateAddress component template:</p><div class="code
panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
-<script class="theme: Default; brush: xml; gutter: false"
type="syntaxhighlighter"><![CDATA[ <t:beaneditform
submitlabel="Create Address" object="address"/>
+<script class="theme: Default; brush: xml; gutter: false"
type="syntaxhighlighter"><![CDATA[ <t:beaneditform
submitlabel="Create Address" object="address"
+
reorder="honorific,firstName,lastName,street1,street2,city,state,zip,email,phone"/>
]]></script>
-</div></div><p>The default for the submitlabel parameter is "Create/Update",
but here we're overriding that default to a specific value.</p><p>The final
result shows the reformatting and relabeling:</p><p><img
class="confluence-embedded-image confluence-content-image-border" width="700"
src="https://cwiki.apache.org/confluence/download/attachments/23340431/address-v5.png?version=1&modificationDate=1286782418000&api=v2"
data-image-src="/confluence/download/attachments/23340431/address-v5.png?version=1&modificationDate=1286782418000&api=v2"><br
clear="none"> Create Address form with proper labels</p><p>Before continuing
on to validation, a side note about message catalogs. Message catalogs are not
just for re-labeling fields and options; we'll see in later chapters how
message catalogs are used in the context of localization and
internationalization.</p><p>Instead of putting the label for the submit button
directly inside the template, we're going to provide a referenc
e to the label; the actual label will go in the message catalog.</p><p>In
Tapestry, when binding a parameter, the value you provide may include a prefix.
The prefix guides Tapestry in how to interpret the rest of the the parameter
value ... is it the name of a property? The id of a component? A message key?
Most parameters have a default prefix, usually "prop:", that is used when you
fail to provide one (this helps to make the templates as terse as
possible).</p><p>Here we want to reference a message from the catalog, so we
use the "message:" prefix:</p><div class="code panel pdl" style="border-width:
1px;"><div class="codeContent panelContent pdl">
+</div></div><p>The default for the submitlabel parameter is "Create/Update",
but here we're overriding that default to a specific value.</p><p>The final
result shows the reformatting and relabelling:</p><p><img
class="confluence-embedded-image confluence-content-image-border"
src="https://cwiki.apache.org/confluence/download/attachments/23340431/address-v5.png?version=2&modificationDate=1417055915000&api=v2"
data-image-src="/confluence/download/attachments/23340431/address-v5.png?version=2&modificationDate=1417055915000&api=v2"><br
clear="none">Before continuing on to validation, a side note about message
catalogs. Message catalogs are not just for re-labeling fields and options;
we'll see in later chapters how message catalogs are used in the context of
localization and internationalization.</p><p>Instead of putting the label for
the submit button directly inside the template, we're going to provide a
reference to the label; the actual label will go in the message c
atalog.</p><p>In Tapestry, when binding a parameter, the value you provide may
include a prefix. The prefix guides Tapestry in how to interpret the rest of
the the parameter value ... is it the name of a property? The id of a
component? A message key? Most parameters have a default prefix, usually
"prop:", that is used when you fail to provide one (this helps to make the
templates as terse as possible).</p><p>Here we want to reference a message from
the catalog, so we use the "message:" prefix:</p><div class="code panel pdl"
style="border-width: 1px;"><div class="codeContent panelContent pdl">
<script class="theme: Default; brush: xml; gutter: false"
type="syntaxhighlighter"><![CDATA[ <t:beaneditform
object="address" submitlabel="message:submit-label"
reorder="honorific,firstName,lastName,street1,street2,city,state,zip,email,phone"
/>
]]></script>
</div></div><p>And then we define the submit-label key in the message
catalog:</p><div class="preformatted panel" style="border-width: 1px;"><div
class="preformattedContent panelContent">
<pre>submit-label=Create Address
</pre>
-</div></div><p>At the end of the day, the exact same HTML is sent to the
client, regardless of whether you include the label text directly in the
template, or indirectly in the message catalog. In the long term, the latter
approach will work better if you later chose to internationalize your
application.</p><h3
id="UsingBeanEditFormToCreateUserForms-AddingValidation">Adding
Validation</h3><p>Before we worry about storing the Address object, we should
make sure that the user provides reasonable values. For example, several of the
fields should be required, and phone numbers and email address have specific
formats.</p><p>The BeanEditForm checks for a Tapestry-specific annotation, @<a
shape="rect" class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/beaneditor/Validate.html">Validate</a>,
on the field, the getter method, or the setter method of each
property.</p><p>Edit the Address entity, and update the lastName, firstName,
street1, city, state a
nd zip fields, adding a @Validate annotation to each:</p><div class="code
panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl">
+</div></div><p>In the end, the exact same HTML is sent to the client,
regardless of whether you include the label text directly in the template, or
indirectly in the message catalog. In the long term, the latter approach will
work better if you later chose to internationalize your application.</p><h3
id="UsingBeanEditFormToCreateUserForms-AddingValidation">Adding
Validation</h3><p>Before we worry about storing the Address object, we should
make sure that the user provides reasonable values. For example, several of the
fields should be required, and phone numbers and email address have specific
formats.</p><p>The BeanEditForm checks for a Tapestry-specific annotation, @<a
shape="rect" class="external-link"
href="http://tapestry.apache.org/current/apidocs/org/apache/tapestry5/beaneditor/Validate.html">Validate</a>,
on the field, the getter method, or the setter method of each
property.</p><p>Edit the Address entity, and update the lastName, firstName,
street1, city, state and zip fiel
ds, adding a @Validate annotation to each:</p><div class="code panel pdl"
style="border-width: 1px;"><div class="codeContent panelContent pdl">
<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[ @Validate("required")
public String firstName;
]]></script>
</div></div><p>What is that string, "required"? That's how you specify the
desired validation. It is a series of names that identify what type of
validation is desired. A number of validators are built in, such as "required",
"minLength" and "maxLength". As elsewhere, Tapestry is case
insensitive.</p><p>You can apply multiple validations, by separating the
validator names with commas. Some validators can be configured (with an equals
sign). Thus you might say "required,minLength=5" for a field that must be
specified, and must be at least five characters long.</p> <div
class="aui-message problem shadowed information-macro">
<span class="aui-icon icon-problem">Icon</span>
<div class="message-content">
- <p>You can easily get confused when you make a
change to an entity class, such as adding the @Validate annotatation, and
<em>not</em> see the result in the browser. Only component classes, and (most)
classes in the Tapestry services layer, are live-reloaded. Data and entity
objects are not reloaded, so this is one area where you need to stop and
restart Jetty to see the change.</p>
+ <p>You can easily get confused when you make a
change to an entity class, such as adding the @Validate annotation, and
<em>not</em> see the result in the browser. Only component classes, and (most)
classes in the Tapestry services layer, are live-reloaded. Data and entity
objects are not reloaded, so this is one area where you need to stop and
restart Jetty to see the change.</p>
</div>
</div>
-<p>Restart the application, and refresh your browser, then hit the submit
button.</p><p><img class="confluence-embedded-image
confluence-content-image-border" height="482" width="760"
src="https://cwiki.apache.org/confluence/download/attachments/23340431/address-v6.png?version=1&modificationDate=1286782418000&api=v2"
data-image-src="/confluence/download/attachments/23340431/address-v6.png?version=1&modificationDate=1286782418000&api=v2"></p><p>Form
with client side validations visible</p><p>This is a shot just after hitting
the submit button; all the fields have been validated and pop-up error bubbles
are displayed. This looks a bit cluttered, but all the bubbles, except for the
one for the focus field (the field the user is actively typing into), will fade
out after a moment. As you tab from field to field, Tapestry will validate your
input and briefly display the error bubble. And <em>all</em> of this is taking
place on the client side, without any communication wi
th the application.</p><p>Each field in error has been highlighted (it's a bit
subtle) and marked with a red "X". Further, the label for each of the fields
has also been highlighted in red, to even more clearly identify what's in
error. The cursor has also been moved to the first field that's in
error.</p><p>Once all the errors are corrected, and the form does submit, all
validations are performed on the server side as well (just in case the client
has JavaScript disabled).</p><p>So ... how about some more interesting
validation than just "required or not". Tapestry has built in support for
validating based on field length and several variations of field value,
including regular expressions. Zip codes are pretty easy to express as a
regular expression.</p><div class="code panel pdl" style="border-width:
1px;"><div class="codeContent panelContent pdl">
+<p>Restart the application, and refresh your browser, then hit the Create
Address button.</p><p><img class="confluence-embedded-image
confluence-content-image-border"
src="https://cwiki.apache.org/confluence/download/attachments/23340431/address-v6.png?version=3&modificationDate=1417056607705&api=v2"
data-image-src="/confluence/download/attachments/23340431/address-v6.png?version=3&modificationDate=1417056607705&api=v2"></p><p>This
is a shot just after hitting the Create Address button; all the fields have
been validated and errors displayed. Each field in error has been highlighted
in red and marked with a red "X". Further, the label for each of the fields has
also been highlighted in red, to even more clearly identify what's in error.
The cursor has also been moved to the first field that's in error. And
<em>all</em> of this is taking place on the client side, without any
communication with the application.</p><p>Once all the errors are corrected,
and the form does
submit, all validations are performed on the server side as well (just in
case the client has JavaScript disabled).</p><p>So ... how about some more
interesting validation than just "required or not". Tapestry has built in
support for validating based on field length and several variations of field
value, including regular expressions. Zip codes are pretty easy to express as a
regular expression.</p><div class="code panel pdl" style="border-width:
1px;"><div class="codeContent panelContent pdl">
<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[
@Validate("required,regexp=^\\d{5}(-\\d{4})?$")
public String zip;
]]></script>
-</div></div><p>Let's give it a try; restart the application and enter an "abc"
for the zip code.</p><p><img class="confluence-embedded-image
confluence-content-image-border" width="700"
src="https://cwiki.apache.org/confluence/download/attachments/23340431/address-v7.png?version=1&modificationDate=1286782418000&api=v2"
data-image-src="/confluence/download/attachments/23340431/address-v7.png?version=1&modificationDate=1286782418000&api=v2"><br
clear="none"> Regexp validation</p><p>This is what you'll see after typing
"abc" and tabbing out of the field, then tabbing back in. It's a little hard to
capture all the animation effects in a still photo.</p><p>In any case, that's
the right validation behavior, but it's the wrong message. Your users are not
going to know or care about regular expressions.</p><p>Fortunately, it's easy
to customize validation messages. All we need to know is the name of the
property ("zip") and the name of the validator ("regexp"). We can then p
ut an entry into the CreateAddress message catalog:</p><div
class="preformatted panel" style="border-width: 1px;"><div
class="preformattedContent panelContent">
+</div></div><p>Let's give it a try; restart the application and enter an "abc"
for the zip code.</p><p><img class="confluence-embedded-image
confluence-content-image-border"
src="https://cwiki.apache.org/confluence/download/attachments/23340431/address-v7.png?version=2&modificationDate=1417056608100&api=v2"
data-image-src="/confluence/download/attachments/23340431/address-v7.png?version=2&modificationDate=1417056608100&api=v2"><br
clear="none">This is what you'll see after typing "abc" and clicking the
Create Address button.</p><p>In any case, that's the right validation behavior,
but it's the wrong message. Your users are not going to know or care about
regular expressions.</p><p>Fortunately, it's easy to customize validation
messages. All we need to know is the name of the property ("zip") and the name
of the validator ("regexp"). We can then put an entry into the CreateAddress
message catalog:</p><div class="preformatted panel" style="border-width:
1px;"><div clas
s="preformattedContent panelContent">
<pre>zip-regexp-message=Zip Codes are five or nine digits. Example: 02134 or
90125-1655.
</pre>
-</div></div><p>Refresh the page and submit again:</p><p><img
class="confluence-embedded-image confluence-content-image-border" width="700"
src="https://cwiki.apache.org/confluence/download/attachments/23340431/address-v8.png?version=1&modificationDate=1286782418000&api=v2"
data-image-src="/confluence/download/attachments/23340431/address-v8.png?version=1&modificationDate=1286782418000&api=v2"></p><p>Regexp
validation with corrected message</p><p>This trick isn't limited to just the
regexp validator, it works equally well with <em>any</em>
validator.</p><p>Let's go one step further. Turns out, we can move the regexp
pattern to the message catalog as well. If you only provide the name of the
validator in the @Validate annotation, Tapestry will search the containing
page's message catalog of the constraint value, as well as the validation
message. The constraint value for the regexp validator is the regular
expression to match against.</p><div class="code panel pdl" sty
le="border-width: 1px;"><div class="codeContent panelContent pdl">
+</div></div><p>Refresh the page and submit again:</p><p><img
class="confluence-embedded-image confluence-content-image-border"
src="https://cwiki.apache.org/confluence/download/attachments/23340431/address-v8.png?version=2&modificationDate=1417056608461&api=v2"
data-image-src="/confluence/download/attachments/23340431/address-v8.png?version=2&modificationDate=1417056608461&api=v2"></p><p>This
trick isn't limited to just the regexp validator, it works equally well with
<em>any</em> validator.</p><p>Let's go one step further. Turns out, we can move
the regexp pattern to the message catalog as well. If you only provide the name
of the validator in the @Validate annotation, Tapestry will search the
containing page's message catalog of the constraint value, as well as the
validation message. The constraint value for the regexp validator is the
regular expression to match against.</p><div class="code panel pdl"
style="border-width: 1px;"><div class="codeContent panelConten
t pdl">
<script class="theme: Default; brush: java; gutter: false"
type="syntaxhighlighter"><![CDATA[ @Validate("required,regexp")
public String zip;
]]></script>