将Map <String,String>转换为POJO

use*_*834 150 json dictionary pojo jackson

我一直在看杰克逊,但似乎我必须将Map转换为JSON,然后将结果JSON转换为POJO.

有没有办法将Map直接转换为POJO?

Jon*_*hoi 298

嗯,你也可以用杰克逊实现这一点.(因为你考虑使用杰克逊,它似乎更舒服).

使用ObjectMapperconvertValue方法:

final ObjectMapper mapper = new ObjectMapper(); // jackson's objectmapper
final MyPojo pojo = mapper.convertValue(map, MyPojo.class);
Run Code Online (Sandbox Code Playgroud)

无需转换为JSON字符串或其他内容; 直接转换的速度要快得多.

  • 您需要包含此库以使用ObjectMapper`comped'com.fasterxml.jackson.core:jackson-databind:2.7.3'` (8认同)
  • 使用convertValue是正确的答案,但不要每次都创建一个ObjectMapper实例.创建和线程安全是昂贵的,所以创建一个并将其缓存到某个地方. (4认同)
  • @RaduSimionescu您是否知道如何将带有嵌套地图/列表的对象深转换为Map &lt;String,Object&gt;实例? (2认同)

Ali*_*aka 49

Gson的解决方案:

Gson gson = new Gson();
JsonElement jsonElement = gson.toJsonTree(map);
MyPojo pojo = gson.fromJson(jsonElement, MyPojo.class);
Run Code Online (Sandbox Code Playgroud)

  • @Esakkiappan.E,为什么你认为“map.toString()”会提供正确的字符串?`toString()` 的实现不保证特定的格式。 (3认同)
  • @Prabs-反之亦然是[gson.toJson()](https://google.github.io/gson/apidocs/com/google/gson/Gson.html#toJson-java.lang.Object-) (2认同)

Sha*_*med 15

ObjectMapper objectMapper = new ObjectMapper();
// Use this if all properties are not in the class
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
final MyPojo pojo = objectMapper.convertValue(map, MyPojo.class);
Run Code Online (Sandbox Code Playgroud)

与第一个答案相同,但我使用它时遇到错误,因为我不希望将 Map 的所有属性转换为类。我也找到了objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);解决方案。


bhd*_*drk 7

if you have generic types in your class you should use TypeReference with convertValue().

final ObjectMapper mapper = new ObjectMapper();
final MyPojo<MyGenericType> pojo = mapper.convertValue(map, new TypeReference<MyPojo<MyGenericType>>() {});
Run Code Online (Sandbox Code Playgroud)

您也可以使用它来将 pojo 转换java.util.Map回来。

final ObjectMapper mapper = new ObjectMapper();
final Map<String, Object> map = mapper.convertValue(pojo, new TypeReference<Map<String, Object>>() {});
Run Code Online (Sandbox Code Playgroud)


Per*_*ion 5

是的,绝对可以避免中间转换为 JSON。使用像Dozer这样的深度复制工具,您可以将地图直接转换为 POJO。这是一个简单的例子:

POJO 示例:

public class MyPojo implements Serializable {
    private static final long serialVersionUID = 1L;

    private String id;
    private String name;
    private Integer age;
    private Double savings;

    public MyPojo() {
        super();
    }

    // Getters/setters

    @Override
    public String toString() {
        return String.format(
                "MyPojo[id = %s, name = %s, age = %s, savings = %s]", getId(),
                getName(), getAge(), getSavings());
    }
}
Run Code Online (Sandbox Code Playgroud)

转换代码示例:

public class CopyTest {
    @Test
    public void testCopyMapToPOJO() throws Exception {
        final Map<String, String> map = new HashMap<String, String>(4);
        map.put("id", "5");
        map.put("name", "Bob");
        map.put("age", "23");
        map.put("savings", "2500.39");
        map.put("extra", "foo");

        final DozerBeanMapper mapper = new DozerBeanMapper();
        final MyPojo pojo = mapper.map(map, MyPojo.class);
        System.out.println(pojo);
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

MyPojo[id = 5,姓名 = Bob,年龄 = 23,储蓄 = 2500.39]

注意:如果将源映射更改为 a Map<String, Object>,则可以复制任意深度的嵌套属性(Map<String, String>仅获得一层)。


Ham*_*edz 5

我测试了Jackson和BeanUtils,发现BeanUtils要快得多.
在我的机器(Windows8.1,JDK1.7)中,我得到了这个结果.

BeanUtils t2-t1 = 286
Jackson t2-t1 = 2203
Run Code Online (Sandbox Code Playgroud)


public class MainMapToPOJO {

public static final int LOOP_MAX_COUNT = 1000;

public static void main(String[] args) {
    Map<String, Object> map = new HashMap<>();
    map.put("success", true);
    map.put("data", "testString");

    runBeanUtilsPopulate(map);

    runJacksonMapper(map);
}

private static void runBeanUtilsPopulate(Map<String, Object> map) {
    long t1 = System.currentTimeMillis();
    for (int i = 0; i < LOOP_MAX_COUNT; i++) {
        try {
            TestClass bean = new TestClass();
            BeanUtils.populate(bean, map);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
    long t2 = System.currentTimeMillis();
    System.out.println("BeanUtils t2-t1 = " + String.valueOf(t2 - t1));
}

private static void runJacksonMapper(Map<String, Object> map) {
    long t1 = System.currentTimeMillis();
    for (int i = 0; i < LOOP_MAX_COUNT; i++) {
        ObjectMapper mapper = new ObjectMapper();
        TestClass testClass = mapper.convertValue(map, TestClass.class);
    }
    long t2 = System.currentTimeMillis();
    System.out.println("Jackson t2-t1 = " + String.valueOf(t2 - t1));
}}
Run Code Online (Sandbox Code Playgroud)

  • 我听说创建`ObjectMapper`实例是一个耗费时间/资源的过程,建议重新使用一个映射器实例,而不是每次重新创建它.我认为最好从测试中把它拿出来 (8认同)
  • 区别在于:杰克逊有一个完整的类型转换框架.例如,`Map`包含`map.put("data","2016-06-26")`和`TestClass`有一个字段`private LocalDate data;`,然后Jackson可以完成任务,而BeanUtils将失败. (6认同)
  • 这不是一个公平的测试,因为 BeanUtils 能够在第一次迭代后进行缓存,而 ObjectMapper 则永远没有机会。 (4认同)