最近在开发过程中,由于部分常量配置在接口而非枚举中,当我们需要通过属性名去获取具体接口中常量对应的值时,或是要获取该接口中所有常量名和对应值的键值对集合,显得有些麻烦或是无从下手,故这里封装一个通用的工具类来满足此类需求(扩展到类和对象中)做以下总结。
大致思路:定义 ReflexObjectUtil 工具类,通过反射获取类或对象信息,并将对应信息组装,按照要求的格式返回。
1. 测试实体
/** 测试实体Person
*
* @author jiayuan9608@163.com
* @version 1.0.0
* @date 2019-05-08 14:19
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Person {
private String name = "zhangsan";
private byte sex = 1;
private int age = 18;
private String introduce = "niuBility";
}
2. 接口常量
/**
* 测试接口常量demo
*
* @author jiayuan9608@163.com
* @version 1.0.0
* @date 2019-05-08 14:23
*/
public interface Constant {
int CONFIG_INT1 = 1;
int CONFIG_INT2 = 2;
int CONFIG_INT3 = 3;
String CONFIG_STRING1 = "1";
String CONFIG_STRING2 = "2";
String CONFIG_STRING3 = "3";
}
3. 获取单个对象的所有键值对(变量名-变量值)
通过泛型参数限定传入一个对象,该方法传入一个对象,返回该对象所有的属性-值。
注意:这里Collectors.toMap(key,value)中的value值不能为空,若对象属性值存在为空的情况,则会抛出空指针异常,查看toMap()方法源码,发现在map集合进行merge合并时进行了非空判断操作,如下:
故这里使用Optional进行空值的包装,在为空时用0代替(看具体业务场景)。ps: 记得写键值冲突策略,养成好习惯,这里采用后者覆盖,(k1, k2) -> k2。
/**
* 获取单个对象的所有键值对
*
* @param t
* @param <T>
* @return
*/
public static <T> Map<String, Object> getKeyAndValue(T t) {
Map<String, Object> map = Maps.newHashMap();
Class clazz = (Class) t.getClass();
Field[] fields = clazz.getDeclaredFields();
map = Arrays.stream(fields).collect(Collectors.toMap(Field::getName, field -> {
Object resultObj = null;
field.setAccessible(true);
try {
resultObj = field.get(t);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return Optional.ofNullable(resultObj).orElse(0);
}, (k1, k2) -> k2));
return map;
}
测试用例:
Map<String, Object> result1 = ReflexObjectUtil.getKeyAndValue(new Person());
测试结果:
4. 获取单个对象指定键的值
/**
* 获取单个对象指定键的值
*
* @param t
* @param key
* @param <T>
* @return
*/
public static <T> Object getValueByKey(T t, String key) {
Class clazz = t.getClass();
Field[] fields = clazz.getDeclaredFields();
Field resultField = Arrays.stream(fields)
.filter(field -> field.getName().equals(key))
.findFirst()
.get();
Object obj = null;
resultField.setAccessible(true);
try {
obj = resultField.get(t);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return obj;
}
测试用例:
Object result2 = ReflexObjectUtil.getValueByKey(new Person(), "name");
测试结果:
5. 获取多个对象的所有键值对
此类需求较少~
/**
* 获取多个对象的所有键值对
*
* @param objects
* @return
*/
public static List<Map<String, Object>> getKeyAndValues(List<Object> objects) {
return objects.stream().map(obj -> {
Class clazz = obj.getClass();
return Arrays.stream(clazz.getDeclaredFields()).collect(Collectors.toMap(Field::getName, field -> {
Object resultObj = null;
field.setAccessible(true);
try {
resultObj = field.get(obj);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return Optional.ofNullable(resultObj).orElse(0);
}, (k1, k2) -> k2));
}).collect(Collectors.toList());
}
测试用例:
List<Map<String, Object>> result3 = ReflexObjectUtil.getKeyAndValues(Arrays.asList(new Person(), new Person()));
测试结果:
6. 获取多个对象指定键的所有值
/**
* 获取多个对象指定键的所有值
*
* @param objects
* @param key
* @return
*/
public static List<Object> getValuesByKey(List<Object> objects, String key) {
return objects.stream().map(obj -> {
Class clazz = obj.getClass();
return Arrays.stream(clazz.getDeclaredFields())
.filter(field -> field.getName().equals(key))
.map(field -> {
Object resultObj = null;
field.setAccessible(true);
try {
resultObj = field.get(obj);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return resultObj;
}).collect(Collectors.toList());
}).collect(Collectors.toList());
}
测试用例:
List<Object> result4 = ReflexObjectUtil.getValuesByKey(Arrays.asList(new Person(), new Person()), "name");
测试结果:
7. 获取静态变量
以下适用与类或接口参数
/**
* 获取静态变量
*
* @param clazz
* @param key
* @return
*/
public static Object getValueByKey(Class<?> clazz, String key) {
Field[] fields = clazz.getDeclaredFields();
Field result = Arrays.stream(fields)
.filter(field -> key.equals(field.getName()))
.findFirst()
.get();
Object obj = null;
try {
obj = clazz.getField(result.getName()).get(null);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
return obj;
}
测试用例:
String result5 = ReflexObjectUtil.getValueByKey(Constant.class, "CONFIG_INT1").toString();
测试结果:
8. 获取类或接口中所有的常量
/**
* 获取类或接口中所有的常量
*
* @param clazz
* @return
*/
public static Map<String, Object> getFinalValues(Class<?> clazz) {
Field[] fields = clazz.getDeclaredFields();
return Arrays.stream(fields)
.filter(field -> Modifier.isFinal(field.getModifiers()))
.collect(Collectors.toMap(Field::getName, field -> {
Object obj = null;
try {
obj = clazz.getField(field.getName()).get(null);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
return obj;
}));
}
测试用例:
Map<String, Object> result6 = ReflexObjectUtil.getFinalValues(Constant.class);
测试结果:
9. 测试用例汇总:
/**
* ReflexObjectUtil工具类测试(测试全部通过)
*
* @author jiayuan9608@163.com
* @version 1.0.0
* @date 2019-05-08 14:26
*/
public class Test1 {
public static void main(String[] args) {
Map<String, Object> result1 = ReflexObjectUtil.getKeyAndValue(new Person());
Object result2 = ReflexObjectUtil.getValueByKey(new Person(), "name");
List<Map<String, Object>> result3 = ReflexObjectUtil.getKeyAndValues(Arrays.asList(new Person(), new Person()));
List<Object> result4 = ReflexObjectUtil.getValuesByKey(Arrays.asList(new Person(), new Person()), "name");
String result5 = ReflexObjectUtil.getValueByKey(Constant.class, "CONFIG_INT1").toString();
Map<String, Object> result6 = ReflexObjectUtil.getFinalValues(Constant.class);
}
}