public HtmlInputNumberSpinner createInputNumberSpinner() {

      // RichFaces 4 uses uppercase 'I' for component, uppercase 'I' for renderer

      return FacesUtils.createComponent(
          HtmlInputNumberSpinner.COMPONENT_TYPE, "org.richfaces.InputNumberSpinnerRenderer");
    }
    public HtmlInputNumberSpinner createInputNumberSpinner() {

      // RichFaces 3 uses lowercase 'i' for component, uppercase 'I' for renderer

      return FacesUtils.createComponent(
          "org.richfaces.inputNumberSpinner", "org.richfaces.InputNumberSpinnerRenderer");
    }
    public UIComponent buildWidget(
        String elementName, Map<String, String> attributes, UIMetawidget metawidget) {

      FacesContext context = FacesContext.getCurrentInstance();
      Application application = context.getApplication();
      Class<?> clazz = WidgetBuilderUtils.getActualClassOrType(attributes, null);

      if (clazz == null) {
        return null;
      }

      // Autocomplete box

      if (String.class.equals(clazz)) {
        String facesSuggest = attributes.get(FACES_SUGGEST);

        if (facesSuggest != null) {
          UIAutocomplete autoComplete =
              FacesUtils.createComponent(
                  UIAutocomplete.COMPONENT_TYPE, "org.richfaces.AutocompleteRenderer");

          // new Class[] { ELContext.class, UIComponent.class, String.class } is what
          // AutocompleteRendererBase.getItems is looking for

          autoComplete.setAutocompleteMethod(
              application
                  .getExpressionFactory()
                  .createMethodExpression(
                      context.getELContext(),
                      facesSuggest,
                      Object.class,
                      new Class[] {ELContext.class, UIComponent.class, String.class}));

          // Some reasonable defaults

          autoComplete.setMinChars(2);
          autoComplete.setMode(AutocompleteMode.cachedAjax);

          return autoComplete;
        }
      }

      return null;
    }
  public UIComponent buildWidget(
      String elementName, Map<String, String> attributes, UIMetawidget metawidget) {

    // Not for RichFaces?

    if (TRUE.equals(attributes.get(HIDDEN))) {
      return null;
    }

    // Note: we tried implementing lookups using org.richfaces.ComboBox, but that
    // allows manual input and if you set enableManualInput=false it behaves a
    // bit screwy for our liking (ie. if you hit backspace the browser goes back)

    if (attributes.containsKey(FACES_LOOKUP) || attributes.containsKey(LOOKUP)) {
      return null;
    }

    // Lookup the class

    Class<?> clazz = WidgetBuilderUtils.getActualClassOrType(attributes, null);

    if (clazz == null) {
      return null;
    }

    // Primitives

    if (clazz.isPrimitive()) {
      // Not for RichFaces

      if (boolean.class.equals(clazz) || char.class.equals(clazz)) {
        return null;
      }

      // Ranged

      UIComponent ranged = createRanged(attributes);

      if (ranged != null) {
        return ranged;
      }

      // Not-ranged

      HtmlInputNumberSpinner spinner = VERSION_SPECIFIC_WIDGET_BUILDER.createInputNumberSpinner();

      // May be ranged in one dimension only. In which case, explictly range the *other*
      // dimension because RichFaces defaults to 0-100

      String minimumValue = attributes.get(MINIMUM_VALUE);

      if (minimumValue != null && !"".equals(minimumValue)) {
        spinner.setMinValue(minimumValue);
      } else if (byte.class.equals(clazz)) {
        spinner.setMinValue(String.valueOf(Byte.MIN_VALUE));
      } else if (short.class.equals(clazz)) {
        spinner.setMinValue(String.valueOf(Short.MIN_VALUE));
      } else if (int.class.equals(clazz)) {
        spinner.setMinValue(String.valueOf(Integer.MIN_VALUE));
      } else if (long.class.equals(clazz)) {
        spinner.setMinValue(String.valueOf(Long.MIN_VALUE));
      } else if (float.class.equals(clazz)) {
        spinner.setMinValue(String.valueOf(-Float.MAX_VALUE));
      } else if (double.class.equals(clazz)) {
        spinner.setMinValue(String.valueOf(-Double.MAX_VALUE));
      }

      String maximumValue = attributes.get(MAXIMUM_VALUE);

      if (maximumValue != null && !"".equals(maximumValue)) {
        spinner.setMaxValue(maximumValue);
      } else if (byte.class.equals(clazz)) {
        spinner.setMaxValue(String.valueOf(Byte.MAX_VALUE));
      } else if (short.class.equals(clazz)) {
        spinner.setMaxValue(String.valueOf(Short.MAX_VALUE));
      } else if (int.class.equals(clazz)) {
        spinner.setMaxValue(String.valueOf(Integer.MAX_VALUE));
      } else if (long.class.equals(clazz)) {
        spinner.setMaxValue(String.valueOf(Long.MAX_VALUE));
      } else if (float.class.equals(clazz)) {
        spinner.setMaxValue(String.valueOf(Float.MAX_VALUE));
      } else if (double.class.equals(clazz)) {
        spinner.setMaxValue(String.valueOf(Double.MAX_VALUE));
      }

      // Wraps around?

      spinner.setCycled(false);

      // Stepped

      if (float.class.equals(clazz) || double.class.equals(clazz)) {
        spinner.setStep("0.1");
      }

      return spinner;
    }

    // Dates
    //
    // Note: when http://jira.jboss.org/jira/browse/RF-2023 gets implemented, that
    // would allow external, app-level configuration of this Calendar

    if (Date.class.isAssignableFrom(clazz)) {
      UICalendar calendar =
          FacesUtils.createComponent(HtmlCalendar.COMPONENT_TYPE, "org.richfaces.CalendarRenderer");

      if (attributes.containsKey(DATETIME_PATTERN)) {
        calendar.setDatePattern(attributes.get(DATETIME_PATTERN));
      }

      if (attributes.containsKey(LOCALE)) {
        calendar.setLocale(new Locale(attributes.get(LOCALE)));
      }

      if (attributes.containsKey(TIME_ZONE)) {
        calendar.setTimeZone(TimeZone.getTimeZone(attributes.get(TIME_ZONE)));
      }

      return calendar;
    }

    // Object primitives

    if (Number.class.isAssignableFrom(clazz)) {
      // Ranged

      UIComponent ranged = createRanged(attributes);

      if (ranged != null) {
        return ranged;
      }

      // Not-ranged
      //
      // Until https://jira.jboss.org/jira/browse/RF-4450 is fixed, do not use
      // UIInputNumberSpinner for nullable numbers
    }

    // RichFaces version-specific

    return VERSION_SPECIFIC_WIDGET_BUILDER.buildWidget(elementName, attributes, metawidget);
  }
    public UIComponent buildWidget(
        String elementName, Map<String, String> attributes, UIMetawidget metawidget) {

      FacesContext context = FacesContext.getCurrentInstance();
      Application application = context.getApplication();
      Class<?> clazz = WidgetBuilderUtils.getActualClassOrType(attributes, null);

      if (clazz == null) {
        return null;
      }

      // Colors (as of RichFaces 3.3.1)

      if (Color.class.equals(clazz)) {
        if (WidgetBuilderUtils.isReadOnly(attributes)) {
          return FacesContext.getCurrentInstance()
              .getApplication()
              .createComponent(HtmlOutputText.COMPONENT_TYPE);
        }

        return application.createComponent("org.richfaces.ColorPicker");
      }

      // Suggestion box
      //
      // Note: for suggestion box to work in table column footer facets, you need
      // https://jira.jboss.org/jira/browse/RF-7700

      if (String.class.equals(clazz)) {
        String facesSuggest = attributes.get(FACES_SUGGEST);

        if (facesSuggest != null) {
          UIComponent stubComponent = application.createComponent(UIStub.COMPONENT_TYPE);
          List<UIComponent> children = stubComponent.getChildren();

          // Standard text box

          HtmlInputText inputText =
              (HtmlInputText) application.createComponent(HtmlInputText.COMPONENT_TYPE);
          inputText.setStyle(((HtmlMetawidget) metawidget).getStyle());
          inputText.setStyleClass(((HtmlMetawidget) metawidget).getStyleClass());
          children.add(inputText);

          UISuggestionBox suggestionBox =
              (UISuggestionBox) application.createComponent(HtmlSuggestionBox.COMPONENT_TYPE);

          // Lock the 'id's so they don't get changed. This is important for the
          // JavaScript getElementById that RichFaces generates. Also, do not just use
          // 'viewRoot.createUniqueId' because, as per the RenderKit specification:
          //
          // "If the value returned from component.getId() is non-null and does not start
          // with UIViewRoot.UNIQUE_ID_PREFIX, call component.getClientId() and render
          // the result as the value of the id attribute in the markup for the component."
          //
          // Therefore the 'id' attribute is never rendered, therefore the JavaScript
          // getElementById doesn't work. Add our own prefix instead

          inputText.setId("suggestionText_" + FacesUtils.createUniqueId());
          suggestionBox.setId("suggestionBox_" + FacesUtils.createUniqueId());

          // Suggestion box

          suggestionBox.setFor(inputText.getId());
          suggestionBox.setVar("_internal");
          children.add(suggestionBox);

          try {
            // RichFaces 3.2/JSF 1.2 mode
            //
            // Note: we wrap the MethodExpression as an Object[] to stop link-time
            // dependencies on javax.el.MethodExpression, so that we still work with
            // JSF 1.1
            //
            // Note: according to JavaDocs returnType is only important when literal
            // (i.e. without #{...}) expression is used, otherwise Object.class is fine
            // (http://community.jboss.org/message/516830#516830)

            Object[] methodExpression =
                new Object[] {
                  application
                      .getExpressionFactory()
                      .createMethodExpression(
                          context.getELContext(),
                          facesSuggest,
                          Object.class,
                          new Class[] {Object.class})
                };
            ClassUtils.setProperty(suggestionBox, "suggestionAction", methodExpression[0]);
          } catch (Exception e) {
            // RichFaces 3.1/JSF 1.1 mode

            MethodBinding methodBinding =
                application.createMethodBinding(facesSuggest, new Class[] {Object.class});
            suggestionBox.setSuggestionAction(methodBinding);
          }

          // Column
          //
          // Note: this must be javax.faces.component.html.HtmlColumn, not
          // org.richfaces.component.html.HtmlColumn. The latter displayed okay, but when
          // a value was selected it did not populate back to the HtmlInputText

          UIColumn column =
              (UIColumn)
                  application.createComponent(javax.faces.component.html.HtmlColumn.COMPONENT_TYPE);
          column.setId(FacesUtils.createUniqueId());
          suggestionBox.getChildren().add(column);

          // Output text box

          UIComponent columnText = application.createComponent(HtmlOutputText.COMPONENT_TYPE);
          columnText.setId(FacesUtils.createUniqueId());
          ValueBinding valueBinding = application.createValueBinding("#{_internal}");
          columnText.setValueBinding("value", valueBinding);
          column.getChildren().add(columnText);

          return stubComponent;
        }
      }

      return null;
    }
  @SuppressWarnings("deprecation")
  public UIComponent processWidget(
      UIComponent component,
      String elementName,
      Map<String, String> attributes,
      UIMetawidget metawidget) {

    // Actions don't get converters

    if (ACTION.equals(elementName)) {
      return component;
    }

    // Recurse into stubs...

    if (component instanceof UIStub) {
      // ...whose children have the same value binding as us...
      //
      // (this is important because choice of Converter is based off the attributes Map, and
      // if the value binding is different then all bets are off as to the accuracy of the
      // attributes)

      javax.faces.el.ValueBinding valueBinding = component.getValueBinding("value");

      if (valueBinding != null) {
        String expressionString = valueBinding.getExpressionString();

        List<UIComponent> children = component.getChildren();

        for (UIComponent componentChild : children) {
          javax.faces.el.ValueBinding childValueBinding = componentChild.getValueBinding("value");

          if (childValueBinding == null) {
            continue;
          }

          if (!expressionString.equals(childValueBinding.getExpressionString())) {
            continue;
          }

          // ...and apply the Converter to them

          processWidget(componentChild, elementName, attributes, metawidget);
        }
      }

      return component;
    }

    // Ignore components that cannot have Converters

    if (!(component instanceof ValueHolder)) {
      return component;
    }

    // Defer evaluation of EL-based converters, else we will fail trying to store/restore them
    // from the ViewState

    ValueHolder valueHolder = (ValueHolder) component;
    String converterId = attributes.get(FACES_CONVERTER);

    if (converterId != null && FacesUtils.isExpression(converterId)) {

      FacesContext context = FacesContext.getCurrentInstance();
      component.setValueBinding(
          "converter", context.getApplication().createValueBinding(converterId));
      return component;
    }

    // Standard Converter

    valueHolder.setConverter(getConverter(valueHolder, attributes));

    return component;
  }