سؤال

هل هناك المكتبة التي سوف متكرر تفريغ/طباعة الكائنات خصائص ؟ أنا أبحث عن شيء مشابه وحدة التحكم.dir() وظيفة في الحرائق.

أنا على علم العموم لانج ReflectionToStringBuilder ولكن هذا لا recurse إلى كائن.I. e., إذا قمت بتشغيل التالية:

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$الخارجي@1b67f74[ intValue=5
innerValue=ToString$الداخلية@530daa ]

وأنا أدرك أن في بلدي على سبيل المثال ، يمكن أن تنقضها أسلوب 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 أزواج فصل مع القولون ، أو fieldnames مع القولون البادئة أي: [<classname>][:<fieldname>]
  • لن الناتج من نفس الكائن مرتين (الإخراج يشير إلى كائن كان سابقا زار ويوفر hashcode عن الارتباط) - هذا يتجنب المراجع الدائرية مما تسبب في مشاكل

يمكنك استدعاء هذه باستخدام إحدى الطريقتين أدناه:

    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());

وحذار من المراجع الدائرية على الرغم من!


ويمكنك أيضا استخدام سلمان-ليب ( http://json-lib.sourceforge.net ) ومجرد القيام:

JSONObject.fromObject(value);

وهذا سوف طباعة كافة المجالات (بما في ذلك صفائف الكائنات) من كائن.

والنسخة الثابتة من آخر بن وليامز من هذا الموضوع

ملحوظة: يستخدم هذا الأسلوب العودية حتى إذا كان لديك رسم بياني الكائن عميق جدا قد تحصل على كومة تجاوز (لا يقصد التورية؛) IF لذلك تحتاج إلى استخدام المعلمة -Xss10m VM. إذا وضعت باستخدام الكسوف بك في المدى> runconfiguration> تقوي (علامة التبويب) VM مربع زيادة واضغط على تطبيق

import java.lang.reflect.Array;
import java.lang.reflect.Field;

public static String dump(Object o) {
    StringBuffer buffer = new StringBuffer();
    Class oClass = o.getClass();
     if (oClass.isArray()) {
         buffer.append("Array: ");
        buffer.append("[");
        for (int i = 0; i < Array.getLength(o); i++) {
            Object value = Array.get(o, i);
            if (value.getClass().isPrimitive() ||
                    value.getClass() == java.lang.Long.class ||
                    value.getClass() == java.lang.Integer.class ||
                    value.getClass() == java.lang.Boolean.class ||
                    value.getClass() == java.lang.String.class ||
                    value.getClass() == java.lang.Double.class ||
                    value.getClass() == java.lang.Short.class ||
                    value.getClass() == java.lang.Byte.class
                    ) {
                buffer.append(value);
                if(i != (Array.getLength(o)-1)) buffer.append(",");
            } else {
                buffer.append(dump(value));
             }
        }
        buffer.append("]\n");
    } else {
         buffer.append("Class: " + oClass.getName());
         buffer.append("{\n");
        while (oClass != null) {
            Field[] fields = oClass.getDeclaredFields();
            for (int i = 0; i < fields.length; i++) {
                fields[i].setAccessible(true);
                buffer.append(fields[i].getName());
                buffer.append("=");
                try {
                    Object value = fields[i].get(o);
                    if (value != null) {
                        if (value.getClass().isPrimitive() ||
                                value.getClass() == java.lang.Long.class ||
                                value.getClass() == java.lang.String.class ||
                                value.getClass() == java.lang.Integer.class ||
                                value.getClass() == java.lang.Boolean.class ||
                                    value.getClass() == java.lang.Double.class ||
                                value.getClass() == java.lang.Short.class ||
                                value.getClass() == java.lang.Byte.class
                                ) {
                            buffer.append(value);
                        } else {
                            buffer.append(dump(value));
                        }
                    }
                } catch (IllegalAccessException e) {
                    buffer.append(e.getMessage());
                }
                buffer.append("\n");
            }
            oClass = oClass.getSuperclass();
        }
        buffer.append("}\n");
    }
    return buffer.toString();
}

أريد حلا لهذه المشكلة:

  • لا تستخدم أي مكتبة خارجي
  • يستخدم انعكاس للوصول إلى الميادين ، بما في ذلك الفائقة المجالات
  • يستخدم العودية لاجتياز كائن الرسم البياني مع واحد فقط الإطار المكدس في الدعوة
  • يستخدم IdentityHashMap التعامل مع الوراء المراجع تجنب لانهائية العودية
  • مقابض الأوليات, السيارات-الملاكمة ، CharSequences, enums ، بالقيم الخالية مناسب
  • يسمح لك باختيار ما إذا كان أو عدم تحليل حقول ثابتة
  • بسيطة بما فيه الكفاية إلى تعديل وفقا التنسيق تفضيلات

كتبت التالية فئة فائدة:

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.IdentityHashMap;
import java.util.Map.Entry;
import java.util.TreeMap;

/**
 * Utility class to dump {@code Object}s to string using reflection and recursion.
 */
public class StringDump {

    /**
     * Uses reflection and recursion to dump the contents of the given object using a custom, JSON-like notation (but not JSON). Does not format static fields.<p>
     * @see #dump(Object, boolean, IdentityHashMap, int)
     * @param object the {@code Object} to dump using reflection and recursion
     * @return a custom-formatted string representing the internal values of the parsed object
     */
    public static String dump(Object object) {
        return dump(object, false, new IdentityHashMap<Object, Object>(), 0);
    }

    /**
     * Uses reflection and recursion to dump the contents of the given object using a custom, JSON-like notation (but not JSON).<p>
     * Parses all fields of the runtime class including super class fields, which are successively prefixed with "{@code super.}" at each level.<p>
     * {@code Number}s, {@code enum}s, and {@code null} references are formatted using the standard {@link String#valueOf()} method.
     * {@code CharSequences}s are wrapped with quotes.<p>
     * The recursive call invokes only one method on each recursive call, so limit of the object-graph depth is one-to-one with the stack overflow limit.<p>
     * Backwards references are tracked using a "visitor map" which is an instance of {@link IdentityHashMap}.
     * When an existing object reference is encountered the {@code "sysId"} is printed and the recursion ends.<p>
     * 
     * @param object             the {@code Object} to dump using reflection and recursion
     * @param isIncludingStatics {@code true} if {@code static} fields should be dumped, {@code false} to skip them
     * @return a custom-formatted string representing the internal values of the parsed object
     */
    public static String dump(Object object, boolean isIncludingStatics) {
        return dump(object, isIncludingStatics, new IdentityHashMap<Object, Object>(), 0);
    }

    private static String dump(Object object, boolean isIncludingStatics, IdentityHashMap<Object, Object> visitorMap, int tabCount) {
        if (object == null ||
                object instanceof Number || object instanceof Character || object instanceof Boolean ||
                object.getClass().isPrimitive() || object.getClass().isEnum()) {
            return String.valueOf(object);
        }

        StringBuilder builder = new StringBuilder();
        int           sysId   = System.identityHashCode(object);
        if (object instanceof CharSequence) {
            builder.append("\"").append(object).append("\"");
        }
        else if (visitorMap.containsKey(object)) {
            builder.append("(sysId#").append(sysId).append(")");
        }
        else {
            visitorMap.put(object, object);

            StringBuilder tabs = new StringBuilder();
            for (int t = 0; t < tabCount; t++) {
                tabs.append("\t");
            }
            if (object.getClass().isArray()) {
                builder.append("[").append(object.getClass().getName()).append(":sysId#").append(sysId);
                int length = Array.getLength(object);
                for (int i = 0; i < length; i++) {
                    Object arrayObject = Array.get(object, i);
                    String dump        = dump(arrayObject, isIncludingStatics, visitorMap, tabCount + 1);
                    builder.append("\n\t").append(tabs).append("\"").append(i).append("\":").append(dump);
                }
                builder.append(length == 0 ? "" : "\n").append(length == 0 ? "" : tabs).append("]");
            }
            else {
                // enumerate the desired fields of the object before accessing
                TreeMap<String, Field> fieldMap    = new TreeMap<String, Field>();  // can modify this to change or omit the sort order
                StringBuilder          superPrefix = new StringBuilder();
                for (Class<?> clazz = object.getClass(); clazz != null && !clazz.equals(Object.class); clazz = clazz.getSuperclass()) {
                    Field[] fields = clazz.getDeclaredFields();
                    for (int i = 0; i < fields.length; i++) {
                        Field field = fields[i];
                        if (isIncludingStatics || !Modifier.isStatic(field.getModifiers())) {
                            fieldMap.put(superPrefix + field.getName(), field);
                        }
                    }
                    superPrefix.append("super.");
                }

                builder.append("{").append(object.getClass().getName()).append(":sysId#").append(sysId);
                for (Entry<String, Field> entry : fieldMap.entrySet()) {
                    String name  = entry.getKey();
                    Field  field = entry.getValue();
                    String dump;
                    try {
                        boolean wasAccessible = field.isAccessible();
                        field.setAccessible(true);
                        Object  fieldObject   = field.get(object);
                        field.setAccessible(wasAccessible);  // the accessibility flag should be restored to its prior ClassLoader state
                        dump                  = dump(fieldObject, isIncludingStatics, visitorMap, tabCount + 1);
                    }
                    catch (Throwable e) {
                        dump = "!" + e.getClass().getName() + ":" + e.getMessage();
                    }
                    builder.append("\n\t").append(tabs).append("\"").append(name).append("\":").append(dump);
                }
                builder.append(fieldMap.isEmpty() ? "" : "\n").append(fieldMap.isEmpty() ? "" : tabs).append("}");
            }
        }
        return builder.toString();
    }
}

لقد اختبرت ذلك على عدد من الفصول و بالنسبة لي انها فعالة للغاية.على سبيل المثال ، حاول استخدام الأمر إلى تفريغ الخيط الرئيسي:

public static void main(String[] args) throws Exception {
    System.out.println(dump(Thread.currentThread()));
}

تحرير

منذ كتابة هذا المنصب كان سبب إنشاء تكرارية نسخة من هذه الخوارزمية.العودية نسخة محدودة في العمق من إجمالي إطارات المكدس ، ولكن قد يكون السبب في تفريغ كبير جدا كائن الرسم البياني.للتعامل مع الوضع بلدي ، المنقحة الخوارزمية إلى استخدام كومة بنية البيانات في مكان التشغيل المكدس.هذا الإصدار هو الوقت كفاءة محدودة بسبب حجم كومة الذاكرة المؤقتة بدلا من الإطار المكدس العمق.

يمكنك تحميل واستخدام تكرارية نسخة هنا.

ويجب عليك استخدام RecursiveToStringStyle:

System.out.println(ReflectionToStringBuilder.toString(new Outer(), new RecursiveToStringStyle()));

ربما يمكنك استخدام XML إطار ملزم مثل XStream, هاضم أو JAXB من أجل ذلك.

هل يمكن استخدام Gson لتمثيل الكائن في شكل سلمان:

new GsonBuilder().setPrettyPrinting().create().toJson(yourObject);
JSONObject.fromObject(value)

ولا يعمل لكائنات خريطة مع مفاتيح أخرى من سلسلة. ربما JsonConfig يمكن التعامل مع هذا.

أنصحك استخدام GSON ليب fo جافا.

إذا كنت تستخدم مخضرم يمكنك استخدام هذا.

أو يمكنك تحميل ملف Jar من هنا.

هنا مثال على كيفية استخدامها:

Gson gson = new GsonBuilder().setPrettyPrinting().create();
String json = gson.toJson(obj);
System.out.println(json);
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top