Skip to content

Commit b34331a

Browse files
committed
Support for object types
fixes #7
1 parent 9a8bead commit b34331a

File tree

9 files changed

+76
-19
lines changed

9 files changed

+76
-19
lines changed

lib/src/main/java/dev/openfeature/javasdk/FeatureProvider.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ public interface FeatureProvider {
55
ProviderEvaluation<Boolean> getBooleanEvaluation(String key, Boolean defaultValue, EvaluationContext ctx, FlagEvaluationOptions options);
66
ProviderEvaluation<String> getStringEvaluation(String key, String defaultValue, EvaluationContext ctx, FlagEvaluationOptions options);
77
ProviderEvaluation<Integer> getIntegerEvaluation(String key, Integer defaultValue, EvaluationContext ctx, FlagEvaluationOptions options);
8+
<T> ProviderEvaluation<T> getObjectEvaluation(String key, T defaultValue, EvaluationContext invocationContext, FlagEvaluationOptions options);
89
}

lib/src/main/java/dev/openfeature/javasdk/Features.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ public interface Features {
2626
FlagEvaluationDetails<Integer> getIntegerDetails(String key, Integer defaultValue, EvaluationContext ctx);
2727
FlagEvaluationDetails<Integer> getIntegerDetails(String key, Integer defaultValue, EvaluationContext ctx, FlagEvaluationOptions options);
2828

29-
// TODO: Object
29+
<T> T getObjectValue(String key, T defaultValue);
30+
<T> T getObjectValue(String key, T defaultValue, EvaluationContext ctx);
31+
<T> T getObjectValue(String key, T defaultValue, EvaluationContext ctx, FlagEvaluationOptions options);
32+
33+
<T> FlagEvaluationDetails<T> getObjectDetails(String key, T defaultValue);
34+
<T> FlagEvaluationDetails<T> getObjectDetails(String key, T defaultValue, EvaluationContext ctx);
35+
<T> FlagEvaluationDetails<T> getObjectDetails(String key, T defaultValue, EvaluationContext ctx, FlagEvaluationOptions options);
3036

3137
}

lib/src/main/java/dev/openfeature/javasdk/NoOpProvider.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,13 @@ public ProviderEvaluation<Integer> getIntegerEvaluation(String key, Integer defa
3232
.reason(Reason.DEFAULT)
3333
.build();
3434
}
35+
36+
@Override
37+
public <T> ProviderEvaluation<T> getObjectEvaluation(String key, T defaultValue, EvaluationContext invocationContext, FlagEvaluationOptions options) {
38+
return ProviderEvaluation.<T>builder()
39+
.value(defaultValue)
40+
.variant("Passed in default")
41+
.reason(Reason.DEFAULT)
42+
.build();
43+
}
3544
}

lib/src/main/java/dev/openfeature/javasdk/OpenFeatureClient.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ <T> FlagEvaluationDetails<T> evaluateFlag(FlagValueType type, String key, T defa
6969
providerEval = (ProviderEvaluation<T>) provider.getStringEvaluation(key, (String) defaultValue, invocationContext, options);
7070
} else if (type == FlagValueType.INTEGER) {
7171
providerEval = (ProviderEvaluation<T>) provider.getIntegerEvaluation(key, (Integer) defaultValue, invocationContext, options);
72+
} else if (type == FlagValueType.OBJECT) {
73+
providerEval = (ProviderEvaluation<T>) provider.getObjectEvaluation(key, defaultValue, invocationContext, options);
7274
} else {
7375
throw new GeneralError("Unknown flag type");
7476
}
@@ -215,4 +217,34 @@ public FlagEvaluationDetails<Integer> getIntegerDetails(String key, Integer defa
215217
public FlagEvaluationDetails<Integer> getIntegerDetails(String key, Integer defaultValue, EvaluationContext ctx, FlagEvaluationOptions options) {
216218
return this.evaluateFlag(FlagValueType.INTEGER, key, defaultValue, ctx, options);
217219
}
220+
221+
@Override
222+
public <T> T getObjectValue(String key, T defaultValue) {
223+
return getObjectDetails(key, defaultValue).getValue();
224+
}
225+
226+
@Override
227+
public <T> T getObjectValue(String key, T defaultValue, EvaluationContext ctx) {
228+
return getObjectDetails(key, defaultValue, ctx).getValue();
229+
}
230+
231+
@Override
232+
public <T> T getObjectValue(String key, T defaultValue, EvaluationContext ctx, FlagEvaluationOptions options) {
233+
return getObjectDetails(key, defaultValue, ctx, options).getValue();
234+
}
235+
236+
@Override
237+
public <T> FlagEvaluationDetails<T> getObjectDetails(String key, T defaultValue) {
238+
return getObjectDetails(key, defaultValue, null);
239+
}
240+
241+
@Override
242+
public <T> FlagEvaluationDetails<T> getObjectDetails(String key, T defaultValue, EvaluationContext ctx) {
243+
return getObjectDetails(key, defaultValue, ctx, FlagEvaluationOptions.builder().build());
244+
}
245+
246+
@Override
247+
public <T> FlagEvaluationDetails<T> getObjectDetails(String key, T defaultValue, EvaluationContext ctx, FlagEvaluationOptions options) {
248+
return this.evaluateFlag(FlagValueType.OBJECT, key, defaultValue, ctx, options);
249+
}
218250
}

lib/src/test/java/dev/openfeature/javasdk/AlwaysBrokenProvider.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,9 @@ public ProviderEvaluation<String> getStringEvaluation(String key, String default
2121
public ProviderEvaluation<Integer> getIntegerEvaluation(String key, Integer defaultValue, EvaluationContext ctx, FlagEvaluationOptions options) {
2222
throw new NotImplementedException();
2323
}
24+
25+
@Override
26+
public <T> ProviderEvaluation<T> getObjectEvaluation(String key, T defaultValue, EvaluationContext invocationContext, FlagEvaluationOptions options) {
27+
throw new NotImplementedException();
28+
}
2429
}

lib/src/test/java/dev/openfeature/javasdk/DoSomethingProvider.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,11 @@ public ProviderEvaluation<Integer> getIntegerEvaluation(String key, Integer defa
2525
.value(defaultValue * 100)
2626
.build();
2727
}
28+
29+
@Override
30+
public <T> ProviderEvaluation<T> getObjectEvaluation(String key, T defaultValue, EvaluationContext invocationContext, FlagEvaluationOptions options) {
31+
return ProviderEvaluation.<T>builder()
32+
.value(null)
33+
.build();
34+
}
2835
}

lib/src/test/java/dev/openfeature/javasdk/FlagEvaluationSpecTests.java

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -99,17 +99,11 @@ Client _client() {
9999
assertEquals(400, c.getIntegerValue(key, 4, new EvaluationContext()));
100100
assertEquals(400, c.getIntegerValue(key, 4, new EvaluationContext(), FlagEvaluationOptions.builder().build()));
101101

102+
assertEquals(null, c.getObjectValue(key, new Node<Integer>()));
103+
assertEquals(null, c.getObjectValue(key, new Node<Integer>(), new EvaluationContext()));
104+
assertEquals(null, c.getObjectValue(key, new Node<Integer>(), new EvaluationContext(), FlagEvaluationOptions.builder().build()));
102105
}
103106

104-
@Specification(spec="flag evaluation", number="1.7", text="The client MUST provide methods for flag evaluation, with" +
105-
" parameters flag key (string, required), default value (boolean | number | string | structure, required), " +
106-
"evaluation context (optional), and evaluation options (optional), which returns the flag value.")
107-
@Disabled
108-
@Test void value_flags__object() {
109-
throw new NotImplementedException();
110-
}
111-
112-
113107
@Specification(spec="flag evaluation", number="1.9", text="The client MUST provide methods for detailed flag value " +
114108
"evaluation with parameters flag key (string, required), default value (boolean | number | string | " +
115109
"structure, required), evaluation context (optional), and evaluation options (optional), which returns an " +

lib/src/test/java/dev/openfeature/javasdk/NoOpProviderTest.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package dev.openfeature.javasdk;
22

3-
import dev.openfeature.javasdk.NoOpProvider;
4-
import dev.openfeature.javasdk.ProviderEvaluation;
53
import org.junit.jupiter.api.Test;
64

75
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -25,4 +23,11 @@ public class NoOpProviderTest {
2523
ProviderEvaluation<Integer> eval = p.getIntegerEvaluation("key", 4, null, null);
2624
assertEquals(4, eval.getValue());
2725
}
26+
27+
@Test void structure() {
28+
NoOpProvider p = new NoOpProvider();
29+
Node<Integer> node = new Node<Integer>();
30+
ProviderEvaluation<Node> eval = p.getObjectEvaluation("key", node, null, null);
31+
assertEquals(node, eval.getValue());
32+
}
2833
}

lib/src/test/java/dev/openfeature/javasdk/ProviderSpecTests.java

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package dev.openfeature.javasdk;
22

3-
import dev.openfeature.javasdk.*;
43
import org.junit.jupiter.api.Disabled;
54
import org.junit.jupiter.api.Test;
65

@@ -15,6 +14,8 @@ public class ProviderSpecTests {
1514
assertNotNull(p.getName());
1615
}
1716

17+
@Specification(spec="provider", number="2.3.1", text="The feature provider interface MUST define methods for typed " +
18+
"flag resolution, including boolean, numeric, string, and structure.")
1819
@Specification(spec="provider", number="2.4", text="In cases of normal execution, the provider MUST populate the " +
1920
"flag resolution structure's value field with the resolved flag value.")
2021
@Specification(spec="provider", number="2.2", text="The feature provider interface MUST define methods to resolve " +
@@ -32,6 +33,9 @@ public class ProviderSpecTests {
3233

3334
ProviderEvaluation<Boolean> boolean_result = p.getBooleanEvaluation("key", false, new EvaluationContext(), FlagEvaluationOptions.builder().build());
3435
assertNotNull(boolean_result.getValue());
36+
37+
ProviderEvaluation<Node<Integer>> object_result = p.getObjectEvaluation("key", new Node<Integer>(), new EvaluationContext(), FlagEvaluationOptions.builder().build());
38+
assertNotNull(boolean_result.getValue());
3539
}
3640

3741
@Specification(spec="provider", number="2.6", text="The provider SHOULD populate the flag resolution structure's " +
@@ -48,12 +52,6 @@ public class ProviderSpecTests {
4852
assertNull(result.getErrorCode());
4953
}
5054

51-
@Specification(spec="provider", number="2.3.1", text="The feature provider interface MUST define methods for typed " +
52-
"flag resolution, including boolean, numeric, string, and structure.")
53-
@Disabled("Don't yet support structures") @Test void structure_validation() {
54-
55-
}
56-
5755
@Specification(spec="provider", number="2.8", text="In cases of abnormal execution, the provider MUST indicate an " +
5856
"error using the idioms of the implementation language, with an associated error code having possible " +
5957
"values PROVIDER_NOT_READY, FLAG_NOT_FOUND, PARSE_ERROR, TYPE_MISMATCH, or GENERAL.")

0 commit comments

Comments
 (0)