public class RecursionCycleDetector<T> extends Object
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.
| Constructor and Description |
|---|
RecursionCycleDetector(T returnValueIfCycleDetected)
Create a new
RecursionCycleDetector used with in a method with
return type T. |
| Modifier and Type | Method and Description |
|---|---|
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.
|
T |
executeWithCycleDetection(Object instance,
Supplier<T> functionToExecute)
Short for
executeWithCycleDetection(instance, null, functionToExecute). |
public RecursionCycleDetector(T returnValueIfCycleDetected)
RecursionCycleDetector used with in a method with
return type T. In most cases it makes sense to have one static instance
of RecursionCycleDetector for one method to protect.returnValueIfCycleDetected - the default value that is returned by
executeWithCycleDetection(Object, Object[], Supplier)
in case a call cycle is detectedpublic T executeWithCycleDetection(Object instance, Supplier<T> functionToExecute)
executeWithCycleDetection(instance, null, functionToExecute).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.executeWithCycleDetection(Object, Object[], Supplier)public T executeWithCycleDetection(Object instance, Object[] params, Supplier<T> functionToExecute)
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.