protected void traceReferences ( Object root ) { if ( root == null ) { return ; } Map < Class , List < Field > > fieldSpecifiers = ( Map ) args . get ( FIELD_SPECIFIERS ) ; final Deque < Object > stack = new ArrayDeque < Object > ( ) ; stack . addFirst ( root ) ; final Map < Object , Long > visited = objVisited ; final Map < Object , Long > referenced = objsReferenced ; while ( ! stack . isEmpty ( ) ) { final Object obj = stack . removeFirst ( ) ; if ( ! MetaUtils . isLogicalPrimitive ( obj . getClass ( ) ) ) { Long id = visited . get ( obj ) ; if ( id != null ) { // Only write an object once. if ( id == ZERO ) { // 2nd time this object has been seen, so give it a unique ID and mark it referenced id = identity ++ ; visited . put ( obj , id ) ; referenced . put ( obj , id ) ; } continue ; } else { // Initially, mark an object with 0 as the ID, in case it is never referenced, // we don't waste the memory to store a Long instance that is never used. visited . put ( obj , ZERO ) ; } } final Class clazz = obj . getClass ( ) ; if ( clazz . isArray ( ) ) { if ( ! MetaUtils . isLogicalPrimitive ( clazz . getComponentType ( ) ) ) { // Speed up: do not traceReferences of primitives, they cannot reference anything final int len = Array . getLength ( obj ) ; for ( int i = 0 ; i < len ; i ++ ) { final Object o = Array . get ( obj , i ) ; if ( o != null ) { // Slight perf gain (null is legal) stack . addFirst ( o ) ; } } } } else if ( Map . class . isAssignableFrom ( clazz ) ) { // Speed up - logically walk maps, as opposed to following their internal structure. Map map = ( Map ) obj ; for ( final Object item : map . entrySet ( ) ) { final Map . Entry entry = ( Map . Entry ) item ; if ( entry . getValue ( ) != null ) { stack . addFirst ( entry . getValue ( ) ) ; } if ( entry . getKey ( ) != null ) { stack . addFirst ( entry . getKey ( ) ) ; } } } else if ( Collection . class . isAssignableFrom ( clazz ) ) { for ( final Object item : ( Collection ) obj ) { if ( item != null ) { stack . addFirst ( item ) ; } } } else { // Speed up: do not traceReferences of primitives, they cannot reference anything if ( ! MetaUtils . isLogicalPrimitive ( obj . getClass ( ) ) ) { traceFields ( stack , obj , fieldSpecifiers ) ; } } } }
Walk object graph and visit each instance following each field each Collection Map and so on . Tracks visited to handle cycles and to determine if an item is referenced elsewhere . If an object is never referenced more than once no