将 Map<String, String> 转换为 POJO
Posted
技术标签:
【中文标题】将 Map<String, String> 转换为 POJO【英文标题】:Convert a Map<String, String> to a POJO 【发布时间】:2013-05-01 23:36:15 【问题描述】:我一直在查看 Jackson,但似乎我必须将 Map 转换为 JSON,然后将生成的 JSON 转换为 POJO。
有没有办法将 Map 直接转换为 POJO?
【问题讨论】:
【参考方案1】:嗯,您也可以通过 Jackson 实现这一目标。 (因为您考虑使用杰克逊,它似乎更舒服)。
使用ObjectMapper
的convertValue
方法:
final ObjectMapper mapper = new ObjectMapper(); // jackson's objectmapper
final MyPojo pojo = mapper.convertValue(map, MyPojo.class);
无需转换成JSON字符串或其他;直接转换的速度要快得多。
【讨论】:
你需要包含这个库才能使用 ObjectMappercompile 'com.fasterxml.jackson.core:jackson-databind:2.7.3'
使用 convertValue 是正确的答案,但不要每次都创建 ObjectMapper 实例。创建和线程安全的成本很高,因此创建一个并将其缓存在某处。
你知道如何做相反的事情 - 或者如何将对象转换为 MapMap<String, Object>
实例吗?
@anon58192932 如果您遵循此答案,它将起作用。我只是在处理一些奇怪的对象,这些对象将列表建模为地图,并且当序列化得到意想不到的结果时。但那是另一个问题,与杰克逊无关【参考方案2】:
Gson的解决方案:
Gson gson = new Gson();
JsonElement jsonElement = gson.toJsonTree(map);
MyPojo pojo = gson.fromJson(jsonElement, MyPojo.class);
【讨论】:
反之亦然 @Prabs - 反之亦然 gson.toJson() 无需将map转json。 map.toString() 就足够了。 Gson gson = 新 Gson(); MyPojo pojo = gson.fromJson(map.toString(), MyPojo.class); @Esakkiappan.E,您为什么认为map.toString()
会提供正确的字符串? toString()
的实现不保证特定格式。【参考方案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>>() );
【讨论】:
使用 convertValue 将 Map@JsonIgnoreProperties(ignoreUnknown = true)
吗?
嘿,用ObjectMapper objMapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
搞定了【参考方案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>
,您只能获得一层)。
【讨论】:
如何从 Map 到 POJO 进行“深拷贝”?比如说你有一个 User.class 封装了一个 Address.class 并且地图有一个像“address.city”,“address.zip”这样的键,这些需要映射到 User.Address.City 和 User.Address.Zip ?它似乎不会自动将 Map 键中的点解释为对象图的子级别。【参考方案5】: ObjectMapper objectMapper = new ObjectMapper();
//if all properties are not in class use this
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
final MyPojo pojo = objectMapper.convertValue(map, MyPojo.class);
与第一个答案相同,但我使用它时出错,因为我不希望地图的所有属性都转换为 calss。我找到 objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
这是解决方案
【讨论】:
【参考方案6】:我测试了 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));
【讨论】:
不同的是:Jackson 有一个完整的类型转换框架。例如Map
包含 map.put("data","2016-06-26")
和 TestClass
有一个字段 private LocalDate data;
,那么 Jackson 将能够完成任务,而 BeanUtils 将失败。
听说创建ObjectMapper
实例是一个耗费时间/资源的过程,建议重复使用一个映射器实例,而不是每次都重新创建它。我认为最好把它从测试 lop 中取出来
不是一个公平的测试,因为 BeanUtils 能够在第一次迭代后缓存,而 ObjectMapper 从来没有机会。【参考方案7】:
到目前为止使用 Jackson 提供的答案非常好,但您仍然可以使用 util 函数来帮助您转换不同的POJO
s,如下所示:
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;
【讨论】:
我知道这是一个离题的评论,但我认为忽略异常是个坏主意。因此,除了objectMapper.convertValue
,我看不到这个实用函数的任何价值。【参考方案8】:
将 Map 转换为 POJO 示例。注意 Map 键包含下划线,字段变量是驼峰。
User.class 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)
*/
【讨论】:
【参考方案9】:@Hamedz 如果使用大量数据,请使用 Jackson 转换 轻数据,使用 apache... 测试用例:
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;
【讨论】:
以上是关于将 Map<String, String> 转换为 POJO的主要内容,如果未能解决你的问题,请参考以下文章
如何将 XML 转换为 java.util.Map,反之亦然?
将 Map<String,Object> 转换为 Map<String,String>
将 Map<String,String> 转换为 Map<String,Object>
Java 8:将 Map<String, List<String>> 转换为 Map<String, String[]> [重复]