Метод Commons для проверки пустого графа объектов Java?
Я обнаружил, что пишу такой метод:
boolean isEmpty(MyStruct myStruct) {
return (myStruct.getStringA() == null || myStruct.getStringA().isEmpty())
&& (myStruct.getListB() == null || myStruct.getListB().isEmpty());
}
И затем представьте эту структуру с множеством других свойств и других вложенных списков, и вы можете себе представить, что этот метод становится очень большим и тесно связан с моделью данных.
Может ли Apache Commons или Spring или какая-либо другая утилита FOSS иметь возможность рекурсивно отражать график объектов и определять, что в основном они лишены каких-либо полезных данных, кроме держателей для списков, массивов, карт и такие? Чтобы я мог просто написать:
boolean isEmpty(MyStruct myStruct) {
return MagicUtility.isObjectEmpty(myStruct);
}
Ответы
Ответ 1
Спасибо Владимиру за то, что он указал мне в правильном направлении (я дал вам возвышение!), хотя мое решение использует PropertyUtils
, а не BeanUtils
Мне нужно было это реализовать, но это было не сложно. Здесь решение. Я делал это только для строк и списков, так как все, что у меня есть в настоящий момент. Может быть расширен для карт и массивов.
import java.lang.reflect.InvocationTargetException;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang.StringUtils;
public class ObjectUtils {
/**
* Tests an object for logical emptiness. An object is considered logically empty if its public gettable property
* values are all either null, empty Strings or Strings with just whitespace, or lists that are either empty or
* contain only other logically empty objects. Currently does not handle Maps or Arrays, just Lists.
*
* @param object
* the Object to test
* @return whether object is logically empty
*
* @author Kevin Pauli
*/
@SuppressWarnings("unchecked")
public static boolean isObjectEmpty(Object object) {
// null
if (object == null) {
return true;
}
// String
else if (object instanceof String) {
return StringUtils.isEmpty(StringUtils.trim((String) object));
}
// List
else if (object instanceof List) {
boolean allEntriesStillEmpty = true;
final Iterator<Object> iter = ((List) object).iterator();
while (allEntriesStillEmpty && iter.hasNext()) {
final Object listEntry = iter.next();
allEntriesStillEmpty = isObjectEmpty(listEntry);
}
return allEntriesStillEmpty;
}
// arbitrary Object
else {
try {
boolean allPropertiesStillEmpty = true;
final Map<String, Object> properties = PropertyUtils.describe(object);
final Iterator<Entry<String, Object>> iter = properties.entrySet().iterator();
while (allPropertiesStillEmpty && iter.hasNext()) {
final Entry<String, Object> entry = iter.next();
final String key = entry.getKey();
final Object value = entry.getValue();
// ignore the getClass() property
if ("class".equals(key))
continue;
allPropertiesStillEmpty = isObjectEmpty(value);
}
return allPropertiesStillEmpty;
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
}
}
Ответ 2
вы можете комбинировать метод Appache Common StringUtils.isEmpty()
с BeanUtils.getProperties()
.
Ответ 3
Эй Кевин, не видел ничего подобного методу, который вы просили (он тоже заинтересован в нем), однако вы считали, что используете рефлексию для запроса своего объекта во время выполнения?
Ответ 4
Я не знаю библиотеку, которая делает это, но используя рефлексию, ее не слишком сложно реализовать самостоятельно.
Вы можете легко перебрать методы getter класса и решить, имеет ли экземпляр значение, установленное, вы также можете решить результат в зависимости от типа возвращаемого результата.
Жесткая часть состоит в том, чтобы определить, какие члены класса вы считаете "полезными данными". Просто оставляя списки, карты и массивы, вероятно, не заставит вас далеко.
Я бы на самом деле подумал о написании собственного типа аннотации, чтобы "отметить" подходящих "полезных" членов (которые затем можно было бы заметить + обрабатывать кодом отражения). Я не знаю, является ли это изящным подходом к вашей проблеме, поскольку я не знаю, сколько классов затронуто.
Ответ 5
Я не могу себе представить ситуацию, когда что-то совершенно лишенное какого-либо контента на всем объектном графе, попадет в приложение. Кроме того, что именно будет считаться "пустым"? Будет ли это просто ссылаться на строки и коллекции? Будет ли строка с только пробелами? Что относительно чисел... может ли любое число сделать объект непустым, или конкретные числа, как -1, считаются пустыми? Как еще одна проблема, похоже, что было бы полезно знать, нет ли в объекте NO контента... обычно вам нужно убедиться, что определенные поля имеют конкретные данные и т.д. Существует слишком много возможностей для какой-то общий метод, как это, имеет смысл, на мой взгляд.
Возможно, более эффективная система проверки, например JSR-303, будет работать лучше. Эталонная реализация для этого Hibernate Validator.
Ответ 6
Хотя ни один из приведенных выше методов утилиты не может быть общим. Единственный способ (насколько мне известно) сравнить с пустым объектом. Создайте экземпляр объекта (без набора свойств) и используйте метод ".equals" для сравнения. Убедитесь, что equals правильно реализовано в true для 2 равных непустых объектов и true для 2 пустых объектов.