-
Notifications
You must be signed in to change notification settings - Fork 53
Added ability to use Caffeine for Caching, which enables additional features like eviction, which is not supported by existing ConcurrentHashMap parseCache (#45) #56
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,10 @@ | ||
package io.github.jamsesso.jsonlogic; | ||
|
||
import io.github.jamsesso.jsonlogic.ast.JsonLogicNode; | ||
import io.github.jamsesso.jsonlogic.ast.JsonLogicParseException; | ||
import io.github.jamsesso.jsonlogic.ast.JsonLogicParser; | ||
import io.github.jamsesso.jsonlogic.cache.CacheManager; | ||
import io.github.jamsesso.jsonlogic.cache.ConcurrentHashMapCacheManager; | ||
import io.github.jamsesso.jsonlogic.evaluator.JsonLogicEvaluator; | ||
import io.github.jamsesso.jsonlogic.evaluator.JsonLogicExpression; | ||
import io.github.jamsesso.jsonlogic.evaluator.expressions.*; | ||
|
@@ -12,11 +15,21 @@ | |
import java.util.function.Function; | ||
|
||
public final class JsonLogic { | ||
private final Map<String, JsonLogicNode> parseCache = new ConcurrentHashMap<>(); | ||
private final CacheManager<String, JsonLogicNode> parseCache; | ||
private final Map<String, JsonLogicExpression> expressions = new ConcurrentHashMap<>(); | ||
private JsonLogicEvaluator evaluator; | ||
|
||
public JsonLogic() { | ||
this.parseCache = new ConcurrentHashMapCacheManager<>(); | ||
initializeOperations(); | ||
} | ||
|
||
public JsonLogic(final CacheManager<String, JsonLogicNode> parseCache) { | ||
this.parseCache = parseCache; | ||
initializeOperations(); | ||
} | ||
|
||
private void initializeOperations() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit, but this could have been: public JsonLogic() {
this(new ConcurrentHashMapCacheManager<>());
}
public JsonLogic(final CacheManager<String, JsonLogicNode> parseCache) {
this.parseCache = parseCache;
// Add default operations
addOperation(MathExpression.ADD);
addOperation(MathExpression.SUBTRACT);
// ...
} |
||
// Add default operations | ||
addOperation(MathExpression.ADD); | ||
addOperation(MathExpression.SUBTRACT); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package io.github.jamsesso.jsonlogic.cache; | ||
|
||
/** | ||
* CacheManager interface for managing cache operations. | ||
* | ||
* @param <K> the type of keys maintained by this cache | ||
* @param <V> the type of cached values | ||
*/ | ||
public interface CacheManager<K, V> { | ||
/** | ||
* Checks if the cache contains a value for the specified key. | ||
* @param key the key to check | ||
* @return true if the cache contains the key, false otherwise | ||
*/ | ||
boolean containsKey(K key); | ||
|
||
/** | ||
* Puts a value in the cache with the specified key. | ||
* @param key the key to associate with the value | ||
* @param value the value to cache | ||
*/ | ||
void put(K key, V value); | ||
|
||
/** | ||
* Retrieves a value from the cache for the specified key. | ||
* @param key the key to look up | ||
* @return the cached value, or null if not found | ||
*/ | ||
V get(K key); | ||
} |
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IMO this should live in your upstream project, not in the source of JsonLogicJava. I don't like the idea of bringing in a dependency for all consumers of this library that may not use it. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
package io.github.jamsesso.jsonlogic.cache; | ||
|
||
import com.github.benmanes.caffeine.cache.Cache; | ||
import com.github.benmanes.caffeine.cache.Caffeine; | ||
|
||
/** | ||
* CaffeineCacheManager is a cache manager that uses Caffeine for caching. | ||
* It provides methods to check if a key exists, put a value in the cache, | ||
* and retrieve a value from the cache. | ||
* | ||
* @param <K> the type of keys maintained by this cache | ||
* @param <V> the type of cached values | ||
*/ | ||
public class CaffeineCacheManager<K, V> implements CacheManager<K, V> { | ||
private final Cache<K, V> cache; | ||
|
||
public CaffeineCacheManager() { | ||
this.cache = Caffeine.newBuilder().build(); | ||
} | ||
|
||
/** | ||
* Constructs a CaffeineCacheManager with the specified maximum capacity. | ||
* | ||
* @param maxCapacity the maximum number of entries the cache can hold | ||
*/ | ||
public CaffeineCacheManager(int maxCapacity) { | ||
this.cache = Caffeine.newBuilder().maximumSize(maxCapacity).build(); | ||
} | ||
|
||
@Override | ||
public boolean containsKey(K key) { | ||
return cache.asMap().containsKey(key); | ||
} | ||
|
||
@Override | ||
public void put(K key, V value) { | ||
cache.put(key, value); | ||
} | ||
|
||
@Override | ||
public V get(K key) { | ||
return cache.getIfPresent(key); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package io.github.jamsesso.jsonlogic.cache; | ||
|
||
import java.util.concurrent.ConcurrentHashMap; | ||
|
||
/** | ||
* ConcurrentHashMapCacheManager is a cache manager that uses ConcurrentHashMap for caching. | ||
* It provides methods to check if a key exists, put a value in the cache, | ||
* and retrieve a value from the cache. | ||
* | ||
* @param <K> the type of keys maintained by this cache | ||
* @param <V> the type of cached values | ||
*/ | ||
public class ConcurrentHashMapCacheManager<K, V> implements CacheManager<K, V> { | ||
private final ConcurrentHashMap<K, V> cache; | ||
|
||
public ConcurrentHashMapCacheManager() { | ||
this.cache = new ConcurrentHashMap<>(); | ||
} | ||
|
||
@Override | ||
public boolean containsKey(K key) { | ||
return cache.containsKey(key); | ||
} | ||
|
||
@Override | ||
public void put(K key, V value) { | ||
cache.put(key, value); | ||
} | ||
|
||
@Override | ||
public V get(K key) { | ||
return cache.get(key); | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package io.github.jamsesso.jsonlogic; | ||
|
||
import org.junit.Test; | ||
|
||
import io.github.jamsesso.jsonlogic.cache.CaffeineCacheManager; | ||
|
||
import static org.junit.Assert.assertEquals; | ||
|
||
public class CaffeineCacheJsonLogicTest { | ||
private static final JsonLogic jsonLogic = new JsonLogic(new CaffeineCacheManager<>()); | ||
private static final JsonLogic jsonLogicWithMaxCacheSize = new JsonLogic(new CaffeineCacheManager<>(1000)); | ||
|
||
|
||
@Test | ||
public void testEmptyArray() throws JsonLogicException { | ||
assertEquals(false, jsonLogic.apply("{\"all\": [[], {\">\": [{\"var\": \"\"}, 0]}]}", null)); | ||
assertEquals(false, jsonLogicWithMaxCacheSize.apply("{\"all\": [[], {\">\": [{\"var\": \"\"}, 0]}]}", null)); | ||
} | ||
|
||
@Test | ||
public void testAll() throws JsonLogicException { | ||
assertEquals(true, jsonLogic.apply("{\"all\": [[1, 2, 3], {\">\": [{\"var\": \"\"}, 0]}]}", null)); | ||
assertEquals(false, jsonLogic.apply("{\"all\": [[1, 2, 3], {\">\": [{\"var\": \"\"}, 1]}]}", null)); | ||
|
||
assertEquals(true, jsonLogicWithMaxCacheSize.apply("{\"all\": [[1, 2, 3], {\">\": [{\"var\": \"\"}, 0]}]}", null)); | ||
assertEquals(false, jsonLogicWithMaxCacheSize.apply("{\"all\": [[1, 2, 3], {\">\": [{\"var\": \"\"}, 1]}]}", null)); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need to touch this file anymore, there is a Github action that handles this all.