diff --git a/openfeature-provider-local/pom.xml b/openfeature-provider-local/pom.xml index 1157f168..907926e8 100644 --- a/openfeature-provider-local/pom.xml +++ b/openfeature-provider-local/pom.xml @@ -42,7 +42,12 @@ org.slf4j slf4j-api - + + + com.google.code.findbugs + jsr305 + + com.google.guava guava diff --git a/openfeature-provider-local/src/main/java/com/spotify/confidence/AccountStateProvider.java b/openfeature-provider-local/src/main/java/com/spotify/confidence/AccountStateProvider.java index 2fdd0d3e..959eb820 100644 --- a/openfeature-provider-local/src/main/java/com/spotify/confidence/AccountStateProvider.java +++ b/openfeature-provider-local/src/main/java/com/spotify/confidence/AccountStateProvider.java @@ -1,5 +1,7 @@ package com.spotify.confidence; +import javax.annotation.Nonnull; + /** * Functional interface for providing AccountState instances. * @@ -19,5 +21,6 @@ public interface AccountStateProvider { * @return the AccountState protobuf containing flag configurations and metadata * @throws RuntimeException if the AccountState cannot be provided */ + @Nonnull byte[] provide(); } diff --git a/openfeature-provider-local/src/main/java/com/spotify/confidence/ApiSecret.java b/openfeature-provider-local/src/main/java/com/spotify/confidence/ApiSecret.java index 79214fd1..5ef927a1 100644 --- a/openfeature-provider-local/src/main/java/com/spotify/confidence/ApiSecret.java +++ b/openfeature-provider-local/src/main/java/com/spotify/confidence/ApiSecret.java @@ -1,5 +1,7 @@ package com.spotify.confidence; +import javax.annotation.Nonnull; + /** * API credentials for authenticating with the Confidence service. * @@ -10,4 +12,4 @@ * @param clientSecret the client secret for your Confidence application * @since 0.2.4 */ -public record ApiSecret(String clientId, String clientSecret) {} +public record ApiSecret(@Nonnull String clientId, @Nonnull String clientSecret) {} diff --git a/openfeature-provider-local/src/main/java/com/spotify/confidence/MaterializationInfo.java b/openfeature-provider-local/src/main/java/com/spotify/confidence/MaterializationInfo.java index aa8d4b10..4d166705 100644 --- a/openfeature-provider-local/src/main/java/com/spotify/confidence/MaterializationInfo.java +++ b/openfeature-provider-local/src/main/java/com/spotify/confidence/MaterializationInfo.java @@ -2,9 +2,10 @@ import java.util.Map; import java.util.Optional; +import javax.annotation.Nonnull; public record MaterializationInfo( - boolean isUnitInMaterialization, Map ruleToVariant) { + boolean isUnitInMaterialization, @Nonnull Map ruleToVariant) { public Optional getVariantForRule(String rule) { return Optional.ofNullable(ruleToVariant.get(rule)); } diff --git a/openfeature-provider-local/src/main/java/com/spotify/confidence/MaterializationRepository.java b/openfeature-provider-local/src/main/java/com/spotify/confidence/MaterializationRepository.java index 8813871e..f421c43a 100644 --- a/openfeature-provider-local/src/main/java/com/spotify/confidence/MaterializationRepository.java +++ b/openfeature-provider-local/src/main/java/com/spotify/confidence/MaterializationRepository.java @@ -2,11 +2,14 @@ import java.util.Map; import java.util.concurrent.CompletableFuture; +import javax.annotation.Nonnull; public non-sealed interface MaterializationRepository extends StickyResolveStrategy { + @Nonnull CompletableFuture> loadMaterializedAssignmentsForUnit( - String unit, String materialization); + @Nonnull String unit, @Nonnull String materialization); + @Nonnull CompletableFuture storeAssignment( - String unit, Map assignments); + @Nonnull String unit, Map assignments); } diff --git a/openfeature-provider-local/src/main/java/com/spotify/confidence/OpenFeatureLocalResolveProvider.java b/openfeature-provider-local/src/main/java/com/spotify/confidence/OpenFeatureLocalResolveProvider.java index e5318123..7e8830a9 100644 --- a/openfeature-provider-local/src/main/java/com/spotify/confidence/OpenFeatureLocalResolveProvider.java +++ b/openfeature-provider-local/src/main/java/com/spotify/confidence/OpenFeatureLocalResolveProvider.java @@ -17,6 +17,7 @@ import io.grpc.StatusRuntimeException; import java.util.concurrent.ExecutionException; import java.util.function.Function; +import javax.annotation.Nonnull; import org.slf4j.Logger; /** @@ -89,7 +90,8 @@ public class OpenFeatureLocalResolveProvider implements FeatureProvider { * configuration * @since 0.2.4 */ - public OpenFeatureLocalResolveProvider(ApiSecret apiSecret, String clientSecret) { + public OpenFeatureLocalResolveProvider( + @Nonnull ApiSecret apiSecret, @Nonnull String clientSecret) { this(apiSecret, clientSecret, new RemoteResolverFallback(), new NoRetryStrategy()); } @@ -110,7 +112,9 @@ public OpenFeatureLocalResolveProvider(ApiSecret apiSecret, String clientSecret) * @since 0.2.4 */ public OpenFeatureLocalResolveProvider( - ApiSecret apiSecret, String clientSecret, StickyResolveStrategy stickyResolveStrategy) { + @Nonnull ApiSecret apiSecret, + @Nonnull String clientSecret, + @Nonnull StickyResolveStrategy stickyResolveStrategy) { this(apiSecret, clientSecret, stickyResolveStrategy, new NoRetryStrategy()); } @@ -133,10 +137,10 @@ public OpenFeatureLocalResolveProvider( * @since 0.2.4 */ public OpenFeatureLocalResolveProvider( - ApiSecret apiSecret, - String clientSecret, - StickyResolveStrategy stickyResolveStrategy, - RetryStrategy retryStrategy) { + @Nonnull ApiSecret apiSecret, + @Nonnull String clientSecret, + @Nonnull StickyResolveStrategy stickyResolveStrategy, + @Nonnull RetryStrategy retryStrategy) { final var env = System.getenv("LOCAL_RESOLVE_MODE"); if (env != null && env.equals("WASM")) { this.flagResolverService = @@ -166,10 +170,10 @@ public OpenFeatureLocalResolveProvider( */ @VisibleForTesting public OpenFeatureLocalResolveProvider( - AccountStateProvider accountStateProvider, - String accountId, - String clientSecret, - StickyResolveStrategy stickyResolveStrategy) { + @Nonnull AccountStateProvider accountStateProvider, + @Nonnull String accountId, + @Nonnull String clientSecret, + @Nonnull StickyResolveStrategy stickyResolveStrategy) { this( accountStateProvider, accountId, @@ -191,11 +195,11 @@ public OpenFeatureLocalResolveProvider( */ @VisibleForTesting public OpenFeatureLocalResolveProvider( - AccountStateProvider accountStateProvider, - String accountId, - String clientSecret, - StickyResolveStrategy stickyResolveStrategy, - RetryStrategy retryStrategy) { + @Nonnull AccountStateProvider accountStateProvider, + @Nonnull String accountId, + @Nonnull String clientSecret, + @Nonnull StickyResolveStrategy stickyResolveStrategy, + @Nonnull RetryStrategy retryStrategy) { this.stickyResolveStrategy = stickyResolveStrategy; this.clientSecret = clientSecret; this.flagResolverService = diff --git a/openfeature-provider/pom.xml b/openfeature-provider/pom.xml index ba126dfb..e8370c4d 100644 --- a/openfeature-provider/pom.xml +++ b/openfeature-provider/pom.xml @@ -102,7 +102,12 @@ org.slf4j slf4j-api - + + + com.google.code.findbugs + jsr305 + + com.google.guava guava diff --git a/openfeature-provider/src/main/java/com/spotify/confidence/ConfidenceFeatureProvider.java b/openfeature-provider/src/main/java/com/spotify/confidence/ConfidenceFeatureProvider.java index 8f7bc644..f220324c 100644 --- a/openfeature-provider/src/main/java/com/spotify/confidence/ConfidenceFeatureProvider.java +++ b/openfeature-provider/src/main/java/com/spotify/confidence/ConfidenceFeatureProvider.java @@ -21,6 +21,7 @@ import java.util.Map; import java.util.concurrent.ExecutionException; import java.util.function.Function; +import javax.annotation.Nonnull; import org.slf4j.Logger; /** OpenFeature Provider for feature flagging with the Confidence platform */ @@ -33,7 +34,7 @@ public class ConfidenceFeatureProvider implements FeatureProvider { * * @param confidenceBuilder a Confidence.Builder */ - public ConfidenceFeatureProvider(Confidence.Builder confidenceBuilder) { + public ConfidenceFeatureProvider(@Nonnull Confidence.Builder confidenceBuilder) { this.confidence = confidenceBuilder.buildForProvider(); } @@ -45,7 +46,7 @@ public ConfidenceFeatureProvider(Confidence.Builder confidenceBuilder) { * #ConfidenceFeatureProvider(Confidence.Builder)} instead. */ @Deprecated() - public ConfidenceFeatureProvider(Confidence confidence) { + public ConfidenceFeatureProvider(@Nonnull Confidence confidence) { this.confidence = confidence; } @@ -61,7 +62,8 @@ public ConfidenceFeatureProvider(Confidence confidence) { * #ConfidenceFeatureProvider(Confidence.Builder)} instead. */ @Deprecated() - public ConfidenceFeatureProvider(String clientSecret, ManagedChannel managedChannel) { + public ConfidenceFeatureProvider( + @Nonnull String clientSecret, @Nonnull ManagedChannel managedChannel) { this(Confidence.builder(clientSecret).flagResolverManagedChannel(managedChannel)); } @@ -73,7 +75,7 @@ public ConfidenceFeatureProvider(String clientSecret, ManagedChannel managedChan * #ConfidenceFeatureProvider(Confidence.Builder)} instead. */ @Deprecated() - public ConfidenceFeatureProvider(String clientSecret) { + public ConfidenceFeatureProvider(@Nonnull String clientSecret) { this(clientSecret, ManagedChannelBuilder.forAddress("edge-grpc.spotify.com", 443).build()); } @@ -88,7 +90,7 @@ public ConfidenceFeatureProvider(String clientSecret) { * #ConfidenceFeatureProvider(Confidence.Builder)} instead. */ @Deprecated() - public ConfidenceFeatureProvider(String clientSecret, String host, int port) { + public ConfidenceFeatureProvider(@Nonnull String clientSecret, @Nonnull String host, int port) { this(clientSecret, ManagedChannelBuilder.forAddress(host, port).usePlaintext().build()); } diff --git a/sdk-java/src/main/java/com/spotify/confidence/Contextual.java b/sdk-java/src/main/java/com/spotify/confidence/Contextual.java index 9bf6cf1f..708e08c6 100644 --- a/sdk-java/src/main/java/com/spotify/confidence/Contextual.java +++ b/sdk-java/src/main/java/com/spotify/confidence/Contextual.java @@ -2,6 +2,7 @@ import com.google.common.annotations.Beta; import java.util.Map; +import javax.annotation.Nonnull; /** * Interface for managing contextual data in Confidence SDK. Provides methods to set, update, and @@ -14,6 +15,7 @@ public interface Contextual { * * @return The current context as a {@link ConfidenceValue.Struct} */ + @Nonnull ConfidenceValue.Struct getContext(); /** @@ -21,14 +23,14 @@ public interface Contextual { * * @param context The new context data to set */ - void setContext(ConfidenceValue.Struct context); + void setContext(@Nonnull ConfidenceValue.Struct context); /** * Sets the context data using a Map of key-value pairs. * * @param context Map of context key-value pairs */ - default void setContext(Map context) { + default void setContext(@Nonnull Map context) { setContext(ConfidenceValue.Struct.of(context)); } @@ -38,14 +40,14 @@ default void setContext(Map context) { * @param key The key to update * @param value The new value for the key */ - void updateContextEntry(String key, ConfidenceValue value); + void updateContextEntry(@Nonnull String key, @Nonnull ConfidenceValue value); /** * Removes a single entry from the context data. * * @param key The key to remove */ - void removeContextEntry(String key); + void removeContextEntry(@Nonnull String key); /** Clears all context data. */ void clearContext(); @@ -56,7 +58,8 @@ default void setContext(Map context) { * @param context The new context to set * @return A new instance with the specified context */ - Contextual withContext(ConfidenceValue.Struct context); + @Nonnull + Contextual withContext(@Nonnull ConfidenceValue.Struct context); /** * Creates a new instance with the specified context map. @@ -64,7 +67,8 @@ default void setContext(Map context) { * @param context Map of context key-value pairs * @return A new instance with the specified context */ - default Contextual withContext(Map context) { + @Nonnull + default Contextual withContext(@Nonnull Map context) { return withContext(ConfidenceValue.Struct.of(context)); } } diff --git a/sdk-java/src/main/java/com/spotify/confidence/EventSender.java b/sdk-java/src/main/java/com/spotify/confidence/EventSender.java index fe9a1608..3ce78d52 100644 --- a/sdk-java/src/main/java/com/spotify/confidence/EventSender.java +++ b/sdk-java/src/main/java/com/spotify/confidence/EventSender.java @@ -2,6 +2,7 @@ import com.google.common.annotations.Beta; import java.util.Map; +import javax.annotation.Nonnull; /** * Interface for sending events to Confidence with context. Extends {@link Contextual} to provide @@ -15,14 +16,14 @@ public interface EventSender extends Contextual { * @param eventName The name of the event to track * @param data The data associated with the event */ - public void track(String eventName, ConfidenceValue.Struct data); + public void track(@Nonnull String eventName, @Nonnull ConfidenceValue.Struct data); /** * Tracks an event without associated data. * * @param eventName The name of the event to track */ - public void track(String eventName); + public void track(@Nonnull String eventName); /** Flushes any pending events to ensure they are sent. */ void flush(); @@ -33,8 +34,9 @@ public interface EventSender extends Contextual { * @param context The new context to set * @return A new instance with the specified context */ + @Nonnull @Override - EventSender withContext(ConfidenceValue.Struct context); + EventSender withContext(@Nonnull ConfidenceValue.Struct context); /** * Creates a new instance with the specified context map. @@ -42,8 +44,9 @@ public interface EventSender extends Contextual { * @param context Map of context key-value pairs * @return A new instance with the specified context */ + @Nonnull @Override - default EventSender withContext(Map context) { + default EventSender withContext(@Nonnull Map context) { return withContext(ConfidenceValue.Struct.of(context)); } } diff --git a/sdk-java/src/main/java/com/spotify/confidence/FlagEvaluator.java b/sdk-java/src/main/java/com/spotify/confidence/FlagEvaluator.java index c3d784ae..d0d50ce3 100644 --- a/sdk-java/src/main/java/com/spotify/confidence/FlagEvaluator.java +++ b/sdk-java/src/main/java/com/spotify/confidence/FlagEvaluator.java @@ -1,6 +1,7 @@ package com.spotify.confidence; import java.util.Map; +import javax.annotation.Nonnull; /** * Interface for evaluating feature flags with context. Extends {@link Contextual} to provide @@ -15,7 +16,8 @@ public interface FlagEvaluator extends Contextual { * @param The type of the flag value * @return The evaluated flag value or the default value if evaluation fails */ - T getValue(String key, T defaultValue); + @Nonnull + T getValue(@Nonnull String key, @Nonnull T defaultValue); /** * Gets a detailed evaluation of a feature flag for the current context. @@ -25,7 +27,8 @@ public interface FlagEvaluator extends Contextual { * @param The type of the flag value * @return A {@link FlagEvaluation} containing the evaluated value and evaluation details */ - FlagEvaluation getEvaluation(String key, T defaultValue); + @Nonnull + FlagEvaluation getEvaluation(@Nonnull String key, @Nonnull T defaultValue); /** * Creates a new instance with the specified context. @@ -33,8 +36,9 @@ public interface FlagEvaluator extends Contextual { * @param context The new context to set * @return A new instance with the specified context */ + @Nonnull @Override - FlagEvaluator withContext(ConfidenceValue.Struct context); + FlagEvaluator withContext(@Nonnull ConfidenceValue.Struct context); /** * Creates a new instance with the specified context map. @@ -42,8 +46,9 @@ public interface FlagEvaluator extends Contextual { * @param context Map of context key-value pairs * @return A new instance with the specified context */ + @Nonnull @Override - default FlagEvaluator withContext(Map context) { + default FlagEvaluator withContext(@Nonnull Map context) { return withContext(ConfidenceValue.Struct.of(context)); } }