动态properties转换
程序员文章站
2022-07-14 14:43:18
...
今天同事和我讨论他遇到的一个问题。具体要求是这样的,在运行时,我们会从模块G得到一个Map,这个Map里面都是一些字符串对,你可以理解成一个字典,有字符串的key和字符串的value。简短节说,就是
非常非常复杂深奥。
好,现在我们事先知道要从这个map里读取一些数据点,比如:id, name, sex等等。
对id,我们知道读出来的是int;对name,是string;对sex,应该对应一个叫Gender的enum类型。
这就涉及一个自动类型转换的问题。我们希望不用对每个数据点做手工类型转换。
另外一个需求,一些数据点是有缺省值的。比如name我们可以缺省为空字符串。
这样,如果map里面没有某个值,我们就看缺省值,如果有,就用这个缺省值,如果没有,就抛异常。
手工做的话,大概是这样:
比较痛苦。于是做了一个动态代理:
convert()函数是调用apache的ConvertUtilsBean做的,没什么说的。
那么,用法呢?
这里面,对annotation的用法比较特别。不过不这么做,java也不提供一个简单并且类型安全的指定缺省值的方法。当然,如果你凑巧不需要缺省值,那么也不用annotation,直接用interface就好。
Map<String, String>
非常非常复杂深奥。
好,现在我们事先知道要从这个map里读取一些数据点,比如:id, name, sex等等。
对id,我们知道读出来的是int;对name,是string;对sex,应该对应一个叫Gender的enum类型。
这就涉及一个自动类型转换的问题。我们希望不用对每个数据点做手工类型转换。
另外一个需求,一些数据点是有缺省值的。比如name我们可以缺省为空字符串。
这样,如果map里面没有某个值,我们就看缺省值,如果有,就用这个缺省值,如果没有,就抛异常。
手工做的话,大概是这样:
String idValue = map.get("id"); if (idValue == null) { throw ...; } int id = Integer.parseInt(idValue); String name = map.get("name"); if (name == null) { name = ""; } String sexValue = map.get("sex"); if (sexValue == null) { throw ...; } Gender sex = Gender.valueOf(sexValue); ...
比较痛苦。于是做了一个动态代理:
public final class PropertyConverter<T> { private final Class<T> targetType; private PropertyConverter(Class<T> targetType) {...} public static <T> PropertyConverter<T> to(Class<T> targetType) { return new PropertyConverter<T>(targetType); } public T from(final Map<String, String> map) { return Proxy.newProxyInstance( new Class[]{targetType}, targetType.getClassLoader(), new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args) { String value = map.get(method.getName()); if (value == null) { Object defaultValue = method.getDefaultValue(); if (defaultValue == null) { throw ...; } return defaultValue; } return convert(value, method.getReturnType()); } }); } }
convert()函数是调用apache的ConvertUtilsBean做的,没什么说的。
那么,用法呢?
@interface Foo { int id(); String name() default ""; Gender sex(); } Map<String, String> map = ...; Foo foo = PropertyConverter.to(Foo.class).from(map); foo.id(); foo.name();
这里面,对annotation的用法比较特别。不过不这么做,java也不提供一个简单并且类型安全的指定缺省值的方法。当然,如果你凑巧不需要缺省值,那么也不用annotation,直接用interface就好。