测试空 Java 对象图的 Commons 方法?

发布于 2024-10-26 09:36:29 字数 521 浏览 6 评论 0原文

我发现自己正在编写这样的方法:

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);
}

I've found myself writing a method like this:

boolean isEmpty(MyStruct myStruct) {
  return (myStruct.getStringA() == null || myStruct.getStringA().isEmpty())
    && (myStruct.getListB() == null || myStruct.getListB().isEmpty());
}

And then imagine this struct with lots of other properties and other nested lists, and you can imagine that this method gets very big and is tightly coupled to the data model.

Does Apache Commons, or Spring, or some other FOSS utility have the ability to recursively reflectively walk an object graph and determine that it's basically devoid of any useful data, other than the holders for Lists, Arrays, Maps, and such? So that I can just write:

boolean isEmpty(MyStruct myStruct) {
  return MagicUtility.isObjectEmpty(myStruct);
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

兮子 2024-11-02 09:36:29

感谢 Vladimir 为我指明了正确的方向(我给了你一个赞成票!)虽然我的解决方案使用 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);
      }
    }
  }

}

Thanks to Vladimir for pointing me in the right direction (I gave you an upvote!) although my solution uses PropertyUtils rather than BeanUtils

I did have to implement it but it wasn't hard. Here's the solution. I only did it for Strings and Lists since that's all I happen to have at the moment. Could be extended for Maps and Arrays.

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);
      }
    }
  }

}
深海夜未眠 2024-11-02 09:36:29

您可以将 Appache Common StringUtils.isEmpty() 方法与 BeanUtils.getProperties() 结合起来。

you can combine Appache Common StringUtils.isEmpty() method with BeanUtils.getProperties().

唯憾梦倾城 2024-11-02 09:36:29

嘿凯文,还没有看到类似你要求的方法(我自己也对此感兴趣),但是,你是否考虑过使用反射在运行时查询你的对象?

Hey Kevin, Haven't seen anything like the method you asked for (interested in it myself as well), however, have you considered using reflection to query your object on runtime?

猫腻 2024-11-02 09:36:29

我不知道有哪个库可以做到这一点,但是使用反射,自己实现并不难。
您可以轻松地循环类的 getter 方法并决定实例是否设置了值,您可以根据 getter 的返回类型进一步决定结果。

困难的部分是定义您认为类中的哪些成员是“有用的数据”。仅仅忽略列表、映射和数组可能不会让你走得太远。

我实际上会考虑编写自己的注释类型,以便“标记”适当的“有用”成员(然后可以由反射代码注意到并处理)。我不知道这是否是解决您的问题的优雅方法,因为我不知道有多少类受到影响。

I don't know a library that does this, but using reflection, it is not too hard to implement by yourself.
You can easily loop over getter methods of a class and decide whether the instance has a value set, you can further decide the outcome depending on the getter's return type.

The hard part is to define which members of a class you consider being "useful data". Just leaving out Lists, Maps and Arrays probably won't get you far.

I would actually consider writing your own Annotation type in order to "mark" the appropiate "useful" members (which could then be noticed+handled by the reflection code). I don't know if this is an elegant approach to your problem, since I don't know how many classes are affected.

孤凫 2024-11-02 09:36:29

我真的无法想象整个对象图中完全没有任何内容的东西会进入应用程序的情况。此外,到底什么才算是“空”呢?那只是指字符串和集合吗?仅包含空格的字符串会计数吗?那么数字呢……任何数字都会使对象非空,还是像 -1 这样的特定数字会被视为空?作为另一个问题,知道对象中是否没有内容通常似乎没有用......通常您需要确保特定字段具有特定数据等。有太多的可能性在我看来,像这样的通用方法是有意义的。

也许像 JSR-303 这样更完整的验证系统会更好。其参考实现是 Hibernate Validator

I can't really imagine a situation where something completely devoid of any content in a whole object graph would get in to an application. Furthermore, what exactly would be considered "empty"? Would that just refer to strings and collections? Would a string with only whitespace count? What about numbers... would any number make the object non-empty, or would specific numbers like -1 count as empty? As yet another issue, it doesn't seem like it'd generally be useful to know if there is NO content in an object... typically you need to ensure that specific fields have specific data, etc. There are too many possibilities for some general method like this to make sense, in my opinion.

Maybe a more complete validation system like JSR-303 would work better. The reference implementation for that is Hibernate Validator.

嗫嚅 2024-11-02 09:36:29

尽管上述实用方法都不能通用。 (据我所知)唯一的方法是与空对象进行比较。创建对象的实例(未设置属性)并使用“.equals”方法进行比较。确保对于 2 个相等的非空对象和 2 个相等的非空对象, equals 正确实现为 true 。对于 2 个空对象为 true。

Although none of the above utility methods can be generic. The only way (to my knowledge) is to compare with a empty object. Create a instance of the object (with no properties set) and use ".equals" method to compare. Make sure that equals is properly implemented to true for 2 equal non empty objects & true for 2 empty objects.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文