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.