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 javax.faces.component;
20  
21  import java.util.ArrayList;
22  import java.util.List;
23  import javax.el.ValueExpression;
24  import javax.faces.FacesException;
25  import javax.faces.application.FacesMessage;
26  import javax.faces.context.FacesContext;
27  import javax.faces.convert.Converter;
28  import javax.faces.convert.ConverterException;
29  import javax.faces.el.EvaluationException;
30  import javax.faces.el.MethodBinding;
31  import javax.faces.event.AbortProcessingException;
32  import javax.faces.event.FacesEvent;
33  import javax.faces.event.ValueChangeEvent;
34  import javax.faces.event.ValueChangeListener;
35  import javax.faces.render.Renderer;
36  import javax.faces.validator.Validator;
37  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFComponent;
38  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFListener;
39  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFProperty;
40  
41  /**
42   * UICommand is a base abstraction for components that implement ActionSource.
43   * <p>
44   * See the javadoc for this class in the <a
45   * href="http://java.sun.com/j2ee/javaserverfaces/1.2/docs/api/index.html">JSF
46   * Specification</a> for further details.
47   * <p>
48   */
49  @JSFComponent(defaultRendererType = "javax.faces.Text")
50  public class UIInput extends UIOutput implements EditableValueHolder
51  {
52      public static final String COMPONENT_TYPE = "javax.faces.Input";
53      public static final String COMPONENT_FAMILY = "javax.faces.Input";
54  
55      public static final String CONVERSION_MESSAGE_ID = "javax.faces.component.UIInput.CONVERSION";
56      public static final String REQUIRED_MESSAGE_ID = "javax.faces.component.UIInput.REQUIRED";
57      public static final String UPDATE_MESSAGE_ID = "javax.faces.component.UIInput.UPDATE";
58      private static final String ERROR_HANDLING_EXCEPTION_LIST = "org.apache.myfaces.errorHandling.exceptionList";
59  
60      private static final Validator[] EMPTY_VALIDATOR_ARRAY = new Validator[0];
61  
62      private boolean _immediate;
63      private boolean _immediateSet;
64  
65      private Object _submittedValue;
66      private boolean _localValueSet = false;
67  
68      private boolean _valid = true;
69  
70      private boolean _required;
71      private boolean _requiredSet;
72  
73      private String _converterMessage;
74      private String _requiredMessage;
75      private String _validatorMessage;
76  
77      private MethodBinding _validator;
78      private List<Validator> _validatorList;
79  
80      private MethodBinding _valueChangeListener;
81  
82      /**
83       * Construct an instance of the UIInput.
84       */
85      public UIInput()
86      {
87          setRendererType("javax.faces.Text");
88      }
89  
90      @Override
91      public String getFamily()
92      {
93          return COMPONENT_FAMILY;
94      }
95  
96      /**
97       * Store the specified object as the "local value" of this component. The
98       * value-binding named "value" (if any) is ignored; the object is only
99       * stored locally on this component. During the "update model" phase, if
100      * there is a value-binding named "value" then this local value will be
101      * stored via that value-binding and the "local value" reset to null.
102      */
103     public void setValue(Object value)
104     {
105         setLocalValueSet(true);
106         super.setValue(value);
107     }
108     
109     /**
110      * Return the current value of this component.
111      * <p>
112      * If a submitted value has been converted but not yet pushed into the
113      * model, then return that locally-cached value (see isLocalValueSet).
114      * <p>
115      * Otherwise, evaluate an EL expression to fetch a value from the model. 
116      */
117     public Object getValue()
118     {
119         if (isLocalValueSet()) return super.getLocalValue();
120         return super.getValue();
121     }
122 
123     /**
124      * Set the "submitted value" of this component from the relevant data in the
125      * current servlet request object.
126      * <p>
127      * If this component is not rendered, then do nothing; no output would have
128      * been sent to the client so no input is expected.
129      * <p>
130      * Invoke the inherited functionality, which typically invokes the renderer
131      * associated with this component to extract and set this component's
132      * "submitted value".
133      * <p>
134      * If this component is marked "immediate", then immediately apply
135      * validation to the submitted value found. On error, call context method
136      * "renderResponse" which will force processing to leap to the "render
137      * response" phase as soon as the "decode" step has completed for all other
138      * components.
139      */
140     public void processDecodes(FacesContext context)
141     {
142         if (context == null)
143         {
144             throw new NullPointerException("context");
145         }
146         try
147         {
148             setCachedFacesContext(context);
149             if (!isRendered())
150             {
151                 return;
152             }
153         }
154         finally
155         {
156             setCachedFacesContext(null);
157         }
158         super.processDecodes(context);
159         try
160         {
161             setCachedFacesContext(context);
162             if (isImmediate())
163             {
164                 try
165                 {
166                     validate(context);
167                 }
168                 catch (RuntimeException e)
169                 {
170                     context.renderResponse();
171                     throw e;
172                 }
173                 if (!isValid())
174                 {
175                     context.renderResponse();
176                 }
177             }
178         }
179         finally
180         {
181             setCachedFacesContext(null);
182         }
183     }
184 
185     public void processValidators(FacesContext context)
186     {
187         if (context == null)
188         {
189             throw new NullPointerException("context");
190         }
191         try
192         {
193             setCachedFacesContext(context);
194             if (!isRendered())
195             {
196                 return;
197             }
198         }
199         finally
200         {
201             setCachedFacesContext(null);
202         }
203 
204         super.processValidators(context);
205 
206         try
207         {
208             setCachedFacesContext(context);
209             if (!isImmediate())
210             {
211                 try
212                 {
213                     validate(context);
214                 }
215                 catch (RuntimeException e)
216                 {
217                     context.renderResponse();
218                     throw e;
219                 }
220                 if (!isValid())
221                 {
222                     context.renderResponse();
223                 }
224             }
225         }
226         finally
227         {
228             setCachedFacesContext(null);
229         }
230     }
231 
232     public void processUpdates(FacesContext context)
233     {
234         if (context == null)
235         {
236             throw new NullPointerException("context");
237         }
238         try
239         {
240             setCachedFacesContext(context);
241             if (!isRendered())
242             {
243                 return;
244             }
245         }
246         finally
247         {
248             setCachedFacesContext(null);
249         }
250 
251         super.processUpdates(context);
252 
253         try
254         {
255             setCachedFacesContext(context);
256             try
257             {
258                 updateModel(context);
259             }
260             catch (RuntimeException e)
261             {
262                 context.renderResponse();
263                 throw e;
264             }
265             if (!isValid())
266             {
267                 context.renderResponse();
268             }
269         }
270         finally
271         {
272             setCachedFacesContext(null);
273         }
274     }
275 
276     public void decode(FacesContext context)
277     {
278         // We (re)set to valid, so that component automatically gets (re)validated
279         setValid(true);
280         super.decode(context);
281     }
282 
283     public void broadcast(FacesEvent event) throws AbortProcessingException
284     {
285         // invoke standard listeners attached to this component first
286         super.broadcast(event);
287 
288         // Check if the event is applicable for ValueChangeListener
289         if (event instanceof ValueChangeEvent)
290         {
291             // invoke the single listener defined directly on the component
292             MethodBinding valueChangeListenerBinding = getValueChangeListener();
293             if (valueChangeListenerBinding != null)
294             {
295                 try
296                 {
297                     valueChangeListenerBinding.invoke(getFacesContext(),
298                             new Object[]
299                             { event });
300                 }
301                 catch (EvaluationException e)
302                 {
303                     Throwable cause = e.getCause();
304                     if (cause != null
305                             && cause instanceof AbortProcessingException)
306                     {
307                         throw (AbortProcessingException) cause;
308                     }
309                     else
310                     {
311                         throw e;
312                     }
313                 }
314             }
315         }
316     }
317 
318     public void updateModel(FacesContext context)
319     {
320         if (!isValid())
321         {
322             return;
323         }
324         if (!isLocalValueSet())
325         {
326             return;
327         }
328         ValueExpression expression = getValueExpression("value");
329         if (expression == null)
330         {
331             return;
332         }
333 
334         try
335         {
336             expression.setValue(context.getELContext(), getLocalValue());
337             setValue(null);
338             setLocalValueSet(false);
339         }
340         catch (Exception e)
341         {
342             context.getExternalContext().log(e.getMessage(), e);
343             _MessageUtils.addErrorMessage(context, this, UPDATE_MESSAGE_ID,
344                     new Object[]
345                     { _MessageUtils.getLabel(context, this) });
346             setValid(false);
347 
348             /*
349              * we are not allowed to throw exceptions here - we still need the
350              * full stack-trace later on to process it later in our
351              * error-handler
352              */
353             queueExceptionInRequest(context, expression, e);
354         }
355     }
356 
357     /**
358      * For development and production, we want to offer a single point to which
359      * error-handlers can attach. So we queue up all ocurring exceptions and
360      * later pass them to the configured error-handler.
361      */
362     private void queueExceptionInRequest(FacesContext context,
363             ValueExpression expression, Exception e)
364     {
365         List li = (List) context.getExternalContext().getRequestMap().get(ERROR_HANDLING_EXCEPTION_LIST);
366         if (null == li)
367         {
368             li = new ArrayList();
369             context.getExternalContext().getRequestMap().put(ERROR_HANDLING_EXCEPTION_LIST, li);
370         }
371         li.add(new FacesException(
372                 "Exception while setting value for expression : "
373                         + expression.getExpressionString()
374                         + " of component with path : "
375                         + _ComponentUtils.getPathToComponent(this), e));
376     }
377 
378     protected void validateValue(FacesContext context, Object convertedValue)
379     {
380         boolean empty = convertedValue == null
381                 || (convertedValue instanceof String && ((String) convertedValue)
382                         .length() == 0);
383 
384         if (isRequired() && empty)
385         {
386             if (getRequiredMessage() != null)
387             {
388                 String requiredMessage = getRequiredMessage();
389                 context.addMessage(this.getClientId(context), new FacesMessage(
390                         FacesMessage.SEVERITY_ERROR, requiredMessage,
391                         requiredMessage));
392             }
393             else
394             {
395                 _MessageUtils.addErrorMessage(context, this,
396                         REQUIRED_MESSAGE_ID, new Object[]
397                         { _MessageUtils.getLabel(context, this) });
398             }
399             setValid(false);
400             return;
401         }
402 
403         if (!empty)
404         {
405             _ComponentUtils.callValidators(context, this, convertedValue);
406         }
407 
408     }
409 
410     /**
411      * Determine whether the new value is valid, and queue a ValueChangeEvent if
412      * necessary.
413      * <p>
414      * The "submitted value" is converted to the necessary type; conversion
415      * failure is reported as an error and validation processing terminates for
416      * this component. See documentation for method getConvertedValue for
417      * details on the conversion process.
418      * <p>
419      * Any validators attached to this component are then run, passing the
420      * converted value.
421      * <p>
422      * The old value of this component is then fetched (possibly involving the
423      * evaluation of a value-binding expression, ie invoking a method on a user
424      * object). The old value is compared to the new validated value, and if
425      * they are different then a ValueChangeEvent is queued for later
426      * processing.
427      * <p>
428      * On successful completion of this method:
429      * <ul>
430      * <li> isValid() is true
431      * <li> isLocalValueSet() is true
432      * <li> submittedValue is reset to null
433      * <li> a ValueChangeEvent is queued if the new value != old value
434      * </ul>
435      */
436     public void validate(FacesContext context)
437     {
438         if (context == null)
439             throw new NullPointerException("context");
440 
441         try
442         {
443 
444             Object submittedValue = getSubmittedValue();
445             if (submittedValue == null)
446                 return;
447 
448             Object convertedValue = getConvertedValue(context, submittedValue);
449 
450             if (!isValid())
451                 return;
452 
453             validateValue(context, convertedValue);
454 
455             if (!isValid())
456                 return;
457 
458             Object previousValue = getValue();
459             setValue(convertedValue);
460             setSubmittedValue(null);
461             if (compareValues(previousValue, convertedValue))
462             {
463                 queueEvent(new ValueChangeEvent(this, previousValue,
464                         convertedValue));
465             }
466         }
467         catch (Exception ex)
468         {
469             throw new FacesException(
470                     "Exception while validating component with path : "
471                             + _ComponentUtils.getPathToComponent(this), ex);
472         }
473 
474     }
475 
476     /**
477      * Convert the provided object to the desired value.
478      * <p>
479      * If there is a renderer for this component, then call the renderer's
480      * getConvertedValue method. While this can of course be implemented in any
481      * way the renderer desires, it typically performs exactly the same
482      * processing that this method would have done anyway (ie that described
483      * below for the no-renderer case).
484      * <p>
485      * Otherwise:
486      * <ul>
487      * <li>If the submittedValue is not a String then just return the
488      * submittedValue unconverted.
489      * <li>If there is no "value" value-binding then just return the
490      * submittedValue unconverted.
491      * <li>Use introspection to determine the type of the target property
492      * specified by the value-binding, and then use Application.createConverter
493      * to find a converter that can map from String to the required type. Apply
494      * the converter to the submittedValue and return the result.
495      * </ul>
496      */
497     protected Object getConvertedValue(FacesContext context, Object submittedValue)
498     {
499         try
500         {
501             Renderer renderer = getRenderer(context);
502             if (renderer != null)
503             {
504                 return renderer
505                         .getConvertedValue(context, this, submittedValue);
506             }
507             else if (submittedValue instanceof String)
508             {
509                 Converter converter = _SharedRendererUtils
510                         .findUIOutputConverter(context, this);
511                 if (converter != null)
512                 {
513                     return converter.getAsObject(context, this,
514                             (String) submittedValue);
515                 }
516             }
517         }
518         catch (ConverterException e)
519         {
520             String converterMessage = getConverterMessage();
521             if (converterMessage != null)
522             {
523                 context.addMessage(getClientId(context), new FacesMessage(
524                         FacesMessage.SEVERITY_ERROR, converterMessage,
525                         converterMessage));
526             }
527             else
528             {
529                 FacesMessage facesMessage = e.getFacesMessage();
530                 if (facesMessage != null)
531                 {
532                     context.addMessage(getClientId(context), facesMessage);
533                 }
534                 else
535                 {
536                     _MessageUtils.addErrorMessage(context, this,
537                             CONVERSION_MESSAGE_ID, new Object[]
538                             { _MessageUtils.getLabel(context, this) });
539                 }
540             }
541             setValid(false);
542         }
543         return submittedValue;
544     }
545 
546     protected boolean compareValues(Object previous, Object value)
547     {
548         return previous == null ? (value != null) : (!previous.equals(value));
549     }
550 
551     /**
552      * @since 1.2
553      */
554     public void resetValue()
555     {
556         setSubmittedValue(null);
557         setValue(null);
558         setLocalValueSet(false);
559         setValid(true);
560     }
561 
562     /**
563      * A boolean value that identifies the phase during which action events should fire.
564      * <p>
565      * During normal event processing, action methods and action listener methods are fired during
566      * the "invoke application" phase of request processing. If this attribute is set to "true",
567      * these methods are fired instead at the end of the "apply request values" phase.
568      * </p>
569      */
570     @JSFProperty
571     public boolean isImmediate()
572     {
573         if (_immediateSet)
574         {
575             return _immediate;
576         }
577         ValueExpression expression = getValueExpression("immediate");
578         if (expression != null)
579         {
580             return (Boolean) expression.getValue(getFacesContext()
581                     .getELContext());
582         }
583         return false;
584     }
585 
586     public void setImmediate(boolean immediate)
587     {
588         this._immediate = immediate;
589         this._immediateSet = true;
590     }
591 
592     /**
593      * A boolean value that indicates whether an input value is required.
594      * <p>
595      * If this value is true and no input value is provided by a postback operation, then
596      * the "requiredMessage" text is registered as a FacesMessage for the request, and
597      * validation fails. 
598      * </p>
599      * <p>
600      * Default value: false.
601      * </p>
602      */
603     @JSFProperty(defaultValue = "false")
604     public boolean isRequired()
605     {
606         if (_requiredSet)
607         {
608             return _required;
609         }
610         ValueExpression expression = getValueExpression("required");
611         if (expression != null)
612         {
613             return (Boolean) expression.getValue(getFacesContext()
614                     .getELContext());
615         }
616         return false;
617     }
618 
619     public void setRequired(boolean required)
620     {
621         this._required = required;
622         this._requiredSet = true;
623     }
624 
625     /**
626      * Text to be displayed to the user as an error message when conversion of a
627      * submitted value to the target type fails.
628      * <p>
629      * </p>
630      */
631     @JSFProperty
632     public String getConverterMessage()
633     {
634         if (_converterMessage != null)
635         {
636             return _converterMessage;
637         }
638         ValueExpression expression = getValueExpression("converterMessage");
639         if (expression != null)
640         {
641             return (String) expression.getValue(getFacesContext()
642                     .getELContext());
643         }
644         return null;
645     }
646 
647     public void setConverterMessage(String converterMessage)
648     {
649         this._converterMessage = converterMessage;
650     }
651 
652     /**
653      * Text to be displayed to the user as an error message when this component is
654      * marked as "required" but no input data is present during a postback (ie the
655      * user left the required field blank).
656      */
657     @JSFProperty
658     public String getRequiredMessage()
659     {
660         if (_requiredMessage != null)
661         {
662             return _requiredMessage;
663         }
664         ValueExpression expression = getValueExpression("requiredMessage");
665         if (expression != null)
666         {
667             return (String) expression.getValue(getFacesContext()
668                     .getELContext());
669         }
670         return null;
671     }
672 
673     public void setRequiredMessage(String requiredMessage)
674     {
675         this._requiredMessage = requiredMessage;
676     }
677 
678     /**
679      * A method-binding EL expression which is invoked during the validation phase for this
680      * component.
681      * <p>
682      * The invoked method is expected to check the submitted value for this component, and if not
683      * acceptable then report a validation error for the component.
684      * </p>
685      * <p>
686      * The method is expected to have the prototype
687      * </p>
688      * <code>public void aMethod(FacesContext, UIComponent,Object)</code>
689      * 
690      * @deprecated
691      */
692     @JSFProperty(stateHolder = true, returnSignature = "void", methodSignature = "javax.faces.context.FacesContext,javax.faces.component.UIComponent,java.lang.Object")
693     public MethodBinding getValidator()
694     {
695         if (_validator != null)
696         {
697             return _validator;
698         }
699         ValueExpression expression = getValueExpression("validator");
700         if (expression != null)
701         {
702             return (MethodBinding) expression.getValue(getFacesContext()
703                     .getELContext());
704         }
705         return null;
706     }
707 
708     /** See getValidator.
709      *  
710      * @deprecated 
711      */
712     public void setValidator(MethodBinding validator)
713     {
714         this._validator = validator;
715     }
716 
717     /** See getValidator. */
718     public void addValidator(Validator validator)
719     {
720         if (validator == null)
721             throw new NullPointerException("validator");
722         if (_validatorList == null)
723             _validatorList = new ArrayList<Validator>();
724 
725         _validatorList.add(validator);
726     }
727 
728     /** See getValidator. */
729     public void removeValidator(Validator validator)
730     {
731         if (validator == null || _validatorList == null)
732             return;
733 
734         _validatorList.remove(validator);
735     }
736 
737     /** See getValidator. */
738     public Validator[] getValidators()
739     {
740         return _validatorList == null ? EMPTY_VALIDATOR_ARRAY : _validatorList
741                 .toArray(new Validator[_validatorList.size()]);
742     }
743 
744     /**
745      * Text which will be shown if validation fails.
746      */
747     @JSFProperty
748     public String getValidatorMessage()
749     {
750         if (_validatorMessage != null)
751         {
752             return _validatorMessage;
753         }
754         ValueExpression expression = getValueExpression("validatorMessage");
755         if (expression != null)
756         {
757             return (String) expression.getValue(getFacesContext()
758                     .getELContext());
759         }
760         return null;
761     }
762 
763     public void setValidatorMessage(String validatorMessage)
764     {
765         this._validatorMessage = validatorMessage;
766     }
767 
768     /**
769      * A method which is invoked during postback processing for the current
770      * view if the submitted value for this component is not equal to the value
771      * which the "value" expression for this component returns.
772      * <p>
773      * The phase in which this method is invoked can be controlled via the immediate
774      * attribute.
775      * </p>
776      * 
777      * @deprecated
778      */
779     @JSFProperty(stateHolder = true, returnSignature = "void", methodSignature = "javax.faces.event.ValueChangeEvent")
780     public MethodBinding getValueChangeListener()
781     {
782         if (_valueChangeListener != null)
783         {
784             return _valueChangeListener;
785         }
786         ValueExpression expression = getValueExpression("valueChangeListener");
787         if (expression != null)
788         {
789             return (MethodBinding) expression.getValue(getFacesContext()
790                     .getELContext());
791         }
792         return null;
793     }
794 
795     /**
796      * See getValueChangeListener.
797      * 
798      * @deprecated
799      */
800     public void setValueChangeListener(MethodBinding valueChangeListener)
801     {
802         this._valueChangeListener = valueChangeListener;
803     }
804 
805     /**
806      * Specifies whether the component's value is currently valid, ie whether the
807      * validators attached to this component have allowed it.
808      */
809     @JSFProperty(defaultValue = "true", tagExcluded = true)
810     public boolean isValid()
811     {
812         return _valid;
813     }
814 
815     public void setValid(boolean valid)
816     {
817         this._valid = valid;
818     }
819 
820     /**
821      * Specifies whether a local value is currently set.
822      * <p>
823      * If false, values are being retrieved from any attached ValueBinding.
824      */
825     @JSFProperty(defaultValue = "false", tagExcluded = true)
826     public boolean isLocalValueSet()
827     {
828         return _localValueSet;
829     }
830 
831     public void setLocalValueSet(boolean localValueSet)
832     {
833         this._localValueSet = localValueSet;
834     }
835 
836     /**
837      * Gets the current submitted value. This value, if non-null, is set by the
838      * Renderer to store a possibly invalid value for later conversion or
839      * redisplay, and has not yet been converted into the proper type for this
840      * component instance. This method should only be used by the decode() and
841      * validate() method of this component, or its corresponding Renderer;
842      * however, user code may manually set it to null to erase any submitted
843      * value.
844      */
845     @JSFProperty(tagExcluded = true)
846     public Object getSubmittedValue()
847     {
848         return _submittedValue;
849     }
850 
851     public void setSubmittedValue(Object submittedValue)
852     {
853         this._submittedValue = submittedValue;
854     }
855 
856     public void addValueChangeListener(ValueChangeListener listener)
857     {
858         addFacesListener(listener);
859     }
860 
861     public void removeValueChangeListener(ValueChangeListener listener)
862     {
863         removeFacesListener(listener);
864     }
865 
866     /**
867      * The valueChange event is delivered when the value attribute
868      * is changed.
869      */
870     @JSFListener(event="javax.faces.event.ValueChangeEvent")
871     public ValueChangeListener[] getValueChangeListeners()
872     {
873         return (ValueChangeListener[]) getFacesListeners(ValueChangeListener.class);
874     }
875 
876     @Override
877     public Object saveState(FacesContext facesContext)
878     {
879         Object[] values = new Object[14];
880         values[0] = super.saveState(facesContext);
881         values[1] = _immediate;
882         values[2] = _immediateSet;
883         values[3] = _required;
884         values[4] = _requiredSet;
885         values[5] = _converterMessage;
886         values[6] = _requiredMessage;
887         values[7] = saveAttachedState(facesContext, _validator);
888         values[8] = saveAttachedState(facesContext, _validatorList);
889         values[9] = _validatorMessage;
890         values[10] = saveAttachedState(facesContext, _valueChangeListener);
891         values[11] = _valid;
892         values[12] = _localValueSet;
893         values[13] = _submittedValue;
894 
895         return values;
896     }
897 
898     @Override
899     public void restoreState(FacesContext facesContext, Object state)
900     {
901         Object[] values = (Object[]) state;
902         super.restoreState(facesContext, values[0]);
903         _immediate = (Boolean) values[1];
904         _immediateSet = (Boolean) values[2];
905         _required = (Boolean) values[3];
906         _requiredSet = (Boolean) values[4];
907         _converterMessage = (String) values[5];
908         _requiredMessage = (String) values[6];
909         _validator = (MethodBinding) restoreAttachedState(facesContext,
910                 values[7]);
911         _validatorList = (List<Validator>) restoreAttachedState(facesContext,
912                 values[8]);
913         _validatorMessage = (String) values[9];
914         _valueChangeListener = (MethodBinding) restoreAttachedState(
915                 facesContext, values[10]);
916         _valid = (Boolean) values[11];
917         _localValueSet = (Boolean) values[12];
918         _submittedValue = values[13];
919     }
920 }