我坚持将Java Bean
转换为Map
。互联网上有很多资源,但不幸的是,它们都将简单的bean转换为地图。我的那些更广泛。
有简化的例子:
public class MyBean {
private String firstName;
private String lastName;
private MyHomeAddress homeAddress;
private int age;
// getters & setters
}
我的观点是产生Map<String, Object>
,在这种情况下,对于以下条件是正确的:
map.containsKey("firstName")
map.containsKey("lastName")
map.containsKey("homeAddress.street") // street is String
map.containsKey("homeAddress.number") // number is int
map.containsKey("homeAddress.city") // city is String
map.containsKey("homeAddress.zipcode") // zipcode is String
map.containsKey("age")
我尝试过使用Apache Commons BeanUtils
。两种方法BeanUtils#describe(Object)
和BeanMap(Object)
都会产生一个“深层次”为1的地图(我的意思是只有"homeAddress"
个密钥,将MyHomeAddress
个对象作为值。我的方法应该越来越深入地进入对象,直到遇到基本类型(或字符串),然后它应该停止挖掘并插入密钥,即"order.customer.contactInfo.home"
。
所以,我的问题是:如何轻松完成(或者是否已经存在允许我这样做的项目)?
更新
我已经扩展了Radiodef的答案,还包括了集合,地图数组和枚举:
private static boolean isValue(Object value) {
final Class<?> clazz = value.getClass();
if (value == null ||
valueClasses.contains(clazz) ||
Collection.class.isAssignableFrom(clazz) ||
Map.class.isAssignableFrom(clazz) ||
value.getClass().isArray() ||
value.getClass().isEnum()) {
return true;
}
return false;
}
答案 0 :(得分:5)
这是一个简单的反思/递归示例。
您应该知道,按照您提出的方式进行转换存在一些问题:
这个例子没有解决这些问题,因为我不确定你想如何解释它们(如果你这样做)。如果你的bean继承了Object
以外的东西,你需要稍微改变一下你的想法。此示例仅考虑子类的字段。
换句话说,如果你有
public class SubBean extends Bean {
此示例仅返回SubBean
。
Java允许我们这样做:
package com.acme.util;
public class Bean {
private int value;
}
package com.acme.misc;
public class Bean extends com.acme.util.Bean {
private int value;
}
并非任何人都应该这样做,但如果您想使用String
作为键,则会出现问题,因为会有两个名为"value"
的键。
import java.lang.reflect.*;
import java.util.*;
public final class BeanFlattener {
private BeanFlattener() {}
public static Map<String, Object> deepToMap(Object bean) {
Map<String, Object> map = new LinkedHashMap<>();
try {
putValues(bean, map, null);
} catch (IllegalAccessException x) {
throw new IllegalArgumentException(x);
}
return map;
}
private static void putValues(Object bean,
Map<String, Object> map,
String prefix)
throws IllegalAccessException {
Class<?> cls = bean.getClass();
for (Field field : cls.getDeclaredFields()) {
if (field.isSynthetic() || Modifier.isStatic(field.getModifiers()))
continue;
field.setAccessible(true);
Object value = field.get(bean);
String key;
if (prefix == null) {
key = field.getName();
} else {
key = prefix + "." + field.getName();
}
if (isValue(value)) {
map.put(key, value);
} else {
putValues(value, map, key);
}
}
}
private static final Set<Class<?>> VALUE_CLASSES =
Collections.unmodifiableSet(new HashSet<>(Arrays.asList(
Object.class, String.class, Boolean.class,
Character.class, Byte.class, Short.class,
Integer.class, Long.class, Float.class,
Double.class
// etc.
)));
private static boolean isValue(Object value) {
return value == null
|| value instanceof Enum<?>
|| VALUE_CLASSES.contains(value.getClass());
}
}
答案 1 :(得分:1)
您可以随时使用Jackson Json Processor。像这样:
import com.fasterxml.jackson.databind.ObjectMapper;
//...
ObjectMapper objectMapper = new ObjectMapper();
//...
@SuppressWarnings("unchecked")
Map<String, Object> map = objectMapper.convertValue(pojo, Map.class);
其中pojo是一些Java bean。您可以在bean上使用一些不错的注释来控制序列化。
您可以重复使用ObjectMapper。