package org.kohsuke.args4j.spi;
import java.util.HashMap;
import java.util.Map;
import org.kohsuke.args4j.*;
/**
* Parses options into a {@link Map}.
*
* <pre>
* class Foo {
* @Option(name="-P",handler={@link MapOptionHandler}.class)
* Map<String,String> args;
* }
* </pre>
*
* <p>
* With this, <tt>-P x=1 -P y=2</tt> parses to map of size 2.
* This option handler can be subtyped if you want to convert values to different types
* or to handle key=value in other formats, like "key:=value".
* */
public class MapOptionHandler extends OptionHandler<Map<?,?>> {
public MapOptionHandler(CmdLineParser parser, OptionDef option, Setter<? super Map<?,?>> setter) {
super(parser, option, setter);
if (setter.asFieldSetter()==null)
throw new IllegalArgumentException("MapOptionHandler can only work with fields");
}
@Override
public String getDefaultMetaVariable() {
return null;
}
@Override
public int parseArguments(Parameters params) throws CmdLineException {
FieldSetter fs = setter.asFieldSetter();
Map v = (Map)fs.getValue();
if (v==null) {
v = createNewCollection(fs.getType());
fs.addValue(v);
}
addToMap(params.getParameter(0),v);
return 1;
}
/**
* Creates a new instance of the collection.
*/
protected Map createNewCollection(Class<? extends Map> type) {
return new HashMap();
}
/**
* Encapsulates how a single string argument gets converted into key and value.
*/
protected void addToMap(String argument, Map m) throws CmdLineException {
if (String.valueOf(argument).indexOf('=') == -1) {
throw new CmdLineException(owner,Messages.FORMAT_ERROR_FOR_MAP.format());
}
String mapKey;
String mapValue;
//Splitting off the key from the value
int idx = argument.indexOf('=');
if (idx>=0) {
mapKey = argument.substring(0, idx);
mapValue = argument.substring(idx + 1);
if (mapValue.length()==0)
// Kohsuke: I think this is a bad choice, but this is needed to remain backward compatible
mapValue = null;
} else {
mapKey = argument;
mapValue = null;
}
if (mapKey.length()==0) {
throw new CmdLineException(owner,Messages.MAP_HAS_NO_KEY.format());
}
addToMap(m, mapKey, mapValue);
}
/**
* This is the opportunity to convert values to some typed objects.
*/
protected void addToMap(Map m, String key, String value) {
m.put(key,value);
}
}