33import java .util .HashMap ;
44import java .util .Map ;
55import java .util .function .Function ;
6+
67import dev .openfeature .sdk .internal .ExcludeFromGeneratedCoverageReport ;
78import lombok .ToString ;
89import lombok .experimental .Delegate ;
910
1011/**
1112 * The EvaluationContext is a container for arbitrary contextual data
1213 * that can be used as a basis for dynamic evaluation.
13- * The ImmutableContext is an EvaluationContext implementation which is threadsafe, and whose attributes can
14+ * The ImmutableContext is an EvaluationContext implementation which is
15+ * threadsafe, and whose attributes can
1416 * not be modified after instantiation.
1517 */
1618@ ToString
@@ -21,7 +23,8 @@ public final class ImmutableContext implements EvaluationContext {
2123 private final ImmutableStructure structure ;
2224
2325 /**
24- * Create an immutable context with an empty targeting_key and attributes provided.
26+ * Create an immutable context with an empty targeting_key and attributes
27+ * provided.
2528 */
2629 public ImmutableContext () {
2730 this (new HashMap <>());
@@ -42,7 +45,7 @@ public ImmutableContext(String targetingKey) {
4245 * @param attributes evaluation context attributes
4346 */
4447 public ImmutableContext (Map <String , Value > attributes ) {
45- this ("" , attributes );
48+ this (null , attributes );
4649 }
4750
4851 /**
@@ -53,9 +56,7 @@ public ImmutableContext(Map<String, Value> attributes) {
5356 */
5457 public ImmutableContext (String targetingKey , Map <String , Value > attributes ) {
5558 if (targetingKey != null && !targetingKey .trim ().isEmpty ()) {
56- final Map <String , Value > actualAttribs = new HashMap <>(attributes );
57- actualAttribs .put (TARGETING_KEY , new Value (targetingKey ));
58- this .structure = new ImmutableStructure (actualAttribs );
59+ this .structure = new ImmutableStructure (targetingKey , attributes );
5960 } else {
6061 this .structure = new ImmutableStructure (attributes );
6162 }
@@ -71,31 +72,33 @@ public String getTargetingKey() {
7172 }
7273
7374 /**
74- * Merges this EvaluationContext object with the passed EvaluationContext, overriding in case of conflict.
75+ * Merges this EvaluationContext object with the passed EvaluationContext,
76+ * overriding in case of conflict.
7577 *
7678 * @param overridingContext overriding context
7779 * @return new, resulting merged context
7880 */
7981 @ Override
8082 public EvaluationContext merge (EvaluationContext overridingContext ) {
8183 if (overridingContext == null || overridingContext .isEmpty ()) {
82- return new ImmutableContext (this .asMap ());
84+ return new ImmutableContext (this .asUnmodifiableMap ());
8385 }
8486 if (this .isEmpty ()) {
85- return new ImmutableContext (overridingContext .asMap ());
87+ return new ImmutableContext (overridingContext .asUnmodifiableMap ());
8688 }
8789
88- return new ImmutableContext (
89- this .merge (ImmutableStructure ::new , this .asMap (), overridingContext .asMap ()));
90+ Map <String , Value > attributes = this .asMap ();
91+ EvaluationContext .mergeMaps (ImmutableStructure ::new , attributes ,
92+ overridingContext .asUnmodifiableMap ());
93+ return new ImmutableContext (attributes );
9094 }
9195
9296 @ SuppressWarnings ("all" )
9397 private static class DelegateExclusions {
9498 @ ExcludeFromGeneratedCoverageReport
95- public <T extends Structure > Map <String , Value > merge (Function <Map <String , Value >, Structure > newStructure ,
99+ public <T extends Structure > Map <String , Value > merge (Function <Map <String , Value >, Structure > newStructure ,
96100 Map <String , Value > base ,
97101 Map <String , Value > overriding ) {
98-
99102 return null ;
100103 }
101104 }
0 commit comments