Package org.coliper.ibean.util
Class RecursionCycleDetector<T>
- java.lang.Object
-
- org.coliper.ibean.util.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 withThreadLocals so it only works if recursion takes place within the same thread. To use this utility create a static instance ofRecursionCycleDetectorfor 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 aexecuteWithCycleDetection(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)); }SeeexecuteWithCycleDetection(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.
-
-
Constructor Summary
Constructors Constructor Description RecursionCycleDetector(T returnValueIfCycleDetected)Create a newRecursionCycleDetectorused with in a method with return type T.
-
Method Summary
All Methods Instance Methods Concrete Methods Modifier and Type Method Description TexecuteWithCycleDetection(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.TexecuteWithCycleDetection(Object instance, Supplier<T> functionToExecute)Short forexecuteWithCycleDetection(instance, null, functionToExecute).
-
-
-
Constructor Detail
-
RecursionCycleDetector
public RecursionCycleDetector(T returnValueIfCycleDetected)
Create a newRecursionCycleDetectorused with in a method with return type T. In most cases it makes sense to have one static instance ofRecursionCycleDetectorfor one method to protect.- Parameters:
returnValueIfCycleDetected- the default value that is returned byexecuteWithCycleDetection(Object, Object[], Supplier)in case a call cycle is detected
-
-
Method Detail
-
executeWithCycleDetection
public T executeWithCycleDetection(Object instance, Supplier<T> functionToExecute)
Short forexecuteWithCycleDetection(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.
-
-