转储Java对象的属性

是否有递归地转储/打印对象属性的库? 我正在寻找类似于Firebug中的console.dir()函数的东西。

我意识到commons-lang ReflectionToStringBuilder,但它不会递归到一个对象中。 即,如果我运行以下操作:

public class ToString {

    public static void main(String [] args) {
        System.out.println(ReflectionToStringBuilder.toString(new Outer(), ToStringStyle.MULTI_LINE_STYLE));
    }

    private static class Outer {
        private int intValue = 5;
        private Inner innerValue = new Inner();
    }

    private static class Inner {
        private String stringValue = "foo";
    }
}

我收到:

ToString $ Outer @ 1b67f74 [intValue = 5
innerValue = ToString $ Inner @ 530daa]

我意识到在我的例子中,我可以重写Inner的toString()方法,但在现实世界中,我正在处理我无法修改的外部对象。


你可以试试XStream。

XStream xstream = new XStream(new Sun14ReflectionProvider(
  new FieldDictionary(new ImmutableFieldKeySorter())),
  new DomDriver("utf-8"));
System.out.println(xstream.toXML(new Outer()));

打印出来:

<foo.ToString_-Outer>
  <intValue>5</intValue>
  <innerValue>
    <stringValue>foo</stringValue>
  </innerValue>
</foo.ToString_-Outer>

你也可以用JSON输出

并注意循环引用;)


我尝试使用XStream原来的建议,但事实证明,我想转储的对象图包括一个引用回到XStream marshaller本身,它并没有太热情(为什么它必须抛出一个异常,而不是忽略它或记录一个很好的警告,我不知道。)

然后我试用了上面user519500的代码,但发现我需要一些调整。 您可以将这个课程放入一个可以提供以下额外功能的项目中:

  • 可以控制最大递归深度
  • 可以限制数组元素的输出
  • 可以忽略任何类,字段或类+字段组合的列表 - 只需传递一个数组,其中包含类名称,以冒号分隔的类名+字段名对,或带冒号前缀的字段名,例如: [<classname>][:<fieldname>]
  • 不会输出两次相同的对象(输出指示何时先前访问过对象并提供相关性的哈希码) - 这可以避免导致问题的循环引用
  • 您可以使用以下两种方法之一调用它:

        String dump = Dumper.dump(myObject);
        String dump = Dumper.dump(myObject, maxDepth, maxArrayElements, ignoreList);
    

    如上所述,你需要注意堆栈溢出,所以使用最大递归深度设施来降低风险。

    希望有人会发现这有用!

    package com.mycompany.myproject;
    
    import java.lang.reflect.Array;
    import java.lang.reflect.Field;
    import java.util.HashMap;
    
    public class Dumper {
        private static Dumper instance = new Dumper();
    
        protected static Dumper getInstance() {
            return instance;
        }
    
        class DumpContext {
            int maxDepth = 0;
            int maxArrayElements = 0;
            int callCount = 0;
            HashMap<String, String> ignoreList = new HashMap<String, String>();
            HashMap<Object, Integer> visited = new HashMap<Object, Integer>();
        }
    
        public static String dump(Object o) {
            return dump(o, 0, 0, null);
        }
    
        public static String dump(Object o, int maxDepth, int maxArrayElements, String[] ignoreList) {
            DumpContext ctx = Dumper.getInstance().new DumpContext();
            ctx.maxDepth = maxDepth;
            ctx.maxArrayElements = maxArrayElements;
    
            if (ignoreList != null) {
                for (int i = 0; i < Array.getLength(ignoreList); i++) {
                    int colonIdx = ignoreList[i].indexOf(':');
                    if (colonIdx == -1)
                        ignoreList[i] = ignoreList[i] + ":";
                    ctx.ignoreList.put(ignoreList[i], ignoreList[i]);
                }
            }
    
            return dump(o, ctx);
        }
    
        protected static String dump(Object o, DumpContext ctx) {
            if (o == null) {
                return "<null>";
            }
    
            ctx.callCount++;
            StringBuffer tabs = new StringBuffer();
            for (int k = 0; k < ctx.callCount; k++) {
                tabs.append("t");
            }
            StringBuffer buffer = new StringBuffer();
            Class oClass = o.getClass();
    
            String oSimpleName = getSimpleNameWithoutArrayQualifier(oClass);
    
            if (ctx.ignoreList.get(oSimpleName + ":") != null)
                return "<Ignored>";
    
            if (oClass.isArray()) {
                buffer.append("n");
                buffer.append(tabs.toString().substring(1));
                buffer.append("[n");
                int rowCount = ctx.maxArrayElements == 0 ? Array.getLength(o) : Math.min(ctx.maxArrayElements, Array.getLength(o));
                for (int i = 0; i < rowCount; i++) {
                    buffer.append(tabs.toString());
                    try {
                        Object value = Array.get(o, i);
                        buffer.append(dumpValue(value, ctx));
                    } catch (Exception e) {
                        buffer.append(e.getMessage());
                    }
                    if (i < Array.getLength(o) - 1)
                        buffer.append(",");
                    buffer.append("n");
                }
                if (rowCount < Array.getLength(o)) {
                    buffer.append(tabs.toString());
                    buffer.append(Array.getLength(o) - rowCount + " more array elements...");
                    buffer.append("n");
                }
                buffer.append(tabs.toString().substring(1));
                buffer.append("]");
            } else {
                buffer.append("n");
                buffer.append(tabs.toString().substring(1));
                buffer.append("{n");
                buffer.append(tabs.toString());
                buffer.append("hashCode: " + o.hashCode());
                buffer.append("n");
                while (oClass != null && oClass != Object.class) {
                    Field[] fields = oClass.getDeclaredFields();
    
                    if (ctx.ignoreList.get(oClass.getSimpleName()) == null) {
                        if (oClass != o.getClass()) {
                            buffer.append(tabs.toString().substring(1));
                            buffer.append("  Inherited from superclass " + oSimpleName + ":n");
                        }
    
                        for (int i = 0; i < fields.length; i++) {
    
                            String fSimpleName = getSimpleNameWithoutArrayQualifier(fields[i].getType());
                            String fName = fields[i].getName();
    
                            fields[i].setAccessible(true);
                            buffer.append(tabs.toString());
                            buffer.append(fName + "(" + fSimpleName + ")");
                            buffer.append("=");
    
                            if (ctx.ignoreList.get(":" + fName) == null &&
                                ctx.ignoreList.get(fSimpleName + ":" + fName) == null &&
                                ctx.ignoreList.get(fSimpleName + ":") == null) {
    
                                try {
                                    Object value = fields[i].get(o);
                                    buffer.append(dumpValue(value, ctx));
                                } catch (Exception e) {
                                    buffer.append(e.getMessage());
                                }
                                buffer.append("n");
                            }
                            else {
                                buffer.append("<Ignored>");
                                buffer.append("n");
                            }
                        }
                        oClass = oClass.getSuperclass();
                        oSimpleName = oClass.getSimpleName();
                    }
                    else {
                        oClass = null;
                        oSimpleName = "";
                    }
                }
                buffer.append(tabs.toString().substring(1));
                buffer.append("}");
            }
            ctx.callCount--;
            return buffer.toString();
        }
    
        protected static String dumpValue(Object value, DumpContext ctx) {
            if (value == null) {
                return "<null>";
            }
            if (value.getClass().isPrimitive() ||
                value.getClass() == java.lang.Short.class ||
                value.getClass() == java.lang.Long.class ||
                value.getClass() == java.lang.String.class ||
                value.getClass() == java.lang.Integer.class ||
                value.getClass() == java.lang.Float.class ||
                value.getClass() == java.lang.Byte.class ||
                value.getClass() == java.lang.Character.class ||
                value.getClass() == java.lang.Double.class ||
                value.getClass() == java.lang.Boolean.class ||
                value.getClass() == java.util.Date.class ||
                value.getClass().isEnum()) {
    
                return value.toString();
    
            } else {
    
                Integer visitedIndex = ctx.visited.get(value);
                if (visitedIndex == null) {
                    ctx.visited.put(value, ctx.callCount);
                    if (ctx.maxDepth == 0 || ctx.callCount < ctx.maxDepth) {
                        return dump(value, ctx);
                    }
                    else {
                        return "<Reached max recursion depth>";
                    }
                }
                else {
                    return "<Previously visited - see hashCode " + value.hashCode() + ">";
                }
            }
        }
    
    
        private static String getSimpleNameWithoutArrayQualifier(Class clazz) {
            String simpleName = clazz.getSimpleName();
            int indexOfBracket = simpleName.indexOf('['); 
            if (indexOfBracket != -1)
                return simpleName.substring(0, indexOfBracket);
            return simpleName;
        }
    }
    

    您可以使用ReflectionToStringBuilder和自定义的ToStringStyle,例如:

    class MyStyle extends ToStringStyle {
        private final static ToStringStyle instance = new MyStyle();
    
        public MyStyle() {
            setArrayContentDetail(true);
            setUseShortClassName(true);
            setUseClassName(false);
            setUseIdentityHashCode(false);
            setFieldSeparator(", " + SystemUtils.LINE_SEPARATOR + "  ");
        }
    
        public static ToStringStyle getInstance() {
            return instance;
        };
    
        @Override
        public void appendDetail(StringBuffer buffer, String fieldName, Object value) {
            if (!value.getClass().getName().startsWith("java")) {
                buffer.append(ReflectionToStringBuilder.toString(value, instance));
            } else {
                super.appendDetail(buffer, fieldName, value);
            }
        }
    
        @Override
        public void appendDetail(StringBuffer buffer, String fieldName, Collection value) {
            appendDetail(buffer, fieldName, value.toArray());
        }
    }
    

    然后你像这样调用它:

    ReflectionToStringBuilder.toString(value, MyStyle.getInstance());
    

    尽管谨防循环引用!


    你也可以使用json-lib(http://json-lib.sourceforge.net),只需要:

    JSONObject.fromObject(value);
    
    链接地址: http://www.djcxy.com/p/47629.html

    上一篇: Dumping a java object's properties

    下一篇: How can incoming calls be answered programmatically in Android 5.0 (Lollipop)?