From d8b4d0de64a0ed7d6687b91019463e26564af8be Mon Sep 17 00:00:00 2001 From: Thomas Poignant Date: Fri, 16 Sep 2022 15:54:16 +0200 Subject: [PATCH 1/3] Add asObjectMap to get the EvaluationContext as Map Signed-off-by: Thomas Poignant --- .../dev/openfeature/javasdk/Structure.java | 76 +++++++++++++++++-- .../exceptions/ValueNotConvertableError.java | 12 +++ .../openfeature/javasdk/EvalContextTest.java | 52 +++++++++++++ 3 files changed, 133 insertions(+), 7 deletions(-) create mode 100644 src/main/java/dev/openfeature/javasdk/exceptions/ValueNotConvertableError.java diff --git a/src/main/java/dev/openfeature/javasdk/Structure.java b/src/main/java/dev/openfeature/javasdk/Structure.java index 38ff2f890..4ecc9a48b 100644 --- a/src/main/java/dev/openfeature/javasdk/Structure.java +++ b/src/main/java/dev/openfeature/javasdk/Structure.java @@ -1,11 +1,10 @@ package dev.openfeature.javasdk; import java.time.Instant; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; +import java.util.stream.Collectors; +import dev.openfeature.javasdk.exceptions.ValueNotConvertableError; import lombok.EqualsAndHashCode; import lombok.ToString; @@ -66,9 +65,9 @@ public Structure add(String key, Double value) { return this; } - /** + /** * Add date-time relevant key. - * + * * @param key feature key * @param value date-time value * @return Structure @@ -90,10 +89,73 @@ public Structure add(String key, List value) { /** * Get all values. - * + * * @return all attributes on the structure */ public Map asMap() { return new HashMap<>(this.attributes); } + + /** + * Get all values, with primitives types. + * + * @return all attributes on the structure into a Map + */ + public Map asObjectMap() { + return attributes + .entrySet() + .stream() + .collect(Collectors.toMap( + Map.Entry::getKey, + e -> convertValue(getValue(e.getKey())) + )); + } + + /** + * convertValue is converting the object type Value in a primitive type. + * @param value - Value object to convert + * @return an Object containing the primitive type. + */ + private Object convertValue(Value value){ + if (value.isBoolean()){ + return value.asBoolean(); + } + + if(value.isNumber()){ + Double valueAsDouble = value.asDouble(); + if ((valueAsDouble == Math.floor(valueAsDouble)) && !Double.isInfinite(valueAsDouble)) { + return value.asInteger(); + } + return valueAsDouble; + } + + if(value.isString()){ + return value.asString(); + } + + if(value.isInstant()) { + return value.asInstant(); + } + + if(value.isList()){ + return value.asList() + .stream() + .map(this::convertValue) + .collect(Collectors.toList()); + } + + if(value.isStructure()){ + Structure s = value.asStructure(); + return s.asMap() + .keySet() + .stream() + .collect( + Collectors.toMap( + key -> key, + key-> convertValue(s.getValue(key)) + ) + ); + } + throw new ValueNotConvertableError(); + } } diff --git a/src/main/java/dev/openfeature/javasdk/exceptions/ValueNotConvertableError.java b/src/main/java/dev/openfeature/javasdk/exceptions/ValueNotConvertableError.java new file mode 100644 index 000000000..1cbff419f --- /dev/null +++ b/src/main/java/dev/openfeature/javasdk/exceptions/ValueNotConvertableError.java @@ -0,0 +1,12 @@ +package dev.openfeature.javasdk.exceptions; + +import dev.openfeature.javasdk.ErrorCode; +import lombok.Getter; +import lombok.experimental.StandardException; + +@StandardException +public class ValueNotConvertableError extends OpenFeatureError { + private static final long serialVersionUID = 1L; + @Getter + private final ErrorCode errorCode = ErrorCode.GENERAL; +} diff --git a/src/test/java/dev/openfeature/javasdk/EvalContextTest.java b/src/test/java/dev/openfeature/javasdk/EvalContextTest.java index 29506919e..3cb207881 100644 --- a/src/test/java/dev/openfeature/javasdk/EvalContextTest.java +++ b/src/test/java/dev/openfeature/javasdk/EvalContextTest.java @@ -4,6 +4,7 @@ import java.time.Instant; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; @@ -148,4 +149,55 @@ public class EvalContextTest { ctxMerged = EvaluationContext.merge(ctx1, ctx2); assertEquals(key1, ctxMerged.getTargetingKey()); } + + @Test void asObjectMap() { + String key1 = "key1"; + EvaluationContext ctx = new EvaluationContext(key1); + ctx.add("stringItem", "stringValue"); + ctx.add("boolItem", false); + ctx.add("integerItem", 1); + ctx.add("doubleItem", 1.2); + ctx.add("instantItem", Instant.ofEpochSecond(1663331342)); + List listItem = new ArrayList<>(); + listItem.add(new Value("item1")); + listItem.add(new Value("item2")); + ctx.add("listItem", listItem); + List listItem2 = new ArrayList<>(); + listItem2.add(new Value(true)); + listItem2.add(new Value(false)); + ctx.add("listItem2", listItem2); + Map structureValue = new HashMap<>(); + structureValue.put("structStringItem", new Value("stringValue")); + structureValue.put("structBoolItem", new Value(false)); + structureValue.put("structIntegerItem", new Value(1)); + structureValue.put("structDoubleItem", new Value(1.2)); + structureValue.put("structInstantItem", new Value(Instant.ofEpochSecond(1663331342))); + Structure structure = new Structure(structureValue); + ctx.add("structureItem", structure); + + + Map want = new HashMap<>(); + want.put("stringItem", "stringValue"); + want.put("boolItem", false); + want.put("integerItem", 1); + want.put("doubleItem", 1.2); + want.put("instantItem", Instant.ofEpochSecond(1663331342)); + List wantListItem = new ArrayList<>(); + wantListItem.add("item1"); + wantListItem.add("item2"); + want.put("listItem", wantListItem); + List wantListItem2 = new ArrayList<>(); + wantListItem2.add(true); + wantListItem2.add(false); + want.put("listItem2", wantListItem2); + Map wantStructureValue = new HashMap<>(); + wantStructureValue.put("structStringItem", "stringValue"); + wantStructureValue.put("structBoolItem", false); + wantStructureValue.put("structIntegerItem", 1); + wantStructureValue.put("structDoubleItem", 1.2); + wantStructureValue.put("structInstantItem", Instant.ofEpochSecond(1663331342)); + want.put("structureItem",wantStructureValue); + + assertEquals(want,ctx.asObjectMap()); + } } From cef8a537d377be26e877f3887f0517ab9d4abc93 Mon Sep 17 00:00:00 2001 From: Thomas Poignant Date: Fri, 16 Sep 2022 16:02:29 +0200 Subject: [PATCH 2/3] Fix liniting issue Signed-off-by: Thomas Poignant --- .../dev/openfeature/javasdk/Structure.java | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/main/java/dev/openfeature/javasdk/Structure.java b/src/main/java/dev/openfeature/javasdk/Structure.java index 4ecc9a48b..3382899e6 100644 --- a/src/main/java/dev/openfeature/javasdk/Structure.java +++ b/src/main/java/dev/openfeature/javasdk/Structure.java @@ -99,16 +99,16 @@ public Map asMap() { /** * Get all values, with primitives types. * - * @return all attributes on the structure into a Map + * @return all attributes on the structure into a Map */ public Map asObjectMap() { return attributes - .entrySet() - .stream() - .collect(Collectors.toMap( - Map.Entry::getKey, - e -> convertValue(getValue(e.getKey())) - )); + .entrySet() + .stream() + .collect(Collectors.toMap( + Map.Entry::getKey, + e -> convertValue(getValue(e.getKey())) + )); } /** @@ -116,12 +116,12 @@ public Map asObjectMap() { * @param value - Value object to convert * @return an Object containing the primitive type. */ - private Object convertValue(Value value){ - if (value.isBoolean()){ + private Object convertValue(Value value) { + if (value.isBoolean()) { return value.asBoolean(); } - if(value.isNumber()){ + if (value.isNumber()) { Double valueAsDouble = value.asDouble(); if ((valueAsDouble == Math.floor(valueAsDouble)) && !Double.isInfinite(valueAsDouble)) { return value.asInteger(); @@ -129,22 +129,22 @@ private Object convertValue(Value value){ return valueAsDouble; } - if(value.isString()){ + if (value.isString()) { return value.asString(); } - if(value.isInstant()) { + if (value.isInstant()) { return value.asInstant(); } - if(value.isList()){ + if (value.isList()) { return value.asList() .stream() .map(this::convertValue) .collect(Collectors.toList()); } - if(value.isStructure()){ + if (value.isStructure()) { Structure s = value.asStructure(); return s.asMap() .keySet() @@ -152,7 +152,7 @@ private Object convertValue(Value value){ .collect( Collectors.toMap( key -> key, - key-> convertValue(s.getValue(key)) + key -> convertValue(s.getValue(key)) ) ); } From 7f96af53e689f56d4ffebb249ec431bd2efed3c7 Mon Sep 17 00:00:00 2001 From: Thomas Poignant Date: Fri, 16 Sep 2022 16:10:49 +0200 Subject: [PATCH 3/3] fix PMD issue Signed-off-by: Thomas Poignant --- src/main/java/dev/openfeature/javasdk/Structure.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/dev/openfeature/javasdk/Structure.java b/src/main/java/dev/openfeature/javasdk/Structure.java index 3382899e6..87491e66c 100644 --- a/src/main/java/dev/openfeature/javasdk/Structure.java +++ b/src/main/java/dev/openfeature/javasdk/Structure.java @@ -123,7 +123,7 @@ private Object convertValue(Value value) { if (value.isNumber()) { Double valueAsDouble = value.asDouble(); - if ((valueAsDouble == Math.floor(valueAsDouble)) && !Double.isInfinite(valueAsDouble)) { + if (valueAsDouble == Math.floor(valueAsDouble) && !Double.isInfinite(valueAsDouble)) { return value.asInteger(); } return valueAsDouble;