Ste*_*ers 10 java eclipse reflection recursion eclipse-plugin
给定一个Java类,我希望能够列出在所有祖先中公开的所有属性,并public以相同的方式递归遍历所有公开的属性(即或使用getter/setter).
用一个简单的例子更容易解释:
public class BaseClass1 {
private int intProperty; // has getter and setter (not shown)
}
public class SubClass1 extends BaseClass1 {
private int privateSoNotListed;
public SubClass2 subClass2Property;
}
public class BaseClass2 {
public String stringProperty;
}
public class SubClass2 extends BaseClass2 {
private long longProperty; // has getter and setter (not shown)
}
Run Code Online (Sandbox Code Playgroud)
鉴于SubClass1上面的输入,输出会是这样的:
intProperty - int [from BaseClass1]
subClass2Property.stringProperty - String [from BaseClass2]
subClass2Property.longProperty - long [from SubClass2]
Run Code Online (Sandbox Code Playgroud)
应该可以使用一些巧妙的反射来写这样的东西,但我宁愿不重新发明轮子 - 是否有现成的工具可以做到这一点(也许是一个Eclipse插件?)
编辑: Eclipse的类型层次结构可以很好地显示单个类的属性 - 在我看来,理想的解决方案是,如果这是一个树视图(类似于包资源管理器),能够扩展自身类的属性.
另请参阅重复的Recursive BeanUtils.describe(),它也可以递归工作.以下是我们使用的自定义版本(登录log4j记录器):
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import org.apache.commons.beanutils.BeanUtilsBean;
import org.apache.commons.beanutils.ConvertUtilsBean;
import org.apache.log4j.Logger;
/*
* See the original version: https://stackoverflow.com/questions/6133660/recursive-beanutils-describe
*/
public class Inspector {
public static void recursivelyDescribeAndLog(Object ob, Logger log){
log.info(ob.getClass());
try {
Map<String, String> props = recursiveDescribe(ob);
for (Map.Entry<String, String> p : props.entrySet()) {
log.info(" -> " + p.getKey() + "="+p.getValue());
}
} catch (Throwable e) {
log.error(e.getMessage(), e);
}
}
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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
刚刚找到了一种有用的方法来实现与最初通过 Eclipse 的类型层次结构提出的要求非常相似的东西。
有一个名为“显示所有继承成员”的切换开关,如下图红色箭头所示:
选择此选项后,除了所选类的字段和方法之外,还会显示所有超类的字段和方法(清楚地指示每个超类的字段和方法来自何处),如下所示:
(当然,这不仅仅包括属性,但由于 getter 按字母顺序显示,并且有公共/私有/受保护的图标,因此可以使用它轻松获取此信息。)
| 归档时间: |
|
| 查看次数: |
7208 次 |
| 最近记录: |