如何将Java对象(bean)转换为键值对(反之亦然)?

Sha*_*baz 89 java reflection collections javabeans

假设我有一个非常简单的java对象,它只有一些getXXX和setXXX属性.此对象仅用于处理值,基本上是记录或类型安全(和性能)映射.我经常需要将此对象转换为键值对(字符串或类型安全)或从键值对转换为此对象.

除了反射或手动编写代码来进行此转换之外,实现此目的的最佳方法是什么?

一个示例可能是通过jms发送此对象,而不使用ObjectMessage类型(或将传入消息转换为正确类型的对象).

Sta*_*Man 173

很多潜在的解决方案,但让我们再添加一个.使用Jackson(JSON处理库)进行"json-less"转换,如:

ObjectMapper m = new ObjectMapper();
Map<String,Object> props = m.convertValue(myBean, Map.class);
MyBean anotherBean = m.convertValue(props, MyBean.class);
Run Code Online (Sandbox Code Playgroud)

(此博客条目有更多示例)

你基本上可以转换任何兼容的类型:兼容意味着如果你确实从类型转换为JSON,从那个JSON转换为结果类型,条目将匹配(如果配置正确也可以忽略无法识别的那些).

适用于人们期望的案例,包括地图,列表,数组,基元,类似bean的POJO.

  • 这应该是公认的答案.`BeanUtils`很好,但无法处理数组和枚举 (2认同)

Mau*_*rry 51

总有apache commons beanutils但当然它使用引擎盖下的反射

  • 确切地说,BeanMap(bean)是常见beanutils的特定部分. (22认同)
  • 此外,在引擎盖下使用反射也没有错.特别是如果缓存结果(供将来使用),基于反射的访问通常对于大多数用例来说足够快. (8认同)
  • 忽略性能方面的考虑我发现在下面的答案中结合使用BeanMap()和Jackson的ObjectMapper给了我最好的结果.BeanMap成功创建了一个更完整的对象映射,然后Jackson将其转换为简单的LinkedHashMap结构,允许在管道中进一步修改.objectAsMap = objectMapper.convertValue(new BeanMap(myObject),Map.class); (3认同)

Mic*_*rdt 8

代码生成将是我能想到的唯一其他方式.就个人而言,我有一个通常可重复使用的反射解决方案(除非该部分代码绝对是性能关键).使用JMS听起来有点过分(额外的依赖性,甚至不是它的意思).此外,它可能也会在引擎盖下使用反射.


DeX*_*XoN 8

这是一种将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;
}
Run Code Online (Sandbox Code Playgroud)

这是如何称呼它

   Test test = new Test()
   Map<String, Object> map = ConvertObjectToMap(test);
Run Code Online (Sandbox Code Playgroud)

  • 我不知道你的目的是你的方法.但是我认为当你想用泛型类型的对象进行编程时,这是非常好的例子 (2认同)

小智 7

可能是聚会迟到了。您可以使用 Jackson 并将其转换为 Properties 对象。这适用于嵌套类,并且如果您想要 for abc=value 中的键。

JavaPropsMapper mapper = new JavaPropsMapper();
Properties properties = mapper.writeValueAsProperties(sct);
Map<Object, Object> map = properties;
Run Code Online (Sandbox Code Playgroud)

如果你想要一些后缀,那就做

SerializationConfig config = mapper.getSerializationConfig()
                .withRootName("suffix");
mapper.setConfig(config);
Run Code Online (Sandbox Code Playgroud)

需要添加这个依赖

<dependency>
  <groupId>com.fasterxml.jackson.dataformat</groupId>
  <artifactId>jackson-dataformat-properties</artifactId>
</dependency>
Run Code Online (Sandbox Code Playgroud)


Jan*_*ski 6

使用 Spring 时,还可以使用 Spring Integration 对象到映射转换器。仅仅为此添加 Spring 作为依赖项可能不值得。

有关文档,请在http://docs.spring.io/spring-integration/docs/4.0.4.RELEASE/reference/html/messaging-transformation-chapter.html上搜索“Object-to-Map Transformer”

本质上,它遍历从作为输入给出的对象可到达的整个对象图,并从对象上的所有原始类型/字符串字段生成映射。它可以配置为输出:

  • 平面地图:{rootObject.someField=Joe, rootObject.leafObject.someField=Jane},或者
  • 结构化映射:{someField=Joe, leafObject={someField=Jane}}。

这是他们页面上的示例:

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
}
Run Code Online (Sandbox Code Playgroud)

输出将是:

{person.name=乔治,person.child.name=珍娜,person.child.nickNames[0]=宾博。。。ETC}

还可以使用反向变压器。