<html><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; "><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; ">In the previous algorithm, parameter values were themselves interpolated which was undesirable and could lead to security issue.<div>I have reworked the algorithm to resolve the custom ResourceBundle in priority, the built-in bundle as a back up and finally regular parameters.</div><div><br></div><div>Check it out</div><div><br></div><div><span class="Apple-style-span" style="font-family: -webkit-sans-serif; font-size: 14px; "><div class="titlepage" style="font-family: sans-serif; font-size: 14px; "><div style="font-family: sans-serif; font-size: 14px; "><div style="font-family: sans-serif; font-size: 14px; "><h2 class="title" style="clear: both; font-family: sans-serif; color: rgb(0, 51, 153); font-size: 140%; margin-top: 10px; padding-top: 5px; font-weight: bold; ">4.3. Message interpolation</h2></div></div><div style="font-family: sans-serif; font-size: 14px; "></div></div><div class="section" lang="en" style="font-family: sans-serif; font-size: 14px; "><div class="titlepage" style="font-family: sans-serif; font-size: 14px; "><div style="font-family: sans-serif; font-size: 14px; "><div style="font-family: sans-serif; font-size: 14px; "><h3 class="title" style="font-family: sans-serif; color: rgb(0, 51, 153); font-size: 120%; margin-top: 10px; padding-top: 5px; font-weight: bold; "><a name="default-messageresolver" style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 204); "></a>4.3.1. Default message interpolation</h3></div></div><div style="font-family: sans-serif; font-size: 14px; "></div></div><p style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 0); ">A conforming implementation includes a default message interpolator. This message interpolator shall use the algorithm defined here to interpolate message descriptors into human-readable messages.</p><p style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 0); ">Each constraint defines a message descriptor via its <tt class="methodname" style="font-size: 100%; color: rgb(17, 17, 17); font-family: monospace; ">message</tt> property. Every constraint definition shall define a default message descriptor for that constraint. Messages can be overridden at declaration time in constraints by setting the <tt class="methodname" style="font-size: 100%; color: rgb(17, 17, 17); font-family: monospace; ">message</tt> property on the constraint.</p><p style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 0); ">The message descriptor is a string literal and may contain one or more message parameters. Message parameters are string literals enclosed in braces.</p><div class="example" style="font-family: sans-serif; font-size: 14px; "><a name="d0e2703" style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 204); "></a><p class="title" style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 0); margin-top: 10px; padding-top: 5px; font-weight: bold; "><b style="font-family: sans-serif; font-size: 14px; ">Example 4.1. Message using parameters</b></p><pre class="programlisting" style="font-size: 100%; padding-top: 5px; padding-right: 5px; padding-bottom: 5px; padding-left: 5px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-color: rgb(204, 204, 204); border-right-color: rgb(204, 204, 204); border-bottom-color: rgb(204, 204, 204); border-left-color: rgb(204, 204, 204); background-color: rgb(244, 244, 244); font-family: monospace; width: auto; ">Value must be between {min} and {max}</pre></div><div class="section" lang="en" style="font-family: sans-serif; font-size: 14px; "><div class="titlepage" style="font-family: sans-serif; font-size: 14px; "><div style="font-family: sans-serif; font-size: 14px; "><div style="font-family: sans-serif; font-size: 14px; "><h4 class="title" style="font-family: sans-serif; color: rgb(0, 51, 153); font-size: 100%; margin-top: 10px; padding-top: 5px; font-weight: bold; "><a name="default-resolution-algorithm" style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 204); "></a>4.3.1.1. Algorithm</h4></div></div><div style="font-family: sans-serif; font-size: 14px; "></div></div><p style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 0); ">The default message interpolator uses the following steps:</p><div class="orderedlist" style="font-family: sans-serif; font-size: 14px; "><ol type="1" style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 0); "><li style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 0); "><p style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 0); ">Message parameters are extracted from the message string and used as keys to search the <tt class="classname" style="font-size: 100%; color: rgb(17, 17, 17); font-family: monospace; ">ResourceBundle</tt> named <tt class="literal" style="font-size: 100%; color: rgb(17, 17, 17); font-family: monospace; ">ValidationMessages</tt> (often materialized as the property file<tt class="filename" style="font-size: 100%; color: rgb(17, 17, 17); font-family: monospace; ">/ValidationMessages.properties</tt> and its locale variations) using the defined locale (see below). If a property is found, the message parameter is replaced with the property value in the message string. Step 1 is applied recursively until no replacement is performed (ie. a message parameter value can itself contain a message parameter).</p></li><li style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 0); "><p style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 0); ">Message parameters are extracted from the message string and used as keys to search the Bean Validation provider's built-in <tt class="classname" style="font-size: 100%; color: rgb(17, 17, 17); font-family: monospace; ">ResourceBundle</tt> using the defined locale (see below). If a property is found, the message parameter is replaced with the property value in the message string. Contrary to step 1, step 2 is not processed recursively.</p></li><li style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 0); "><p style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 0); ">If step 2 triggers a replacement, then step 1 is applied again. Otherwise step 4 is performed.</p></li><li style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 0); "><p style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 0); ">Message parameters are extracted from the message string. Those matching the name of an attribute of the constraint declaration are replaced by the value of that attribute.</p></li></ol></div><p style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 0); ">The defined locale is as followed:</p><div class="itemizedlist" style="font-family: sans-serif; font-size: 14px; "><ul type="disc" style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 0); "><li style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 0); "><p style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 0); ">if the locale is passed to the interpolator method i<tt class="methodname" style="font-size: 100%; color: rgb(17, 17, 17); font-family: monospace; ">nterpolate(String, CosntraintDescriptor, Object, Locale)</tt>, this <tt class="classname" style="font-size: 100%; color: rgb(17, 17, 17); font-family: monospace; ">Locale</tt> instance is used.</p></li><li style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 0); "><p style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 0); ">otherwise, the default <tt class="classname" style="font-size: 100%; color: rgb(17, 17, 17); font-family: monospace; ">Locale</tt> as provided by <tt class="methodname" style="font-size: 100%; color: rgb(17, 17, 17); font-family: monospace; ">Locale.getDefault()</tt> is used.</p></li></ul></div><p style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 0); ">The proposed algorithm ensures that custom resource bundle always have priority over built-in resource bundle at all level of the recursive resolution. It also ensures that constraint declarations attributes values are not expanded further.</p></div></div><div class="section" lang="en" style="font-family: sans-serif; font-size: 14px; "><div class="titlepage" style="font-family: sans-serif; font-size: 14px; "><div style="font-family: sans-serif; font-size: 14px; "><div style="font-family: sans-serif; font-size: 14px; "><h3 class="title" style="font-family: sans-serif; color: rgb(0, 51, 153); font-size: 120%; margin-top: 10px; padding-top: 5px; font-weight: bold; "><a name="custom-message-resolution" style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 204); "></a>4.3.2. Custom message interpolation</h3></div></div><div style="font-family: sans-serif; font-size: 14px; "></div></div><p style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 0); ">A custom message interpolator may be provided (e.g., to interpolate contextual data, or to adjust the default <tt class="classname" style="font-size: 100%; color: rgb(17, 17, 17); font-family: monospace; ">Locale </tt>used). A message interpolator implements the <tt class="classname" style="font-size: 100%; color: rgb(17, 17, 17); font-family: monospace; ">MessageInterpolator</tt> interface.</p><pre class="programlisting" style="font-size: 100%; padding-top: 5px; padding-right: 5px; padding-bottom: 5px; padding-left: 5px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-color: rgb(204, 204, 204); border-right-color: rgb(204, 204, 204); border-bottom-color: rgb(204, 204, 204); border-left-color: rgb(204, 204, 204); background-color: rgb(244, 244, 244); font-family: monospace; width: auto; ">/**
* Interpolate a given constraint violation message.
*
* @author Emmanuel Bernard
* @author Hardy Ferentschik
*/
public interface MessageInterpolator {
        /**
         * Interpolate the message from the constraint parameters and the actual validated object.
         * The locale is defaulted according to the <code>MessageInterpolator</code> implementation
         * See the implementation documentation for more detail.
         *
         * @param message The message to interpolate.
         * @param constraintDescriptor The constraint descriptor.
         * @param value The object being validated
         *
         * @return Interpolated error message.
         */
        String interpolate(String message,
                                         ConstraintDescriptor constraintDescriptor,
                                         Object value);
        /**
         * Interpolate the message from the constraint parameters and the actual validated object.
         * The Locale used is provided as a parameter
         *
         * @param message The message to interpolate.
         * @param constraintDescriptor The constraint descriptor.
         * @param value The object being validated
         * @param locale the locale targeted for the message
         *
         * @return Interpolated error message.
         */
        String interpolate(String message,
                                         ConstraintDescriptor constraintDescriptor,
                                         Object value,
                                         Locale locale);
}</pre><p style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 0); "><i class="parameter" style="font-family: sans-serif; font-size: 14px; "><tt style="font-size: 100%; color: rgb(17, 17, 17); font-family: monospace; ">message</tt></i> is the message descriptor as seen in <tt class="literal" style="font-size: 100%; color: rgb(17, 17, 17); font-family: monospace; ">@ConstraintAnnotation.message</tt> or provided to the <tt class="classname" style="font-size: 100%; color: rgb(17, 17, 17); font-family: monospace; ">ConstraintContext</tt> methods.</p><p style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 0); "><i class="parameter" style="font-family: sans-serif; font-size: 14px; "><tt style="font-size: 100%; color: rgb(17, 17, 17); font-family: monospace; ">constraintDescriptor</tt></i> is the <tt class="classname" style="font-size: 100%; color: rgb(17, 17, 17); font-family: monospace; ">ConstraintDescriptor</tt> object representing the metadata of the failing constraint (see <a href="file:///Users/manu/projects/specs/303/specbook/build/en/html/constraintmetadata.html" style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 204); ">Constraint metadata request API</a>).</p><p style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 0); "><i class="parameter" style="font-family: sans-serif; font-size: 14px; "><tt style="font-size: 100%; color: rgb(17, 17, 17); font-family: monospace; ">value</tt></i> is the value being validated.</p><p style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 0); "><tt class="methodname" style="font-size: 100%; color: rgb(17, 17, 17); font-family: monospace; ">MessageInterpolator.interpolate(String, ConstraintDescriptor, Object)</tt> is invoked by for each constraint violation report generated. The default <tt class="classname" style="font-size: 100%; color: rgb(17, 17, 17); font-family: monospace; ">Locale</tt> is implementation specific.</p><p style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 0); "><tt class="methodname" style="font-size: 100%; color: rgb(17, 17, 17); font-family: monospace; ">MessageInterpolator.interpolate(String, ConstraintDescriptor, Object, Locale)</tt> can be invoked by a wrapping <tt class="classname" style="font-size: 100%; color: rgb(17, 17, 17); font-family: monospace; ">MessageInterpolator</tt> to enforce a specific <tt class="classname" style="font-size: 100%; color: rgb(17, 17, 17); font-family: monospace; ">Locale</tt> value by bypassing or overriding the default <tt class="classname" style="font-size: 100%; color: rgb(17, 17, 17); font-family: monospace; ">Locale</tt> strategy.</p><p style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 0); ">A message interpolator implementation shall be threadsafe.</p><p style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 0); ">The message interpolator is provided to the <tt class="classname" style="font-size: 100%; color: rgb(17, 17, 17); font-family: monospace; ">ValidatorFactory</tt> at construction time using <tt class="methodname" style="font-size: 100%; color: rgb(17, 17, 17); font-family: monospace; ">ValidatorFactoryBuilder.messageInterpolator(MessageInterpolator)</tt>. This message interpolator is shared by all validators generated by this <tt class="classname" style="font-size: 100%; color: rgb(17, 17, 17); font-family: monospace; ">ValidatorFactory</tt>.</p><p style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 0); ">It is possible to override the <tt class="classname" style="font-size: 100%; color: rgb(17, 17, 17); font-family: monospace; ">MessageInterpolator</tt> implementation for a given <tt class="classname" style="font-size: 100%; color: rgb(17, 17, 17); font-family: monospace; ">Validator</tt> instance by invoking<tt class="methodname" style="font-size: 100%; color: rgb(17, 17, 17); font-family: monospace; ">ValidatorFactory.defineValidatorState().messageInterpolator(messageInterpolator).getValidator()</tt>.</p><p style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 0); ">It is recommended that <tt class="classname" style="font-size: 100%; color: rgb(17, 17, 17); font-family: monospace; ">MessageInterpolator</tt> implementations delegate final interpolation to the Bean Validation default <tt class="classname" style="font-size: 100%; color: rgb(17, 17, 17); font-family: monospace; ">MessageInterpolator</tt> to ensure standard Bean Validation interpolation rules are followed, The default implementation is accessible through <tt class="methodname" style="font-size: 100%; color: rgb(17, 17, 17); font-family: monospace; ">ValidatorFactoryBuilder.getDefaultMessageInterpolator()</tt>.</p></div><div class="section" lang="en" style="font-family: sans-serif; font-size: 14px; "><div class="titlepage" style="font-family: sans-serif; font-size: 14px; "><div style="font-family: sans-serif; font-size: 14px; "><div style="font-family: sans-serif; font-size: 14px; "><h3 class="title" style="font-family: sans-serif; color: rgb(0, 51, 153); font-size: 120%; margin-top: 10px; padding-top: 5px; font-weight: bold; "><a name="validationapi-message-examples" style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 204); "></a>4.3.3. Examples</h3></div></div><div style="font-family: sans-serif; font-size: 14px; "></div></div><p style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 0); ">These examples describe message interpolation based on the default message interpolator's built-in messages (see <a href="file:///Users/manu/projects/specs/303/specbook/build/en/html/standard-resolver-messages.html" title="Appendix B. Standard ResourceBundle messages" style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 204); ">Appendix B, <i style="font-family: sans-serif; font-size: 14px; ">Standard ResourceBundle messages</i></a>), and the <tt class="filename" style="font-size: 100%; color: rgb(17, 17, 17); font-family: monospace; ">ValidationMessages.properties</tt>file shown in table <a href="file:///Users/manu/projects/specs/303/specbook/build/en/html/validationapi.html#table-messageinterpolation" title="Table 4.2. message interpolation" style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 204); ">Table 4.2, “message interpolation”</a>. The current locale is assumed English.</p><pre class="programlisting" style="font-size: 100%; padding-top: 5px; padding-right: 5px; padding-bottom: 5px; padding-left: 5px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-color: rgb(204, 204, 204); border-right-color: rgb(204, 204, 204); border-bottom-color: rgb(204, 204, 204); border-left-color: rgb(204, 204, 204); background-color: rgb(244, 244, 244); font-family: monospace; width: auto; ">//ValidationMessages.properties
myapp.creditcard.error=credit card number not valid</pre><div style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 0); "><br class="webkit-block-placeholder"></div><div class="table" style="font-family: sans-serif; font-size: 14px; "><a name="table-messageinterpolation" style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 204); "></a><p class="title" style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 0); margin-top: 10px; padding-top: 5px; font-weight: bold; "><b style="font-family: sans-serif; font-size: 14px; ">Table 4.2. message interpolation</b></p><table summary="message interpolation" border="1" style="font-family: sans-serif; font-size: 14px; border-collapse: collapse; -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical-spacing: 0px; empty-cells: hide; width: 100%; "><colgroup style="font-family: sans-serif; font-size: 14px; "><col align="center" style="font-family: sans-serif; font-size: 14px; "><col style="font-family: sans-serif; font-size: 14px; "></colgroup><tbody style="font-family: sans-serif; font-size: 14px; "><tr style="font-family: sans-serif; font-size: 14px; "><td align="center" style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 0); padding-top: 4pt; padding-right: 4pt; padding-bottom: 4pt; padding-left: 4pt; ">Failing constraint declaration</td><td style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 0); padding-top: 4pt; padding-right: 4pt; padding-bottom: 4pt; padding-left: 4pt; ">interpolated message</td></tr><tr style="font-family: sans-serif; font-size: 14px; "><td align="center" style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 0); padding-top: 4pt; padding-right: 4pt; padding-bottom: 4pt; padding-left: 4pt; ">@NotNull</td><td style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 0); padding-top: 4pt; padding-right: 4pt; padding-bottom: 4pt; padding-left: 4pt; ">must not be null</td></tr><tr style="font-family: sans-serif; font-size: 14px; "><td align="center" style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 0); padding-top: 4pt; padding-right: 4pt; padding-bottom: 4pt; padding-left: 4pt; ">@Max(30)</td><td style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 0); padding-top: 4pt; padding-right: 4pt; padding-bottom: 4pt; padding-left: 4pt; ">must be less than or equal to 30</td></tr><tr style="font-family: sans-serif; font-size: 14px; "><td align="center" style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 0); padding-top: 4pt; padding-right: 4pt; padding-bottom: 4pt; padding-left: 4pt; ">@Size(min=5, max=15, message="Key must have between {min} and {max} characters")</td><td style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 0); padding-top: 4pt; padding-right: 4pt; padding-bottom: 4pt; padding-left: 4pt; ">Key must have between 5 and 15 characters</td></tr><tr style="font-family: sans-serif; font-size: 14px; "><td align="center" style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 0); padding-top: 4pt; padding-right: 4pt; padding-bottom: 4pt; padding-left: 4pt; ">@Digits(integer=9, fraction=2)</td><td style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 0); padding-top: 4pt; padding-right: 4pt; padding-bottom: 4pt; padding-left: 4pt; ">numeric value out of bounds (<9 digits>.<2 digits> expected)</td></tr><tr style="font-family: sans-serif; font-size: 14px; "><td align="center" style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 0); padding-top: 4pt; padding-right: 4pt; padding-bottom: 4pt; padding-left: 4pt; ">@CreditCard(message={myapp.creditcard.error})</td><td style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 0); padding-top: 4pt; padding-right: 4pt; padding-bottom: 4pt; padding-left: 4pt; ">credit card number not valid</td></tr></tbody></table></div><p style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 0); ">Here is an approach to specify the <tt class="classname" style="font-size: 100%; color: rgb(17, 17, 17); font-family: monospace; ">Locale</tt> value to choose on a given <tt class="classname" style="font-size: 100%; color: rgb(17, 17, 17); font-family: monospace; ">Validator</tt>. <tt class="classname" style="font-size: 100%; color: rgb(17, 17, 17); font-family: monospace; ">Locale</tt> aware <tt class="classname" style="font-size: 100%; color: rgb(17, 17, 17); font-family: monospace; ">MessageInterpolator</tt>. See <a href="file:///Users/manu/projects/specs/303/specbook/build/en/html/validationapi.html#bootstrapping" title="4.4. Bootstrapping" style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 204); ">Section 4.4, “Bootstrapping”</a> for more details on the APIs.</p><div class="example" style="font-family: sans-serif; font-size: 14px; "><a name="validationapi-message-examples-specificlocale" style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 204); "></a><p class="title" style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 0); margin-top: 10px; padding-top: 5px; font-weight: bold; "><b style="font-family: sans-serif; font-size: 14px; ">Example 4.2. Use MessageInterpolator to use a specific Locale value</b></p><pre class="programlisting" style="font-size: 100%; padding-top: 5px; padding-right: 5px; padding-bottom: 5px; padding-left: 5px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-color: rgb(204, 204, 204); border-right-color: rgb(204, 204, 204); border-bottom-color: rgb(204, 204, 204); border-left-color: rgb(204, 204, 204); background-color: rgb(244, 244, 244); font-family: monospace; width: auto; position: static; z-index: auto; ">/**
* delegates to a MessageInterpolator implementation but enforce a given Locale
*/
public class LocaleSpecificMessageInterpolator implements MessageInterpolator {
private final MessageInterpolator defaultInterpolator;
private final Locale defaultLocale;
public LocaleSpecificMessageInterpolator(MessageInterpolator interpolator, Locale locale) {
this.defaultLocale = locale;
this.defaultInterpolator = interpolator;
}
/**
* enforece the locale passed to the interpolator
*/
public String interpolate(String message,
ConstraintDescriptor constraintDescriptor,
Object value) {
return defaultInterpolator.interpolate(message, constraintDescriptor,
value, this.defaultLocale);
}
// no real use, implemented for completeness
public String interpolate(String message,
ConstraintDescriptor constraintDescriptor,
Object value,
Locale locale) {
return defaultInterpolator.interpolate(message, constraintDescriptor, value, locale);
}
}
Locale locale = getMyCurrentLocale();
MessageInterpolator interpolator = new LocaleSpecificMessageInterpolator(
validatorFactory.getMessageInterpolator(),
locale);
Validator validator = validatorFactory.defineValidatorState()
.messageInterpolator(interpolator)
.getValidator();</pre></div><p style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 0); ">Most of the time, however, the relevant <tt class="classname" style="font-size: 100%; color: rgb(17, 17, 17); font-family: monospace; ">Locale</tt> will be provided by your application framework transparently. This framework will implement its own version of <tt class="classname" style="font-size: 100%; color: rgb(17, 17, 17); font-family: monospace; ">MessageInterpolator</tt> and pass it during the<tt class="classname" style="font-size: 100%; color: rgb(17, 17, 17); font-family: monospace; ">ValidatorFactory</tt> configuration. The application will not have to set the <tt class="classname" style="font-size: 100%; color: rgb(17, 17, 17); font-family: monospace; ">Locale</tt> itself. This example shows how a container framework would implement <tt class="classname" style="font-size: 100%; color: rgb(17, 17, 17); font-family: monospace; ">MessageInterpolator</tt> to provide a user specific default locale.</p><div class="example" style="font-family: sans-serif; font-size: 14px; "><a name="validationapi-message-examples-jsflocale" style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 204); "></a><p class="title" style="font-family: sans-serif; font-size: 14px; color: rgb(0, 0, 0); margin-top: 10px; padding-top: 5px; font-weight: bold; "><b style="font-family: sans-serif; font-size: 14px; ">Example 4.3. Contextual container possible MessageInterpolator implementation</b></p><pre class="programlisting" style="font-size: 100%; padding-top: 5px; padding-right: 5px; padding-bottom: 5px; padding-left: 5px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-color: rgb(204, 204, 204); border-right-color: rgb(204, 204, 204); border-bottom-color: rgb(204, 204, 204); border-left-color: rgb(204, 204, 204); background-color: rgb(244, 244, 244); font-family: monospace; width: auto; position: static; z-index: auto; ">public class ContextualMessageInterpolator {
private final MessageInterpolator delegate;
public ContextualMessageInterpolator(MessageInterpolator delegate) {
this.delegate = delegate;
}
public String interpolate(String message, ConstraintDescriptor constraintDescriptor,
Object value) {
Locale locale = Container.getManager().getUserLocale();
return this.delegate.interpolate(
message, constraintDescriptor, value, locale );
}
public String interpolate(String message, ConstraintDescriptor constraintDescriptor,
Object value, Locale locale) {
return this.delegate.interpolate(message, constraintDescriptor, value, locale);
}
}
//Build the ValidatorFactory
ValidatorFactoryBuilder builder = Validation.getBuilder();
ValidatorFactory factory = builder
.messageInterpolator( new ContextualMessageInterpolator( builder.getDefaultMessageInterpolator() ) )
.build();
//The container uses the factory to validate constraints using the specific MessageInterpolator
Validator validator = factory.getValidator();</pre></div></div></span></div></div></body></html>