FunctionFactory implements Function<X,Y> { public Y apply(X item) { Y result; synchronized (function) { ownStack.push(item); globalStack.push(item); try { result = cache != null ? cache.get(item) : null; if (result == null) { int recursionLevel = ownStack != null ? Collections.frequency(ownStack, item) : 0; int nestingDepth = globalStack.size(); boolean recursionLevelExceeded = recursionLevel > maximumRecursionLevel && maximumRecursionLevel > 0; boolean nestringDeptExceeded =nestingDepth > maximumNestingDepth && maximumNestingDepth > 0; boolean predicateMatched = fallbackPredicate != null && fallbackPredicate.apply(item); if ((recursionLevelExceeded || nestringDeptExceeded || predicateMatched) && fallback != null) { result = fallback.apply(item); } else { result = function.apply(item); cacheIfEnabled(item, result); } } } finally { ownStack.pop(); globalStack.pop(); } return result; } } FunctionFactory(Map<X, Y> cache, Function<X, Y> function, Function<X, Y> fallback, Function<X, Boolean> fallbackPredicate, int maximumRecursionLevel, int maximumNestingDepth, Stack<X> ownStack); Y apply(X item); static FunctionFactory<X, Y> cache(Function<X, Y> function); static FunctionFactory<X, Y> wrap(Function<X, Y> function); FunctionFactory<X,Y> withFallback(Function<X,Y> fallback); FunctionFactory<X,Y> withMaximumRecursionLevel(int maximumRecursionLevel); FunctionFactory<X,Y> withMaximumNestingDepth(int maximumNestingDepth); FunctionFactory<X,Y> withFallbackPredicate(Function<X,Boolean> fallbackPredicate);  }
@Test public void testCachingWithOverflowProtection() { String expectedResult = "RRRRRRRRRRoverflow"; String result = TEST_FUNCTION.apply(""); Assert.assertEquals(expectedResult, result); result = TEST_FUNCTION.apply(""); Assert.assertEquals(expectedResult, result); }