About six months ago I did a tutorial series on passing a List or Set into a Value Picker. That covered the scenario where the label and value are the same. Somewhat belatedly, I’m concluding the series with the code for passing in a Map – the scenario where the label and the value need to be different. Some developers may already have implemented that based on my previous blog posts and the XSnippet for the ListPicker dataProvider for Value Picker, though I haven’t seen that blogged or published anywhere. So today I’ve posted a corresponding XSnippet for a MapPicker dataProvider for Value Picker.

There are not a huge number of differences, and if you have the understanding from my previous tutorials, it makes perfect sense. The first difference is the extended constructor. Instead of Lists and Sets, there is just the one generic class needed, Map. So there’s just one extended constructor:

private Map options_ = null;
MapPicker(Map<String, String> options) {
options_ = options;
}

This just passes the Map into the options variable, which this time is a Map. By using the generic youo can pass in a LinkedHashMap (retains the order in which the elements were added) or TreeMap (sorts the elements that were added) or any other kind of Map.

The readEntries method is not significantly different:

public IPickerResult readEntries(IPickerOptions options) {
String startKey = options.getStartKey();
String key = options.getKey();
int start = options.getStart();
int count = options.getCount();
int searchIndex = 0;
LinkedHashMap<String, String> opts = filteredOptions(key, startKey, start, searchIndex);
List<IPickerEntry> entries = new ArrayList<IPickerEntry>();
Iterator<String> it = opts.keySet().iterator();
while (it.hasNext()) {
String mapKey = it.next();
entries.add(new SimplePickerResult.Entry(opts.get(mapKey), mapKey));
}
return new SimplePickerResult(entries, -1);
}

The main differences are that filteredOptions returns a LinkedHashMap – we want to ensure the order of the entries isn’t changed. The entries object is still an ArrayList – the IPickerEntries are objects that contain the label-value pair, so there’s no change to their container. But then, instead of using a for loop, we need to use an Iterator. An Iterator, as its name suggests, is a specific Java object that has specific methods for iterating over objects. We iterate over the keys, because we can pass the key in and use that same key to get the corresponding object. Those keys are Strings, so we explicitly state that the Iterator will comprise elements of type String. While the Iterator has any more elements, we get the next element and add a new SimplePickerResult.Entry passing in the value as the first parameter and the label as the second parameter.

The filteredOptions method then returns a LinkedHashMap instead of an ArrayList – we’re filtering the Map that was added in.

private LinkedHashMap<String, String> filteredOptions(String key, String startKey, int start, int searchIndex) {
LinkedHashMap<String, String> retVal = new LinkedHashMap<String, String>();
if (StringUtil.isNotEmpty(key)) {
// We've got a typeahead key passed in, filter to entries beginning with that key
Iterator<String> it = options_.keySet().iterator();
while (it.hasNext()) {
String mapKey = it.next();
if (StringUtil.startsWithIgnoreCase(mapKey, key)) {
retVal.put(mapKey, options_.get(mapKey));
}
}
} else if (StringUtil.isNotEmpty(startKey)) {
// We've got a search key passed in, jump to that entry and add all remaining entries
Iterator<String> it = options_.keySet().iterator();
boolean found = false;
while (it.hasNext()) {
String mapKey = it.next();
if (found || StringUtil.startsWithIgnoreCase(mapKey, key)) {
retVal.put(mapKey, options_.get(mapKey));
found = true;
}
}
} else {
retVal.putAll(options_);
}
return retVal;
}

If a typeahead key was passed in, we again use an Iterator to loop through the keys and only retain the ones that match the typeahead key. If a search was used, we use an Iterator to loop through the keys and retain those starting from the search key.

Similarly the loadEntries method checks that the value stored matches something in the Map values, and loads back in the corresponding label-value pair from the Map.

public List<IPickerEntry> loadEntries(Object[] values, String[] attributes) {
List<IPickerEntry> entries = new ArrayList<IPickerEntry>();
if (null != values) {
for (int i = 0; i < values.length; i++) {
String checkStr = values[i].toString();
if (StringUtil.isNotEmpty(checkStr)) {
Iterator<String> it = options_.keySet().iterator();
while (it.hasNext()) {
String mapKey = it.next();
if (StringUtils.equals(checkStr, options_.get(mapKey))) {
entries.add(new SimplePickerResult.Entry(options_.get(mapKey), mapKey));
break;
}
}
}
}
}
}

The changes are not significant,  but the functionality certainly is – to avoid you creating a bean for every Map you want to allow users to select label-value pairs from.

Leave a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.