[英]Flattening Java Bean to a Map
I am stuck at converting Java Bean
to Map
. 我坚持将
Java Bean
转换为Map
。 There are many resources on the internet, but unfortunately they all treat converting simple beans to Maps. 互联网上有很多资源,但不幸的是,它们都将简单的bean转换为地图。 My ones are a little bit more extensive.
我的那些更广泛。
There's simplified example: 有简化的例子:
public class MyBean {
private String firstName;
private String lastName;
private MyHomeAddress homeAddress;
private int age;
// getters & setters
}
My point is to produce Map<String, Object>
which, in this case, is true for following conditions: 我的观点是生成
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")
I have tried using Apache Commons BeanUtils
. 我尝试过使用
Apache Commons BeanUtils
。 Both approaches BeanUtils#describe(Object)
and BeanMap(Object)
produce a Map which "deep level" is 1 (I mean that there's only "homeAddress"
key, holding MyHomeAddress
object as a value). 这两种方法都是
BeanUtils#describe(Object)
和BeanMap(Object)
生成一个“深层次”为1的Map(我的意思是只有"homeAddress"
键,将MyHomeAddress
对象保存为值)。 My method should enter the objects deeper and deeper until it meets a primitive type (or String), then it should stop digging and insert key ie "order.customer.contactInfo.home"
. 我的方法应该越来越深入地进入对象,直到它遇到基本类型(或字符串),然后它应该停止挖掘并插入键,即
"order.customer.contactInfo.home"
。
So, my question is: how can it be easliy done (or is there already existing project which would allow me to do that)? 所以,我的问题是:如何轻松完成(或者是否已经存在允许我这样做的项目)?
update 更新
I have expanded Radiodef answer to include also Collections, Maps Arrays and Enums: 我已经扩展了Radiodef的答案,还包括Collections,Maps Arrays和Enums:
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;
}
Here's a simple reflective/recursive example. 这是一个简单的反射/递归示例。
You should be aware that there are some issues with doing a conversion the way you've asked: 您应该知道,按照您提出的方式进行转换存在一些问题:
This example doesn't address those because I'm not sure how you want to account for them (if you do). 这个例子没有解决这些问题,因为我不确定你想如何解释它们(如果你这样做)。 If your beans inherit from something other than
Object
, you will need to change your idea a little bit. 如果你的bean继承自
Object
以外的东西,你需要稍微改变一下你的想法。 This example only considers the fields of the subclass. 此示例仅考虑子类的字段。
In other words, if you have 换句话说,如果你有
public class SubBean extends Bean {
this example will only return fields from SubBean
. 此示例仅返回
SubBean
字段。
Java lets us do this: 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;
}
Not that anybody should be doing that, but it's a problem if you want to use String
as the keys, because there would be two keys named "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());
}
}
You could always use the Jackson Json Processor . 你总是可以使用Jackson Json处理器 。 Like this:
像这样:
import com.fasterxml.jackson.databind.ObjectMapper;
//...
ObjectMapper objectMapper = new ObjectMapper();
//...
@SuppressWarnings("unchecked")
Map<String, Object> map = objectMapper.convertValue(pojo, Map.class);
where pojo is some Java bean. 其中pojo是一些Java bean。 You can use some nice annotations on the bean to control the serialization.
您可以在bean上使用一些不错的注释来控制序列化。
You can re-use the ObjectMapper. 您可以重用ObjectMapper。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.