Java中将对象转换为Map

后端 潘老师 7个月前 (10-14) 193 ℃ (0) 扫码查看

本教程将教您如何使用Jackson和Gson API提供的不同方式将对象转换为Java Map。您还可以使用Java反射创建自己的解决方案,除非提供的解决方案不适用时,否则不建议重新造轮子。

1.介绍

在本教程中,我们将把以下Employee类的实例转换为Map。Employee类包含简单类型,如String,以及新的Java类型,如LocalDate和集合类型。

我们有一个Role类型的List,以进一步演示不同解决方案的行为。我们将看到不同的解决方案如何将转换后的Map中的嵌套类型进行转换。

class Employee {
  private Integer id;
  private String name;
  private LocalDate dateOfBirth;
  private List<String> locations;
  private List<Role> roles;
}
class Role {
  private Integer id;
  private String name;
}

2.使用Jackson

Jackson是一个多用途的库,非常好地支持不同类型的转换,如JSON或XML。Jackson还支持使用以下方式将对象转换为Map:

2.1. 使用ObjectMapper.convertValue()

convertValue()方法从给定值转换为给定值类型的实例进行两步转换。它首先将给定值序列化为JSON,然后将JSON数据绑定到给定类型的值上。但由于不需要进行完全序列化,所以转换更加高效。

请注意,在以下示例中,我们正在注册JavaTimeModule类,因为Jackson默认不支持新的Java 8日期时间类。

Employee employee = new Employee(1, "Alex",
        LocalDate.of(1995, 1, 2),
        List.of("Delhi", "Nevada"),
        List.of(new Role(11, "Finance"), new Role(12, "HR")));
System.out.println(convertObjectToMapUsingObjectMapper(employee));
//转换方法
static Map<String, String> convertObjectToMapUsingObjectMapper(Employee employee) {
  ObjectMapper objectMapper = new ObjectMapper();
  objectMapper.registerModule(new JavaTimeModule());
  objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd"));
  return objectMapper.convertValue(employee, Map.class);
}

输出:

{
    id=1,
    name=Alex,
    dateOfBirth=1995-01-02,
    locations=[Delhi, Nevada],
    roles=[
        {id=11, name=Finance},
        {id=12, name=HR}
    ]
}

请注意,此方法还将关联和嵌套类(例如Role)转换为LinkedHashMap。

2.2. 使用JavaPropsMapper将其转换为Properties

另一种有趣的解决方案是将对象转换为Properties。Properties具有扁平结构。即使嵌套结构和集合也会转换为扁平结构,所有字段/值都会转换为字符串。在某些情况下,这可能是一个不错的解决方案。

Employee employee = new Employee(1, "Alex",
        LocalDate.of(1995, 1, 2),
        List.of("Delhi", "Nevada"),
        List.of(new Role(11, "Finance"), new Role(12, "HR")));
System.out.println(convertObjectToMapUsingJavaPropsMapper(employee));
//转换方法
static Properties convertObjectToMapUsingJavaPropsMapper(Employee employee) throws IOException {
  JavaPropsMapper mapper = new JavaPropsMapper();
  mapper.registerModule(new JavaTimeModule());
  mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd"));
  Properties properties = mapper.writeValueAsProperties(employee);
  return properties;
}

输出:

{
    id=1,
    name=Alex,
    dateOfBirth=1995-01-02,
    locations.1=Delhi,
    locations.2=Nevada,
    roles.1.id=11,
    roles.1.name=Finance,
    roles.2.id=12,
    roles.2.name=HR
}

3.使用Gson的TypeToken

如果我们的项目已经在应用程序中具有Gson依赖项,我们可以考虑使用Gson.fromJson()将对象转换为JSON,然后在第二步中将JSON转换为HashMap。

这种技术使用完全的序列化和反序列化,因此性能可能不如Jackson。如果由于某种原因无法使用Jackson,那么可以考虑使用Gson。

Employee employee = new Employee(1, "Alex",
        LocalDate.of(1995, 1, 2),
        List.of("Delhi", "Nevada"),
        List.of(new Role(11, "Finance"), new Role(12, "HR")));
System.out.println(convertObjectToMapUsingGson(employee));
static Map<String, String> convertObjectToMapUsingGson(Employee employee) {
  Gson gson = new GsonBuilder()
      .registerTypeAdapter(LocalDate.class, new LocalDateAdapter())
      .create();
  return gson.fromJson(gson.toJson(employee),
      new TypeToken<HashMap<String, Object>>() {
      }.getType()
  );
}

程序输出:

{
    id=1.0,
    name=Alex,
    dateOfBirth=1995-01-02,
    locations=[Delhi, Nevada],
    roles=[
        {id=11.0, name=Finance},
        {id=12.0, name=HR}
    ]
}

Gson和Jackson之间主要有两个差异:

  • Gson默认将所有数值转换为Double类型。
  • Gson在嵌套类中使用LinkedTreeMap,而Jackson使用LinkedHashMap

4.使用反射

另一种可能的方法,尽管不建议使用,是使用反射。使用反射,我们必须自己编写所有逻辑,因此存在出错的机会。如果采用这种方法,请确保在部署到生产环境之前进行充分测试。

以下是一个用于简单POJO类的非常基本的代码片段,它依赖于按名称获取字段的值。如果有这样的要求,我们可以调整方法以通过其getter获取值。

public static Map<String, Object> toKeyValuePairs(Object instance) {

  return Arrays.stream(Employee.class.getDeclaredFields())
      .collect(Collectors.toMap(
          Field::getName,
          field -> {
            try {
              Object result = null;
              field.setAccessible(true);
              result = field.get(instance);
              return result != null ? result : "";
            } catch (Exception e) {
              return "";
            }
          }));
}

程序输出:

{
    id=1,
    name=Alex,
    dateOfBirth=1995-01-02,
    locations=[Delhi, Nevada],
    roles=[
        Role(id=11, name=Finance),
        Role(id=12, name=HR)
    ]
}

我们可以发现Map结构保持了嵌套类的原样,因为我们没有访问它们或在我们的逻辑中处理它们。如果需要在应用程序中处理它们,那么请进一步扩展toKeyValuePairs()方法中的逻辑。

5.结论

这个Java教程教会了我们如何使用不同的解决方案将给定的Java对象转换为Map。通过查看所有解决方案,从易用性和性能的角度来看,Jackson似乎是最佳解决方案,并在大多数情况下是推荐的方法。

对于创建扁平结构,我们可以使用JavaPropsMapper将对象转换为Properties。

使用Gson与Jackson非常相似,但它没有提供任何额外的优势,而所有数字都被转换为Double,这在某些情况下可能不是一个理想的情况。因此,当无法使用Jackson时使用Gson。

最后,反射可以完全掌握在您手中,您必须自己编写每种可能的用例/条件。


版权声明:本站文章,如无说明,均为本站原创,转载请注明文章来源。如有侵权,请联系博主删除。
本文链接:https://www.panziye.com/back/9537.html
喜欢 (0)
请潘老师喝杯Coffee吧!】
分享 (0)
用户头像
发表我的评论
取消评论
表情 贴图 签到 代码

Hi,您需要填写昵称和邮箱!

  • 昵称【必填】
  • 邮箱【必填】
  • 网址【可选】