我决定在Java中编写自己的小型ArgumentParser, 关键是它有方法
public void addOption(String optionName, Class valueType, boolean required)
执行类似
的操作ArgumentParser parser = new ArgumentParser();
parser.addOption("--input_path", String.class, true);
Map<String, Object> options = parser.parse(args); //args is String[]
String inputPath = (String)options.get("--input_path"); //hooray!
但我无法弄清楚如何尝试自动将String转换为某个用户指定的类? 下面的代码显然不起作用
options.put(currentOption, registeredOptions.get(currentOption).valueOf(arg));
有一些简单的方法可以做到这一点,我无法弄明白吗? 或许你说它是坏的和恶毒的想法,我感谢任何建议! 谢谢!
答案 0 :(得分:4)
您基本上的目标是创建一个函数,该函数将返回其类作为参数传递的对象。
我不知道这个问题的一般解决方案。
但是有一些部分解决方案在一起,所以我相信,会回答你正在寻找的东西:
A。返回的对象是数字:
对于int和float,解决方案很明显:
int ival = Integer.parseInt(strParam);
float fval = Float.parseFloat(strParam);
B。返回的对象类有一个字符串构造函数,即接收单个字符串参数的构造函数
那是:
parser.addOption("--input_path", MySpecialClass.class, true);
其中:
class MySpecialClass {
public MySpecialClass(String param) // <----------- string constructor
}
在这里,您可以使用反射通过获取和激活构造函数来实例化所需的对象。 注意:我们的代码不需要知道返回类标识,但天气与否它有一个字符串构造函数:
Constructor stringConstructor = classObject.getConstructor(new Class[]{String.class});
Object objectToReturn = stringConstructor.newInstance(stringParam);
最后结合上面给出了一个与此类似的参数处理函数:
Object processAnyParam(String strParam, Class returnClass, boolean mandatory) {
if (returnClass.equals(int.class)) {
return Integer.parseInt(strParam);
}
else if (returnClass.equals(float.class)) {
return Float.parseFloat(strParam);
}
else if (maybe other numeric types here...) {
}
else {
try {
Constructor stringConstructor = classObject.getConstructor(new Class[]{String.class});
} catch (NoSuchMethodException e) {
// no string constructor; bail out..
return null;
}
return stringConstructor.newInstance(strParam);
}
}
答案 1 :(得分:2)
如果不传递一些方法将String转换为正确的对象类型,则无法进行转换(假设您不要求所有类都有一个带String
的构造函数作为参数想用来解析String
)。一种可能性是将Function<String, ?>
个对象传递给addOption
,例如:
public void addOption(String optionName, Function<String, ?> valueConverter, boolean required)
parser.addOption("--stringParameter", Function.identity(), true); // remains identical
parser.addOption("--integerParameter", Integer::parseInt, true); // use Integer.parseInt(String)
parser.addOption("--binaryIntParameter", s->Integer.parseInt(s, 2), true); // integer given in binary format
parser.addOption("--fileParameter", s -> new File(s), true); // use File(String) constructor
您的解析函数将String转换为对象的代码将包含以下内容:
Map<String, Object> result = //...
// ...
String key = //...
String stringValue = //...
Function<String, ?> converter = //... get the converter from where you stored it
result.put(key, converter.apply(stringValue));
//...
return result;
答案 2 :(得分:1)
有几个图书馆已经这样做了,比如JCommander,几乎所有图书馆都使用Strategy pattern。也就是说,它们允许客户端注册将输入字符串转换为特定类的对象的转换器对象。对于最明显的类,当然也有相当多的内置转换器,例如Number
,Boolean
,File
或列表。
所以你会有这样的事情。
public interface Converter<T> {
public T convert( String arg );
}
public class IntegerConverter implements Converter<Integer> {
public Integer convert( String arg ) {
return Integer.parseInt( arg );
}
}
在您的ArgumentParser
中,您会保留已注册转换商的地图并拨打相应的地址。
当然,您可以通过指定转换器的层次结构来详细说明,以获得更多和更少的特定策略,但总体思路是相同的。