Skip to content

Commit

Permalink
feat: Add asObjectMap to get the EvaluationContext as Map<String,Obje…
Browse files Browse the repository at this point in the history
…ct> (#75)

* Add asObjectMap to get the EvaluationContext as Map<String,Object>

Signed-off-by: Thomas Poignant <thomas.poignant@gofeatureflag.org>

* Fix liniting issue

Signed-off-by: Thomas Poignant <thomas.poignant@gofeatureflag.org>

* fix PMD issue

Signed-off-by: Thomas Poignant <thomas.poignant@gofeatureflag.org>

Signed-off-by: Thomas Poignant <thomas.poignant@gofeatureflag.org>
  • Loading branch information
thomaspoignant authored Sep 16, 2022
1 parent 5db90f1 commit 2eec1a5
Show file tree
Hide file tree
Showing 3 changed files with 133 additions and 7 deletions.
76 changes: 69 additions & 7 deletions src/main/java/dev/openfeature/javasdk/Structure.java
Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -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
Expand All @@ -90,10 +89,73 @@ public <T> Structure add(String key, List<Value> value) {

/**
* Get all values.
*
*
* @return all attributes on the structure
*/
public Map<String, Value> asMap() {
return new HashMap<>(this.attributes);
}

/**
* Get all values, with primitives types.
*
* @return all attributes on the structure into a Map
*/
public Map<String, Object> 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();
}
}
Original file line number Diff line number Diff line change
@@ -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;
}
52 changes: 52 additions & 0 deletions src/test/java/dev/openfeature/javasdk/EvalContextTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import java.time.Instant;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

Expand Down Expand Up @@ -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<Value> listItem = new ArrayList<>();
listItem.add(new Value("item1"));
listItem.add(new Value("item2"));
ctx.add("listItem", listItem);
List<Value> listItem2 = new ArrayList<>();
listItem2.add(new Value(true));
listItem2.add(new Value(false));
ctx.add("listItem2", listItem2);
Map<String, Value> 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<String, Object> 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<String> wantListItem = new ArrayList<>();
wantListItem.add("item1");
wantListItem.add("item2");
want.put("listItem", wantListItem);
List<Boolean> wantListItem2 = new ArrayList<>();
wantListItem2.add(true);
wantListItem2.add(false);
want.put("listItem2", wantListItem2);
Map<String, Object> 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());
}
}

0 comments on commit 2eec1a5

Please sign in to comment.