Skip to content

Commit 0dee929

Browse files
committed
feat: add HookContext decorator
Signed-off-by: Simon Schrottner <[email protected]>
1 parent a4fc956 commit 0dee929

File tree

6 files changed

+115
-35
lines changed

6 files changed

+115
-35
lines changed
Lines changed: 27 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,14 @@
11
package dev.openfeature.sdk;
22

3-
import lombok.Builder;
4-
import lombok.NonNull;
5-
import lombok.Value;
6-
import lombok.With;
3+
import dev.openfeature.sdk.HookContextWithoutData.HookContextWithoutDataBuilder;
74

85
/**
9-
* A data class to hold immutable context that {@link Hook} instances use.
6+
* A interface to hold immutable context that {@link Hook} instances use.
107
*
11-
* @param <T> the type for the flag being evaluated
128
*/
13-
@Value
14-
@Builder(toBuilder = true)
15-
@With
16-
public class HookContext<T> {
17-
@NonNull String flagKey;
18-
19-
@NonNull FlagValueType type;
20-
21-
@NonNull T defaultValue;
22-
23-
@NonNull EvaluationContext ctx;
24-
25-
ClientMetadata clientMetadata;
26-
Metadata providerMetadata;
27-
9+
public interface HookContext<T> {
2810
/**
29-
* Hook data provides a way for hooks to maintain state across their execution stages.
30-
* Each hook instance gets its own isolated data store.
31-
*/
32-
HookData hookData;
33-
34-
/**
35-
* Builds a {@link HookContext} instances from request data.
11+
* Builds a {@link HookContextWithoutData} instances from request data.
3612
*
3713
* @param key feature flag key
3814
* @param type flag value type
@@ -43,14 +19,14 @@ public class HookContext<T> {
4319
* @param <T> type that the flag is evaluating against
4420
* @return resulting context for hook
4521
*/
46-
public static <T> HookContext<T> from(
22+
static <T> HookContext<T> from(
4723
String key,
4824
FlagValueType type,
4925
ClientMetadata clientMetadata,
5026
Metadata providerMetadata,
5127
EvaluationContext ctx,
5228
T defaultValue) {
53-
return HookContext.<T>builder()
29+
return HookContextWithoutData.<T>builder()
5430
.flagKey(key)
5531
.type(type)
5632
.clientMetadata(clientMetadata)
@@ -60,4 +36,25 @@ public static <T> HookContext<T> from(
6036
.hookData(null) // Explicitly set to null for backward compatibility
6137
.build();
6238
}
39+
40+
/**
41+
* Returns a builder for our default HookContext object.
42+
*/
43+
static <T> HookContextWithoutDataBuilder<T> builder() {
44+
return HookContextWithoutData.<T>builder();
45+
}
46+
47+
String getFlagKey();
48+
49+
FlagValueType getType();
50+
51+
T getDefaultValue();
52+
53+
EvaluationContext getCtx();
54+
55+
ClientMetadata getClientMetadata();
56+
57+
Metadata getProviderMetadata();
58+
59+
HookData getHookData();
6360
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package dev.openfeature.sdk;
2+
3+
class HookContextWithData<T> implements HookContext<T> {
4+
private final HookContext<T> context;
5+
private final HookData data;
6+
7+
private HookContextWithData(HookContext<T> context, HookData data) {
8+
this.context = context;
9+
this.data = data;
10+
}
11+
12+
public static <T> HookContextWithData<T> of(HookContext<T> context, HookData data) {
13+
return new HookContextWithData<>(context, data);
14+
}
15+
16+
@Override
17+
public String getFlagKey() {
18+
return context.getFlagKey();
19+
}
20+
21+
@Override
22+
public FlagValueType getType() {
23+
return context.getType();
24+
}
25+
26+
@Override
27+
public T getDefaultValue() {
28+
return context.getDefaultValue();
29+
}
30+
31+
@Override
32+
public EvaluationContext getCtx() {
33+
return context.getCtx();
34+
}
35+
36+
@Override
37+
public ClientMetadata getClientMetadata() {
38+
return context.getClientMetadata();
39+
}
40+
41+
@Override
42+
public Metadata getProviderMetadata() {
43+
return context.getProviderMetadata();
44+
}
45+
46+
@Override
47+
public HookData getHookData() {
48+
return data;
49+
}
50+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package dev.openfeature.sdk;
2+
3+
import lombok.Builder;
4+
import lombok.NonNull;
5+
import lombok.Value;
6+
import lombok.With;
7+
8+
/**
9+
* A data class to hold immutable context that {@link Hook} instances use.
10+
*
11+
* @param <T> the type for the flag being evaluated
12+
*/
13+
@Value
14+
@Builder
15+
@With
16+
class HookContextWithoutData<T> implements HookContext<T> {
17+
@NonNull String flagKey;
18+
19+
@NonNull FlagValueType type;
20+
21+
@NonNull T defaultValue;
22+
23+
@NonNull EvaluationContext ctx;
24+
25+
ClientMetadata clientMetadata;
26+
Metadata providerMetadata;
27+
28+
/**
29+
* Hook data provides a way for hooks to maintain state across their execution stages.
30+
* Each hook instance gets its own isolated data store.
31+
*/
32+
HookData hookData;
33+
}

src/main/java/dev/openfeature/sdk/HookSupport.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ private <T> void executeChecked(
9090
BiConsumer<Hook<T>, HookContext> hookCode,
9191
String hookMethod) {
9292
try {
93-
var hookCtxWithData = hookContext.withHookData(hookData);
93+
var hookCtxWithData = HookContextWithData.of(hookContext, hookData);
9494
hookCode.accept(hook, hookCtxWithData);
9595
} catch (Exception exception) {
9696
log.error(
@@ -112,7 +112,7 @@ private <T> void executeHooksUnchecked(
112112
Hook hook = hookDataPair.getLeft();
113113
HookData hookData = hookDataPair.getRight();
114114
if (hook.supportsFlagValueType(flagValueType)) {
115-
var hookCtxWithData = hookContext.withHookData(hookData);
115+
var hookCtxWithData = HookContextWithData.of(hookContext, hookData);
116116
hookCode.accept(hook, hookCtxWithData);
117117
}
118118
}
@@ -135,7 +135,7 @@ private EvaluationContext callBeforeHooks(
135135

136136
if (hook.supportsFlagValueType(flagValueType)) {
137137
// Create a new context with this hook's data
138-
HookContext contextWithHookData = hookCtx.withHookData(hookData);
138+
HookContext contextWithHookData = HookContextWithData.of(hookCtx, hookData);
139139
Optional<EvaluationContext> optional = Optional.ofNullable(hook.before(contextWithHookData, hints))
140140
.orElse(Optional.empty());
141141
if (optional.isPresent()) {

src/test/java/dev/openfeature/sdk/HookContextTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ void shouldCreateHookContextWithHookDataUsingWith() {
7171
HookData hookData = HookData.create();
7272
hookData.set("timing", System.currentTimeMillis());
7373

74-
HookContext<String> contextWithHookData = originalContext.withHookData(hookData);
74+
HookContext<String> contextWithHookData = HookContextWithData.of(originalContext, hookData);
7575

7676
assertNull(originalContext.getHookData());
7777
assertNotNull(contextWithHookData.getHookData());

src/test/java/dev/openfeature/sdk/HookSupportTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ void shouldMergeEvaluationContextsOnBeforeHooksCorrectly() {
2525
attributes.put("baseKey", new Value("baseValue"));
2626
EvaluationContext baseContext = new ImmutableContext(attributes);
2727
FlagValueType valueType = FlagValueType.STRING;
28-
HookContext<String> hookContext = HookContext.<String>builder()
28+
HookContext<String> hookContext = HookContextWithoutData.<String>builder()
2929
.flagKey("flagKey")
3030
.type(valueType)
3131
.defaultValue("defaultValue")

0 commit comments

Comments
 (0)