Class RecursionCycleDetector<T>


  • public class RecursionCycleDetector<T>
    extends Object
    Utility class to help detecting endless loops in recusive methods. It works by recording all instances and parameters a method is called on resp with. This utility internally works with ThreadLocals so it only works if recursion takes place within the same thread. To use this utility create a static instance of RecursionCycleDetector for the method you want to protect against endless loops. The generic type of this class should match the return type of the recursive method. The cycle detection is done via embedding the recursive call (the call of the method on itself) in a executeWithCycleDetection(Object, Object[], Supplier) call via a lambda expression. The following example shows a recursive method. Integer recursiveMethod(Integer i) { return recursiveMethod(i.intValue() / 2); } Now the same with cycle protection: private static final RecursionCycleDetector DETECTOR = new RecursionCycleDetector<Integer>(Integer.valueOf(0)); Integer recursiveMethod(int i) { return DETECTOR.executeWithCycleDetection(this, new Object[] { i }, () -> recursiveMethod(i / 2)); } See executeWithCycleDetection(Object, Object[], Supplier) for a more detailled description of its parameters.

    Note that on cycle detection no exception is thrown but a predefined (in constructor) value is returned.

    • Method Detail

      • executeWithCycleDetection

        public T executeWithCycleDetection​(Object instance,
                                           Supplier<T> functionToExecute)
        Short for executeWithCycleDetection(instance, null, functionToExecute).
        Parameters:
        instance - the object instance the referred method is executed on. As this method is normally called inside the protected method, in that cases 'this' would be passed here.
        functionToExecute - the lambda expression to call if no cycle is detected yet. In most cases this will be the recursive call of the protected method to itself.
        Returns:
        if a cycle is detected the cycle detection value is returned that was set in the constructor.
        See Also:
        executeWithCycleDetection(Object, Object[], Supplier)
      • executeWithCycleDetection

        public T executeWithCycleDetection​(Object instance,
                                           Object[] params,
                                           Supplier<T> functionToExecute)
        Checks a method call for a recursion cycle and if no cycle is detected executes a given lambda expression. The two first arguments are first compared against the internal call stack and if no identical matches are found in the stack the lambda expression in the third argument is executed. Any RuntimeExceptions thrown in the lambda block will simply be passed through.
        Parameters:
        instance - the object instance the referred method is executed on. As this method is normally called inside the protected method, in that cases 'this' would be passed here.
        params - all parameters of the protected method as an object array. If some arguments have primitive types the values have to be converted to their object representations.
        functionToExecute - the lambda expression to call if no cycle is detected yet. In most cases this will be the recursive call of the protected method to itself.
        Returns:
        if a cycle is detected the cycle detection value is returned that was set in the constructor.