В настоящее время я использую инструмент под названием Нетуно для разработки API, поэтому для экспорта объектов в json необходимо выполнить преобразование объекта в HashMap, для этого в родительском классе был разработан метод для экспорта объекта.
The method: 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"
}
}
Вы можете добавить условие, если field.get(obj) является экземпляром Master cast to master и поместить результат метода экспорта карты, но, как отметил Марк, существуют библиотеки с этой функциональностью.
@Mark Спасибо за библиотеки :), но я старался не использовать их, чтобы не нарушать стандарт моего фреймворка.
Вам нужно решить, должно ли значение быть указано на карте просто или рекурсивно. Поэтому вы можете использовать простой метод, подобный этому:
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);
}
Этот метод возвращает true
для всех примитивных типов или объектов-оболочек, строк и перечислений. Вы можете просто настроить эти методы в соответствии с вашими потребностями. Подробнее о том, как определить, является ли класс простым, см. здесь.
Теперь вы можете использовать для преобразования объекта:
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}
Кроме того, я бы настоятельно рекомендовал использовать библиотеку (например, Джексон), которая уже делает подобные вещи в совершенстве. Вот то же решение с использованием Джексона:
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);
Существуют библиотеки, которые также дадут вам желаемый результат (сериализация объекта в JSON/десериализация JSON в объект), например, Gson/Jackson/много других, может быть, что-то посмотреть?