public JComponent buildWidget(
      String elementName, Map<String, String> attributes, SwingMetawidget metawidget) {

    // Not read-only?

    if (!WidgetBuilderUtils.isReadOnly(attributes)) {
      return null;
    }

    // Hidden

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

    // Action

    if (ACTION.equals(elementName)) {
      JButton button = new JButton(metawidget.getLabelString(attributes));
      button.setEnabled(false);

      return button;
    }

    // Masked (return a JPanel, so that we DO still render a label)

    if (TRUE.equals(attributes.get(MASKED))) {
      return new JPanel();
    }

    // Lookups

    String lookup = attributes.get(LOOKUP);

    if (lookup != null && !"".equals(lookup)) {
      // May have alternate labels

      String lookupLabels = attributes.get(LOOKUP_LABELS);

      if (lookupLabels != null && !"".equals(lookupLabels)) {
        return new LookupLabel(
            CollectionUtils.newHashMap(
                CollectionUtils.fromString(lookup), CollectionUtils.fromString(lookupLabels)));
      }

      return new JLabel();
    }

    // Lookup the Class

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

    if (clazz != null) {
      // Primitives

      if (clazz.isPrimitive()) {
        return new JLabel();
      }

      if (String.class.equals(clazz)) {
        if (TRUE.equals(attributes.get(LARGE))) {
          // Do not use a JLabel: JLabels do not support carriage returns like JTextAreas
          // do, so a multi-line JTextArea formats to a single line JLabel. Instead use
          // a non-editable JTextArea within a borderless JScrollPane

          JTextArea textarea = new JTextArea();

          // Since we know we are dealing with Strings, we consider
          // word-wrapping a sensible default

          textarea.setLineWrap(true);
          textarea.setWrapStyleWord(true);
          textarea.setEditable(false);

          // We also consider 2 rows a sensible default, so that the
          // read-only JTextArea is always distinguishable from a JLabel

          textarea.setRows(2);
          JScrollPane scrollPane = new JScrollPane(textarea);
          scrollPane.setBorder(null);

          return scrollPane;
        }

        return new JLabel();
      }

      if (Character.class.equals(clazz)) {
        return new JLabel();
      }

      if (Date.class.equals(clazz)) {
        return new JLabel();
      }

      if (Boolean.class.equals(clazz)) {
        return new JLabel();
      }

      if (Number.class.isAssignableFrom(clazz)) {
        return new JLabel();
      }

      // Collections

      if (Collection.class.isAssignableFrom(clazz)) {
        return new Stub();
      }
    }

    // Not simple, but don't expand

    if (TRUE.equals(attributes.get(DONT_EXPAND))) {
      return new JLabel();
    }

    // Nested Metawidget

    return null;
  }
  public Component processWidget(
      final Component component,
      String elementName,
      Map<String, String> attributes,
      VaadinMetawidget metawidget) {

    // Only bind to non-read-only Actions

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

    if (component instanceof Stub) {
      return component;
    }

    if (!(component instanceof Button)) {
      throw WidgetProcessorException.newException(
          "ReflectionBindingProcessor only supports binding actions to Buttons");
    }

    if (WidgetBuilderUtils.isReadOnly(attributes)) {
      return component;
    }

    if (metawidget == null) {
      return component;
    }

    Object toInspect = metawidget.getToInspect();

    if (toInspect == null) {
      return component;
    }

    Button button = (Button) component;

    // Traverse to the last Object...

    String[] names = PathUtils.parsePath(metawidget.getPath()).getNamesAsArray();

    for (String name : names) {
      toInspect = ClassUtils.getProperty(toInspect, name);

      if (toInspect == null) {
        return component;
      }
    }

    // ...and wire it up

    final Object fireActionOn = toInspect;
    final Class<?> fireActionOnClass = fireActionOn.getClass();
    final String actionName = attributes.get(NAME);

    button.addListener(
        new ClickListener() {

          public void buttonClick(ClickEvent event) {

            try {
              Method method = fireActionOnClass.getMethod(actionName, (Class[]) null);
              method.invoke(fireActionOn, (Object[]) null);
            } catch (Exception e) {
              throw WidgetProcessorException.newException(e);
            }
          }
        });

    return component;
  }
  public View buildWidget(
      String elementName, Map<String, String> attributes, AndroidMetawidget metawidget) {

    // Not read-only?

    if (!WidgetBuilderUtils.isReadOnly(attributes)) {
      return null;
    }

    // Hidden

    if (TRUE.equals(attributes.get(HIDDEN))) {
      return new Stub(metawidget.getContext());
    }

    // Action

    if (ACTION.equals(elementName)) {
      return new Stub(metawidget.getContext());
    }

    // Masked (return an invisible View, so that we DO still
    // render a label and reserve some blank space)

    if (TRUE.equals(attributes.get(MASKED))) {
      TextView view = new TextView(metawidget.getContext());
      view.setVisibility(View.INVISIBLE);

      return view;
    }

    // Lookups

    String lookup = attributes.get(LOOKUP);

    if (lookup != null && !"".equals(lookup)) {
      return new TextView(metawidget.getContext());
    }

    // Lookup the Class

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

    if (clazz != null) {
      if (clazz.isPrimitive()) {
        return new TextView(metawidget.getContext());
      }

      if (String.class.equals(clazz)) {
        return new TextView(metawidget.getContext());
      }

      if (Character.class.equals(clazz)) {
        return new TextView(metawidget.getContext());
      }

      if (Date.class.equals(clazz)) {
        return new TextView(metawidget.getContext());
      }

      if (Boolean.class.equals(clazz)) {
        return new TextView(metawidget.getContext());
      }

      if (Number.class.isAssignableFrom(clazz)) {
        return new TextView(metawidget.getContext());
      }

      // Collections

      if (Collection.class.isAssignableFrom(clazz)) {
        return new Stub(metawidget.getContext());
      }
    }

    // Not simple, but don't expand

    if (TRUE.equals(attributes.get(DONT_EXPAND))) {
      return new TextView(metawidget.getContext());
    }

    // Nested Metawidget

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