From ae0d6e414e2614c899ca153549525fbb4f342cd4 Mon Sep 17 00:00:00 2001 From: Steve Arch Date: Fri, 1 Jul 2022 13:07:05 +0100 Subject: [PATCH 1/3] Made EvaluationContext constructor public --- src/main/java/dev/openfeature/javasdk/EvaluationContext.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/dev/openfeature/javasdk/EvaluationContext.java b/src/main/java/dev/openfeature/javasdk/EvaluationContext.java index 7eb3b16db..f8ad671dc 100644 --- a/src/main/java/dev/openfeature/javasdk/EvaluationContext.java +++ b/src/main/java/dev/openfeature/javasdk/EvaluationContext.java @@ -18,7 +18,7 @@ public class EvaluationContext { private final Map booleanAttributes; final Map jsonAttributes; - EvaluationContext() { + public EvaluationContext() { objMapper = new ObjectMapper(); this.targetingKey = ""; this.integerAttributes = new HashMap<>(); From b757365d2d560235a816c489f8afa24f65beafb0 Mon Sep 17 00:00:00 2001 From: Steve Arch Date: Fri, 1 Jul 2022 13:08:14 +0100 Subject: [PATCH 2/3] Added toMap/fromMap to EvaluationContext --- .../javasdk/EvaluationContext.java | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/main/java/dev/openfeature/javasdk/EvaluationContext.java b/src/main/java/dev/openfeature/javasdk/EvaluationContext.java index f8ad671dc..64a399a8b 100644 --- a/src/main/java/dev/openfeature/javasdk/EvaluationContext.java +++ b/src/main/java/dev/openfeature/javasdk/EvaluationContext.java @@ -1,6 +1,8 @@ package dev.openfeature.javasdk; import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.collect.ImmutableMap; +import java.util.stream.Collectors; import lombok.*; import java.time.ZonedDateTime; @@ -103,4 +105,49 @@ public static EvaluationContext merge(EvaluationContext ctx1, EvaluationContext return ec; } + + public EvaluationContext fromMap(Map map) { + EvaluationContext context = new EvaluationContext(); + context.integerAttributes.putAll( + map.entrySet() + .stream() + .filter(entry -> entry.getValue() instanceof Integer) + .collect(Collectors.toMap(Map.Entry::getKey, e -> (Integer) e.getValue())) + ); + context.stringAttributes.putAll( + map.entrySet() + .stream() + .filter(entry -> entry.getValue() instanceof String) + .collect(Collectors.toMap(Map.Entry::getKey, e -> (String)e.getValue())) + ); + context.booleanAttributes.putAll( + map.entrySet() + .stream() + .filter(entry -> entry.getValue() instanceof Boolean) + .collect(Collectors.toMap(Map.Entry::getKey, e -> (Boolean)e.getValue())) + ); +// Hmmm, this won't work as we already have a string type. +// I would recommend changing the type to Map from Jackson +// context.jsonAttributes.putAll( +// map.entrySet() +// .stream() +// .filter(entry -> entry.getValue() instanceof String) +// .collect(Collectors.toMap(e -> e.getKey(), e -> (String)e.getValue())) +// ); + + return null; + } + + /** + * Converts the Evaluation Context into a standard {@link Map} + */ + public Map toMap() { + Map map = new HashMap<>(); + // 🤔 This will fail if two different maps have the same key. + map.putAll(integerAttributes); + map.putAll(stringAttributes); + map.putAll(booleanAttributes); + map.putAll(jsonAttributes); + return ImmutableMap.copyOf(map); + } } From 85ecccd521218bb4787e940822b4a7f052bac054 Mon Sep 17 00:00:00 2001 From: Steve Arch Date: Fri, 1 Jul 2022 13:09:53 +0100 Subject: [PATCH 3/3] Fluent setters in EvaluationContext --- .../openfeature/javasdk/EvaluationContext.java | 15 ++++++++++----- .../dev/openfeature/javasdk/EvalContextTest.java | 10 +++++----- .../dev/openfeature/javasdk/HookSpecTest.java | 6 +++--- .../dev/openfeature/javasdk/HookSupportTest.java | 4 ++-- 4 files changed, 20 insertions(+), 15 deletions(-) diff --git a/src/main/java/dev/openfeature/javasdk/EvaluationContext.java b/src/main/java/dev/openfeature/javasdk/EvaluationContext.java index 64a399a8b..41088cfdd 100644 --- a/src/main/java/dev/openfeature/javasdk/EvaluationContext.java +++ b/src/main/java/dev/openfeature/javasdk/EvaluationContext.java @@ -31,8 +31,9 @@ public EvaluationContext() { // TODO Not sure if I should have sneakythrows or checked exceptions here.. @SneakyThrows - public void addStructureAttribute(String key, T value) { + public EvaluationContext withStructureAttribute(String key, T value) { jsonAttributes.put(key, objMapper.writeValueAsString(value)); + return this; } @SneakyThrows @@ -41,16 +42,18 @@ public T getStructureAttribute(String key, Class klass) { return objMapper.readValue(val, klass); } - public void addStringAttribute(String key, String value) { + public EvaluationContext withStringAttribute(String key, String value) { stringAttributes.put(key, value); + return this; } public String getStringAttribute(String key) { return stringAttributes.get(key); } - public void addIntegerAttribute(String key, Integer value) { + public EvaluationContext withIntegerAttribute(String key, Integer value) { integerAttributes.put(key, value); + return this; } public Integer getIntegerAttribute(String key) { @@ -61,12 +64,14 @@ public Boolean getBooleanAttribute(String key) { return booleanAttributes.get(key); } - public void addBooleanAttribute(String key, Boolean b) { + public EvaluationContext withBooleanAttribute(String key, Boolean b) { booleanAttributes.put(key, b); + return this; } - public void addDatetimeAttribute(String key, ZonedDateTime value) { + public EvaluationContext withDatetimeAttribute(String key, ZonedDateTime value) { this.stringAttributes.put(key, value.format(DateTimeFormatter.ISO_ZONED_DATE_TIME)); + return this; } public ZonedDateTime getDatetimeAttribute(String key) { diff --git a/src/test/java/dev/openfeature/javasdk/EvalContextTest.java b/src/test/java/dev/openfeature/javasdk/EvalContextTest.java index 4efcc3c80..eb410b1aa 100644 --- a/src/test/java/dev/openfeature/javasdk/EvalContextTest.java +++ b/src/test/java/dev/openfeature/javasdk/EvalContextTest.java @@ -22,17 +22,17 @@ public class EvalContextTest { @Test void eval_context() { EvaluationContext ec = new EvaluationContext(); - ec.addStringAttribute("str", "test"); + ec.withStringAttribute("str", "test"); assertEquals("test", ec.getStringAttribute("str")); - ec.addBooleanAttribute("bool", true); + ec.withBooleanAttribute("bool", true); assertEquals(true, ec.getBooleanAttribute("bool")); - ec.addIntegerAttribute("int", 4); + ec.withIntegerAttribute("int", 4); assertEquals(4, ec.getIntegerAttribute("int")); ZonedDateTime dt = ZonedDateTime.now(); - ec.addDatetimeAttribute("dt", dt); + ec.withDatetimeAttribute("dt", dt); assertEquals(dt, ec.getDatetimeAttribute("dt")); } @@ -47,7 +47,7 @@ public class EvalContextTest { n2.left = n1; EvaluationContext ec = new EvaluationContext(); - ec.addStructureAttribute("obj", n2); + ec.withStructureAttribute("obj", n2); String stringyObject = ec.jsonAttributes.get("obj"); diff --git a/src/test/java/dev/openfeature/javasdk/HookSpecTest.java b/src/test/java/dev/openfeature/javasdk/HookSpecTest.java index 9d38f03ed..2fcae5ac5 100644 --- a/src/test/java/dev/openfeature/javasdk/HookSpecTest.java +++ b/src/test/java/dev/openfeature/javasdk/HookSpecTest.java @@ -429,11 +429,11 @@ public void finallyAfter(HookContext ctx, Map hints) { @Specification(number="4.3.4", text="When before hooks have finished executing, any resulting evaluation context MUST be merged with the invocation evaluation context with the invocation evaluation context taking precedence in the case of any conflicts.") @Test void mergeHappensCorrectly() { EvaluationContext hookCtx = new EvaluationContext(); - hookCtx.addStringAttribute("test", "broken"); - hookCtx.addStringAttribute("another", "exists"); + hookCtx.withStringAttribute("test", "broken"); + hookCtx.withStringAttribute("another", "exists"); EvaluationContext invocationCtx = new EvaluationContext(); - invocationCtx.addStringAttribute("test", "works"); + invocationCtx.withStringAttribute("test", "works"); Hook hook = mockBooleanHook(); when(hook.before(any(), any())).thenReturn(Optional.of(hookCtx)); diff --git a/src/test/java/dev/openfeature/javasdk/HookSupportTest.java b/src/test/java/dev/openfeature/javasdk/HookSupportTest.java index ece43553b..134d9493e 100644 --- a/src/test/java/dev/openfeature/javasdk/HookSupportTest.java +++ b/src/test/java/dev/openfeature/javasdk/HookSupportTest.java @@ -16,7 +16,7 @@ class HookSupportTest implements HookFixtures { @DisplayName("should merge EvaluationContexts on before hooks correctly") void shouldMergeEvaluationContextsOnBeforeHooksCorrectly() { EvaluationContext baseContext = new EvaluationContext(); - baseContext.addStringAttribute("baseKey", "baseValue"); + baseContext.withStringAttribute("baseKey", "baseValue"); HookContext hookContext = new HookContext<>("flagKey", FlagValueType.STRING, "defaultValue", baseContext, () -> "client", () -> "provider"); Hook hook1 = mockStringHook(); Hook hook2 = mockStringHook(); @@ -69,7 +69,7 @@ private Object createDefaultValue(FlagValueType flagValueType) { private EvaluationContext evaluationContextWithValue(String key, String value) { EvaluationContext result = new EvaluationContext(); - result.addStringAttribute(key, value); + result.withStringAttribute(key, value); return result; }