22
33import static com .nordstrom .automation .junit .LifecycleHooks .getFieldValue ;
44
5+ import java .util .HashMap ;
6+ import java .util .Map ;
57import java .util .Objects ;
68import java .util .Optional ;
79import java .util .ServiceLoader ;
8- import java .util .Set ;
910import java .util .concurrent .Callable ;
10- import java .util .concurrent .CopyOnWriteArraySet ;
11-
1211import org .junit .After ;
1312import org .junit .AfterClass ;
1413import org .junit .Before ;
3029public class RunReflectiveCall {
3130
3231 private static final ServiceLoader <MethodWatcher > methodWatcherLoader ;
33- private static final Set <Integer > beforeNotified = new CopyOnWriteArraySet <>();
34- private static final Set <Integer > afterNotified = new CopyOnWriteArraySet <>();
32+ private static final ThreadLocal <Map <Integer , DepthGauge >> methodDepth = ThreadLocal .withInitial (HashMap ::new );
3533
3634 static {
3735 methodWatcherLoader = ServiceLoader .load (MethodWatcher .class );
@@ -82,9 +80,9 @@ public static Object intercept(@This final Object callable, @SuperCall final Cal
8280
8381 Object result = null ;
8482 Throwable thrown = null ;
85- fireBeforeInvocation (runner , target , method , params );
8683
8784 try {
85+ fireBeforeInvocation (runner , target , method , params );
8886 result = LifecycleHooks .callProxy (proxy );
8987 } catch (Throwable t ) {
9088 thrown = t ;
@@ -144,13 +142,16 @@ public static boolean isParticleMethod(FrameworkMethod method) {
144142 * @return {@code true} if event the {@code beforeInvocation} was fired; otherwise {@code false}
145143 */
146144 private static boolean fireBeforeInvocation (Object runner , Object target , FrameworkMethod method , Object ... params ) {
147- if ((runner != null ) && (method != null ) && (beforeNotified .add (methodHash (runner , method )))) {
148- synchronized (methodWatcherLoader ) {
149- for (MethodWatcher watcher : methodWatcherLoader ) {
150- watcher .beforeInvocation (runner , target , method , params );
145+ if ((runner != null ) && (method != null )) {
146+ DepthGauge depthGauge = methodDepth .get ().computeIfAbsent (methodHash (runner , method ), k -> new DepthGauge ());
147+ if (0 == depthGauge .increaseDepth ()) {
148+ synchronized (methodWatcherLoader ) {
149+ for (MethodWatcher watcher : methodWatcherLoader ) {
150+ watcher .beforeInvocation (runner , target , method , params );
151+ }
151152 }
153+ return true ;
152154 }
153- return true ;
154155 }
155156 return false ;
156157 }
@@ -167,13 +168,16 @@ private static boolean fireBeforeInvocation(Object runner, Object target, Framew
167168 * @return {@code true} if event the {@code afterInvocation} was fired; otherwise {@code false}
168169 */
169170 private static boolean fireAfterInvocation (Object runner , Object target , FrameworkMethod method , Throwable thrown ) {
170- if ((runner != null ) && (method != null ) && (afterNotified .add (methodHash (runner , method )))) {
171- synchronized (methodWatcherLoader ) {
172- for (MethodWatcher watcher : methodWatcherLoader ) {
173- watcher .afterInvocation (runner , target , method , thrown );
171+ if ((runner != null ) && (method != null )) {
172+ DepthGauge depthGauge = methodDepth .get ().computeIfAbsent (methodHash (runner , method ), k -> new DepthGauge ());
173+ if (0 == depthGauge .decreaseDepth ()) {
174+ synchronized (methodWatcherLoader ) {
175+ for (MethodWatcher watcher : methodWatcherLoader ) {
176+ watcher .afterInvocation (runner , target , method , thrown );
177+ }
174178 }
179+ return true ;
175180 }
176- return true ;
177181 }
178182 return false ;
179183 }
@@ -185,7 +189,7 @@ private static boolean fireAfterInvocation(Object runner, Object target, Framewo
185189 * @param method {@link FrameworkMethod} object
186190 * @return hash code for the specified runner/method pair
187191 */
188- private static int methodHash (Object runner , FrameworkMethod method ) {
189- return runner . toString ().hashCode () * 31 + method .hashCode ();
192+ public static int methodHash (Object runner , FrameworkMethod method ) {
193+ return (( Thread . currentThread ().hashCode () * 31 ) + runner . hashCode () ) * 31 + method .hashCode ();
190194 }
191195}
0 commit comments