From 485bc618e0113683d7eb442a47d74ac4969fb8bc Mon Sep 17 00:00:00 2001 From: Darin Kelkhoff Date: Sun, 19 May 2024 20:21:03 -0500 Subject: [PATCH] CE-938 update memoization to say if it should store null values or not --- .../core/utils/memoization/Memoization.java | 78 ++++++++++++++++++- .../utils/memoization/MemoizationTest.java | 51 ++++++++++++ 2 files changed, 127 insertions(+), 2 deletions(-) diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/utils/memoization/Memoization.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/utils/memoization/Memoization.java index ae373024..4ed6cbce 100644 --- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/utils/memoization/Memoization.java +++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/utils/memoization/Memoization.java @@ -43,8 +43,9 @@ public class Memoization private final Map> map = Collections.synchronizedMap(new LinkedHashMap<>()); - private Duration timeout = Duration.ofSeconds(600); - private Integer maxSize = 1000; + private Duration timeout = Duration.ofSeconds(600); + private Integer maxSize = 1000; + private boolean mayStoreNullValues = true; @@ -58,6 +59,40 @@ public class Memoization + /******************************************************************************* + ** Constructor + ** + *******************************************************************************/ + public Memoization(Integer maxSize) + { + this.maxSize = maxSize; + } + + + + /******************************************************************************* + ** Constructor + ** + *******************************************************************************/ + public Memoization(Duration timeout) + { + this.timeout = timeout; + } + + + + /******************************************************************************* + ** Constructor + ** + *******************************************************************************/ + public Memoization(Duration timeout, Integer maxSize) + { + this.timeout = timeout; + this.maxSize = maxSize; + } + + + /******************************************************************************* ** Get the memoized Value for a given input Key - computing it if it wasn't previously ** memoized (or expired). @@ -153,6 +188,14 @@ public class Memoization *******************************************************************************/ public void storeResult(K key, V value) { + ////////////////////////////////////////////////////////////////////////////////////////// + // if the value is null, and we're not supposed to store nulls, then return w/o storing // + ////////////////////////////////////////////////////////////////////////////////////////// + if(value == null && !mayStoreNullValues) + { + return; + } + map.put(key, new MemoizedResult<>(value)); ////////////////////////////////////// @@ -277,4 +320,35 @@ public class Memoization return (this); } + + + /******************************************************************************* + ** Getter for mayStoreNullValues + *******************************************************************************/ + public boolean getMayStoreNullValues() + { + return (this.mayStoreNullValues); + } + + + + /******************************************************************************* + ** Setter for mayStoreNullValues + *******************************************************************************/ + public void setMayStoreNullValues(boolean mayStoreNullValues) + { + this.mayStoreNullValues = mayStoreNullValues; + } + + + + /******************************************************************************* + ** Fluent setter for mayStoreNullValues + *******************************************************************************/ + public Memoization withMayStoreNullValues(boolean mayStoreNullValues) + { + this.mayStoreNullValues = mayStoreNullValues; + return (this); + } + } diff --git a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/utils/memoization/MemoizationTest.java b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/utils/memoization/MemoizationTest.java index 5d999353..9bc9c367 100644 --- a/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/utils/memoization/MemoizationTest.java +++ b/qqq-backend-core/src/test/java/com/kingsrook/qqq/backend/core/utils/memoization/MemoizationTest.java @@ -119,6 +119,57 @@ class MemoizationTest extends BaseTest + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void testMayNotStoreNull() + { + Memoization memoization = new Memoization<>(); + memoization.setMayStoreNullValues(false); + + AtomicInteger callCounter = new AtomicInteger(); + callCounter.set(0); + UnsafeFunction supplier = name -> + { + callCounter.getAndIncrement(); + if(name.equals("throw")) + { + throw (new Exception("You asked me to throw")); + } + else if(name.equals("null")) + { + return (null); + } + else + { + return (name); + } + }; + + assertThat(memoization.getResult("null", supplier)).isEmpty(); + assertEquals(1, callCounter.get()); + + assertThat(memoization.getResult("null", supplier)).isEmpty(); + assertEquals(2, callCounter.get()); // should re-run the supplier, incrementing the counter + + assertThat(memoization.getResult("throw", supplier)).isEmpty(); + assertEquals(3, callCounter.get()); + + assertThat(memoization.getResult("throw", supplier)).isEmpty(); + assertEquals(4, callCounter.get()); // should re-run the supplier, incrementing the counter + + //noinspection AssertBetweenInconvertibleTypes + assertThat(memoization.getResult("foo", supplier)).isPresent().get().isEqualTo("foo"); + assertEquals(5, callCounter.get()); + + //noinspection AssertBetweenInconvertibleTypes + assertThat(memoization.getResult("foo", supplier)).isPresent().get().isEqualTo("foo"); + assertEquals(5, callCounter.get()); // should NOT re-run the supplier, NOT incrementing the counter + } + + + /******************************************************************************* ** *******************************************************************************/