diff --git a/src/main/java/dev/openfeature/sdk/FlagEvaluationDetails.java b/src/main/java/dev/openfeature/sdk/FlagEvaluationDetails.java index f1697e309..beeadde15 100644 --- a/src/main/java/dev/openfeature/sdk/FlagEvaluationDetails.java +++ b/src/main/java/dev/openfeature/sdk/FlagEvaluationDetails.java @@ -1,6 +1,5 @@ package dev.openfeature.sdk; -import java.util.Optional; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -26,7 +25,7 @@ public class FlagEvaluationDetails implements BaseEvaluation { private String errorMessage; @Builder.Default - private ImmutableMetadata flagMetadata = ImmutableMetadata.builder().build(); + private ImmutableMetadata flagMetadata = ImmutableMetadata.EMPTY; /** * Generate detail payload from the provider response. @@ -37,15 +36,18 @@ public class FlagEvaluationDetails implements BaseEvaluation { * @return detail payload */ public static FlagEvaluationDetails from(ProviderEvaluation providerEval, String flagKey) { - return FlagEvaluationDetails.builder() - .flagKey(flagKey) - .value(providerEval.getValue()) - .variant(providerEval.getVariant()) - .reason(providerEval.getReason()) - .errorMessage(providerEval.getErrorMessage()) - .errorCode(providerEval.getErrorCode()) - .flagMetadata(Optional.ofNullable(providerEval.getFlagMetadata()) - .orElse(ImmutableMetadata.builder().build())) - .build(); + var flagMetadata = providerEval.getFlagMetadata(); + if (flagMetadata == null) { + flagMetadata = ImmutableMetadata.EMPTY; + } + + return new FlagEvaluationDetails<>( + flagKey, + providerEval.getValue(), + providerEval.getVariant(), + providerEval.getReason(), + providerEval.getErrorCode(), + providerEval.getErrorMessage(), + flagMetadata); } } diff --git a/src/main/java/dev/openfeature/sdk/FlagEvaluationOptions.java b/src/main/java/dev/openfeature/sdk/FlagEvaluationOptions.java index 01ecb9b2e..f73bd9631 100644 --- a/src/main/java/dev/openfeature/sdk/FlagEvaluationOptions.java +++ b/src/main/java/dev/openfeature/sdk/FlagEvaluationOptions.java @@ -10,6 +10,10 @@ @lombok.Value @Builder public class FlagEvaluationOptions { + + public static final FlagEvaluationOptions EMPTY = + FlagEvaluationOptions.builder().build(); + @Singular List hooks; diff --git a/src/main/java/dev/openfeature/sdk/HashMapUtils.java b/src/main/java/dev/openfeature/sdk/HashMapUtils.java new file mode 100644 index 000000000..88d255c25 --- /dev/null +++ b/src/main/java/dev/openfeature/sdk/HashMapUtils.java @@ -0,0 +1,11 @@ +package dev.openfeature.sdk; + +import java.util.HashMap; + +class HashMapUtils { + private HashMapUtils() {} + + static HashMap forEntries(int expectedEntries) { + return new HashMap<>((int) Math.ceil(expectedEntries / .75)); + } +} diff --git a/src/main/java/dev/openfeature/sdk/ImmutableContext.java b/src/main/java/dev/openfeature/sdk/ImmutableContext.java index e4916dfca..35f28d4f4 100644 --- a/src/main/java/dev/openfeature/sdk/ImmutableContext.java +++ b/src/main/java/dev/openfeature/sdk/ImmutableContext.java @@ -1,6 +1,7 @@ package dev.openfeature.sdk; import dev.openfeature.sdk.internal.ExcludeFromGeneratedCoverageReport; +import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.function.Function; @@ -20,7 +21,7 @@ @SuppressWarnings("PMD.BeanMembersShouldSerialize") public final class ImmutableContext implements EvaluationContext { - public static final ImmutableContext EMPTY = new ImmutableContext(); + public static final ImmutableContext EMPTY = new ImmutableContext(Collections.emptyMap()); @Delegate(excludes = DelegateExclusions.class) private final ImmutableStructure structure; @@ -58,7 +59,7 @@ public ImmutableContext(Map attributes) { * @param attributes evaluation context attributes */ public ImmutableContext(String targetingKey, Map attributes) { - if (targetingKey != null && !targetingKey.trim().isEmpty()) { + if (targetingKey != null && !targetingKey.isBlank()) { this.structure = new ImmutableStructure(targetingKey, attributes); } else { this.structure = new ImmutableStructure(attributes); diff --git a/src/main/java/dev/openfeature/sdk/ImmutableStructure.java b/src/main/java/dev/openfeature/sdk/ImmutableStructure.java index 849359424..313e13057 100644 --- a/src/main/java/dev/openfeature/sdk/ImmutableStructure.java +++ b/src/main/java/dev/openfeature/sdk/ImmutableStructure.java @@ -4,7 +4,6 @@ import java.util.HashSet; import java.util.Map; import java.util.Map.Entry; -import java.util.Optional; import java.util.Set; import lombok.EqualsAndHashCode; import lombok.ToString; @@ -69,15 +68,21 @@ private static Map copyAttributes(Map in) { } private static Map copyAttributes(Map in, String targetingKey) { - Map copy = new HashMap<>(); + Map copy; if (in != null) { + var numMappings = in.size(); + if (targetingKey != null) { + numMappings++; + } + copy = HashMapUtils.forEntries(numMappings); for (Entry entry : in.entrySet()) { - copy.put( - entry.getKey(), - Optional.ofNullable(entry.getValue()) - .map((Value val) -> val.clone()) - .orElse(null)); + var key = entry.getKey(); + var value = entry.getValue(); + Value cloned = value == null ? null : value.clone(); + copy.put(key, cloned); } + } else { + copy = new HashMap<>(targetingKey == null ? 0 : 1); } if (targetingKey != null) { copy.put(EvaluationContext.TARGETING_KEY, new Value(targetingKey)); diff --git a/src/main/java/dev/openfeature/sdk/OpenFeatureClient.java b/src/main/java/dev/openfeature/sdk/OpenFeatureClient.java index c5548b394..0d5d0e643 100644 --- a/src/main/java/dev/openfeature/sdk/OpenFeatureClient.java +++ b/src/main/java/dev/openfeature/sdk/OpenFeatureClient.java @@ -163,8 +163,13 @@ private FlagEvaluationDetails evaluateFlag( FlagEvaluationDetails details = null; HookSupportData hookSupportData = new HookSupportData(); - var flagOptions = ObjectUtils.defaultIfNull( - options, () -> FlagEvaluationOptions.builder().build()); + FlagEvaluationOptions flagOptions; + if (options == null) { + flagOptions = FlagEvaluationOptions.EMPTY; + } else { + flagOptions = options; + } + hookSupportData.hints = Collections.unmodifiableMap(flagOptions.getHookHints()); var context = new LayeredEvaluationContext( openfeatureApi.getEvaluationContext(), @@ -323,8 +328,7 @@ public FlagEvaluationDetails getBooleanDetails(String key, Boolean defa @Override public FlagEvaluationDetails getBooleanDetails(String key, Boolean defaultValue, EvaluationContext ctx) { - return getBooleanDetails( - key, defaultValue, ctx, FlagEvaluationOptions.builder().build()); + return getBooleanDetails(key, defaultValue, ctx, FlagEvaluationOptions.EMPTY); } @Override @@ -356,8 +360,7 @@ public FlagEvaluationDetails getStringDetails(String key, String default @Override public FlagEvaluationDetails getStringDetails(String key, String defaultValue, EvaluationContext ctx) { - return getStringDetails( - key, defaultValue, ctx, FlagEvaluationOptions.builder().build()); + return getStringDetails(key, defaultValue, ctx, FlagEvaluationOptions.EMPTY); } @Override @@ -389,8 +392,7 @@ public FlagEvaluationDetails getIntegerDetails(String key, Integer defa @Override public FlagEvaluationDetails getIntegerDetails(String key, Integer defaultValue, EvaluationContext ctx) { - return getIntegerDetails( - key, defaultValue, ctx, FlagEvaluationOptions.builder().build()); + return getIntegerDetails(key, defaultValue, ctx, FlagEvaluationOptions.EMPTY); } @Override @@ -454,8 +456,7 @@ public FlagEvaluationDetails getObjectDetails(String key, Value defaultVa @Override public FlagEvaluationDetails getObjectDetails(String key, Value defaultValue, EvaluationContext ctx) { - return getObjectDetails( - key, defaultValue, ctx, FlagEvaluationOptions.builder().build()); + return getObjectDetails(key, defaultValue, ctx, FlagEvaluationOptions.EMPTY); } @Override @@ -466,7 +467,7 @@ public FlagEvaluationDetails getObjectDetails( @Override public ClientMetadata getMetadata() { - return () -> domain; + return this::getDomain; } /**