public UIComponent buildWidget(
      String elementName, Map<String, String> attributes, UIMetawidget metawidget) {

    // Not for Tomahawk?

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

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

    Application application = FacesContext.getCurrentInstance().getApplication();
    String type = WidgetBuilderUtils.getActualClassOrType(attributes);

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

    Class<?> clazz = ClassUtils.niceForName(type);

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

    // HtmlInputFileUpload

    if (UploadedFile.class.isAssignableFrom(clazz)) {
      return application.createComponent("org.apache.myfaces.HtmlInputFileUpload");
    }

    // Not for Tomahawk

    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);
  }