Differences between revisions 1 and 2
Revision 1 as of 2008-08-19 03:03:41
Size: 3023
Comment:
Revision 2 as of 2009-09-20 23:20:43
Size: 3023
Editor: localhost
Comment: converted to 1.6 markup
No differences found!

This page describes how to add a map binding prefix to Tapestry 5.

The map binding prefix allows you to specify a map like this:

${map:key1=value1,key2=value2} or <t:component t:parameter="map:key1=value1,key2=value2"/>

This will create a Map<String, Object> with key1 and key2 as keys and the values of the bindings value1 and value2 as values.

First create the MapBinding:

public class MapBinding extends AbstractBinding {

  private final Map<String, Binding> delegates;
  private final boolean invariant;

  public MapBinding(Map<String, Binding> delegates, boolean invariant) {
    this.delegates = delegates;
    this.invariant = invariant;
  }

  public Object get() {
    Map<String, Object> values = new HashMap<String, Object>(delegates.size());

    for (Map.Entry<String, Binding> entry : delegates.entrySet()) {
      values.put(entry.getKey(), entry.getValue().get());
    }

    return values;
  }

  public boolean isInvariant() {
    return invariant;
  }

  public Class<Map> getBindingType() {
    return Map.class;
  }
}

Then create the MapBindingFactory:

/**
 * Factory for map bindings. Map bindings parse comma-delimited lists of key=value pairs into {@link Map maps}. Keys are
 * always string literals while the values can be any binding expression, for which the default prefix is prop.
 */
public class MapBindingFactory implements BindingFactory {

  private final BindingSource bindingSource;

  public MapBindingFactory(BindingSource source) {
    this.bindingSource = source;
  }

  public Binding newBinding(String description, ComponentResources container, ComponentResources component,
                            String expression, Location location) {
    Map<String, Binding> delegates = new HashMap<String, Binding>();
    String[] entries = expression.split(",");
    boolean invariant = true;

    for (String entry : entries) {
      String[] parts = entry.split("=");

      if (parts.length != 2) throw new RuntimeException(String.format("Entry '%s' is malformed", entry));

      String name = parts[0];
      String value = parts[1];

      Binding binding = bindingSource.newBinding(description, container, component,
                                                 BindingConstants.PROP, value, location);
      invariant = invariant && binding.isInvariant();
      delegates.put(name, binding);
    }

    return new MapBinding(delegates, invariant);
  }
}

And then contribute it to the BindingSource configuration:

  public static void contributeBindingSource(MappedConfiguration<String, BindingFactory> configuration,
                                             BindingSource bindingSource) {
    configuration.add("map", new MapBindingFactory(bindingSource));
  }

Again, the keys are always string literals and the values themselves can be any binding expression, for which the default binding prefix is prop.

That's all there is to it.

Tapestry5HowToAddMapBindingPrefix (last edited 2009-09-20 23:20:43 by localhost)