是否有BeanUtils.describe(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);

一些警告。
  • 我不确定BeanUtils如何格式化集合中的属性,因此我选择了“attribute [index]”。
  • 我不确定它如何格式化 map 中的属性,所以我选择了“attribute [key]”。
  • 对于名称冲突,优先级是这样的:首先,从 super 类的字段中加载属性,然后从类中加载,然后从getter方法中加载。
  • 我尚未分析此方法的性能。如果您的对象包含大量对象,这些对象也包含集合,则可能会有一些问题。
  • 这是Alpha代码,不保证没有bug。
  • 我假设您拥有最新版本的Commons beanutils

  • 另外,仅供引用,这大致取自我一直在从事的项目java in jails,因此您可以下载它然后运行:
    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);
            }
        }
    }
    

    关于java - 递归BeanUtils.describe(),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/6133660/

    10-12 03:11