当前位置: 首页 > 面试题库 >

递归BeanUtils.describe()

微生令
2023-03-14
问题内容

是否存在BeanUtils.describe(customer)的版本,该版本递归调用“
customer”的复杂属性的describe()方法。

class Customer {

String id;
Address address;

}

在这里,我希望describe方法也能检索address属性的内容。

目前,我所能看到的类名称如下:

{id=123, address=com.test.entities.Address@2a340e}

问题答案:

有趣的是,我也想使用describe方法来检索嵌套属性的内容,我不明白为什么不这样做。不过,我继续前进并推出了自己的游戏。在这里,您可以致电:

Map<String,String> beanMap = BeanUtils.recursiveDescribe(customer);

一些警告。

  1. 我不确定BeanUtils的通用格式如何格式化集合中的属性,因此我选择了“ attribute [index]”。
  2. 我不确定它如何格式化地图中的属性,所以我选择了“ attribute [key]”。
  3. 对于名称冲突,优先级是这样的:首先,从超级类的字段中加载属性,然后从类中加载,然后从getter方法中加载。
  4. 我还没有分析这种方法的性能。如果您的对象包含大量对象,这些对象也包含集合,则可能会有一些问题。
  5. 这是Alpha代码,不保证没有bug。
  6. 我假设您具有最新版本的commons beanutils

另外,仅供参考,这大致取自我一直在从事的一个项目,该项目被亲切地称为“
监狱中的java”,因此您可以下载它然后运行:

Map<String, String[]> beanMap = new SimpleMapper().toMap(customer);

不过,您会注意到它返回的是String [],而不是String,这可能无法满足您的需求。无论如何,下面的代码应该可以正常工作,敬请期待!

public class BeanUtils {
    public static Map<String, String> recursiveDescribe(Object object) {
        Set cache = new HashSet();
        return recursiveDescribe(object, null, cache);
    }

    private static Map<String, String> recursiveDescribe(Object object, String prefix, Set cache) {
        if (object == null || cache.contains(object)) return Collections.EMPTY_MAP;
        cache.add(object);
        prefix = (prefix != null) ? prefix + "." : "";

        Map<String, String> beanMap = new TreeMap<String, String>();

        Map<String, Object> properties = getProperties(object);
        for (String property : properties.keySet()) {
            Object value = properties.get(property);
            try {
                if (value == null) {
                    //ignore nulls
                } else if (Collection.class.isAssignableFrom(value.getClass())) {
                    beanMap.putAll(convertAll((Collection) value, prefix + property, cache));
                } else if (value.getClass().isArray()) {
                    beanMap.putAll(convertAll(Arrays.asList((Object[]) value), prefix + property, cache));
                } else if (Map.class.isAssignableFrom(value.getClass())) {
                    beanMap.putAll(convertMap((Map) value, prefix + property, cache));
                } else {
                    beanMap.putAll(convertObject(value, prefix + property, cache));
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return beanMap;
    }

    private static Map<String, Object> getProperties(Object object) {
        Map<String, Object> propertyMap = getFields(object);
        //getters take precedence in case of any name collisions
        propertyMap.putAll(getGetterMethods(object));
        return propertyMap;
    }

    private static Map<String, Object> getGetterMethods(Object object) {
        Map<String, Object> result = new HashMap<String, Object>();
        BeanInfo info;
        try {
            info = Introspector.getBeanInfo(object.getClass());
            for (PropertyDescriptor pd : info.getPropertyDescriptors()) {
                Method reader = pd.getReadMethod();
                if (reader != null) {
                    String name = pd.getName();
                    if (!"class".equals(name)) {
                        try {
                            Object value = reader.invoke(object);
                            result.put(name, value);
                        } catch (Exception e) {
                            //you can choose to do something here
                        }
                    }
                }
            }
        } catch (IntrospectionException e) {
            //you can choose to do something here
        } finally {
            return result;
        }

    }

    private static Map<String, Object> getFields(Object object) {
        return getFields(object, object.getClass());
    }

    private static Map<String, Object> getFields(Object object, Class<?> classType) {
        Map<String, Object> result = new HashMap<String, Object>();

        Class superClass = classType.getSuperclass();
        if (superClass != null) result.putAll(getFields(object, superClass));

        //get public fields only
        Field[] fields = classType.getFields();
        for (Field field : fields) {
            try {
                result.put(field.getName(), field.get(object));
            } catch (IllegalAccessException e) {
                //you can choose to do something here
            }
        }
        return result;
    }

    private static Map<String, String> convertAll(Collection<Object> values, String key, Set cache) {
        Map<String, String> valuesMap = new HashMap<String, String>();
        Object[] valArray = values.toArray();
        for (int i = 0; i < valArray.length; i++) {
            Object value = valArray[i];
            if (value != null) valuesMap.putAll(convertObject(value, key + "[" + i + "]", cache));
        }
        return valuesMap;
    }

    private static Map<String, String> convertMap(Map<Object, Object> values, String key, Set cache) {
        Map<String, String> valuesMap = new HashMap<String, String>();
        for (Object thisKey : values.keySet()) {
            Object value = values.get(thisKey);
            if (value != null) valuesMap.putAll(convertObject(value, key + "[" + thisKey + "]", cache));
        }
        return valuesMap;
    }

    private static ConvertUtilsBean converter = BeanUtilsBean.getInstance().getConvertUtils();

    private static Map<String, String> convertObject(Object value, String key, Set cache) {
        //if this type has a registered converted, then get the string and return
        if (converter.lookup(value.getClass()) != null) {
            String stringValue = converter.convert(value);
            Map<String, String> valueMap = new HashMap<String, String>();
            valueMap.put(key, stringValue);
            return valueMap;
        } else {
            //otherwise, treat it as a nested bean that needs to be described itself
            return recursiveDescribe(value, key, cache);
        }
    }
}


 类似资料:
  • 我对函数式编程很陌生,尤其是下面使用的Scheme。我正在尝试使以下函数是递归的,尾递归的。基本上,该函数的作用是对两个字符串的对齐方式进行评分。当给定两个字符串作为输入时,它会比较每个“列”字符,并根据在称为 scorer 的函数中实现的评分方案(由下面的代码中的函数调用)来累积该对齐的分数。 我有一个想法,用一个帮助函数来累积分数,但我不太确定如何去做,因此我该如何让下面的函数尾递归呢?

  • 5.2. 递归 函数可以是递归的,这意味着函数可以直接或间接的调用自身。对许多问题而言,递归是一种强有力的技术,例如处理递归的数据结构。在4.4节,我们通过遍历二叉树来实现简单的插入排序,在本章节,我们再次使用它来处理HTML文件。 下文的示例代码使用了非标准包 golang.org/x/net/html ,解析HTML。golang.org/x/... 目录下存储了一些由Go团队设计、维护,对网

  • 递归允许函数调用自身。 固定的代码步骤一次又一次地执行新值。 我们还必须设置标准来决定递归调用何时结束。 在下面的例子中,我们看到了二进制搜索的递归方法。 我们采用排序列表并将其索引范围作为递归函数的输入。 使用递归进行二进制搜索 我们使用python实现二进制搜索算法,如下所示。 我们使用一个有序的项目列表,并设计一个递归函数,以带有开始和结束索引作为输入的列表。 然后二进制搜索函数调用自己直到

  • 递归过程就是自称过程。 有两种递归:直接和间接。 在直接递归中,过程调用自身并在间接递归中,第一个过程调用第二个过程,该过程又调用第一个过程。 可以在许多数学算法中观察到递归。 例如,考虑计算数字的阶乘的情况。 一个数的因子由等式给出 - Fact (n) = n * fact (n-1) for n > 0 例如:5的阶乘是1 x 2 x 3 x 4 x 5 = 5 x阶乘4,这可以是显示递归

  • 我们在前面的主题中看到了recur语句,而'for'循环有点像循环, recur是Clojure中的一个真正的循环。 如果你有编程背景,你可能听说过尾递归,这是函数式语言的一个主要特性。 这种复现特殊形式是实现尾递归的形式。 正如单词“tail recursion”所示,必须在尾部位置调用recur。 换句话说,复发必须是最后评估的东西。 最简单的recur语句示例在'for'循环中使用。 在以下

  • 递归是以自相似的方式重复项目的过程。 在编程语言中,如果程序允许您在同一函数内调用函数,则称其为函数的递归调用。 void recursion() { recursion(); /* function calls itself */ } int main() { recursion(); } C编程语言支持递归,即调用自身的函数。 但是在使用递归时,程序员需要小心地从函数中定义退出条