Support for arbitrary classes in EvaluationContext
This commit is contained in:
parent
c9fae1b868
commit
9a8beadfd6
|
|
@ -26,6 +26,8 @@ repositories {
|
|||
|
||||
dependencies {
|
||||
implementation 'org.slf4j:slf4j-log4j12:1.7.29'
|
||||
implementation 'com.fasterxml.jackson.core:jackson-databind:2.13.0'
|
||||
|
||||
// This dependency is used internally, and not exposed to consumers on their own compile classpath.
|
||||
implementation 'com.google.guava:guava:30.1.1-jre'
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
package dev.openfeature.javasdk;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.*;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
|
@ -13,14 +11,32 @@ import java.util.Map;
|
|||
@ToString @EqualsAndHashCode
|
||||
@SuppressWarnings("PMD.BeanMembersShouldSerialize")
|
||||
public class EvaluationContext {
|
||||
@EqualsAndHashCode.Exclude private final ObjectMapper objMapper;
|
||||
@Setter @Getter private String targetingKey;
|
||||
private final Map<String, Integer> integerAttributes;
|
||||
private final Map<String, String> stringAttributes;
|
||||
private final Map<String, Boolean> booleanAttributes;
|
||||
final Map<String, String> jsonAttributes;
|
||||
|
||||
EvaluationContext() {
|
||||
objMapper = new ObjectMapper();
|
||||
this.targetingKey = "";
|
||||
this.integerAttributes = new HashMap<>();
|
||||
this.stringAttributes = new HashMap<>();
|
||||
booleanAttributes = new HashMap<>();
|
||||
jsonAttributes = new HashMap<>();
|
||||
}
|
||||
|
||||
// TODO Not sure if I should have sneakythrows or checked exceptions here..
|
||||
@SneakyThrows
|
||||
public <T> void addStructureAttribute(String key, T value) {
|
||||
jsonAttributes.put(key, objMapper.writeValueAsString(value));
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public <T> T getStructureAttribute(String key, Class<T> klass) {
|
||||
String val = jsonAttributes.get(key);
|
||||
return objMapper.readValue(val, klass);
|
||||
}
|
||||
|
||||
public void addStringAttribute(String key, String value) {
|
||||
|
|
@ -40,19 +56,17 @@ public class EvaluationContext {
|
|||
}
|
||||
|
||||
public Boolean getBooleanAttribute(String key) {
|
||||
return Boolean.valueOf(stringAttributes.get(key));
|
||||
return booleanAttributes.get(key);
|
||||
}
|
||||
|
||||
public void addBooleanAttribute(String key, Boolean b) {
|
||||
stringAttributes.put(key, b.toString());
|
||||
booleanAttributes.put(key, b);
|
||||
}
|
||||
|
||||
public void addDatetimeAttribute(String key, ZonedDateTime value) {
|
||||
this.stringAttributes.put(key, value.format(DateTimeFormatter.ISO_ZONED_DATE_TIME));
|
||||
}
|
||||
|
||||
// TODO: addStructure or similar.
|
||||
|
||||
public ZonedDateTime getDatetimeAttribute(String key) {
|
||||
String attr = this.stringAttributes.get(key);
|
||||
if (attr == null) {
|
||||
|
|
@ -66,21 +80,19 @@ public class EvaluationContext {
|
|||
*/
|
||||
public static EvaluationContext merge(EvaluationContext ctx1, EvaluationContext ctx2) {
|
||||
EvaluationContext ec = new EvaluationContext();
|
||||
for (Map.Entry<String, Integer> e : ctx1.integerAttributes.entrySet()) {
|
||||
ec.addIntegerAttribute(e.getKey(), e.getValue());
|
||||
}
|
||||
|
||||
for (Map.Entry<String, Integer> e : ctx2.integerAttributes.entrySet()) {
|
||||
ec.addIntegerAttribute(e.getKey(), e.getValue());
|
||||
}
|
||||
ec.stringAttributes.putAll(ctx1.stringAttributes);
|
||||
ec.stringAttributes.putAll(ctx2.stringAttributes);
|
||||
|
||||
for (Map.Entry<String, String> e : ctx1.stringAttributes.entrySet()) {
|
||||
ec.addStringAttribute(e.getKey(), e.getValue());
|
||||
}
|
||||
ec.integerAttributes.putAll(ctx1.integerAttributes);
|
||||
ec.integerAttributes.putAll(ctx2.integerAttributes);
|
||||
|
||||
ec.booleanAttributes.putAll(ctx1.booleanAttributes);
|
||||
ec.booleanAttributes.putAll(ctx2.booleanAttributes);
|
||||
|
||||
ec.jsonAttributes.putAll(ctx1.jsonAttributes);
|
||||
ec.jsonAttributes.putAll(ctx2.jsonAttributes);
|
||||
|
||||
for (Map.Entry<String, String> e : ctx2.stringAttributes.entrySet()) {
|
||||
ec.addStringAttribute(e.getKey(), e.getValue());
|
||||
}
|
||||
if (ctx1.getTargetingKey() != null) {
|
||||
ec.setTargetingKey(ctx1.getTargetingKey());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package dev.openfeature.javasdk;
|
||||
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
|
|
@ -40,6 +39,24 @@ public class EvalContextTests {
|
|||
@Specification(spec="Evaluation Context", number="3.2", text="The evaluation context MUST support the inclusion of " +
|
||||
"custom fields, having keys of type `string`, and " +
|
||||
"values of type `boolean | string | number | datetime | structure`.")
|
||||
@Disabled("Structure support")
|
||||
@Test void eval_context__structure() {}
|
||||
@Test void eval_context__structure() {
|
||||
Node<Integer> n1 = new Node<>();
|
||||
n1.value = 4;
|
||||
Node<Integer> n2 = new Node<>();
|
||||
n2.value = 2;
|
||||
n2.left = n1;
|
||||
|
||||
EvaluationContext ec = new EvaluationContext();
|
||||
ec.addStructureAttribute("obj", n2);
|
||||
|
||||
|
||||
String stringyObject = ec.jsonAttributes.get("obj");
|
||||
assertEquals("{\"left\":{\"left\":null,\"right\":null,\"value\":4},\"right\":null,\"value\":2}", stringyObject);
|
||||
|
||||
Node nodeFromString = ec.getStructureAttribute("obj", Node.class);
|
||||
assertEquals(n2, nodeFromString);
|
||||
assertEquals(n1, nodeFromString.left);
|
||||
assertEquals(2, nodeFromString.value);
|
||||
assertEquals(4, nodeFromString.left.value);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
package dev.openfeature.javasdk;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
/**
|
||||
* This is only for testing that object serialization works with both generics and nested classes.
|
||||
*/
|
||||
class Node<T> {
|
||||
Node<T> left, right;
|
||||
T value;
|
||||
}
|
||||
Loading…
Reference in New Issue