章
目
录
本教程将教您如何使用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。
最后,反射可以完全掌握在您手中,您必须自己编写每种可能的用例/条件。