Java – recursive BeanUtils describe()
Is there a version of BeanUtils Describe (customer) recursively calls the describe () method to the complex attribute of 'customer'
class Customer { String id; Address address; }
Here, I want to use the describe method to retrieve the contents of the address attribute
At present, I can see the name of the class as follows:
{id=123,address=com.test.entities.Address@2a340e}
Solution
Interestingly, I want to use the describe method to retrieve the contents of nested attributes, and I don't understand why not I moved on and rolled over myself Here, you can call:
Map<String,String> beanMap = BeanUtils.recursiveDescribe(customer);
Some warnings
>I don't know how to use BeanUtils format attributes in the collection, so I use "attribute [index]". > I don't know how to format attributes in the map, so I use "attribute [key]. > For name conflicts, the priority is as follows: the first attribute is from the field of the super class, then the class, and then loaded from the getter method. > I did not analyze the performance of this method If an object that contains a large number of collections also contains collections, there may be some problems. > This is alpha code, not free. > I assume you have the latest version of Commons beautils
In addition, FYI, this is probably from a project I have been working on. Affectionately, Java in sails, so you can download it and run it:
Map<String,String[]> beanMap = new SimpleMapper().toMap(customer);
Although, you will notice that it returns a string [] instead of a string, which may not meet your needs Anyway, the following code should work, so there is it!
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),cache)); } else if (Map.class.isAssignableFrom(value.getClass())) { beanMap.putAll(convertMap((Map) value,cache)); } else { beanMap.putAll(convertObject(value,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>(); 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>(); 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,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); } } }