Answers:
总是有apache commons beanutils,但是当然它在后台使用了反射
许多潜在的解决方案,但让我们再添加一个。使用Jackson(JSON处理库)进行“少JSON”转换,例如:
ObjectMapper m = new ObjectMapper();
Map<String,Object> props = m.convertValue(myBean, Map.class);
MyBean anotherBean = m.convertValue(props, MyBean.class);
(此博客条目有更多示例)
您基本上可以转换任何兼容的类型:兼容的意思是,如果您确实从类型转换为JSON,并且从该JSON转换为结果类型,则条目将匹配(如果配置正确,也可以忽略无法识别的条目)。
对于可能会遇到的情况,包括Maps,Lists,数组,原语和类bean POJO,效果很好。
BeanUtils
很好,但是不能处理数组和枚举
代码生成将是我能想到的唯一其他方法。就个人而言,我有一个通常可重用的反射解决方案(除非部分代码绝对对性能至关重要)。使用JMS听起来像是过分杀伤(附加的依赖关系,这甚至不是它的意思)。此外,它可能在引擎盖下也使用反射。
这是一种将Java对象转换为Map的方法
public static Map<String, Object> ConvertObjectToMap(Object obj) throws
IllegalAccessException,
IllegalArgumentException,
InvocationTargetException {
Class<?> pomclass = obj.getClass();
pomclass = obj.getClass();
Method[] methods = obj.getClass().getMethods();
Map<String, Object> map = new HashMap<String, Object>();
for (Method m : methods) {
if (m.getName().startsWith("get") && !m.getName().startsWith("getClass")) {
Object value = (Object) m.invoke(obj);
map.put(m.getName().substring(3), (Object) value);
}
}
return map;
}
这是怎么称呼的
Test test = new Test()
Map<String, Object> map = ConvertObjectToMap(test);
可能迟到了。您可以使用Jackson并将其转换为Properties对象。这适用于嵌套类,如果您想在abc = value中输入键。
JavaPropsMapper mapper = new JavaPropsMapper();
Properties properties = mapper.writeValueAsProperties(sct);
Map<Object, Object> map = properties;
如果您想要一些后缀,那就去做吧
SerializationConfig config = mapper.getSerializationConfig()
.withRootName("suffix");
mapper.setConfig(config);
需要添加此依赖项
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-properties</artifactId>
</dependency>
使用Java 8,您可以尝试以下操作:
public Map<String, Object> toKeyValuePairs(Object instance) {
return Arrays.stream(Bean.class.getDeclaredMethods())
.collect(Collectors.toMap(
Method::getName,
m -> {
try {
Object result = m.invoke(instance);
return result != null ? result : "";
} catch (Exception e) {
return "";
}
}));
}
只需使用反射和Groovy即可:
def Map toMap(object) {
return object?.properties.findAll{ (it.key != 'class') }.collectEntries {
it.value == null || it.value instanceof Serializable ? [it.key, it.value] : [it.key, toMap(it.value)]
}
}
def toObject(map, obj) {
map.each {
def field = obj.class.getDeclaredField(it.key)
if (it.value != null) {
if (field.getType().equals(it.value.class)){
obj."$it.key" = it.value
}else if (it.value instanceof Map){
def objectFieldValue = obj."$it.key"
def fieldValue = (objectFieldValue == null) ? field.getType().newInstance() : objectFieldValue
obj."$it.key" = toObject(it.value,fieldValue)
}
}
}
return obj;
}
使用juffrou-reflect的BeanWrapper。这是非常表现。
这是将bean转换为地图的方法:
public static Map<String, Object> getBeanMap(Object bean) {
Map<String, Object> beanMap = new HashMap<String, Object>();
BeanWrapper beanWrapper = new BeanWrapper(BeanWrapperContext.create(bean.getClass()));
for(String propertyName : beanWrapper.getPropertyNames())
beanMap.put(propertyName, beanWrapper.getValue(propertyName));
return beanMap;
}
我自己开发了Juffrou。它是开源的,因此您可以自由使用和修改它。如果您对此有任何疑问,我们将非常乐意答复。
干杯
卡洛斯
使用Spring时,也可以使用Spring Integration object-to-map-transformer。为此,不值得将Spring添加为依赖项。
有关文档,请在http://docs.spring.io/spring-integration/docs/4.0.4.RELEASE/reference/html/messaging-transformation-chapter.html上搜索“ Object-to-Map Transformer”
本质上,它遍历从作为输入给定的对象可到达的整个对象图,并根据对象上的所有原始类型/字符串字段生成映射。可以将其配置为输出:
这是他们页面上的示例:
public class Parent{
private Child child;
private String name;
// setters and getters are omitted
}
public class Child{
private String name;
private List<String> nickNames;
// setters and getters are omitted
}
输出将是:
{person.name = George,person.child.name = Jenna,person.child.nickNames [0] = Bimbo。。。等等}
也可以使用反向变压器。
您可以使用Joda框架:
并利用JodaProperties。这确实要求您以特定方式创建bean,并实现特定接口。但是,它确实允许您从特定类返回属性映射,而无需进行反射。示例代码在这里:
http://pbin.oogly.co.uk/listings/viewlistingdetail/0e78eb6c76d071b4e22bbcac748c57
如果您不希望对每个getter和setter的调用进行硬编码,则反射是调用这些方法的唯一方法(但这并不困难)。
您可以重构所涉及的类以使用Properties对象保存实际数据,并让每个getter和setter对其进行调用/设置吗?然后,您将拥有一个非常适合您想要做的结构。甚至还有方法以键值形式保存和加载它们。
最好的解决方案是使用推土机。您只需要在映射器文件中添加以下内容:
<mapping map-id="myTestMapping">
<class-a>org.dozer.vo.map.SomeComplexType</class-a>
<class-b>java.util.Map</class-b>
</mapping>
就是这样,推土机负责其余的工作!!!
您可以使用Java 8流过滤器收集器属性,
public Map<String, Object> objectToMap(Object obj) {
return Arrays.stream(YourBean.class.getDeclaredMethods())
.filter(p -> !p.getName().startsWith("set"))
.filter(p -> !p.getName().startsWith("getClass"))
.filter(p -> !p.getName().startsWith("setClass"))
.collect(Collectors.toMap(
d -> d.getName().substring(3),
m -> {
try {
Object result = m.invoke(obj);
return result;
} catch (Exception e) {
return "";
}
}, (p1, p2) -> p1)
);
}
我的JavaDude Bean注释处理器生成了执行此操作的代码。
http://javadude.googlecode.com
例如:
@Bean(
createPropertyMap=true,
properties={
@Property(name="name"),
@Property(name="phone", bound=true),
@Property(name="friend", type=Person.class, kind=PropertyKind.LIST)
}
)
public class Person extends PersonGen {}
上面的代码生成了超类PersonGen,该类包括一个createPropertyMap()方法,该方法为使用@Bean定义的所有属性生成一个Map。
(请注意,我将稍微更改下一个版本的API,注释属性将为defineCreatePropertyMap = true)
您应该编写一个通用的转换服务!使用泛型使其保持自由类型(以便您可以将每个对象转换为key => value并返回)。
哪个字段应该是关键?从Bean中获取该字段,并将任何其他非瞬态值附加到值映射中。
回来的路很容易。读取key(x)并首先写入密钥,然后将每个列表条目写回到新对象。
您可以使用apache commons beanutils获得bean的属性名称!
如果您真的想要性能,可以采用代码生成途径。
您可以通过自己进行反思并构建一个mixin AspectJ ITD来实现此目的。
或者,您可以使用Spring Roo并制作一个Spring Roo Addon。您的Roo插件将执行与上述操作类似的操作,但所有使用Spring Roo的用户都可以使用,而您不必使用运行时注释。
我都做过 人们不喜欢Spring Roo,但这确实是Java最全面的代码生成。
如果涉及到简单的对象树到键值列表的映射,其中键可能是从对象的根元素到要检查的叶子的点状路径描述,那么很明显,从树到键值列表的转换可与对象到xml的映射。XML文档中的每个元素都有一个定义的位置,可以转换为路径。因此,我将XStream用作基本且稳定的转换工具,并用自己的实现替换了分层驱动程序和编写器部件。XStream还具有基本的路径跟踪机制,该机制与其他两种结合使用,严格地导致了适合该任务的解决方案。
借助Jackson库,我能够找到String / integer / double类型的所有类属性,以及Map类中的各个值。(不使用反射API!)
TestClass testObject = new TestClass();
com.fasterxml.jackson.databind.ObjectMapper m = new com.fasterxml.jackson.databind.ObjectMapper();
Map<String,Object> props = m.convertValue(testObject, Map.class);
for(Map.Entry<String, Object> entry : props.entrySet()){
if(entry.getValue() instanceof String || entry.getValue() instanceof Integer || entry.getValue() instanceof Double){
System.out.println(entry.getKey() + "-->" + entry.getValue());
}
}
我们可以使用Jackson库将Java对象轻松转换为Map。
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.6.3</version>
</dependency>
如果在Android项目中使用,则可以按以下步骤在应用程序的build.gradle中添加jackson:
implementation 'com.fasterxml.jackson.core:jackson-core:2.9.8'
implementation 'com.fasterxml.jackson.core:jackson-annotations:2.9.8'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.9.8'
样例实施
public class Employee {
private String name;
private int id;
private List<String> skillSet;
// getters setters
}
public class ObjectToMap {
public static void main(String[] args) {
ObjectMapper objectMapper = new ObjectMapper();
Employee emp = new Employee();
emp.setName("XYZ");
emp.setId(1011);
emp.setSkillSet(Arrays.asList("python","java"));
// object -> Map
Map<String, Object> map = objectMapper.convertValue(emp,
Map.class);
System.out.println(map);
}
}
输出:
{name = XYZ,id = 1011,技能= [python,java]}
java.beans.Introspector
.getBeanInfo()
。它内置在JDK中。