在做一个hadoop的editlog查看工具,由于editlog都是用dataoutputStream输出的,在载入这类文件需要完全相反的方向DatainputStream先转换成对应的类,这个非常麻烦。特别是有部分类的成员是private的,也没有提供get方法,如何方便打印这些信息。想到只有用终极武器反射来完成这样的使命,以下就是我写的可以完全遍历对象树并将对象用json格式打印处理的code。
public class ObjectViewer {
public ObjectViewer() {
}
@SuppressWarnings("rawtypes")
private void fetchAllFields(Class c, List<Field> fields) {
assert fields != null;
if (c == Object.class || c.isPrimitive() || c.isArray() || c == String.class) {
return;
} else {
fetchAllFields(c.getSuperclass(), fields);
for (Field field : c.getDeclaredFields()) {
field.setAccessible(true);
fields.add(field);
}
}
}
private StringBuilder buildPrimitiveField(Field field, Object instance,
StringBuilder builder) throws IllegalArgumentException,
IllegalAccessException {
assert field.getType().isPrimitive();
Object v = field.get(instance);
if(v == null){
return builder;
}
return builder.append(field.getName() + ":" + v);
}
private StringBuilder buildStringField(Field field, Object instance,
StringBuilder builder) throws IllegalArgumentException,
IllegalAccessException {
assert field.getType() == String.class;
Object v = field.get(instance);
if(v == null){
return builder;
}
return builder.append(field.getName() + ":\"" + v + "\"");
}
private StringBuilder buildArrayField(Field field, Object instance,
StringBuilder builder) throws Exception{
assert field.getType().isArray();
Object v = field.get(instance);
if(v == null){
return builder;
}
builder.append(field.getName());
builder.append(":[");
boolean isFirst = true;
for (int i = 0; i < Array.getLength(v); i++) {
if(!isFirst){
builder.append(',');
}else{
isFirst = false;
}
buildObject(Array.get(v, i),builder);
}
builder.append(']');
return builder;
}
private StringBuilder buildClassField(Field field, Object instance,
StringBuilder builder) throws Exception {
assert !(field.getType().isPrimitive()
|| field.getType() == String.class || field.getType().isArray());
Object v = field.get(instance);
if(v == null){
return builder;
}
buildObject(v,builder);
return builder;
}
@SuppressWarnings("rawtypes")
public StringBuilder buildObject(Object obj, StringBuilder builder){
try{
Class objClazz = obj.getClass();
if(objClazz.isPrimitive() || objClazz == String.class || obj instanceof Number){
return builder.append("" + obj);
}
List<Field> allFields = new ArrayList<Field>();
fetchAllFields(obj.getClass(), allFields);
builder.append('{');
boolean isFirst = true;
for (Field field : allFields) {
if(!isFirst){
builder.append(',');
}else{
isFirst = false;
}
Class type = field.getType();
if (type.isPrimitive()) {
buildPrimitiveField(field, obj, builder);
} else if (type == String.class) {
buildStringField(field, obj, builder);
} else if (type.isArray()) {
buildArrayField(field, obj, builder);
} else {
buildClassField(field, obj, builder);
}
}
builder.append('}');
return builder;
}catch (Exception e) {
e.printStackTrace();
return builder;
}
}
public static void main(String[] args) throws Exception{
// System.out.println(Integer.class.isPrimitive());
ObjectViewer objviever = new ObjectViewer();
System.out.println(objviever.buildObject(objviever,new StringBuilder()).toString());
// System.out.println(objviever.buildObject(new ArrayObj()));
}
}
使用方法非常简单,扔个对象进去,不管他有多复杂的结构,都会把对象的所有属性打印出来。