code: @Override
      protected void validateValue(FacesContext context, Object value)
      {
          super.validateValue(context, value);
  
          if (!isValid() || value == null)
          {
              return;
          }
  
          // selected value must match to one of the available options
          // and if required is true it must not match an option with noSelectionOption set to true (since 2.0)
          Converter converter = getConverter();
  
          // Since the iterator is used twice, it has sense to traverse it only once.
          Collection<SelectItem> items = new ArrayList<SelectItem>();
          for (Iterator<SelectItem> iter = new _SelectItemsIterator(this, context); iter.hasNext();)
          {
              items.add(iter.next());
          }
          
          if (_SelectItemsUtil.matchValue(context, this, value, items.iterator(), converter))
          {
              if (! this.isRequired())
              {
                  return; // Matched & Required false, so return ok.
              }
              if (! _SelectItemsUtil.isNoSelectionOption(context, this, value, 
                      items.iterator(), converter))
              {
                  return; // Matched & Required true & No-selection did NOT match, so return ok.
              }
          }
          _MessageUtils.addErrorMessage(context, this, INVALID_MESSAGE_ID, 
                  new Object[] {_MessageUtils.getLabel(context, this) });
          setValid(false);
      }
docs: Verify that the result of converting the newly submitted value is <i>equal</i> to the value property of one of
  the child SelectItem objects. If this is not true, a validation error is reported.
  
  @see javax.faces.component.UIInput#validateValue(javax.faces.context.FacesContext,java.lang.Object)