View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.trinidad.validator;
20  
21  import javax.el.ValueExpression;
22  
23  import javax.faces.application.FacesMessage;
24  import javax.faces.component.UIComponent;
25  import javax.faces.context.FacesContext;
26  import javax.faces.el.ValueBinding;
27  
28  import javax.faces.validator.Validator;
29  import javax.faces.validator.ValidatorException;
30  
31  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFProperty;
32  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFValidator;
33  import org.apache.myfaces.trinidad.bean.FacesBean;
34  import org.apache.myfaces.trinidad.bean.PropertyKey;
35  import org.apache.myfaces.trinidad.util.ComponentUtils;
36  import org.apache.myfaces.trinidad.util.MessageFactory;
37  
38  /**
39   * <p>Implementation for length of <code>java.lang.String</code> values.</p>
40   *
41   */
42  @JSFValidator(configExcluded=true)
43  public class LengthValidator extends javax.faces.validator.LengthValidator
44  {
45    
46    public static final String VALIDATOR_ID = "org.apache.myfaces.trinidad.Length";
47  
48    /**
49     * <p>The message identifier of the {@link javax.faces.application.FacesMessage}
50     * to be created if the maximum length check fails.  The message format
51     * string for this message may optionally include <code>{0}</code>,
52     * <code>{1}</code> and <code>{3}</code> placeholders,
53     * which will be replaced by user input, component label and configured
54     * maximum length.</p>
55     */
56    public static final String MAXIMUM_MESSAGE_ID =
57        "org.apache.myfaces.trinidad.validator.LengthValidator.MAXIMUM";
58  
59    /**
60     * <p>The message identifier of the {@link javax.faces.application.FacesMessage}
61     * to be created if the minimum length check fails.  The message format
62     * string for this message may optionally include <code>{0}</code>,
63     * <code>{1}</code> and <code>{2}</code> placeholders, which will be replaced
64     * by user input, component label and configured minimum length.</p>
65     */
66    public static final String MINIMUM_MESSAGE_ID =
67        "org.apache.myfaces.trinidad.validator.LengthValidator.MINIMUM";
68  
69  
70    /**
71     * <p>The message identifier of the {@link javax.faces.application.FacesMessage}
72     * to be created if the maximum or minimum length check fails, and both
73     * the maximum and minimum lengths for this validator have been set.
74     * The message format string for this message may optionally include
75     * <code>{0}</code>, <code>{1}</code>, <code>{2}</code> and <code>{3}</code>
76     * placeholders, which will be replaced by user input, component label,
77     * configured minimum length and configured maximum length.</p>
78     */
79    public static final String NOT_IN_RANGE_MESSAGE_ID =
80        "org.apache.myfaces.trinidad.validator.LengthValidator.NOT_IN_RANGE";
81  
82    /**
83     * <p>The message identifier of the {@link javax.faces.application.FacesMessage}
84     * to be created if the maximum and minimum lengths are the same,
85     * and the length check fails, and both
86     * the maximum and minimum values for this validator have been set.
87     * The message format string for this message may optionally include
88     * <code>{0}</code>, <code>{1}</code>, <code>{2}</code>
89     * placeholders, which will be replaced by user input, component label,
90     * configured minimum/maximum length.</p>
91     */
92    public static final String EXACT_MESSAGE_ID =
93        "org.apache.myfaces.trinidad.validator.LengthValidator.EXACT";
94  
95    
96    /**
97     * Construct a {@link Validator} with no preconfigured limits.
98     */
99    public LengthValidator()
100   {
101     super();
102   }
103 
104   /**
105    * Construct a {@link Validator} with the specified preconfigured
106    * limit.
107    *
108    * @param maximum Maximum length to allow
109    */
110   public LengthValidator(int maximum)
111   {
112     super(maximum);
113   }
114 
115   /**
116    * Construct a {@link Validator} with the specified preconfigured
117    * limits.
118    *
119    * @param maximum Maximum length to allow
120    * @param minimum Minimum length to allow
121    *
122    */
123   public LengthValidator(int maximum, int minimum)
124   {
125     super(maximum, minimum);
126   }
127   
128   /**
129    * Return the maximum length to be enforced by this {@link
130    * Validator} or null if it has not been
131    * set.
132    */
133   @JSFProperty
134   @Override
135   public int getMaximum()
136   {
137     Object maxInt = _facesBean.getProperty(_MAXIMUM_KEY);
138     return ComponentUtils.resolveInteger(maxInt);
139   }
140 
141   /**
142    * Set the maximum length to be enforced by this {@link Validator}.
143    *
144    * @param maximum The new maximum length
145    *
146    */
147   @Override
148   public void setMaximum(int maximum)
149   {
150     _facesBean.setProperty(_MAXIMUM_KEY, Integer.valueOf(maximum));
151   }
152 
153 
154   /**
155    * Return the minimum length to be enforced by this {@link
156    * Validator}, or null if it has not been
157    * set.
158    */
159   @JSFProperty
160   @Override
161   public int getMinimum()
162   {
163     Object minInt = _facesBean.getProperty(_MINIMUM_KEY);
164     return ComponentUtils.resolveInteger(minInt);
165   }
166 
167   /**
168    * Set the minimum length to be enforced by this {@link Validator}.
169    *
170    * @param minimum The new minimum length
171    *
172    */
173   @Override
174   public void setMinimum(int minimum)
175   {
176     _facesBean.setProperty(_MINIMUM_KEY, Integer.valueOf(minimum));
177   }
178 
179   /**
180    * <p>Custom error message to be used, for creating detail part of the
181    * {@link FacesMessage}, when input length exceeds the maximum length set.</p>
182    * Overrides detail message identified by message id {@link #MAXIMUM_MESSAGE_ID}
183    * @param maximumMessageDetail Custom error message.
184    */
185   public void setMessageDetailMaximum(String maximumMessageDetail)
186   {
187     _facesBean.setProperty(_MAXIMUM_MESSAGE_DETAIL_KEY, maximumMessageDetail);
188   }
189 
190   /**
191    *  <p>Return custom detail error message that was set for creating {@link FacesMessage},
192    *  for cases where input length exceeds the <code>maximum</code> length set.</p>
193    * @return Custom error message.
194    * @see #setMessageDetailMaximum(String)
195    */
196   @JSFProperty
197   public String getMessageDetailMaximum()
198   {
199     Object maxMsgDet = _facesBean.getProperty(_MAXIMUM_MESSAGE_DETAIL_KEY);
200     return ComponentUtils.resolveString(maxMsgDet);
201   }
202 
203   /**
204    * <p>Custom error message to be used, for creating detail part of the
205    * {@link FacesMessage}, when input length is less the set
206    * <code>minimum</code> length.</p>
207    * Overrides detail message identified by message id {@link #MINIMUM_MESSAGE_ID}
208    * @param minimumMessageDetail Custom error message.
209    */
210   public void setMessageDetailMinimum(String minimumMessageDetail)
211   {
212     _facesBean.setProperty(_MINIMUM_MESSAGE_DETAIL_KEY, minimumMessageDetail);
213   }
214 
215   /**
216    * <p>Return custom detail error message that was set for creating {@link FacesMessage},
217    * for cases where, input length is less than the <code>minimum</code> length set.</p>
218    * @return Custom error message.
219    * @see #setMessageDetailMinimum(String)
220    */
221   @JSFProperty
222   public String getMessageDetailMinimum()
223   {
224     Object minMsgDet = _facesBean.getProperty(_MINIMUM_MESSAGE_DETAIL_KEY);
225     return ComponentUtils.resolveString(minMsgDet);
226   }
227 
228   /**
229    * <p>Custom error message to be used, for creating detail part of the
230    * {@link FacesMessage}, when input length is not with in the range,
231    * when <code>minimum</code> and <code>maximum</code> is set.</p>
232    * Overrides detail message identified by message id {@link #NOT_IN_RANGE_MESSAGE_ID}
233    * @param notInRangeMessageDetail Custom error message.
234    */
235   public void setMessageDetailNotInRange(String notInRangeMessageDetail)
236   {
237     _facesBean.setProperty(_NOT_IN_RANGE_MESSAGE_DETAIL_KEY, notInRangeMessageDetail);
238   }
239 
240   /**
241    * <p>Return custom detail error message that was set for creating {@link FacesMessage},
242    * for cases where, input length exceeds the <code>maximum</code> length and is
243    * less than the <code>minimum</code> length set.</p>
244    * @return Custom error message.
245    * @see #setMessageDetailNotInRange(String)
246    */
247   @JSFProperty
248   public String getMessageDetailNotInRange()
249   {
250     Object notInRngMsg = _facesBean.getProperty(_NOT_IN_RANGE_MESSAGE_DETAIL_KEY);
251     return ComponentUtils.resolveString(notInRngMsg);
252   }
253 
254 
255   /**
256    * <p>Custom error message to be used, for creating detail part of the
257    * {@link FacesMessage}, 
258    * for cases where the maximum and minimum lengths are the same, and
259    * the input length does not match.
260    * Overrides detail message identified by message id {@link #EXACT_MESSAGE_ID}
261    * @param exactMessageDetail Custom error message.
262    */
263   public void setMessageDetailExact(String exactMessageDetail)
264   {
265     _facesBean.setProperty(_EXACT_MESSAGE_DETAIL_KEY, exactMessageDetail);
266   }
267 
268   /**
269    * <p>Return custom detail error message that was set for creating {@link FacesMessage},
270    * for cases where the maximum and minimum lengths are the same, and
271    * the input length does not match.</p>
272    * @return Custom error message.
273    * @see #setMessageDetailExact(String)
274    */
275   @JSFProperty
276   public String getMessageDetailExact()
277   {
278     Object msg = _facesBean.getProperty(_EXACT_MESSAGE_DETAIL_KEY);
279     return ComponentUtils.resolveString(msg);
280   }
281 
282   
283   /**
284    * <p>Custom hint maximum message.</p>
285    * Overrides default hint message
286    * @param hintMaximum Custom hint message.
287    */
288   public void setHintMaximum(String hintMaximum)
289   {
290     _facesBean.setProperty(_HINT_MAXIMUM_KEY, hintMaximum);
291   }
292 
293   /**
294    * <p>Return custom hint maximum message.</p>
295    * @return Custom hint message.
296    * @see  #setHintMaximum(String)
297    */
298   @JSFProperty(tagExcluded=true)
299   public String getHintMaximum()
300   {
301     Object obj = _facesBean.getProperty(_HINT_MAXIMUM_KEY);
302     return ComponentUtils.resolveString(obj);
303   }
304 
305   /**
306    * <p>Custom hint minimum message.</p>
307    * Overrides default hint message
308    * @param hintMinimum Custom hint message.
309    */
310   public void setHintMinimum(String hintMinimum)
311   {
312     _facesBean.setProperty(_HINT_MINIMUM_KEY, hintMinimum);
313   }
314 
315   /**
316    * <p>Return custom hint minimum message.</p>
317    * @return Custom hint message.
318    * @see  #setHintMinimum(String)
319    */
320   @JSFProperty(tagExcluded=true)
321   public String getHintMinimum()
322   {
323     Object obj = _facesBean.getProperty(_HINT_MINIMUM_KEY);
324     return ComponentUtils.resolveString(obj);
325   }
326 
327   /**
328    * <p>Custom hint notInRange message.</p>
329    * Overrides default hint message
330    * @param hintNotInRange Custom hint message.
331    */
332   public void setHintNotInRange(String hintNotInRange)
333   {
334     _facesBean.setProperty(_HINT_NOT_IN_RANGE, hintNotInRange);
335   }
336 
337   /**
338    * <p>Return custom hint notInRange message.</p>
339    * @return Custom hint message.
340    * @see  #setHintNotInRange
341    */
342   @JSFProperty(tagExcluded=true)
343   public String getHintNotInRange()
344   {
345     Object obj = _facesBean.getProperty(_HINT_NOT_IN_RANGE);
346     return ComponentUtils.resolveString(obj);
347   }
348 
349 
350   /**
351    * <p>Custom hint exact message.</p>
352    * Overrides default hint message
353    * @param hintExact Custom hint message.
354    */
355   public void setHintExact(String hintExact)
356   {
357     _facesBean.setProperty(_HINT_EXACT, hintExact);
358   }
359 
360   /**
361    * <p>Return custom hint exact message.</p>
362    * @return Custom hint message.
363    * @see  #setHintExact
364    */
365   @JSFProperty(tagExcluded=true)
366   public String getHintExact()
367   {
368     Object obj = _facesBean.getProperty(_HINT_EXACT);
369     return ComponentUtils.resolveString(obj);
370   }
371   
372   @Override
373   public void validate(
374     FacesContext context,
375     UIComponent component,
376     Object value
377     ) throws ValidatorException
378   {   
379     if (isDisabled())
380       return;
381     
382     if ((context == null) || (component == null))
383     {
384       throw new NullPointerException();
385     }
386 
387     if(value != null)
388     {
389       String theValue  = (value instanceof String)? (String)value : value.toString();
390       int max = getMaximum();
391       int min = getMinimum();
392 
393       // Skip validating empty field values, even if a minimum length is specified. 
394       // Forcing minimum length validation on empty fields will break the use-case where the 
395       // app would like a field to remain optional, but in case some value is entered, it should
396       // adhere to some min/max length rules. For ex: A "pin code" field that is optional.
397       if (theValue.isEmpty())
398         return;
399 
400       int length = theValue.length();
401 
402       // range validation
403       if(isMaximumSet() && isMinimumSet())
404       {
405         if(length<min || length>max)
406         {
407           throw new ValidatorException(
408             _getNotInRangeMessage(context, component, value, min, max));
409         }
410       }
411       // too short
412       if(isMinimumSet())
413       {
414         if (length < min)
415         {
416           throw new ValidatorException(
417             _getMinimumMessage(context, component, value, min));
418         }
419       }
420       // too long
421       if(isMaximumSet())
422       {
423         if (length > max)
424         {
425           throw new ValidatorException(
426             _getMaximumMessage(context, component, value, max));
427         }
428       }
429     }
430   }
431 
432   //  StateHolder Methods
433   @Override
434   public Object saveState(FacesContext context)
435   {
436     return _facesBean.saveState(context);
437   }
438 
439 
440   @Override
441   public void restoreState(FacesContext context, Object state)
442   {
443     _facesBean.restoreState(context, state);
444   }
445 
446   /**
447    * <p>Set the {@link ValueExpression} used to calculate the value for the
448    * specified attribute if any.</p>
449    *
450    * @param name Name of the attribute for which to set a {@link ValueExpression}
451    * @param expression The {@link ValueExpression} to set, or <code>null</code>
452    *  to remove any currently set {@link ValueExpression}
453    *
454    * @exception NullPointerException if <code>name</code>
455    *  is <code>null</code>
456    * @exception IllegalArgumentException if <code>name</code> is not a valid
457    *            attribute of this converter
458    */
459   public void setValueExpression(String name, ValueExpression expression)
460   {
461     ValidatorUtils.setValueExpression(_facesBean, name, expression) ;
462   }
463 
464 
465   /**
466    * <p>Return the {@link ValueExpression} used to calculate the value for the
467    * specified attribute name, if any.</p>
468    *
469    * @param name Name of the attribute or property for which to retrieve a
470    *  {@link ValueExpression}
471    *
472    * @exception NullPointerException if <code>name</code>
473    *  is <code>null</code>
474    * @exception IllegalArgumentException if <code>name</code> is not a valid
475    * attribute of this converter
476    */
477   public ValueExpression getValueExpression(String name)
478   {
479     return ValidatorUtils.getValueExpression(_facesBean, name);
480   }
481 
482 
483   /**
484    * <p>Set the {@link ValueBinding} used to calculate the value for the
485    * specified attribute if any.</p>
486    *
487    * @param name Name of the attribute for which to set a {@link ValueBinding}
488    * @param binding The {@link ValueBinding} to set, or <code>null</code>
489    *  to remove any currently set {@link ValueBinding}
490    *
491    * @exception NullPointerException if <code>name</code>
492    *  is <code>null</code>
493    * @exception IllegalArgumentException if <code>name</code> is not a valid
494    *            attribute of this validator
495    * @deprecated
496    */
497   public void setValueBinding(String name, ValueBinding binding)
498   {
499     ValidatorUtils.setValueBinding(_facesBean, name, binding) ;
500   }
501 
502   /**
503    * <p>Return the {@link ValueBinding} used to calculate the value for the
504    * specified attribute name, if any.</p>
505    *
506    * @param name Name of the attribute or property for which to retrieve a
507    *  {@link ValueBinding}
508    *
509    * @exception NullPointerException if <code>name</code>
510    *  is <code>null</code>
511    * @exception IllegalArgumentException if <code>name</code> is not a valid
512    * attribute of this validator
513    * @deprecated
514    */
515   public ValueBinding getValueBinding(String name)
516   {
517     return ValidatorUtils.getValueBinding(_facesBean, name);
518   }
519   
520   @JSFProperty(istransient=true, tagExcluded=true)
521   @Override
522   public boolean isTransient()
523   {
524     return (_transientValue);
525   }
526 
527 
528   @Override
529   public void setTransient(boolean transientValue)
530   {
531     _transientValue = transientValue;
532   }
533 
534   @Override
535   public boolean equals(Object otherObj) 
536   {
537     if (!(otherObj instanceof LengthValidator)) 
538     {
539       return false;
540     }
541     
542     LengthValidator other = (LengthValidator) otherObj;
543     
544     return ((this.getMaximum() == other.getMaximum())
545             && (this.getMinimum() == other.getMinimum())
546             && (this.isMinimumSet() == other.isMinimumSet())
547             && (this.isMaximumSet() == other.isMaximumSet())
548             && (this.isDisabled() == other.isDisabled())
549             && (this.isTransient() == other.isTransient()));
550   }
551 
552   @Override
553   public int hashCode() 
554   {
555     int result = 17;
556     Object msgDetExact      =  getMessageDetailExact();
557     Object maxMsgDet        =  getMessageDetailMaximum();
558     Object minMsgDet        =  getMessageDetailMinimum();
559     Object notInRangeMsgDet =  getMessageDetailNotInRange();
560     
561     result = 37 * result + (isDisabled() ? 1 : 0);    
562     result = 37 * result + (isTransient() ? 0 : 1);
563     result = 37 * result + (isMaximumSet() ? 0 : 1);
564     result = 37 * result + (isMinimumSet() ? 0 : 1);
565     result = 37 * result + Integer.valueOf(getMinimum()).hashCode();
566     result = 37 * result + Integer.valueOf(getMaximum()).hashCode();
567     result = 37 * result + ( msgDetExact == null ? 0 : msgDetExact.hashCode());
568     result = 37 * result + ( maxMsgDet == null ? 0 : maxMsgDet.hashCode());
569     result = 37 * result + ( minMsgDet == null ? 0 : minMsgDet.hashCode());
570     result = 37 * result + ( notInRangeMsgDet == null ? 0 : notInRangeMsgDet.hashCode());
571     
572     return result;
573   }
574 
575   /**
576     * Return whether it is disabled.
577     * @return true if it's disabled and false if it's enabled. 
578     */ 
579   public void setDisabled(boolean isDisabled)
580   {
581     _facesBean.setProperty(_DISABLED_KEY, Boolean.valueOf(isDisabled));
582   }
583 
584   /**
585     * Return whether it is disabled.
586     * @return true if it's disabled and false if it's enabled. 
587     */  
588   public boolean isDisabled()
589   {
590     Boolean disabled = (Boolean) _facesBean.getProperty(_DISABLED_KEY);
591     
592     return (disabled != null) ? disabled.booleanValue() : false;
593   }  
594 
595   protected boolean isMaximumSet()
596   {
597     return _facesBean.getProperty(_MAXIMUM_KEY) != null;
598   }
599 
600   protected boolean isMinimumSet()
601   {
602     return _facesBean.getProperty(_MINIMUM_KEY) != null;
603   }
604 
605   private FacesMessage _getNotInRangeMessage(
606       FacesContext context,
607       UIComponent component,
608       Object value,
609       Object min,
610       Object max)
611   {
612     if (min.equals(max))
613       return _getExactMessage(context, component, value, min);
614 
615     Object msg   = _getRawNotInRangeMessageDetail();
616     Object label = ValidatorUtils.getComponentLabel(component);
617     
618     Object[] params = {label, value, min, max};
619     
620     return MessageFactory.getMessage(context, NOT_IN_RANGE_MESSAGE_ID,
621                                      msg, params, component);
622   }
623 
624   
625   private Object _getRawNotInRangeMessageDetail()
626   {
627     return _facesBean.getRawProperty(_NOT_IN_RANGE_MESSAGE_DETAIL_KEY);
628   }
629 
630 
631   private FacesMessage _getExactMessage(
632       FacesContext context,
633       UIComponent component,
634       Object value,
635       Object minMax)
636   {
637     Object msg   = _getRawExactMessageDetail();
638     Object label = ValidatorUtils.getComponentLabel(component);
639     
640     Object[] params = {label, value, minMax};
641     
642     return MessageFactory.getMessage(context, EXACT_MESSAGE_ID,
643                                      msg, params, component);
644   }
645   
646 
647   private Object _getRawExactMessageDetail()
648   {
649     return _facesBean.getRawProperty(_EXACT_MESSAGE_DETAIL_KEY);
650   }
651   
652   
653   private FacesMessage _getMaximumMessage(
654     FacesContext context,
655     UIComponent component,
656     Object value,
657     Object max)
658   {
659     
660     Object msg   = _getRawMaximumMessageDetail();
661     Object label = ValidatorUtils.getComponentLabel(component);
662     
663     Object[] params = {label, value, max};
664     
665     return MessageFactory.getMessage(context,
666                                      MAXIMUM_MESSAGE_ID,
667                                      msg,
668                                      params,
669                                      component);
670   }
671   
672   private Object _getRawMaximumMessageDetail()
673   {
674     return _facesBean.getRawProperty(_MAXIMUM_MESSAGE_DETAIL_KEY);
675   }
676   
677   private FacesMessage _getMinimumMessage(
678     FacesContext context,
679     UIComponent component,
680     Object value,
681     Object min)
682   {
683     Object msg      = _getRawMinimumMessageDetail();
684     Object label    = ValidatorUtils.getComponentLabel(component);
685     
686     Object[] params = {label, value, min};
687     
688     return MessageFactory.getMessage(context, MINIMUM_MESSAGE_ID,
689                                      msg, params, component);
690   }
691   
692   private Object _getRawMinimumMessageDetail()
693   {
694     return _facesBean.getRawProperty(_MINIMUM_MESSAGE_DETAIL_KEY);
695   }
696   
697   private static final FacesBean.Type _TYPE = new FacesBean.Type();
698  
699   // Default is false
700   private static final PropertyKey _DISABLED_KEY =
701     _TYPE.registerKey("disabled",
702                       Boolean.class,
703                       Boolean.FALSE);
704   
705   // Default is zero, not MIN_VALUE
706   private static final PropertyKey _MINIMUM_KEY =
707     _TYPE.registerKey("minimum",
708                       Integer.class,
709                       // Don't rely on autoboxing: there's a method overload
710                       Integer.valueOf(0));
711 
712   // FIXME: the default of the superclass is 0, not MAX_VALUE
713   private static final PropertyKey _MAXIMUM_KEY =
714     _TYPE.registerKey("maximum", Integer.class,
715                       // Don't rely on autoboxing: there's a method overload
716                       Integer.valueOf(0));
717 
718   private static final PropertyKey _MAXIMUM_MESSAGE_DETAIL_KEY =
719     _TYPE.registerKey("messageDetailMaximum", String.class);
720 
721   private static final PropertyKey _MINIMUM_MESSAGE_DETAIL_KEY =
722     _TYPE.registerKey("messageDetailMinimum", String.class);
723 
724   private static final PropertyKey _NOT_IN_RANGE_MESSAGE_DETAIL_KEY =
725     _TYPE.registerKey("messageDetailNotInRange", String.class);
726 
727   private static final PropertyKey _EXACT_MESSAGE_DETAIL_KEY =
728     _TYPE.registerKey("messageDetailExact", String.class);
729 
730   private static final PropertyKey  _HINT_MAXIMUM_KEY =
731     _TYPE.registerKey("hintMaximum", String.class);
732 
733   private static final PropertyKey  _HINT_MINIMUM_KEY =
734     _TYPE.registerKey("hintMinimum", String.class);
735 
736   private static final PropertyKey  _HINT_NOT_IN_RANGE =
737     _TYPE.registerKey("hintNotInRange", String.class);
738 
739   private static final PropertyKey  _HINT_EXACT =
740     _TYPE.registerKey("hintExact", String.class);
741 
742   private FacesBean _facesBean = ValidatorUtils.getFacesBean(_TYPE);
743 
744   private boolean _transientValue = false;
745 }