将Map <String,String>转换为POJO


185

我一直在研究Jackson,但似乎我必须将Map转换为JSON,然后将所得的JSON转换为POJO。

有没有一种方法可以将Map直接转换为POJO?

Answers:


355

好吧,您也可以使用Jackson来实现。(由于您正在考虑使用杰克逊,因此似乎更舒适)。

使用ObjectMapperconvertValue方法:

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

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


8
您需要包括此库才能使用ObjectMappercompile 'com.fasterxml.jackson.core:jackson-databind:2.7.3'
Shajeel Afzal

5
使用convertValue是正确的答案,但不要每次都创建一个ObjectMapper实例。创建线程安全的线程很昂贵,因此创建一个线程并将其缓存在某个地方。
空地

1
你知道如何做相反的事情-或如何将对象转换为Map <String,Object>?
anon58192932'7

2
@RaduSimionescu您是否知道如何将带有嵌套地图/列表的对象深度转换为Map<String, Object>实例?
anon58192932'7

@ anon58192932,如果您遵循此答案,它将起作用。我只是在处理一些奇怪的对象,这些对象将列表建模为映射,并且在序列化获得意外结果时使用。但那是另外一个问题,无关杰克逊
拉杜Simionescu

60

Gson的解决方案:

Gson gson = new Gson();
JsonElement jsonElement = gson.toJsonTree(map);
MyPojo pojo = gson.fromJson(jsonElement, MyPojo.class);

1
反之亦然
Prabs

2
@Prabs-反之亦然是gson.toJson()
AlikElzin-kilaka

无需将地图转换为json。map.toString()就足够了。Gson gson =新的Gson(); MyPojo pojo = gson.fromJson(map.toString(),MyPojo.class);
Esakkiappan .E

1
@ Esakkiappan.E,您为什么认为map.toString()将提供正确的字符串?的实现toString()不保证特定格式。
AlikElzin-kilaka

4

是的,绝对有可能避免中间转换为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());
    }
}

转换代码示例:

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);
    }
}

输出:

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

注意:如果将源映射更改为,Map<String, Object>则可以复制任意深的嵌套属性(Map<String, String>只有一个级别)。


1
您如何从Map到POJO进行“深度复制”?假设您有一个User.class,它封装了一个Address.class,并且地图上有一个键,例如“ address.city”,“ address.zip”,这些键需要映射到User.Address.City和User.Address.Zip ?似乎没有自动将Map键中的点解释为对象图的子级别。
szxnyc 2015年

3

如果您的班级中有通用类型,则应TypeReference与一起使用convertValue()

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

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

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

2

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

BeanUtils t2-t1 = 286
Jackson t2-t1 = 2203


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));
}}

5
区别在于:Jackson具有一个完整的类型转换框架。例如Mapcontains map.put("data","2016-06-26")TestClass有一个field private LocalDate data;,那么Jackson就能完成工作,而BeanUtils会失败。
本杰明·M

6
我听说创建ObjectMapper实例是一个时间/资源消耗过程,建议重用一个映射器实例,而不是每次都重新创建它。我认为这将是更好地利用它从测试垂耳
Mixaz

3
这不是一个公平的测试,因为BeanUtils能够在第一次迭代后进行缓存,而ObjectMapper却没有机会。
卢卡斯·罗斯

1

到目前为止,使用Jackson所提供的答案都很好,但是仍然可以使用util函数来帮助您转换不同的POJOs,如下所示:

    public static <T> T convert(Map<String, Object> aMap, Class<T> t) {
        try {
            return objectMapper
                    .convertValue(aMap, objectMapper.getTypeFactory().constructType(t));
        } catch (Exception e) {
            log.error("converting failed! aMap: {}, class: {}", getJsonString(aMap), t.getClass().getSimpleName(), e);
        }
        return null;
    }

0

将Map转换为POJO示例。注意Map键包含下划线,且字段变量为驼峰。

用户类POJO

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;

@Data
public class User {
    @JsonProperty("user_name")
    private String userName;
    @JsonProperty("pass_word")
    private String passWord;
}

App.class测试示例

import java.util.HashMap;
import java.util.Map;

import com.fasterxml.jackson.databind.ObjectMapper;

public class App {
    public static void main(String[] args) {
        Map<String, String> info = new HashMap<>();
        info.put("user_name", "Q10Viking");
        info.put("pass_word", "123456");

        ObjectMapper mapper = new ObjectMapper();
        User user = mapper.convertValue(info, User.class);

        System.out.println("-------------------------------");
        System.out.println(user);
    }
}
/**output
-------------------------------
User(userName=Q10Viking, passWord=123456)
 */

0

@Hamedz如果使用许多数据,请使用Jackson转换灯光数据,请使用apache ... TestCase:

import java.lang.reflect.InvocationTargetException; import java.util.HashMap; import java.util.Map; import org.apache.commons.beanutils.BeanUtils; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; public class TestPerf { 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("number", 1000); map.put("longer", 1000L); map.put("doubler", 1000D); map.put("data1", "testString"); map.put("data2", "testString"); map.put("data3", "testString"); map.put("data4", "testString"); map.put("data5", "testString"); map.put("data6", "testString"); map.put("data7", "testString"); map.put("data8", "testString"); map.put("data9", "testString"); map.put("data10", "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)); } @Data @AllArgsConstructor @NoArgsConstructor public static class TestClass { private Boolean success; private Integer number; private Long longer; private Double doubler; private String data1; private String data2; private String data3; private String data4; private String data5; private String data6; private String data7; private String data8; private String data9; private String data10; } }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.