1616
1717package de .danielbechler .diff ;
1818
19+ import de .danielbechler .diff .node .*;
1920import de .danielbechler .util .*;
2021
2122/** @author Daniel Bechler */
22- abstract class AbstractDiffer implements Differ , Configurable
23+ abstract class AbstractDiffer < T extends Node > implements Differ < T > , Configurable
2324{
25+ static final ThreadLocal <CircularReferenceDetector > CIRCULAR_REFERENCE_DETECTOR_THREAD_LOCAL ;
26+
27+ static
28+ {
29+ CIRCULAR_REFERENCE_DETECTOR_THREAD_LOCAL = new CircularReferenceDetectorThreadLocal ();
30+ }
31+
2432 private DelegatingObjectDiffer delegate ;
2533
2634 protected AbstractDiffer ()
@@ -33,6 +41,41 @@ protected AbstractDiffer(final DelegatingObjectDiffer delegate)
3341 this .delegate = delegate ;
3442 }
3543
44+ @ Override
45+ public final T compare (final Node parentNode , final Instances instances )
46+ {
47+ final Object working = instances .getWorking ();
48+ final CircularReferenceDetector circularReferenceDetector = CIRCULAR_REFERENCE_DETECTOR_THREAD_LOCAL .get ();
49+ final boolean destroyOnReturn = circularReferenceDetector .isNew ();
50+ T node ;
51+ try
52+ {
53+ circularReferenceDetector .push (working );
54+ try
55+ {
56+ node = internalCompare (parentNode , instances );
57+ }
58+ finally
59+ {
60+ circularReferenceDetector .remove (working );
61+ }
62+ }
63+ catch (CircularReferenceDetector .CircularReferenceException e )
64+ {
65+ node = newNode (parentNode , instances );
66+ node .setState (Node .State .CIRCULAR );
67+ }
68+ if (destroyOnReturn )
69+ {
70+ CIRCULAR_REFERENCE_DETECTOR_THREAD_LOCAL .remove ();
71+ }
72+ return node ;
73+ }
74+
75+ protected abstract T internalCompare (Node parentNode , Instances instances );
76+
77+ protected abstract T newNode (Node parentNode , Instances instances );
78+
3679 public final DelegatingObjectDiffer getDelegate ()
3780 {
3881 return delegate ;
@@ -48,4 +91,13 @@ public final Configuration getConfiguration()
4891 {
4992 return delegate .getConfiguration ();
5093 }
94+
95+ private static final class CircularReferenceDetectorThreadLocal extends ThreadLocal <CircularReferenceDetector >
96+ {
97+ @ Override
98+ protected CircularReferenceDetector initialValue ()
99+ {
100+ return new CircularReferenceDetector ();
101+ }
102+ }
51103}
0 commit comments