将 HashMap 转换为包含列表属性的对象
Convert HashMap to Object containing list attributes
是否可以将这个HashMap转换为对应的Object?也许使用 Jackson Object Mapper、Gson,甚至是 Mapstruct。这里的技巧是如何映射 List 属性,在我的 INPUT 中有一个数字作为属性名称的后缀:
Map<String, String> map = new HashMap<String, String>() {{
put("fooName", "foo name");
put("bars1.barName", "bar at position 0 name");
put("bars1.barValue", "bar at position 0 value");
put("bars2.barName", "bar at position 1 name");
put("bars2.barValue", "bar at position 1 value");
}};
public class Foo {
String fooName;
List<Bar> bars;
// getters/setters
}
public class Bar {
String barName;
String barValue;
// getters/setters
}
PS: 此输入来自外部 API 调用,我无法修改源。
您可以使用中间哈希图进行转换。尝试下面的示例转换器。
备注:您可能希望为 Foo 和 Bar 使用适当的构造函数或使用 setter(为简单起见,我使用 public 字段)。而且没有错误处理。
static Foo convertMap(Map<String, String> map){
Foo foo = new Foo();
foo.fooName = map.remove("fooName");
Map<String, Bar> barsMap = new HashMap<String, Bar>();
for(String key : map.keySet()){
String[] split = key.split("\.");
String name = split[0];
String attribute = split[1];
Bar bar = null;
if(barsMap.containsKey(name)){
bar = barsMap.get(name);
}
else{
bar = new Bar();
barsMap.put(name, bar);
}
switch(attribute){
case "barName": bar.barName = map.get(key); break;
case "barValue": bar.barValue = map.get(key); break;
default: break;
}
}
foo.bars = new ArrayList(barsMap.values());
return foo;
}
您可以使用 @JsonAnySetter
注释以及 Bar 实例的映射:
public class Foo {
String fooName;
private Map<Integer, Bar> map = new TreeMap<>();
// getters/setters
public String getFooName() {
return fooName;
}
public void setFooName(String fooName) {
this.fooName = fooName;
}
public List<Bar> getBars() {
return map.values().stream().collect(Collectors.toList());
}
@JsonAnySetter
public void bars(String key, String value) {
String[] ids = key.split("\.");
if (ids[0].startsWith("bars")) {
Integer barKey = Integer.parseInt(ids[0].substring("bars".length())) - 1;
String field = ids[1];
Bar bar = map.computeIfAbsent(barKey, k -> new Bar());
if ("barName".equals(field)) {
bar.setBarName(value);
} else if ("barValue".equals(field)) {
bar.setBarValue(value);
}
map.put(barKey, bar);
} // else handle other properties
}
}
测试:
ObjectMapper m = new ObjectMapper();
Map<String, String> map = new HashMap<String, String>() {{
put("fooName", "foo name");
put("bars1.barName", "bar at position 0 name");
put("bars1.barValue", "bar at position 0 value");
put("bars2.barName", "bar at position 1 name");
put("bars2.barValue", "bar at position 1 value");
}};
String json = m.writerWithDefaultPrettyPrinter().writeValueAsString(map);
Foo foo = m.readValue(json, Foo.class);
System.out.println("reserialized = " + m.writerWithDefaultPrettyPrinter().writeValueAsString(foo));
输出:
reserialized = {
"fooName" : "foo name",
"bars" : [ {
"barName" : "bar at position 0 name",
"barValue" : "bar at position 0 value"
}, {
"barName" : "bar at position 1 name",
"barValue" : "bar at position 1 value"
} ]
}
是否可以将这个HashMap转换为对应的Object?也许使用 Jackson Object Mapper、Gson,甚至是 Mapstruct。这里的技巧是如何映射 List 属性,在我的 INPUT 中有一个数字作为属性名称的后缀:
Map<String, String> map = new HashMap<String, String>() {{
put("fooName", "foo name");
put("bars1.barName", "bar at position 0 name");
put("bars1.barValue", "bar at position 0 value");
put("bars2.barName", "bar at position 1 name");
put("bars2.barValue", "bar at position 1 value");
}};
public class Foo {
String fooName;
List<Bar> bars;
// getters/setters
}
public class Bar {
String barName;
String barValue;
// getters/setters
}
PS: 此输入来自外部 API 调用,我无法修改源。
您可以使用中间哈希图进行转换。尝试下面的示例转换器。 备注:您可能希望为 Foo 和 Bar 使用适当的构造函数或使用 setter(为简单起见,我使用 public 字段)。而且没有错误处理。
static Foo convertMap(Map<String, String> map){
Foo foo = new Foo();
foo.fooName = map.remove("fooName");
Map<String, Bar> barsMap = new HashMap<String, Bar>();
for(String key : map.keySet()){
String[] split = key.split("\.");
String name = split[0];
String attribute = split[1];
Bar bar = null;
if(barsMap.containsKey(name)){
bar = barsMap.get(name);
}
else{
bar = new Bar();
barsMap.put(name, bar);
}
switch(attribute){
case "barName": bar.barName = map.get(key); break;
case "barValue": bar.barValue = map.get(key); break;
default: break;
}
}
foo.bars = new ArrayList(barsMap.values());
return foo;
}
您可以使用 @JsonAnySetter
注释以及 Bar 实例的映射:
public class Foo {
String fooName;
private Map<Integer, Bar> map = new TreeMap<>();
// getters/setters
public String getFooName() {
return fooName;
}
public void setFooName(String fooName) {
this.fooName = fooName;
}
public List<Bar> getBars() {
return map.values().stream().collect(Collectors.toList());
}
@JsonAnySetter
public void bars(String key, String value) {
String[] ids = key.split("\.");
if (ids[0].startsWith("bars")) {
Integer barKey = Integer.parseInt(ids[0].substring("bars".length())) - 1;
String field = ids[1];
Bar bar = map.computeIfAbsent(barKey, k -> new Bar());
if ("barName".equals(field)) {
bar.setBarName(value);
} else if ("barValue".equals(field)) {
bar.setBarValue(value);
}
map.put(barKey, bar);
} // else handle other properties
}
}
测试:
ObjectMapper m = new ObjectMapper();
Map<String, String> map = new HashMap<String, String>() {{
put("fooName", "foo name");
put("bars1.barName", "bar at position 0 name");
put("bars1.barValue", "bar at position 0 value");
put("bars2.barName", "bar at position 1 name");
put("bars2.barValue", "bar at position 1 value");
}};
String json = m.writerWithDefaultPrettyPrinter().writeValueAsString(map);
Foo foo = m.readValue(json, Foo.class);
System.out.println("reserialized = " + m.writerWithDefaultPrettyPrinter().writeValueAsString(foo));
输出:
reserialized = {
"fooName" : "foo name",
"bars" : [ {
"barName" : "bar at position 0 name",
"barValue" : "bar at position 0 value"
}, {
"barName" : "bar at position 1 name",
"barValue" : "bar at position 1 value"
} ]
}