Метод 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 пустых объектов.