src/main/java/com/cedarsoftware/util/io/JsonWriter.java
protected void traceFields(final Deque<Object> stack, final Object obj, final Map<Class, List<Field>> fieldSpecifiers)
    {
        // If caller has special Field specifier for a given class
        // then use it, otherwise use reflection.
        Collection<Field> fields = getFieldsUsingSpecifier(obj.getClass(), fieldSpecifiers);
        Collection<Field> fieldsBySpec = fields;
        if (fields == null)
        {   // Trace fields using reflection
            fields = MetaUtils.getDeepDeclaredFields(obj.getClass()).values();
        }
        for (final Field field : fields)
        {
            if ((field.getModifiers() & Modifier.TRANSIENT) != 0)
            {
                if (fieldsBySpec == null || !fieldsBySpec.contains(field))
                {   // Skip tracing transient fields EXCEPT when the field is listed explicitly by using the fieldSpecifiers Map.
                    // In that case, the field must be traced, even though it is transient.
                    continue;
                }
            }
            try
            {
                final Object o = field.get(obj);
                if (o != null && !MetaUtils.isLogicalPrimitive(o.getClass()))
                {   // Trace through objects that can reference other objects
                    stack.addFirst(o);
                }
            }
            catch (Exception ignored) { }
        }
    }
protected void traceFields(final Deque<Object> stack, final Object obj, final Map<Class, List<Field>> fieldSpecifiers)
    {
        // If caller has special Field specifier for a given class
        // then use it, otherwise use reflection.
        Collection<Field> fields = getFieldsUsingSpecifier(obj.getClass(), fieldSpecifiers);
        Collection<Field> fieldsBySpec = fields;
        if (fields == null)
        {   // Trace fields using reflection
            fields = MetaUtils.getDeepDeclaredFields(obj.getClass()).values();
        }
        for (final Field field : fields)
        {
            if ((field.getModifiers() & Modifier.TRANSIENT) != 0)
            {
                if (fieldsBySpec == null || !fieldsBySpec.contains(field))
                {   // Skip tracing transient fields EXCEPT when the field is listed explicitly by using the fieldSpecifiers Map.
                    // In that case, the field must be traced, even though it is transient.
                    continue;
                }
            }
            try
            {
                final Object o = field.get(obj);
                if (o != null && !MetaUtils.isLogicalPrimitive(o.getClass()))
                {   // Trace through objects that can reference other objects
                    stack.addFirst(o);
                }
            }
            catch (Exception ignored) { }
        }
    }
Reach-ability trace to visit all objects within the graph to be written.
This API will handle any object, using either reflection APIs or by
consulting a specified FIELD_SPECIFIERS map if provided.
@param stack Deque used to manage descent into graph (rather than using Java stack.) This allows for
much larger graph processing.
@param obj Object root of graph
@param fieldSpecifiers Map of optional field specifiers, which are used to override the field list returned by
the JDK reflection operations.  This allows a subset of the actual fields on an object to be serialized.