Object in Object to HashMap with reflection
Object in Object to HashMap with reflection
项目:
我目前正在使用一个名为 Netuno 的工具来开发 api,因此要将对象导出到 json,必须将对象转换为HashMap,为此在父 class 中开发了一种方法来导出对象。
方法:
public Map<String, Object> export() {
Object obj = this;
Map<String, Object> map = new HashMap<>();
for (Field field : obj.getClass().getDeclaredFields()) {
field.setAccessible(true);
try {
map.put(field.getName(), field.get(obj));
} catch (Exception e) {
//todo e
}
}
return map;
}
这有效,但仅适用于简单对象。
我的问题:
如果对象在我的方法中有复杂的对象,它也无法将它们导出到 HashMap。
示例结构:
public abstract class Master {
public Map < String, Object >
export () {
Object obj = this;
Map < String, Object > map = new HashMap < > ();
for (Field field: obj.getClass().getDeclaredFields()) {
field.setAccessible(true);
try {
map.put(field.getName(), field.get(obj));
} catch (Exception e) {
//todo e
}
}
return map;
}
}
public class Foo extends Master {
private int a;
private int b;
private String c;
private Bar bar;
//...
}
public class Bar extends Master {
private int q;
private int w;
private String e;
//...
}
我是这样用的:
return new Bar(/*data*/).export();
输出:
{
"a": 2,
"b": 5,
"c": "abc",
"bar": "myproject.myPackage.Bar@XXXXX"
}
预期输出:
{
"a": 2,
"b": 5,
"c": "abc",
"bar": {
"q": 10,
"w": 15,
"e": "it works"
}
}
您需要决定一个值是应该直接放在地图中还是递归地放置。因此,您可以使用如下简单的方法:
private boolean isSimpleType(Class<?> type) {
return type.isPrimitive() ||
Boolean.class == type ||
Character.class == type ||
CharSequence.class.isAssignableFrom(type) ||
Number.class.isAssignableFrom(type) ||
Enum.class.isAssignableFrom(type);
}
此方法returns true
适用于所有原始类型或包装器对象、字符串和枚举。您可以简单地调整该方法以满足您的需要。有关如何确定 class 是否简单的更多详细信息,请查看 here。
现在您可以使用它来变换对象:
public Map<String, Object> convert(Object object) {
Map<String, Object> map = new HashMap<>();
for (Field field : object.getClass().getDeclaredFields()) {
field.setAccessible(true);
try {
if (isSimpleType(field.getType())) {
map.put(field.getName(), field.get(object));
} else {
map.put(field.getName(), convert(field.get(object)));
}
} catch (Exception e) {
e.printStackTrace();
}
}
return map;
}
您也可以根据您的 export
方法进行调整。
您的示例的结果将是这样的:
{a=2, b=5, bar={q=10, e=it works, w=15}, c=abc}
除此之外,我强烈建议使用一个库(如 Jackson),它已经完美地完成了类似的事情。这是使用 Jackson 的相同解决方案:
Map result = new ObjectMapper().convertValue(object, Map.class);
或者如果你需要类型安全:
ObjectMapper mapper = new ObjectMapper();
MapType mapType = mapper.getTypeFactory().constructMapType(Map.class, String.class, Object.class);
Map<String, Object> result = mapper.convertValue(value, mapType);
项目:
我目前正在使用一个名为 Netuno 的工具来开发 api,因此要将对象导出到 json,必须将对象转换为HashMap,为此在父 class 中开发了一种方法来导出对象。
方法: public Map<String, Object> export() {
Object obj = this;
Map<String, Object> map = new HashMap<>();
for (Field field : obj.getClass().getDeclaredFields()) {
field.setAccessible(true);
try {
map.put(field.getName(), field.get(obj));
} catch (Exception e) {
//todo e
}
}
return map;
}
这有效,但仅适用于简单对象。
我的问题:
如果对象在我的方法中有复杂的对象,它也无法将它们导出到 HashMap。
示例结构:
public abstract class Master {
public Map < String, Object >
export () {
Object obj = this;
Map < String, Object > map = new HashMap < > ();
for (Field field: obj.getClass().getDeclaredFields()) {
field.setAccessible(true);
try {
map.put(field.getName(), field.get(obj));
} catch (Exception e) {
//todo e
}
}
return map;
}
}
public class Foo extends Master {
private int a;
private int b;
private String c;
private Bar bar;
//...
}
public class Bar extends Master {
private int q;
private int w;
private String e;
//...
}
我是这样用的:
return new Bar(/*data*/).export();
输出:
{
"a": 2,
"b": 5,
"c": "abc",
"bar": "myproject.myPackage.Bar@XXXXX"
}
预期输出:
{
"a": 2,
"b": 5,
"c": "abc",
"bar": {
"q": 10,
"w": 15,
"e": "it works"
}
}
您需要决定一个值是应该直接放在地图中还是递归地放置。因此,您可以使用如下简单的方法:
private boolean isSimpleType(Class<?> type) {
return type.isPrimitive() ||
Boolean.class == type ||
Character.class == type ||
CharSequence.class.isAssignableFrom(type) ||
Number.class.isAssignableFrom(type) ||
Enum.class.isAssignableFrom(type);
}
此方法returns true
适用于所有原始类型或包装器对象、字符串和枚举。您可以简单地调整该方法以满足您的需要。有关如何确定 class 是否简单的更多详细信息,请查看 here。
现在您可以使用它来变换对象:
public Map<String, Object> convert(Object object) {
Map<String, Object> map = new HashMap<>();
for (Field field : object.getClass().getDeclaredFields()) {
field.setAccessible(true);
try {
if (isSimpleType(field.getType())) {
map.put(field.getName(), field.get(object));
} else {
map.put(field.getName(), convert(field.get(object)));
}
} catch (Exception e) {
e.printStackTrace();
}
}
return map;
}
您也可以根据您的 export
方法进行调整。
您的示例的结果将是这样的:
{a=2, b=5, bar={q=10, e=it works, w=15}, c=abc}
除此之外,我强烈建议使用一个库(如 Jackson),它已经完美地完成了类似的事情。这是使用 Jackson 的相同解决方案:
Map result = new ObjectMapper().convertValue(object, Map.class);
或者如果你需要类型安全:
ObjectMapper mapper = new ObjectMapper();
MapType mapType = mapper.getTypeFactory().constructMapType(Map.class, String.class, Object.class);
Map<String, Object> result = mapper.convertValue(value, mapType);