From 00c2a9cce91a40ffac5ccb35a2dca02ab6cffcd7 Mon Sep 17 00:00:00 2001 From: Volodymyr Nazarkevych Date: Tue, 4 Feb 2025 21:06:25 +0200 Subject: [PATCH 1/4] Refactor: move classes to appropriate packages --- .../java/growthbook/sdk/java/GrowthBook.java | 11 +++++ .../java/growthbook/sdk/java/IGrowthBook.java | 4 ++ .../java/growthbook/sdk/java/Version.java | 4 +- .../{ => callback}/ExperimentRunCallback.java | 5 ++- .../FeatureRefreshCallback.java | 4 +- .../{ => callback}/FeatureUsageCallback.java | 4 +- .../java/{ => callback}/TrackingCallback.java | 5 ++- .../{ => evaluators}/ConditionEvaluator.java | 10 +++-- .../{ => evaluators}/ExperimentEvaluator.java | 30 +++++++++---- .../{ => evaluators}/FeatureEvaluator.java | 15 ++++++- .../{ => evaluators}/IConditionEvaluator.java | 2 +- .../IExperimentEvaluator.java | 5 ++- .../{ => evaluators}/IFeatureEvaluator.java | 4 +- .../FeatureFetchException.java | 3 +- .../java/{ => model}/AssignedExperiment.java | 2 +- .../sdk/java/{ => model}/BucketRange.java | 2 +- .../sdk/java/{ => model}/DataType.java | 2 +- .../sdk/java/{ => model}/Experiment.java | 3 +- .../java/{ => model}/ExperimentResult.java | 4 +- .../sdk/java/{ => model}/Feature.java | 2 +- .../java/{ => model}/FeatureResponseKey.java | 4 +- .../sdk/java/{ => model}/FeatureResult.java | 4 +- .../java/{ => model}/FeatureResultSource.java | 2 +- .../sdk/java/{ => model}/FeatureRule.java | 2 +- .../sdk/java/{ => model}/Filter.java | 3 +- .../sdk/java/{ => model}/GBContext.java | 6 ++- ...neratedStickyBucketAssignmentDocModel.java | 4 +- .../HashAttributeAndHashValue.java | 4 +- .../sdk/java/{ => model}/HttpHeaders.java | 4 +- .../sdk/java/{ => model}/HttpMethods.java | 4 +- .../sdk/java/{ => model}/Namespace.java | 2 +- .../sdk/java/{ => model}/Operator.java | 2 +- .../sdk/java/{ => model}/OptionalField.java | 2 +- .../sdk/java/{ => model}/ParentCondition.java | 2 +- .../{ => model}/RequestBodyForRemoteEval.java | 2 +- .../sdk/java/{ => model}/SseKey.java | 4 +- .../{ => model}/StickyBucketVariation.java | 4 +- .../sdk/java/{ => model}/TrackData.java | 3 +- .../sdk/java/{ => model}/VariationMeta.java | 4 +- .../java/multiusermode/GrowthBookClient.java | 13 +++++- .../configurations/GlobalContext.java | 3 +- .../multiusermode/configurations/Options.java | 6 ++- .../usage/FeatureUsageCallbackAdapter.java | 4 +- .../usage/FeatureUsageCallbackWithUser.java | 2 +- .../usage/TrackingCallbackAdapter.java | 6 +-- .../usage/TrackingCallbackWithUser.java | 4 +- .../util/TransformationUtil.java | 4 +- .../FeatureRefreshStrategy.java | 2 +- .../GBFeaturesRepository.java | 11 ++++- ...BFeaturesRepositoryRequestInterceptor.java | 3 +- .../IGBFeaturesRepository.java | 7 ++- .../LocalGbFeatureRepository.java | 4 +- .../NativeJavaGbFeatureRepository.java | 20 ++++++--- .../java/{ => sandbox}/CachingManager.java | 2 +- .../sdk/java/{ => util}/DecryptionUtils.java | 2 +- .../sdk/java/{ => util}/ExperimentHelper.java | 13 +++--- .../java/{ => util}/GrowthBookJsonUtils.java | 7 ++- .../sdk/java/{ => util}/GrowthBookUtils.java | 14 +++++- .../sdk/java/{ => util}/MathUtils.java | 4 +- .../sdk/java/{ => util}/StringUtils.java | 4 +- .../sdk/java/{ => util}/UrlUtils.java | 4 +- .../growthbook/sdk/java/BucketRangeTest.java | 6 ++- .../sdk/java/CachingManagerTest.java | 1 + .../sdk/java/ConditionEvaluatorTest.java | 8 +++- .../sdk/java/DecryptionUtilsTest.java | 1 + ...FeatureWithStickyBucketingFeatureTest.java | 4 ++ .../sdk/java/ExperimentResultTest.java | 2 + .../growthbook/sdk/java/ExperimentTest.java | 43 ++++++++++--------- .../sdk/java/FeatureFetchExceptionTest.java | 1 + .../sdk/java/FeatureResultTest.java | 8 +++- .../growthbook/sdk/java/FeatureRuleTest.java | 29 +++++++------ .../java/growthbook/sdk/java/FilterTest.java | 2 + .../growthbook/sdk/java/GBContextTest.java | 4 ++ .../GBFeaturesRepositoryRefreshingTest.java | 3 ++ .../sdk/java/GBFeaturesRepositoryTest.java | 6 +++ .../sdk/java/GrowthBookJsonUtilsTest.java | 4 ++ .../growthbook/sdk/java/GrowthBookTest.java | 19 ++++++-- .../sdk/java/GrowthBookUtilsTest.java | 4 ++ .../java/LocalGbFeatureRepositoryTest.java | 2 + .../growthbook/sdk/java/MathUtilsTest.java | 1 + .../growthbook/sdk/java/NamespaceTest.java | 1 + .../NativeJavaGbFeatureRepositoryTest.java | 4 ++ .../growthbook/sdk/java/OperatorTest.java | 1 + .../growthbook/sdk/java/StringUtilsTest.java | 1 + .../growthbook/sdk/java/TrackDataTest.java | 4 ++ .../growthbook/sdk/java/UrlUtilsTest.java | 1 + .../sdk/java/VariationMetaTest.java | 1 + .../multiusermode/GrowthBookClientTest.java | 7 ++- .../sdk/java/testhelpers/SSETestServer.java | 8 ++-- 89 files changed, 349 insertions(+), 149 deletions(-) rename lib/src/main/java/growthbook/sdk/java/{ => callback}/ExperimentRunCallback.java (76%) rename lib/src/main/java/growthbook/sdk/java/{ => callback}/FeatureRefreshCallback.java (84%) rename lib/src/main/java/growthbook/sdk/java/{ => callback}/FeatureUsageCallback.java (66%) rename lib/src/main/java/growthbook/sdk/java/{ => callback}/TrackingCallback.java (81%) rename lib/src/main/java/growthbook/sdk/java/{ => evaluators}/ConditionEvaluator.java (98%) rename lib/src/main/java/growthbook/sdk/java/{ => evaluators}/ExperimentEvaluator.java (93%) rename lib/src/main/java/growthbook/sdk/java/{ => evaluators}/FeatureEvaluator.java (97%) rename lib/src/main/java/growthbook/sdk/java/{ => evaluators}/IConditionEvaluator.java (84%) rename lib/src/main/java/growthbook/sdk/java/{ => evaluators}/IExperimentEvaluator.java (68%) rename lib/src/main/java/growthbook/sdk/java/{ => evaluators}/IFeatureEvaluator.java (86%) rename lib/src/main/java/growthbook/sdk/java/{ => exception}/FeatureFetchException.java (95%) rename lib/src/main/java/growthbook/sdk/java/{ => model}/AssignedExperiment.java (86%) rename lib/src/main/java/growthbook/sdk/java/{ => model}/BucketRange.java (98%) rename lib/src/main/java/growthbook/sdk/java/{ => model}/DataType.java (96%) rename lib/src/main/java/growthbook/sdk/java/{ => model}/Experiment.java (97%) rename lib/src/main/java/growthbook/sdk/java/{ => model}/ExperimentResult.java (97%) rename lib/src/main/java/growthbook/sdk/java/{ => model}/Feature.java (95%) rename lib/src/main/java/growthbook/sdk/java/{ => model}/FeatureResponseKey.java (81%) rename lib/src/main/java/growthbook/sdk/java/{ => model}/FeatureResult.java (97%) rename lib/src/main/java/growthbook/sdk/java/{ => model}/FeatureResultSource.java (98%) rename lib/src/main/java/growthbook/sdk/java/{ => model}/FeatureRule.java (99%) rename lib/src/main/java/growthbook/sdk/java/{ => model}/Filter.java (94%) rename lib/src/main/java/growthbook/sdk/java/{ => model}/GBContext.java (97%) rename lib/src/main/java/growthbook/sdk/java/{ => model}/GeneratedStickyBucketAssignmentDocModel.java (88%) rename lib/src/main/java/growthbook/sdk/java/{ => model}/HashAttributeAndHashValue.java (85%) rename lib/src/main/java/growthbook/sdk/java/{ => model}/HttpHeaders.java (82%) rename lib/src/main/java/growthbook/sdk/java/{ => model}/HttpMethods.java (71%) rename lib/src/main/java/growthbook/sdk/java/{ => model}/Namespace.java (98%) rename lib/src/main/java/growthbook/sdk/java/{ => model}/Operator.java (98%) rename lib/src/main/java/growthbook/sdk/java/{ => model}/OptionalField.java (92%) rename lib/src/main/java/growthbook/sdk/java/{ => model}/ParentCondition.java (95%) rename lib/src/main/java/growthbook/sdk/java/{ => model}/RequestBodyForRemoteEval.java (93%) rename lib/src/main/java/growthbook/sdk/java/{ => model}/SseKey.java (71%) rename lib/src/main/java/growthbook/sdk/java/{ => model}/StickyBucketVariation.java (83%) rename lib/src/main/java/growthbook/sdk/java/{ => model}/TrackData.java (76%) rename lib/src/main/java/growthbook/sdk/java/{ => model}/VariationMeta.java (90%) rename lib/src/main/java/growthbook/sdk/java/{ => repository}/FeatureRefreshStrategy.java (81%) rename lib/src/main/java/growthbook/sdk/java/{ => repository}/GBFeaturesRepository.java (98%) rename lib/src/main/java/growthbook/sdk/java/{ => repository}/GBFeaturesRepositoryRequestInterceptor.java (89%) rename lib/src/main/java/growthbook/sdk/java/{ => repository}/IGBFeaturesRepository.java (71%) rename lib/src/main/java/growthbook/sdk/java/{ => repository}/LocalGbFeatureRepository.java (95%) rename lib/src/main/java/growthbook/sdk/java/{ => repository}/NativeJavaGbFeatureRepository.java (96%) rename lib/src/main/java/growthbook/sdk/java/{ => sandbox}/CachingManager.java (98%) rename lib/src/main/java/growthbook/sdk/java/{ => util}/DecryptionUtils.java (98%) rename lib/src/main/java/growthbook/sdk/java/{ => util}/ExperimentHelper.java (61%) rename lib/src/main/java/growthbook/sdk/java/{ => util}/GrowthBookJsonUtils.java (96%) rename lib/src/main/java/growthbook/sdk/java/{ => util}/GrowthBookUtils.java (98%) rename lib/src/main/java/growthbook/sdk/java/{ => util}/MathUtils.java (95%) rename lib/src/main/java/growthbook/sdk/java/{ => util}/StringUtils.java (96%) rename lib/src/main/java/growthbook/sdk/java/{ => util}/UrlUtils.java (95%) diff --git a/lib/src/main/java/growthbook/sdk/java/GrowthBook.java b/lib/src/main/java/growthbook/sdk/java/GrowthBook.java index f6b6c2ec..e9fa5b95 100644 --- a/lib/src/main/java/growthbook/sdk/java/GrowthBook.java +++ b/lib/src/main/java/growthbook/sdk/java/GrowthBook.java @@ -7,6 +7,17 @@ import java.util.Objects; import javax.annotation.Nullable; import com.google.gson.JsonObject; +import growthbook.sdk.java.callback.ExperimentRunCallback; +import growthbook.sdk.java.evaluators.ConditionEvaluator; +import growthbook.sdk.java.evaluators.ExperimentEvaluator; +import growthbook.sdk.java.evaluators.FeatureEvaluator; +import growthbook.sdk.java.model.AssignedExperiment; +import growthbook.sdk.java.model.Experiment; +import growthbook.sdk.java.model.ExperimentResult; +import growthbook.sdk.java.model.FeatureResult; +import growthbook.sdk.java.model.GBContext; +import growthbook.sdk.java.util.GrowthBookJsonUtils; +import growthbook.sdk.java.util.GrowthBookUtils; import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; diff --git a/lib/src/main/java/growthbook/sdk/java/IGrowthBook.java b/lib/src/main/java/growthbook/sdk/java/IGrowthBook.java index 4a5a35a4..756cdf3f 100644 --- a/lib/src/main/java/growthbook/sdk/java/IGrowthBook.java +++ b/lib/src/main/java/growthbook/sdk/java/IGrowthBook.java @@ -1,6 +1,10 @@ package growthbook.sdk.java; import com.google.gson.JsonObject; +import growthbook.sdk.java.callback.ExperimentRunCallback; +import growthbook.sdk.java.model.Experiment; +import growthbook.sdk.java.model.ExperimentResult; +import growthbook.sdk.java.model.FeatureResult; import growthbook.sdk.java.stickyBucketing.StickyBucketService; import javax.annotation.Nullable; diff --git a/lib/src/main/java/growthbook/sdk/java/Version.java b/lib/src/main/java/growthbook/sdk/java/Version.java index ca2592e8..78ed1a6a 100644 --- a/lib/src/main/java/growthbook/sdk/java/Version.java +++ b/lib/src/main/java/growthbook/sdk/java/Version.java @@ -3,8 +3,6 @@ /** * Tag for the published GrowthBook SDK version */ -class Version { - private Version() {} - +public interface Version { static final String SDK_VERSION = "0.9.92"; } diff --git a/lib/src/main/java/growthbook/sdk/java/ExperimentRunCallback.java b/lib/src/main/java/growthbook/sdk/java/callback/ExperimentRunCallback.java similarity index 76% rename from lib/src/main/java/growthbook/sdk/java/ExperimentRunCallback.java rename to lib/src/main/java/growthbook/sdk/java/callback/ExperimentRunCallback.java index 6422d20b..09367e5d 100644 --- a/lib/src/main/java/growthbook/sdk/java/ExperimentRunCallback.java +++ b/lib/src/main/java/growthbook/sdk/java/callback/ExperimentRunCallback.java @@ -1,4 +1,7 @@ -package growthbook.sdk.java; +package growthbook.sdk.java.callback; + +import growthbook.sdk.java.model.Experiment; +import growthbook.sdk.java.model.ExperimentResult; /** * A callback to be executed with an {@link ExperimentResult} whenever an experiment is run. diff --git a/lib/src/main/java/growthbook/sdk/java/FeatureRefreshCallback.java b/lib/src/main/java/growthbook/sdk/java/callback/FeatureRefreshCallback.java similarity index 84% rename from lib/src/main/java/growthbook/sdk/java/FeatureRefreshCallback.java rename to lib/src/main/java/growthbook/sdk/java/callback/FeatureRefreshCallback.java index c5101e76..c0fd5232 100644 --- a/lib/src/main/java/growthbook/sdk/java/FeatureRefreshCallback.java +++ b/lib/src/main/java/growthbook/sdk/java/callback/FeatureRefreshCallback.java @@ -1,4 +1,6 @@ -package growthbook.sdk.java; +package growthbook.sdk.java.callback; + +import growthbook.sdk.java.repository.GBFeaturesRepository; /** * See {@link GBFeaturesRepository#onFeaturesRefresh(FeatureRefreshCallback)} diff --git a/lib/src/main/java/growthbook/sdk/java/FeatureUsageCallback.java b/lib/src/main/java/growthbook/sdk/java/callback/FeatureUsageCallback.java similarity index 66% rename from lib/src/main/java/growthbook/sdk/java/FeatureUsageCallback.java rename to lib/src/main/java/growthbook/sdk/java/callback/FeatureUsageCallback.java index e72a26c0..03c2459b 100644 --- a/lib/src/main/java/growthbook/sdk/java/FeatureUsageCallback.java +++ b/lib/src/main/java/growthbook/sdk/java/callback/FeatureUsageCallback.java @@ -1,4 +1,6 @@ -package growthbook.sdk.java; +package growthbook.sdk.java.callback; + +import growthbook.sdk.java.model.FeatureResult; /** * Listen for feature usage events diff --git a/lib/src/main/java/growthbook/sdk/java/TrackingCallback.java b/lib/src/main/java/growthbook/sdk/java/callback/TrackingCallback.java similarity index 81% rename from lib/src/main/java/growthbook/sdk/java/TrackingCallback.java rename to lib/src/main/java/growthbook/sdk/java/callback/TrackingCallback.java index ef8ba266..241fe1c9 100644 --- a/lib/src/main/java/growthbook/sdk/java/TrackingCallback.java +++ b/lib/src/main/java/growthbook/sdk/java/callback/TrackingCallback.java @@ -1,4 +1,7 @@ -package growthbook.sdk.java; +package growthbook.sdk.java.callback; + +import growthbook.sdk.java.model.Experiment; +import growthbook.sdk.java.model.ExperimentResult; /** * This callback is called with the {@link Experiment} and {@link ExperimentResult} when an experiment is evaluated. diff --git a/lib/src/main/java/growthbook/sdk/java/ConditionEvaluator.java b/lib/src/main/java/growthbook/sdk/java/evaluators/ConditionEvaluator.java similarity index 98% rename from lib/src/main/java/growthbook/sdk/java/ConditionEvaluator.java rename to lib/src/main/java/growthbook/sdk/java/evaluators/ConditionEvaluator.java index f40f2546..3fd9e6db 100644 --- a/lib/src/main/java/growthbook/sdk/java/ConditionEvaluator.java +++ b/lib/src/main/java/growthbook/sdk/java/evaluators/ConditionEvaluator.java @@ -1,10 +1,14 @@ -package growthbook.sdk.java; +package growthbook.sdk.java.evaluators; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; import com.google.gson.reflect.TypeToken; +import growthbook.sdk.java.util.GrowthBookJsonUtils; +import growthbook.sdk.java.model.Operator; +import growthbook.sdk.java.util.StringUtils; +import growthbook.sdk.java.model.DataType; import lombok.extern.slf4j.Slf4j; import javax.annotation.Nullable; import java.lang.reflect.Type; @@ -107,7 +111,7 @@ public Boolean evaluateCondition(JsonObject attributes, JsonObject conditionJson * @param object The object to evaluate * @return if all keys start with $ */ - Boolean isOperatorObject(JsonElement object) { + public Boolean isOperatorObject(JsonElement object) { if (!object.isJsonObject()) { return false; } @@ -134,7 +138,7 @@ Boolean isOperatorObject(JsonElement object) { * @return the value at that path (or null if the path doesn't exist) */ @Nullable - Object getPath(JsonElement attributes, String path) { + public Object getPath(JsonElement attributes, String path) { if (Objects.equals(path, "")) return null; ArrayList paths = new ArrayList<>(); diff --git a/lib/src/main/java/growthbook/sdk/java/ExperimentEvaluator.java b/lib/src/main/java/growthbook/sdk/java/evaluators/ExperimentEvaluator.java similarity index 93% rename from lib/src/main/java/growthbook/sdk/java/ExperimentEvaluator.java rename to lib/src/main/java/growthbook/sdk/java/evaluators/ExperimentEvaluator.java index d101f480..2e8f2883 100644 --- a/lib/src/main/java/growthbook/sdk/java/ExperimentEvaluator.java +++ b/lib/src/main/java/growthbook/sdk/java/evaluators/ExperimentEvaluator.java @@ -1,6 +1,20 @@ -package growthbook.sdk.java; +package growthbook.sdk.java.evaluators; import com.google.gson.JsonObject; +import growthbook.sdk.java.model.GeneratedStickyBucketAssignmentDocModel; +import growthbook.sdk.java.util.GrowthBookJsonUtils; +import growthbook.sdk.java.util.GrowthBookUtils; +import growthbook.sdk.java.model.HashAttributeAndHashValue; +import growthbook.sdk.java.model.Namespace; +import growthbook.sdk.java.model.ParentCondition; +import growthbook.sdk.java.model.BucketRange; +import growthbook.sdk.java.model.Experiment; +import growthbook.sdk.java.model.ExperimentResult; +import growthbook.sdk.java.model.FeatureResult; +import growthbook.sdk.java.model.FeatureResultSource; +import growthbook.sdk.java.model.Filter; +import growthbook.sdk.java.model.StickyBucketVariation; +import growthbook.sdk.java.model.VariationMeta; import growthbook.sdk.java.multiusermode.ExperimentTracker; import growthbook.sdk.java.multiusermode.configurations.EvaluationContext; import growthbook.sdk.java.multiusermode.usage.TrackingCallbackWithUser; @@ -336,8 +350,8 @@ private ExperimentResult getExperimentResult( List experimentMeta = new ArrayList<>(); - if (experiment.meta != null) { - experimentMeta = experiment.meta; + if (experiment.getMeta() != null) { + experimentMeta = experiment.getMeta(); } VariationMeta meta = null; @@ -350,8 +364,8 @@ private ExperimentResult getExperimentResult( Boolean passThrough = meta != null ? meta.getPassThrough() : null; ValueType targetValue = null; - if (experiment.variations.size() > targetVariationIndex) { - targetValue = experiment.variations.get(targetVariationIndex); + if (experiment.getVariations().size() > targetVariationIndex) { + targetValue = experiment.getVariations().get(targetVariationIndex); } return ExperimentResult @@ -373,10 +387,10 @@ private ExperimentResult getExperimentResult( // Track experiments to trigger callbacks. private boolean isExperimentTracked(Experiment experiment, ExperimentResult result) { - String experimentKey = experiment.key; + String experimentKey = experiment.getKey(); String key = ( - result.hashAttribute != null ? result.getHashAttribute() : "") + result.getHashAttribute() != null ? result.getHashAttribute() : "") + (result.getHashValue() != null ? result.getHashValue() : "") + (experimentKey + result.getVariationId()); @@ -391,7 +405,7 @@ private boolean isExperimentTracked(Experiment experiment private boolean isStickyBucketingEnabledForExperiment(EvaluationContext context, Experiment experiment) { return context.getOptions().getStickyBucketService() != null - && !Boolean.TRUE.equals(experiment.disableStickyBucketing); + && !Boolean.TRUE.equals(experiment.getDisableStickyBucketing()); } private Map getForcedVariations(EvaluationContext evaluationContext) { diff --git a/lib/src/main/java/growthbook/sdk/java/FeatureEvaluator.java b/lib/src/main/java/growthbook/sdk/java/evaluators/FeatureEvaluator.java similarity index 97% rename from lib/src/main/java/growthbook/sdk/java/FeatureEvaluator.java rename to lib/src/main/java/growthbook/sdk/java/evaluators/FeatureEvaluator.java index a03ecbd5..cc40cdb1 100644 --- a/lib/src/main/java/growthbook/sdk/java/FeatureEvaluator.java +++ b/lib/src/main/java/growthbook/sdk/java/evaluators/FeatureEvaluator.java @@ -1,7 +1,18 @@ -package growthbook.sdk.java; +package growthbook.sdk.java.evaluators; import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import growthbook.sdk.java.util.GrowthBookJsonUtils; +import growthbook.sdk.java.util.GrowthBookUtils; +import growthbook.sdk.java.model.ParentCondition; +import growthbook.sdk.java.model.Experiment; +import growthbook.sdk.java.model.ExperimentResult; +import growthbook.sdk.java.model.Feature; +import growthbook.sdk.java.model.FeatureResult; +import growthbook.sdk.java.model.FeatureResultSource; +import growthbook.sdk.java.model.FeatureRule; +import growthbook.sdk.java.model.Filter; +import growthbook.sdk.java.model.TrackData; import growthbook.sdk.java.multiusermode.configurations.EvaluationContext; import growthbook.sdk.java.multiusermode.usage.FeatureUsageCallbackWithUser; import growthbook.sdk.java.multiusermode.usage.TrackingCallbackWithUser; @@ -240,7 +251,7 @@ public FeatureResult evaluateFeature( } boolean gate1 = context.getOptions().getStickyBucketService() != null; - boolean gate2 = !Boolean.TRUE.equals(rule.disableStickyBucketing); + boolean gate2 = !Boolean.TRUE.equals(rule.getDisableStickyBucketing()); boolean shouldFallbackAttributeBePassed = gate1 && gate2; // Pass fallback attribute if sticky bucketing is enabled. diff --git a/lib/src/main/java/growthbook/sdk/java/IConditionEvaluator.java b/lib/src/main/java/growthbook/sdk/java/evaluators/IConditionEvaluator.java similarity index 84% rename from lib/src/main/java/growthbook/sdk/java/IConditionEvaluator.java rename to lib/src/main/java/growthbook/sdk/java/evaluators/IConditionEvaluator.java index aabf64cd..1dee0813 100644 --- a/lib/src/main/java/growthbook/sdk/java/IConditionEvaluator.java +++ b/lib/src/main/java/growthbook/sdk/java/evaluators/IConditionEvaluator.java @@ -1,4 +1,4 @@ -package growthbook.sdk.java; +package growthbook.sdk.java.evaluators; import com.google.gson.JsonObject; diff --git a/lib/src/main/java/growthbook/sdk/java/IExperimentEvaluator.java b/lib/src/main/java/growthbook/sdk/java/evaluators/IExperimentEvaluator.java similarity index 68% rename from lib/src/main/java/growthbook/sdk/java/IExperimentEvaluator.java rename to lib/src/main/java/growthbook/sdk/java/evaluators/IExperimentEvaluator.java index a94b52d0..6be1e482 100644 --- a/lib/src/main/java/growthbook/sdk/java/IExperimentEvaluator.java +++ b/lib/src/main/java/growthbook/sdk/java/evaluators/IExperimentEvaluator.java @@ -1,6 +1,7 @@ -package growthbook.sdk.java; +package growthbook.sdk.java.evaluators; -import com.google.gson.JsonObject; +import growthbook.sdk.java.model.Experiment; +import growthbook.sdk.java.model.ExperimentResult; import growthbook.sdk.java.multiusermode.configurations.EvaluationContext; import javax.annotation.Nullable; diff --git a/lib/src/main/java/growthbook/sdk/java/IFeatureEvaluator.java b/lib/src/main/java/growthbook/sdk/java/evaluators/IFeatureEvaluator.java similarity index 86% rename from lib/src/main/java/growthbook/sdk/java/IFeatureEvaluator.java rename to lib/src/main/java/growthbook/sdk/java/evaluators/IFeatureEvaluator.java index 984c1155..3cfdc910 100644 --- a/lib/src/main/java/growthbook/sdk/java/IFeatureEvaluator.java +++ b/lib/src/main/java/growthbook/sdk/java/evaluators/IFeatureEvaluator.java @@ -1,6 +1,6 @@ -package growthbook.sdk.java; +package growthbook.sdk.java.evaluators; -import com.google.gson.JsonObject; +import growthbook.sdk.java.model.FeatureResult; import growthbook.sdk.java.multiusermode.configurations.EvaluationContext; interface IFeatureEvaluator { diff --git a/lib/src/main/java/growthbook/sdk/java/FeatureFetchException.java b/lib/src/main/java/growthbook/sdk/java/exception/FeatureFetchException.java similarity index 95% rename from lib/src/main/java/growthbook/sdk/java/FeatureFetchException.java rename to lib/src/main/java/growthbook/sdk/java/exception/FeatureFetchException.java index 04623cdd..35a2475d 100644 --- a/lib/src/main/java/growthbook/sdk/java/FeatureFetchException.java +++ b/lib/src/main/java/growthbook/sdk/java/exception/FeatureFetchException.java @@ -1,5 +1,6 @@ -package growthbook.sdk.java; +package growthbook.sdk.java.exception; +import growthbook.sdk.java.repository.GBFeaturesRepository; import lombok.Getter; /** diff --git a/lib/src/main/java/growthbook/sdk/java/AssignedExperiment.java b/lib/src/main/java/growthbook/sdk/java/model/AssignedExperiment.java similarity index 86% rename from lib/src/main/java/growthbook/sdk/java/AssignedExperiment.java rename to lib/src/main/java/growthbook/sdk/java/model/AssignedExperiment.java index 33485faf..8e4458dd 100644 --- a/lib/src/main/java/growthbook/sdk/java/AssignedExperiment.java +++ b/lib/src/main/java/growthbook/sdk/java/model/AssignedExperiment.java @@ -1,4 +1,4 @@ -package growthbook.sdk.java; +package growthbook.sdk.java.model; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/lib/src/main/java/growthbook/sdk/java/BucketRange.java b/lib/src/main/java/growthbook/sdk/java/model/BucketRange.java similarity index 98% rename from lib/src/main/java/growthbook/sdk/java/BucketRange.java rename to lib/src/main/java/growthbook/sdk/java/model/BucketRange.java index ae2b6289..00d9cae0 100644 --- a/lib/src/main/java/growthbook/sdk/java/BucketRange.java +++ b/lib/src/main/java/growthbook/sdk/java/model/BucketRange.java @@ -1,4 +1,4 @@ -package growthbook.sdk.java; +package growthbook.sdk.java.model; import com.google.gson.JsonArray; import com.google.gson.JsonDeserializer; diff --git a/lib/src/main/java/growthbook/sdk/java/DataType.java b/lib/src/main/java/growthbook/sdk/java/model/DataType.java similarity index 96% rename from lib/src/main/java/growthbook/sdk/java/DataType.java rename to lib/src/main/java/growthbook/sdk/java/model/DataType.java index 14487c3a..3e64e6ec 100644 --- a/lib/src/main/java/growthbook/sdk/java/DataType.java +++ b/lib/src/main/java/growthbook/sdk/java/model/DataType.java @@ -1,4 +1,4 @@ -package growthbook.sdk.java; +package growthbook.sdk.java.model; /** * A data type class used internally to help evaluate conditions diff --git a/lib/src/main/java/growthbook/sdk/java/Experiment.java b/lib/src/main/java/growthbook/sdk/java/model/Experiment.java similarity index 97% rename from lib/src/main/java/growthbook/sdk/java/Experiment.java rename to lib/src/main/java/growthbook/sdk/java/model/Experiment.java index b875bfd1..deb953a4 100644 --- a/lib/src/main/java/growthbook/sdk/java/Experiment.java +++ b/lib/src/main/java/growthbook/sdk/java/model/Experiment.java @@ -1,8 +1,9 @@ -package growthbook.sdk.java; +package growthbook.sdk.java.model; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.annotations.SerializedName; +import growthbook.sdk.java.util.GrowthBookJsonUtils; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; diff --git a/lib/src/main/java/growthbook/sdk/java/ExperimentResult.java b/lib/src/main/java/growthbook/sdk/java/model/ExperimentResult.java similarity index 97% rename from lib/src/main/java/growthbook/sdk/java/ExperimentResult.java rename to lib/src/main/java/growthbook/sdk/java/model/ExperimentResult.java index 7cf251c0..386e8703 100644 --- a/lib/src/main/java/growthbook/sdk/java/ExperimentResult.java +++ b/lib/src/main/java/growthbook/sdk/java/model/ExperimentResult.java @@ -1,7 +1,9 @@ -package growthbook.sdk.java; +package growthbook.sdk.java.model; import com.google.gson.JsonElement; import com.google.gson.annotations.SerializedName; +import growthbook.sdk.java.GrowthBook; +import growthbook.sdk.java.util.GrowthBookJsonUtils; import lombok.Builder; import lombok.Data; diff --git a/lib/src/main/java/growthbook/sdk/java/Feature.java b/lib/src/main/java/growthbook/sdk/java/model/Feature.java similarity index 95% rename from lib/src/main/java/growthbook/sdk/java/Feature.java rename to lib/src/main/java/growthbook/sdk/java/model/Feature.java index 206b2dbd..1b7c604f 100644 --- a/lib/src/main/java/growthbook/sdk/java/Feature.java +++ b/lib/src/main/java/growthbook/sdk/java/model/Feature.java @@ -1,4 +1,4 @@ -package growthbook.sdk.java; +package growthbook.sdk.java.model; import lombok.Data; diff --git a/lib/src/main/java/growthbook/sdk/java/FeatureResponseKey.java b/lib/src/main/java/growthbook/sdk/java/model/FeatureResponseKey.java similarity index 81% rename from lib/src/main/java/growthbook/sdk/java/FeatureResponseKey.java rename to lib/src/main/java/growthbook/sdk/java/model/FeatureResponseKey.java index 24d2c159..6e90803b 100644 --- a/lib/src/main/java/growthbook/sdk/java/FeatureResponseKey.java +++ b/lib/src/main/java/growthbook/sdk/java/model/FeatureResponseKey.java @@ -1,9 +1,9 @@ -package growthbook.sdk.java; +package growthbook.sdk.java.model; import lombok.Getter; @Getter -enum FeatureResponseKey { +public enum FeatureResponseKey { ENCRYPTED_FEATURES_KEY("encryptedFeatures"), ENCRYPTED_SAVED_GROUPS_KEY("encryptedSavedGroups"), FEATURE_KEY("features"), diff --git a/lib/src/main/java/growthbook/sdk/java/FeatureResult.java b/lib/src/main/java/growthbook/sdk/java/model/FeatureResult.java similarity index 97% rename from lib/src/main/java/growthbook/sdk/java/FeatureResult.java rename to lib/src/main/java/growthbook/sdk/java/model/FeatureResult.java index f71f95c4..4c58ff75 100644 --- a/lib/src/main/java/growthbook/sdk/java/FeatureResult.java +++ b/lib/src/main/java/growthbook/sdk/java/model/FeatureResult.java @@ -1,10 +1,12 @@ -package growthbook.sdk.java; +package growthbook.sdk.java.model; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; import com.google.gson.JsonSerializer; import com.google.gson.annotations.SerializedName; +import growthbook.sdk.java.evaluators.FeatureEvaluator; +import growthbook.sdk.java.util.GrowthBookJsonUtils; import growthbook.sdk.java.multiusermode.configurations.EvaluationContext; import lombok.AllArgsConstructor; import lombok.Builder; diff --git a/lib/src/main/java/growthbook/sdk/java/FeatureResultSource.java b/lib/src/main/java/growthbook/sdk/java/model/FeatureResultSource.java similarity index 98% rename from lib/src/main/java/growthbook/sdk/java/FeatureResultSource.java rename to lib/src/main/java/growthbook/sdk/java/model/FeatureResultSource.java index 263efa52..1479f417 100644 --- a/lib/src/main/java/growthbook/sdk/java/FeatureResultSource.java +++ b/lib/src/main/java/growthbook/sdk/java/model/FeatureResultSource.java @@ -1,4 +1,4 @@ -package growthbook.sdk.java; +package growthbook.sdk.java.model; import com.google.gson.annotations.SerializedName; diff --git a/lib/src/main/java/growthbook/sdk/java/FeatureRule.java b/lib/src/main/java/growthbook/sdk/java/model/FeatureRule.java similarity index 99% rename from lib/src/main/java/growthbook/sdk/java/FeatureRule.java rename to lib/src/main/java/growthbook/sdk/java/model/FeatureRule.java index e0d38ab5..55d50067 100644 --- a/lib/src/main/java/growthbook/sdk/java/FeatureRule.java +++ b/lib/src/main/java/growthbook/sdk/java/model/FeatureRule.java @@ -1,4 +1,4 @@ -package growthbook.sdk.java; +package growthbook.sdk.java.model; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializer; diff --git a/lib/src/main/java/growthbook/sdk/java/Filter.java b/lib/src/main/java/growthbook/sdk/java/model/Filter.java similarity index 94% rename from lib/src/main/java/growthbook/sdk/java/Filter.java rename to lib/src/main/java/growthbook/sdk/java/model/Filter.java index d594a9a0..2be3dfd1 100644 --- a/lib/src/main/java/growthbook/sdk/java/Filter.java +++ b/lib/src/main/java/growthbook/sdk/java/model/Filter.java @@ -1,5 +1,6 @@ -package growthbook.sdk.java; +package growthbook.sdk.java.model; +import growthbook.sdk.java.util.GrowthBookJsonUtils; import lombok.Builder; import lombok.Getter; diff --git a/lib/src/main/java/growthbook/sdk/java/GBContext.java b/lib/src/main/java/growthbook/sdk/java/model/GBContext.java similarity index 97% rename from lib/src/main/java/growthbook/sdk/java/GBContext.java rename to lib/src/main/java/growthbook/sdk/java/model/GBContext.java index 1c4a8a8a..667984e2 100644 --- a/lib/src/main/java/growthbook/sdk/java/GBContext.java +++ b/lib/src/main/java/growthbook/sdk/java/model/GBContext.java @@ -1,7 +1,9 @@ -package growthbook.sdk.java; +package growthbook.sdk.java.model; -import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import growthbook.sdk.java.util.ExperimentHelper; +import growthbook.sdk.java.callback.FeatureUsageCallback; +import growthbook.sdk.java.callback.TrackingCallback; import growthbook.sdk.java.multiusermode.util.TransformationUtil; import growthbook.sdk.java.stickyBucketing.StickyAssignmentsDocument; import growthbook.sdk.java.stickyBucketing.StickyBucketService; diff --git a/lib/src/main/java/growthbook/sdk/java/GeneratedStickyBucketAssignmentDocModel.java b/lib/src/main/java/growthbook/sdk/java/model/GeneratedStickyBucketAssignmentDocModel.java similarity index 88% rename from lib/src/main/java/growthbook/sdk/java/GeneratedStickyBucketAssignmentDocModel.java rename to lib/src/main/java/growthbook/sdk/java/model/GeneratedStickyBucketAssignmentDocModel.java index 9e1ca06f..716c1bb8 100644 --- a/lib/src/main/java/growthbook/sdk/java/GeneratedStickyBucketAssignmentDocModel.java +++ b/lib/src/main/java/growthbook/sdk/java/model/GeneratedStickyBucketAssignmentDocModel.java @@ -1,4 +1,4 @@ -package growthbook.sdk.java; +package growthbook.sdk.java.model; import growthbook.sdk.java.stickyBucketing.StickyAssignmentsDocument; import lombok.AllArgsConstructor; @@ -11,7 +11,7 @@ @Data @AllArgsConstructor @RequiredArgsConstructor -class GeneratedStickyBucketAssignmentDocModel { +public class GeneratedStickyBucketAssignmentDocModel { /** * Unique key of StickyAssignment Document in format: "attributeName||attributeValue" */ diff --git a/lib/src/main/java/growthbook/sdk/java/HashAttributeAndHashValue.java b/lib/src/main/java/growthbook/sdk/java/model/HashAttributeAndHashValue.java similarity index 85% rename from lib/src/main/java/growthbook/sdk/java/HashAttributeAndHashValue.java rename to lib/src/main/java/growthbook/sdk/java/model/HashAttributeAndHashValue.java index d5da9d35..05b4e811 100644 --- a/lib/src/main/java/growthbook/sdk/java/HashAttributeAndHashValue.java +++ b/lib/src/main/java/growthbook/sdk/java/model/HashAttributeAndHashValue.java @@ -1,4 +1,4 @@ -package growthbook.sdk.java; +package growthbook.sdk.java.model; import lombok.AllArgsConstructor; import lombok.Data; @@ -10,7 +10,7 @@ @Data @AllArgsConstructor @RequiredArgsConstructor -class HashAttributeAndHashValue { +public class HashAttributeAndHashValue { /** * All users included in the experiment will be forced into the specific variation index */ diff --git a/lib/src/main/java/growthbook/sdk/java/HttpHeaders.java b/lib/src/main/java/growthbook/sdk/java/model/HttpHeaders.java similarity index 82% rename from lib/src/main/java/growthbook/sdk/java/HttpHeaders.java rename to lib/src/main/java/growthbook/sdk/java/model/HttpHeaders.java index f4491285..9fa2c922 100644 --- a/lib/src/main/java/growthbook/sdk/java/HttpHeaders.java +++ b/lib/src/main/java/growthbook/sdk/java/model/HttpHeaders.java @@ -1,9 +1,9 @@ -package growthbook.sdk.java; +package growthbook.sdk.java.model; import lombok.Getter; @Getter -enum HttpHeaders { +public enum HttpHeaders { X_SSE_SUPPORT("x-sse-support"), ACCEPT("Accept"), SSE_HEADER("text/event-stream"), diff --git a/lib/src/main/java/growthbook/sdk/java/HttpMethods.java b/lib/src/main/java/growthbook/sdk/java/model/HttpMethods.java similarity index 71% rename from lib/src/main/java/growthbook/sdk/java/HttpMethods.java rename to lib/src/main/java/growthbook/sdk/java/model/HttpMethods.java index f44fefd6..254b25a1 100644 --- a/lib/src/main/java/growthbook/sdk/java/HttpMethods.java +++ b/lib/src/main/java/growthbook/sdk/java/model/HttpMethods.java @@ -1,9 +1,9 @@ -package growthbook.sdk.java; +package growthbook.sdk.java.model; import lombok.Getter; @Getter -enum HttpMethods { +public enum HttpMethods { GET("GET"); private final String method; diff --git a/lib/src/main/java/growthbook/sdk/java/Namespace.java b/lib/src/main/java/growthbook/sdk/java/model/Namespace.java similarity index 98% rename from lib/src/main/java/growthbook/sdk/java/Namespace.java rename to lib/src/main/java/growthbook/sdk/java/model/Namespace.java index 27a7bb60..3ac9e589 100644 --- a/lib/src/main/java/growthbook/sdk/java/Namespace.java +++ b/lib/src/main/java/growthbook/sdk/java/model/Namespace.java @@ -1,4 +1,4 @@ -package growthbook.sdk.java; +package growthbook.sdk.java.model; import com.google.gson.JsonArray; import com.google.gson.JsonDeserializer; diff --git a/lib/src/main/java/growthbook/sdk/java/Operator.java b/lib/src/main/java/growthbook/sdk/java/model/Operator.java similarity index 98% rename from lib/src/main/java/growthbook/sdk/java/Operator.java rename to lib/src/main/java/growthbook/sdk/java/model/Operator.java index 9a52515e..f2b30770 100644 --- a/lib/src/main/java/growthbook/sdk/java/Operator.java +++ b/lib/src/main/java/growthbook/sdk/java/model/Operator.java @@ -1,4 +1,4 @@ -package growthbook.sdk.java; +package growthbook.sdk.java.model; import javax.annotation.Nullable; diff --git a/lib/src/main/java/growthbook/sdk/java/OptionalField.java b/lib/src/main/java/growthbook/sdk/java/model/OptionalField.java similarity index 92% rename from lib/src/main/java/growthbook/sdk/java/OptionalField.java rename to lib/src/main/java/growthbook/sdk/java/model/OptionalField.java index d764c813..d956d12a 100644 --- a/lib/src/main/java/growthbook/sdk/java/OptionalField.java +++ b/lib/src/main/java/growthbook/sdk/java/model/OptionalField.java @@ -1,4 +1,4 @@ -package growthbook.sdk.java; +package growthbook.sdk.java.model; import javax.annotation.Nullable; diff --git a/lib/src/main/java/growthbook/sdk/java/ParentCondition.java b/lib/src/main/java/growthbook/sdk/java/model/ParentCondition.java similarity index 95% rename from lib/src/main/java/growthbook/sdk/java/ParentCondition.java rename to lib/src/main/java/growthbook/sdk/java/model/ParentCondition.java index 059a5654..e71c6449 100644 --- a/lib/src/main/java/growthbook/sdk/java/ParentCondition.java +++ b/lib/src/main/java/growthbook/sdk/java/model/ParentCondition.java @@ -1,4 +1,4 @@ -package growthbook.sdk.java; +package growthbook.sdk.java.model; import com.google.gson.JsonObject; import lombok.AllArgsConstructor; diff --git a/lib/src/main/java/growthbook/sdk/java/RequestBodyForRemoteEval.java b/lib/src/main/java/growthbook/sdk/java/model/RequestBodyForRemoteEval.java similarity index 93% rename from lib/src/main/java/growthbook/sdk/java/RequestBodyForRemoteEval.java rename to lib/src/main/java/growthbook/sdk/java/model/RequestBodyForRemoteEval.java index 50e8b7ee..53c22dd4 100644 --- a/lib/src/main/java/growthbook/sdk/java/RequestBodyForRemoteEval.java +++ b/lib/src/main/java/growthbook/sdk/java/model/RequestBodyForRemoteEval.java @@ -1,4 +1,4 @@ -package growthbook.sdk.java; +package growthbook.sdk.java.model; import com.google.gson.JsonObject; import lombok.AllArgsConstructor; diff --git a/lib/src/main/java/growthbook/sdk/java/SseKey.java b/lib/src/main/java/growthbook/sdk/java/model/SseKey.java similarity index 71% rename from lib/src/main/java/growthbook/sdk/java/SseKey.java rename to lib/src/main/java/growthbook/sdk/java/model/SseKey.java index 1d461e38..09fb8a55 100644 --- a/lib/src/main/java/growthbook/sdk/java/SseKey.java +++ b/lib/src/main/java/growthbook/sdk/java/model/SseKey.java @@ -1,9 +1,9 @@ -package growthbook.sdk.java; +package growthbook.sdk.java.model; import lombok.Getter; @Getter -enum SseKey { +public enum SseKey { DATA("data:"); private final String key; diff --git a/lib/src/main/java/growthbook/sdk/java/StickyBucketVariation.java b/lib/src/main/java/growthbook/sdk/java/model/StickyBucketVariation.java similarity index 83% rename from lib/src/main/java/growthbook/sdk/java/StickyBucketVariation.java rename to lib/src/main/java/growthbook/sdk/java/model/StickyBucketVariation.java index cf47daf1..6b011e75 100644 --- a/lib/src/main/java/growthbook/sdk/java/StickyBucketVariation.java +++ b/lib/src/main/java/growthbook/sdk/java/model/StickyBucketVariation.java @@ -1,4 +1,4 @@ -package growthbook.sdk.java; +package growthbook.sdk.java.model; import lombok.AllArgsConstructor; import lombok.Data; @@ -10,7 +10,7 @@ @Data @AllArgsConstructor @RequiredArgsConstructor -class StickyBucketVariation { +public class StickyBucketVariation { private Integer variation; /** diff --git a/lib/src/main/java/growthbook/sdk/java/TrackData.java b/lib/src/main/java/growthbook/sdk/java/model/TrackData.java similarity index 76% rename from lib/src/main/java/growthbook/sdk/java/TrackData.java rename to lib/src/main/java/growthbook/sdk/java/model/TrackData.java index 0d389aa3..5db5315c 100644 --- a/lib/src/main/java/growthbook/sdk/java/TrackData.java +++ b/lib/src/main/java/growthbook/sdk/java/model/TrackData.java @@ -1,5 +1,6 @@ -package growthbook.sdk.java; +package growthbook.sdk.java.model; +import growthbook.sdk.java.callback.TrackingCallback; import lombok.AllArgsConstructor; import lombok.Getter; diff --git a/lib/src/main/java/growthbook/sdk/java/VariationMeta.java b/lib/src/main/java/growthbook/sdk/java/model/VariationMeta.java similarity index 90% rename from lib/src/main/java/growthbook/sdk/java/VariationMeta.java rename to lib/src/main/java/growthbook/sdk/java/model/VariationMeta.java index 42e9271b..c4225e82 100644 --- a/lib/src/main/java/growthbook/sdk/java/VariationMeta.java +++ b/lib/src/main/java/growthbook/sdk/java/model/VariationMeta.java @@ -1,4 +1,4 @@ -package growthbook.sdk.java; +package growthbook.sdk.java.model; import com.google.gson.annotations.SerializedName; import lombok.AllArgsConstructor; @@ -16,7 +16,7 @@ @Builder @AllArgsConstructor @RequiredArgsConstructor -class VariationMeta { +public class VariationMeta { /** * A unique key for this variation */ diff --git a/lib/src/main/java/growthbook/sdk/java/multiusermode/GrowthBookClient.java b/lib/src/main/java/growthbook/sdk/java/multiusermode/GrowthBookClient.java index 109a6d32..d0fc32db 100644 --- a/lib/src/main/java/growthbook/sdk/java/multiusermode/GrowthBookClient.java +++ b/lib/src/main/java/growthbook/sdk/java/multiusermode/GrowthBookClient.java @@ -3,12 +3,23 @@ import java.util.*; import com.google.gson.JsonElement; -import growthbook.sdk.java.*; +import growthbook.sdk.java.callback.ExperimentRunCallback; +import growthbook.sdk.java.callback.FeatureRefreshCallback; +import growthbook.sdk.java.evaluators.ExperimentEvaluator; +import growthbook.sdk.java.evaluators.FeatureEvaluator; +import growthbook.sdk.java.exception.FeatureFetchException; +import growthbook.sdk.java.model.AssignedExperiment; +import growthbook.sdk.java.model.Experiment; +import growthbook.sdk.java.model.ExperimentResult; +import growthbook.sdk.java.model.FeatureResult; +import growthbook.sdk.java.model.RequestBodyForRemoteEval; import growthbook.sdk.java.multiusermode.configurations.EvaluationContext; import growthbook.sdk.java.multiusermode.configurations.GlobalContext; import growthbook.sdk.java.multiusermode.configurations.Options; import growthbook.sdk.java.multiusermode.configurations.UserContext; import growthbook.sdk.java.multiusermode.util.TransformationUtil; +import growthbook.sdk.java.repository.GBFeaturesRepository; +import growthbook.sdk.java.util.GrowthBookJsonUtils; import lombok.extern.slf4j.Slf4j; import java.util.ArrayList; diff --git a/lib/src/main/java/growthbook/sdk/java/multiusermode/configurations/GlobalContext.java b/lib/src/main/java/growthbook/sdk/java/multiusermode/configurations/GlobalContext.java index a85907af..ba619e68 100644 --- a/lib/src/main/java/growthbook/sdk/java/multiusermode/configurations/GlobalContext.java +++ b/lib/src/main/java/growthbook/sdk/java/multiusermode/configurations/GlobalContext.java @@ -1,8 +1,7 @@ package growthbook.sdk.java.multiusermode.configurations; import com.google.gson.JsonObject; -import growthbook.sdk.java.Experiment; -import growthbook.sdk.java.multiusermode.util.TransformationUtil; +import growthbook.sdk.java.model.Experiment; import lombok.Builder; import lombok.Data; import lombok.Getter; diff --git a/lib/src/main/java/growthbook/sdk/java/multiusermode/configurations/Options.java b/lib/src/main/java/growthbook/sdk/java/multiusermode/configurations/Options.java index 0d55a899..dc6e71e9 100644 --- a/lib/src/main/java/growthbook/sdk/java/multiusermode/configurations/Options.java +++ b/lib/src/main/java/growthbook/sdk/java/multiusermode/configurations/Options.java @@ -1,10 +1,14 @@ package growthbook.sdk.java.multiusermode.configurations; import com.google.gson.JsonObject; -import growthbook.sdk.java.*; +import growthbook.sdk.java.callback.FeatureRefreshCallback; +import growthbook.sdk.java.model.Experiment; +import growthbook.sdk.java.model.ExperimentResult; +import growthbook.sdk.java.model.FeatureResult; import growthbook.sdk.java.multiusermode.usage.FeatureUsageCallbackWithUser; import growthbook.sdk.java.multiusermode.usage.TrackingCallbackWithUser; import growthbook.sdk.java.multiusermode.util.TransformationUtil; +import growthbook.sdk.java.repository.FeatureRefreshStrategy; import growthbook.sdk.java.stickyBucketing.InMemoryStickyBucketServiceImpl; import growthbook.sdk.java.stickyBucketing.StickyBucketService; import lombok.Builder; diff --git a/lib/src/main/java/growthbook/sdk/java/multiusermode/usage/FeatureUsageCallbackAdapter.java b/lib/src/main/java/growthbook/sdk/java/multiusermode/usage/FeatureUsageCallbackAdapter.java index 7d658680..c68ad25a 100644 --- a/lib/src/main/java/growthbook/sdk/java/multiusermode/usage/FeatureUsageCallbackAdapter.java +++ b/lib/src/main/java/growthbook/sdk/java/multiusermode/usage/FeatureUsageCallbackAdapter.java @@ -1,7 +1,7 @@ package growthbook.sdk.java.multiusermode.usage; -import growthbook.sdk.java.FeatureResult; -import growthbook.sdk.java.FeatureUsageCallback; +import growthbook.sdk.java.model.FeatureResult; +import growthbook.sdk.java.callback.FeatureUsageCallback; import growthbook.sdk.java.multiusermode.configurations.UserContext; // Use Wrapper adapter design pattern - to allow an existing interface to function as if it was a new interface diff --git a/lib/src/main/java/growthbook/sdk/java/multiusermode/usage/FeatureUsageCallbackWithUser.java b/lib/src/main/java/growthbook/sdk/java/multiusermode/usage/FeatureUsageCallbackWithUser.java index 76710749..e76c6231 100644 --- a/lib/src/main/java/growthbook/sdk/java/multiusermode/usage/FeatureUsageCallbackWithUser.java +++ b/lib/src/main/java/growthbook/sdk/java/multiusermode/usage/FeatureUsageCallbackWithUser.java @@ -1,6 +1,6 @@ package growthbook.sdk.java.multiusermode.usage; -import growthbook.sdk.java.FeatureResult; +import growthbook.sdk.java.model.FeatureResult; import growthbook.sdk.java.multiusermode.configurations.UserContext; public interface FeatureUsageCallbackWithUser { diff --git a/lib/src/main/java/growthbook/sdk/java/multiusermode/usage/TrackingCallbackAdapter.java b/lib/src/main/java/growthbook/sdk/java/multiusermode/usage/TrackingCallbackAdapter.java index f3adc30c..2b1d2272 100644 --- a/lib/src/main/java/growthbook/sdk/java/multiusermode/usage/TrackingCallbackAdapter.java +++ b/lib/src/main/java/growthbook/sdk/java/multiusermode/usage/TrackingCallbackAdapter.java @@ -1,8 +1,8 @@ package growthbook.sdk.java.multiusermode.usage; -import growthbook.sdk.java.Experiment; -import growthbook.sdk.java.ExperimentResult; -import growthbook.sdk.java.TrackingCallback; +import growthbook.sdk.java.model.Experiment; +import growthbook.sdk.java.model.ExperimentResult; +import growthbook.sdk.java.callback.TrackingCallback; import growthbook.sdk.java.multiusermode.configurations.UserContext; // Use Wrapper adapter design pattern - to allow an existing interface to function as if it was a new interface diff --git a/lib/src/main/java/growthbook/sdk/java/multiusermode/usage/TrackingCallbackWithUser.java b/lib/src/main/java/growthbook/sdk/java/multiusermode/usage/TrackingCallbackWithUser.java index e6c61bbf..e9b5f04b 100644 --- a/lib/src/main/java/growthbook/sdk/java/multiusermode/usage/TrackingCallbackWithUser.java +++ b/lib/src/main/java/growthbook/sdk/java/multiusermode/usage/TrackingCallbackWithUser.java @@ -1,7 +1,7 @@ package growthbook.sdk.java.multiusermode.usage; -import growthbook.sdk.java.Experiment; -import growthbook.sdk.java.ExperimentResult; +import growthbook.sdk.java.model.Experiment; +import growthbook.sdk.java.model.ExperimentResult; import growthbook.sdk.java.multiusermode.configurations.UserContext; public interface TrackingCallbackWithUser { diff --git a/lib/src/main/java/growthbook/sdk/java/multiusermode/util/TransformationUtil.java b/lib/src/main/java/growthbook/sdk/java/multiusermode/util/TransformationUtil.java index 4e90d179..23dd6137 100644 --- a/lib/src/main/java/growthbook/sdk/java/multiusermode/util/TransformationUtil.java +++ b/lib/src/main/java/growthbook/sdk/java/multiusermode/util/TransformationUtil.java @@ -2,8 +2,8 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; -import growthbook.sdk.java.DecryptionUtils; -import growthbook.sdk.java.GrowthBookJsonUtils; +import growthbook.sdk.java.util.DecryptionUtils; +import growthbook.sdk.java.util.GrowthBookJsonUtils; import lombok.extern.slf4j.Slf4j; import javax.annotation.Nullable; diff --git a/lib/src/main/java/growthbook/sdk/java/FeatureRefreshStrategy.java b/lib/src/main/java/growthbook/sdk/java/repository/FeatureRefreshStrategy.java similarity index 81% rename from lib/src/main/java/growthbook/sdk/java/FeatureRefreshStrategy.java rename to lib/src/main/java/growthbook/sdk/java/repository/FeatureRefreshStrategy.java index 28efc87b..6b828825 100644 --- a/lib/src/main/java/growthbook/sdk/java/FeatureRefreshStrategy.java +++ b/lib/src/main/java/growthbook/sdk/java/repository/FeatureRefreshStrategy.java @@ -1,4 +1,4 @@ -package growthbook.sdk.java; +package growthbook.sdk.java.repository; /** * Enum that used in strategy for building url diff --git a/lib/src/main/java/growthbook/sdk/java/GBFeaturesRepository.java b/lib/src/main/java/growthbook/sdk/java/repository/GBFeaturesRepository.java similarity index 98% rename from lib/src/main/java/growthbook/sdk/java/GBFeaturesRepository.java rename to lib/src/main/java/growthbook/sdk/java/repository/GBFeaturesRepository.java index 870272cc..b7d76c08 100644 --- a/lib/src/main/java/growthbook/sdk/java/GBFeaturesRepository.java +++ b/lib/src/main/java/growthbook/sdk/java/repository/GBFeaturesRepository.java @@ -1,7 +1,16 @@ -package growthbook.sdk.java; +package growthbook.sdk.java.repository; import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import growthbook.sdk.java.sandbox.CachingManager; +import growthbook.sdk.java.util.DecryptionUtils; +import growthbook.sdk.java.exception.FeatureFetchException; +import growthbook.sdk.java.callback.FeatureRefreshCallback; +import growthbook.sdk.java.model.FeatureResponseKey; +import growthbook.sdk.java.util.GrowthBookJsonUtils; +import growthbook.sdk.java.model.HttpHeaders; +import growthbook.sdk.java.model.RequestBodyForRemoteEval; +import growthbook.sdk.java.model.GBContext; import lombok.Builder; import lombok.Getter; import lombok.extern.slf4j.Slf4j; diff --git a/lib/src/main/java/growthbook/sdk/java/GBFeaturesRepositoryRequestInterceptor.java b/lib/src/main/java/growthbook/sdk/java/repository/GBFeaturesRepositoryRequestInterceptor.java similarity index 89% rename from lib/src/main/java/growthbook/sdk/java/GBFeaturesRepositoryRequestInterceptor.java rename to lib/src/main/java/growthbook/sdk/java/repository/GBFeaturesRepositoryRequestInterceptor.java index 14bc23a0..2025097a 100644 --- a/lib/src/main/java/growthbook/sdk/java/GBFeaturesRepositoryRequestInterceptor.java +++ b/lib/src/main/java/growthbook/sdk/java/repository/GBFeaturesRepositoryRequestInterceptor.java @@ -1,5 +1,6 @@ -package growthbook.sdk.java; +package growthbook.sdk.java.repository; +import growthbook.sdk.java.Version; import okhttp3.Interceptor; import okhttp3.Request; import okhttp3.Response; diff --git a/lib/src/main/java/growthbook/sdk/java/IGBFeaturesRepository.java b/lib/src/main/java/growthbook/sdk/java/repository/IGBFeaturesRepository.java similarity index 71% rename from lib/src/main/java/growthbook/sdk/java/IGBFeaturesRepository.java rename to lib/src/main/java/growthbook/sdk/java/repository/IGBFeaturesRepository.java index 7d462fbf..ff8c4ba2 100644 --- a/lib/src/main/java/growthbook/sdk/java/IGBFeaturesRepository.java +++ b/lib/src/main/java/growthbook/sdk/java/repository/IGBFeaturesRepository.java @@ -1,9 +1,12 @@ -package growthbook.sdk.java; +package growthbook.sdk.java.repository; + +import growthbook.sdk.java.exception.FeatureFetchException; +import growthbook.sdk.java.callback.FeatureRefreshCallback; /** * INTERNAL: Interface that is used internally for the {@link GBFeaturesRepository} */ -interface IGBFeaturesRepository { +public interface IGBFeaturesRepository { void initialize() throws FeatureFetchException; void initialize(Boolean retryOnFailure) throws FeatureFetchException; diff --git a/lib/src/main/java/growthbook/sdk/java/LocalGbFeatureRepository.java b/lib/src/main/java/growthbook/sdk/java/repository/LocalGbFeatureRepository.java similarity index 95% rename from lib/src/main/java/growthbook/sdk/java/LocalGbFeatureRepository.java rename to lib/src/main/java/growthbook/sdk/java/repository/LocalGbFeatureRepository.java index d81c2de5..2d6a54e3 100644 --- a/lib/src/main/java/growthbook/sdk/java/LocalGbFeatureRepository.java +++ b/lib/src/main/java/growthbook/sdk/java/repository/LocalGbFeatureRepository.java @@ -1,8 +1,10 @@ -package growthbook.sdk.java; +package growthbook.sdk.java.repository; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonObject; +import growthbook.sdk.java.exception.FeatureFetchException; +import growthbook.sdk.java.callback.FeatureRefreshCallback; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; diff --git a/lib/src/main/java/growthbook/sdk/java/NativeJavaGbFeatureRepository.java b/lib/src/main/java/growthbook/sdk/java/repository/NativeJavaGbFeatureRepository.java similarity index 96% rename from lib/src/main/java/growthbook/sdk/java/NativeJavaGbFeatureRepository.java rename to lib/src/main/java/growthbook/sdk/java/repository/NativeJavaGbFeatureRepository.java index 8d36d52c..018fdede 100644 --- a/lib/src/main/java/growthbook/sdk/java/NativeJavaGbFeatureRepository.java +++ b/lib/src/main/java/growthbook/sdk/java/repository/NativeJavaGbFeatureRepository.java @@ -1,7 +1,18 @@ -package growthbook.sdk.java; +package growthbook.sdk.java.repository; import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import growthbook.sdk.java.sandbox.CachingManager; +import growthbook.sdk.java.util.DecryptionUtils; +import growthbook.sdk.java.exception.FeatureFetchException; +import growthbook.sdk.java.callback.FeatureRefreshCallback; +import growthbook.sdk.java.model.FeatureResponseKey; +import growthbook.sdk.java.util.GrowthBookJsonUtils; +import growthbook.sdk.java.model.HttpHeaders; +import growthbook.sdk.java.model.HttpMethods; +import growthbook.sdk.java.model.RequestBodyForRemoteEval; +import growthbook.sdk.java.model.SseKey; +import growthbook.sdk.java.model.GBContext; import lombok.Builder; import lombok.Getter; import lombok.extern.slf4j.Slf4j; @@ -17,7 +28,6 @@ import java.time.Instant; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; @@ -281,7 +291,7 @@ private void refreshExpiresAt() { ); } - void fetchFeatures() throws FeatureFetchException { + public void fetchFeatures() throws FeatureFetchException { if (this.featuresEndpoint == null) { throw new IllegalArgumentException("features endpoint cannot be null"); } @@ -430,13 +440,13 @@ private void onResponseJson(String responseJsonString, boolean isFromCache) thro } } - void onRefreshSuccess(String featuresJson) { + public void onRefreshSuccess(String featuresJson) { for (FeatureRefreshCallback callback : this.refreshCallbacks) { callback.onRefresh(featuresJson); } } - void onRefreshFailed(Throwable throwable) { + public void onRefreshFailed(Throwable throwable) { for (FeatureRefreshCallback callback : this.refreshCallbacks) { callback.onError(throwable); } diff --git a/lib/src/main/java/growthbook/sdk/java/CachingManager.java b/lib/src/main/java/growthbook/sdk/java/sandbox/CachingManager.java similarity index 98% rename from lib/src/main/java/growthbook/sdk/java/CachingManager.java rename to lib/src/main/java/growthbook/sdk/java/sandbox/CachingManager.java index dfd06dfa..81f01ba6 100644 --- a/lib/src/main/java/growthbook/sdk/java/CachingManager.java +++ b/lib/src/main/java/growthbook/sdk/java/sandbox/CachingManager.java @@ -1,4 +1,4 @@ -package growthbook.sdk.java; +package growthbook.sdk.java.sandbox; import lombok.extern.slf4j.Slf4j; diff --git a/lib/src/main/java/growthbook/sdk/java/DecryptionUtils.java b/lib/src/main/java/growthbook/sdk/java/util/DecryptionUtils.java similarity index 98% rename from lib/src/main/java/growthbook/sdk/java/DecryptionUtils.java rename to lib/src/main/java/growthbook/sdk/java/util/DecryptionUtils.java index d43727c5..a69573a7 100644 --- a/lib/src/main/java/growthbook/sdk/java/DecryptionUtils.java +++ b/lib/src/main/java/growthbook/sdk/java/util/DecryptionUtils.java @@ -1,4 +1,4 @@ -package growthbook.sdk.java; +package growthbook.sdk.java.util; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; diff --git a/lib/src/main/java/growthbook/sdk/java/ExperimentHelper.java b/lib/src/main/java/growthbook/sdk/java/util/ExperimentHelper.java similarity index 61% rename from lib/src/main/java/growthbook/sdk/java/ExperimentHelper.java rename to lib/src/main/java/growthbook/sdk/java/util/ExperimentHelper.java index b18f131d..0e138bd8 100644 --- a/lib/src/main/java/growthbook/sdk/java/ExperimentHelper.java +++ b/lib/src/main/java/growthbook/sdk/java/util/ExperimentHelper.java @@ -1,21 +1,24 @@ -package growthbook.sdk.java; +package growthbook.sdk.java.util; + +import growthbook.sdk.java.model.Experiment; +import growthbook.sdk.java.model.ExperimentResult; import java.util.HashSet; import java.util.Set; -class ExperimentHelper { +public class ExperimentHelper { private final Set trackedExperiments = new HashSet<>(); public boolean isTracked(Experiment experiment, ExperimentResult result) { - String experimentKey = experiment.key; + String experimentKey = experiment.getKey(); String key = ( - result.hashAttribute != null ? result.getHashAttribute() : "") + result.getHashAttribute() != null ? result.getHashAttribute() : "") + (result.getHashValue() != null ? result.getHashValue() : "") + (experimentKey + result.getVariationId()); if (trackedExperiments.contains(key)) { - return false; + return true; } trackedExperiments.add(key); return false; diff --git a/lib/src/main/java/growthbook/sdk/java/GrowthBookJsonUtils.java b/lib/src/main/java/growthbook/sdk/java/util/GrowthBookJsonUtils.java similarity index 96% rename from lib/src/main/java/growthbook/sdk/java/GrowthBookJsonUtils.java rename to lib/src/main/java/growthbook/sdk/java/util/GrowthBookJsonUtils.java index 7c90e8cf..00716707 100644 --- a/lib/src/main/java/growthbook/sdk/java/GrowthBookJsonUtils.java +++ b/lib/src/main/java/growthbook/sdk/java/util/GrowthBookJsonUtils.java @@ -1,10 +1,15 @@ -package growthbook.sdk.java; +package growthbook.sdk.java.util; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonElement; import com.google.gson.JsonPrimitive; import com.google.gson.ToNumberPolicy; +import growthbook.sdk.java.model.BucketRange; +import growthbook.sdk.java.model.DataType; +import growthbook.sdk.java.model.FeatureResult; +import growthbook.sdk.java.model.FeatureRule; +import growthbook.sdk.java.model.Namespace; import lombok.extern.slf4j.Slf4j; import javax.annotation.Nullable; import java.math.BigDecimal; diff --git a/lib/src/main/java/growthbook/sdk/java/GrowthBookUtils.java b/lib/src/main/java/growthbook/sdk/java/util/GrowthBookUtils.java similarity index 98% rename from lib/src/main/java/growthbook/sdk/java/GrowthBookUtils.java rename to lib/src/main/java/growthbook/sdk/java/util/GrowthBookUtils.java index b4f47a26..67a772e6 100644 --- a/lib/src/main/java/growthbook/sdk/java/GrowthBookUtils.java +++ b/lib/src/main/java/growthbook/sdk/java/util/GrowthBookUtils.java @@ -1,9 +1,19 @@ -package growthbook.sdk.java; +package growthbook.sdk.java.util; import com.google.gson.Gson; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; +import growthbook.sdk.java.model.GeneratedStickyBucketAssignmentDocModel; +import growthbook.sdk.java.model.BucketRange; +import growthbook.sdk.java.model.Feature; +import growthbook.sdk.java.model.FeatureRule; +import growthbook.sdk.java.model.Filter; +import growthbook.sdk.java.model.GBContext; +import growthbook.sdk.java.model.HashAttributeAndHashValue; +import growthbook.sdk.java.model.Namespace; +import growthbook.sdk.java.model.StickyBucketVariation; +import growthbook.sdk.java.model.VariationMeta; import growthbook.sdk.java.multiusermode.configurations.EvaluationContext; import growthbook.sdk.java.stickyBucketing.StickyAssignmentsDocument; import growthbook.sdk.java.stickyBucketing.StickyBucketService; @@ -27,7 +37,7 @@ * INTERNAL: Implementation of for internal utility methods to support {@link growthbook.sdk.java.GrowthBook} */ @Slf4j -class GrowthBookUtils { +public class GrowthBookUtils { /** * Hashes a string to a float between 0 and 1, or null if the hash version is unsupported. * Uses the simple Fowler–Noll–Vo algorithm, specifically fnv32a. diff --git a/lib/src/main/java/growthbook/sdk/java/MathUtils.java b/lib/src/main/java/growthbook/sdk/java/util/MathUtils.java similarity index 95% rename from lib/src/main/java/growthbook/sdk/java/MathUtils.java rename to lib/src/main/java/growthbook/sdk/java/util/MathUtils.java index 7862a837..8e9f03e1 100644 --- a/lib/src/main/java/growthbook/sdk/java/MathUtils.java +++ b/lib/src/main/java/growthbook/sdk/java/util/MathUtils.java @@ -1,8 +1,8 @@ -package growthbook.sdk.java; +package growthbook.sdk.java.util; import java.util.List; -class MathUtils { +public class MathUtils { private static final long INIT32 = 0x811c9dc5L; private static final long PRIME32 = 0x01000193L; private static final long MOD32 = 1L << 32; diff --git a/lib/src/main/java/growthbook/sdk/java/StringUtils.java b/lib/src/main/java/growthbook/sdk/java/util/StringUtils.java similarity index 96% rename from lib/src/main/java/growthbook/sdk/java/StringUtils.java rename to lib/src/main/java/growthbook/sdk/java/util/StringUtils.java index 0da4a2fd..ba255314 100644 --- a/lib/src/main/java/growthbook/sdk/java/StringUtils.java +++ b/lib/src/main/java/growthbook/sdk/java/util/StringUtils.java @@ -1,10 +1,10 @@ -package growthbook.sdk.java; +package growthbook.sdk.java.util; import java.util.ArrayList; import java.util.Arrays; import java.util.stream.Collectors; -class StringUtils { +public class StringUtils { public static String padLeftZeros(String inputString, Integer length) { if (inputString.length() >= length) { return inputString; diff --git a/lib/src/main/java/growthbook/sdk/java/UrlUtils.java b/lib/src/main/java/growthbook/sdk/java/util/UrlUtils.java similarity index 95% rename from lib/src/main/java/growthbook/sdk/java/UrlUtils.java rename to lib/src/main/java/growthbook/sdk/java/util/UrlUtils.java index e2f72893..19e0c4b9 100644 --- a/lib/src/main/java/growthbook/sdk/java/UrlUtils.java +++ b/lib/src/main/java/growthbook/sdk/java/util/UrlUtils.java @@ -1,4 +1,4 @@ -package growthbook.sdk.java; +package growthbook.sdk.java.util; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; @@ -8,7 +8,7 @@ import lombok.extern.slf4j.Slf4j; @Slf4j -class UrlUtils { +public class UrlUtils { /** * Parse a query string into a map of key/value pairs. diff --git a/lib/src/test/java/growthbook/sdk/java/BucketRangeTest.java b/lib/src/test/java/growthbook/sdk/java/BucketRangeTest.java index e931ab0c..bf4defbd 100644 --- a/lib/src/test/java/growthbook/sdk/java/BucketRangeTest.java +++ b/lib/src/test/java/growthbook/sdk/java/BucketRangeTest.java @@ -1,5 +1,7 @@ package growthbook.sdk.java; +import growthbook.sdk.java.model.BucketRange; +import growthbook.sdk.java.util.GrowthBookJsonUtils; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -38,7 +40,7 @@ void canBeJsonSerialized() { void canBeJsonDeSerialized() { BucketRange subject = GrowthBookJsonUtils.getInstance().gson.fromJson("[0.3,0.7]", BucketRange.class); - assertEquals(subject.rangeStart, 0.3f); - assertEquals(subject.rangeEnd, 0.7f); + assertEquals(subject.getRangeStart(), 0.3f); + assertEquals(subject.getRangeEnd(), 0.7f); } } diff --git a/lib/src/test/java/growthbook/sdk/java/CachingManagerTest.java b/lib/src/test/java/growthbook/sdk/java/CachingManagerTest.java index 3b1fbdcc..0711a170 100644 --- a/lib/src/test/java/growthbook/sdk/java/CachingManagerTest.java +++ b/lib/src/test/java/growthbook/sdk/java/CachingManagerTest.java @@ -6,6 +6,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; +import growthbook.sdk.java.sandbox.CachingManager; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/lib/src/test/java/growthbook/sdk/java/ConditionEvaluatorTest.java b/lib/src/test/java/growthbook/sdk/java/ConditionEvaluatorTest.java index 23d75916..2c4c05f1 100644 --- a/lib/src/test/java/growthbook/sdk/java/ConditionEvaluatorTest.java +++ b/lib/src/test/java/growthbook/sdk/java/ConditionEvaluatorTest.java @@ -8,13 +8,17 @@ import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import growthbook.sdk.java.evaluators.ConditionEvaluator; import growthbook.sdk.java.testhelpers.TestCasesJsonHelper; import java.io.ByteArrayOutputStream; import java.io.PrintStream; + +import growthbook.sdk.java.util.GrowthBookJsonUtils; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import java.util.ArrayList; +import java.util.Objects; class ConditionEvaluatorTest { @@ -109,8 +113,8 @@ void test_getPath() { JsonElement attributes = GrowthBookJsonUtils.getInstance().gson .fromJson("{ \"name\": \"sarah\", \"job\": { \"title\": \"developer\" } }", JsonElement.class); - assertEquals("sarah", ((JsonElement) evaluator.getPath(attributes, "name")).getAsString()); - assertEquals("developer", ((JsonElement) evaluator.getPath(attributes, "job.title")).getAsString()); + assertEquals("sarah", ((JsonElement) Objects.requireNonNull(evaluator.getPath(attributes, "name"))).getAsString()); + assertEquals("developer", ((JsonElement) Objects.requireNonNull(evaluator.getPath(attributes, "job.title"))).getAsString()); assertNull(evaluator.getPath(attributes, "job.company")); } diff --git a/lib/src/test/java/growthbook/sdk/java/DecryptionUtilsTest.java b/lib/src/test/java/growthbook/sdk/java/DecryptionUtilsTest.java index 64a3d334..e064094b 100644 --- a/lib/src/test/java/growthbook/sdk/java/DecryptionUtilsTest.java +++ b/lib/src/test/java/growthbook/sdk/java/DecryptionUtilsTest.java @@ -7,6 +7,7 @@ import com.google.gson.JsonArray; import com.google.gson.JsonElement; import growthbook.sdk.java.testhelpers.TestCasesJsonHelper; +import growthbook.sdk.java.util.DecryptionUtils; import org.junit.jupiter.api.Test; class DecryptionUtilsTest { diff --git a/lib/src/test/java/growthbook/sdk/java/EvaluateFeatureWithStickyBucketingFeatureTest.java b/lib/src/test/java/growthbook/sdk/java/EvaluateFeatureWithStickyBucketingFeatureTest.java index 35322741..a2f7d704 100644 --- a/lib/src/test/java/growthbook/sdk/java/EvaluateFeatureWithStickyBucketingFeatureTest.java +++ b/lib/src/test/java/growthbook/sdk/java/EvaluateFeatureWithStickyBucketingFeatureTest.java @@ -6,10 +6,14 @@ import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonNull; +import growthbook.sdk.java.model.ExperimentResult; +import growthbook.sdk.java.model.FeatureResult; +import growthbook.sdk.java.model.GBContext; import growthbook.sdk.java.stickyBucketing.InMemoryStickyBucketServiceImpl; import growthbook.sdk.java.stickyBucketing.StickyAssignmentsDocument; import growthbook.sdk.java.stickyBucketing.StickyBucketService; import growthbook.sdk.java.testhelpers.TestCasesJsonHelper; +import growthbook.sdk.java.util.GrowthBookJsonUtils; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/lib/src/test/java/growthbook/sdk/java/ExperimentResultTest.java b/lib/src/test/java/growthbook/sdk/java/ExperimentResultTest.java index 27690a5b..a52b91a6 100644 --- a/lib/src/test/java/growthbook/sdk/java/ExperimentResultTest.java +++ b/lib/src/test/java/growthbook/sdk/java/ExperimentResultTest.java @@ -5,6 +5,8 @@ import static org.junit.jupiter.api.Assertions.assertNull; import com.google.gson.reflect.TypeToken; +import growthbook.sdk.java.model.ExperimentResult; +import growthbook.sdk.java.util.GrowthBookJsonUtils; import org.junit.jupiter.api.Test; import java.lang.reflect.Type; diff --git a/lib/src/test/java/growthbook/sdk/java/ExperimentTest.java b/lib/src/test/java/growthbook/sdk/java/ExperimentTest.java index 618f859f..5a71bd3e 100644 --- a/lib/src/test/java/growthbook/sdk/java/ExperimentTest.java +++ b/lib/src/test/java/growthbook/sdk/java/ExperimentTest.java @@ -5,6 +5,9 @@ import com.google.gson.JsonObject; import com.google.gson.reflect.TypeToken; +import growthbook.sdk.java.model.Experiment; +import growthbook.sdk.java.model.Namespace; +import growthbook.sdk.java.util.GrowthBookJsonUtils; import org.junit.jupiter.api.Test; import java.lang.reflect.Type; import java.util.ArrayList; @@ -46,18 +49,18 @@ void canBeConstructed() { null, null ); - assertEquals(0.5f, experiment.coverage); assertEquals(0.5f, experiment.getCoverage()); - assertEquals(1, experiment.force); + assertEquals(0.5f, experiment.getCoverage()); + assertEquals(1, experiment.getForce()); assertEquals(1, experiment.getForce()); - assertEquals("my_experiment", experiment.key); assertEquals("my_experiment", experiment.getKey()); - assertEquals("_id", experiment.hashAttribute); + assertEquals("my_experiment", experiment.getKey()); assertEquals("_id", experiment.getHashAttribute()); - assert experiment.weights != null; - assertEquals(0.3f, experiment.weights.get(0)); - assertEquals(0.7f, experiment.weights.get(1)); - assertEquals(Boolean.TRUE, experiment.isActive); + assertEquals("_id", experiment.getHashAttribute()); + assert experiment.getWeights() != null; + assertEquals(0.3f, experiment.getWeights().get(0)); + assertEquals(0.7f, experiment.getWeights().get(1)); + assertEquals(Boolean.TRUE, experiment.getIsActive()); assertEquals(Boolean.TRUE, experiment.getIsActive()); } @@ -77,17 +80,17 @@ void canBeBuilt() { .hashAttribute("_id") .build(); - assertEquals(0.5f, experiment.coverage); assertEquals(0.5f, experiment.getCoverage()); - assertEquals(1, experiment.force); + assertEquals(0.5f, experiment.getCoverage()); assertEquals(1, experiment.getForce()); - assertEquals(0.3f, experiment.weights.get(0)); - assertEquals(0.7f, experiment.weights.get(1)); - assertEquals("my_experiment", experiment.key); + assertEquals(1, experiment.getForce()); + assertEquals(0.3f, experiment.getWeights().get(0)); + assertEquals(0.7f, experiment.getWeights().get(1)); + assertEquals("my_experiment", experiment.getKey()); assertEquals("my_experiment", experiment.getKey()); - assertEquals("_id", experiment.hashAttribute); assertEquals("_id", experiment.getHashAttribute()); - assertEquals(Boolean.TRUE, experiment.isActive); + assertEquals("_id", experiment.getHashAttribute()); + assertEquals(Boolean.TRUE, experiment.getIsActive()); assertEquals(Boolean.TRUE, experiment.getIsActive()); } @@ -97,11 +100,11 @@ void hasDefaultBuilderArguments() { .builder() .build(); - assertNull(experiment.coverage); - assertNull(experiment.force); - assertNull(experiment.key); - assertNull(experiment.isActive); - assertEquals("id", experiment.hashAttribute); + assertNull(experiment.getCoverage()); + assertNull(experiment.getForce()); + assertNull(experiment.getKey()); + assertNull(experiment.getIsActive()); + assertEquals("id", experiment.getHashAttribute()); assertEquals("id", experiment.getHashAttribute()); } diff --git a/lib/src/test/java/growthbook/sdk/java/FeatureFetchExceptionTest.java b/lib/src/test/java/growthbook/sdk/java/FeatureFetchExceptionTest.java index 7736c063..d3e63cd5 100644 --- a/lib/src/test/java/growthbook/sdk/java/FeatureFetchExceptionTest.java +++ b/lib/src/test/java/growthbook/sdk/java/FeatureFetchExceptionTest.java @@ -2,6 +2,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; +import growthbook.sdk.java.exception.FeatureFetchException; import org.junit.jupiter.api.Test; class FeatureFetchExceptionTest { diff --git a/lib/src/test/java/growthbook/sdk/java/FeatureResultTest.java b/lib/src/test/java/growthbook/sdk/java/FeatureResultTest.java index b363c21d..e9e99280 100644 --- a/lib/src/test/java/growthbook/sdk/java/FeatureResultTest.java +++ b/lib/src/test/java/growthbook/sdk/java/FeatureResultTest.java @@ -6,6 +6,10 @@ import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import growthbook.sdk.java.model.FeatureResult; +import growthbook.sdk.java.model.FeatureResultSource; +import growthbook.sdk.java.model.GBContext; +import growthbook.sdk.java.util.GrowthBookJsonUtils; import org.junit.jupiter.api.Test; import java.util.ArrayList; @@ -23,7 +27,7 @@ void canBeConstructed() { "my-rule-id" ); - assertNull(subject.experiment); + assertNull(subject.getExperiment()); assertEquals(100, subject.getValue()); } @@ -38,7 +42,7 @@ void canBeBuilt() { .source(FeatureResultSource.EXPERIMENT) .build(); - assertNull(subject.experiment); + assertNull(subject.getExperiment()); assertEquals("hello", subject.getValue()); } diff --git a/lib/src/test/java/growthbook/sdk/java/FeatureRuleTest.java b/lib/src/test/java/growthbook/sdk/java/FeatureRuleTest.java index 748f12b3..087c8e2c 100644 --- a/lib/src/test/java/growthbook/sdk/java/FeatureRuleTest.java +++ b/lib/src/test/java/growthbook/sdk/java/FeatureRuleTest.java @@ -3,6 +3,9 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; +import growthbook.sdk.java.model.FeatureRule; +import growthbook.sdk.java.model.Namespace; +import growthbook.sdk.java.model.OptionalField; import org.junit.jupiter.api.Test; import java.util.ArrayList; @@ -49,15 +52,15 @@ void canBeConstructed() { null ); - assertEquals(0.5f, subject.coverage); + assertEquals(0.5f, subject.getCoverage()); assertEquals(0.5f, subject.getCoverage()); assertEquals(100, subject.getForce().getValue()); assertEquals(100, subject.getForce().getValue()); - assertEquals(namespace, subject.namespace); assertEquals(namespace, subject.getNamespace()); - assertEquals("_id", subject.hashAttribute); + assertEquals(namespace, subject.getNamespace()); + assertEquals("_id", subject.getHashAttribute()); assertEquals("_id", subject.getHashAttribute()); - assertEquals(weights, subject.weights); + assertEquals(weights, subject.getWeights()); assertEquals(weights, subject.getWeights()); } @@ -85,15 +88,15 @@ void canBeBuilt() { .hashAttribute("_id") .build(); - assertEquals(0.5f, subject.coverage); + assertEquals(0.5f, subject.getCoverage()); assertEquals(0.5f, subject.getCoverage()); assertEquals("forced-value", subject.getForce().getValue()); assertEquals("forced-value", subject.getForce().getValue()); - assertEquals(namespace, subject.namespace); assertEquals(namespace, subject.getNamespace()); - assertEquals(weights, subject.weights); + assertEquals(namespace, subject.getNamespace()); + assertEquals(weights, subject.getWeights()); assertEquals(weights, subject.getWeights()); - assertEquals("_id", subject.hashAttribute); + assertEquals("_id", subject.getHashAttribute()); assertEquals("_id", subject.getHashAttribute()); } @@ -103,11 +106,11 @@ void defaultBuilderValues() { .builder() .build(); - assertNull(subject.coverage); - assertNull(subject.force); - assertNull(subject.namespace); - assertNull(subject.weights); - assertEquals("id", subject.hashAttribute); + assertNull(subject.getCoverage()); + assertNull(subject.getForce()); + assertNull(subject.getNamespace()); + assertNull(subject.getWeights()); + assertEquals("id", subject.getHashAttribute()); assertEquals("id", subject.getHashAttribute()); } } diff --git a/lib/src/test/java/growthbook/sdk/java/FilterTest.java b/lib/src/test/java/growthbook/sdk/java/FilterTest.java index f2b3bdb7..39fa28d1 100644 --- a/lib/src/test/java/growthbook/sdk/java/FilterTest.java +++ b/lib/src/test/java/growthbook/sdk/java/FilterTest.java @@ -2,6 +2,8 @@ import static org.junit.jupiter.api.Assertions.assertEquals; +import growthbook.sdk.java.model.BucketRange; +import growthbook.sdk.java.model.Filter; import org.junit.jupiter.api.Test; import java.util.ArrayList; diff --git a/lib/src/test/java/growthbook/sdk/java/GBContextTest.java b/lib/src/test/java/growthbook/sdk/java/GBContextTest.java index beff57f2..01f972a1 100644 --- a/lib/src/test/java/growthbook/sdk/java/GBContextTest.java +++ b/lib/src/test/java/growthbook/sdk/java/GBContextTest.java @@ -7,6 +7,10 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.verify; +import growthbook.sdk.java.callback.TrackingCallback; +import growthbook.sdk.java.model.Experiment; +import growthbook.sdk.java.model.ExperimentResult; +import growthbook.sdk.java.model.GBContext; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/lib/src/test/java/growthbook/sdk/java/GBFeaturesRepositoryRefreshingTest.java b/lib/src/test/java/growthbook/sdk/java/GBFeaturesRepositoryRefreshingTest.java index 7bf86d28..41c551dd 100644 --- a/lib/src/test/java/growthbook/sdk/java/GBFeaturesRepositoryRefreshingTest.java +++ b/lib/src/test/java/growthbook/sdk/java/GBFeaturesRepositoryRefreshingTest.java @@ -6,6 +6,9 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import growthbook.sdk.java.exception.FeatureFetchException; +import growthbook.sdk.java.repository.FeatureRefreshStrategy; +import growthbook.sdk.java.repository.GBFeaturesRepository; import okhttp3.Call; import okhttp3.MediaType; import okhttp3.OkHttpClient; diff --git a/lib/src/test/java/growthbook/sdk/java/GBFeaturesRepositoryTest.java b/lib/src/test/java/growthbook/sdk/java/GBFeaturesRepositoryTest.java index 597bae6f..c3ae59cf 100644 --- a/lib/src/test/java/growthbook/sdk/java/GBFeaturesRepositoryTest.java +++ b/lib/src/test/java/growthbook/sdk/java/GBFeaturesRepositoryTest.java @@ -14,6 +14,12 @@ import static org.mockito.Mockito.when; import com.google.gson.JsonObject; +import growthbook.sdk.java.callback.FeatureRefreshCallback; +import growthbook.sdk.java.exception.FeatureFetchException; +import growthbook.sdk.java.model.RequestBodyForRemoteEval; +import growthbook.sdk.java.repository.FeatureRefreshStrategy; +import growthbook.sdk.java.repository.GBFeaturesRepository; +import growthbook.sdk.java.sandbox.CachingManager; import okhttp3.Call; import okhttp3.Callback; import okhttp3.MediaType; diff --git a/lib/src/test/java/growthbook/sdk/java/GrowthBookJsonUtilsTest.java b/lib/src/test/java/growthbook/sdk/java/GrowthBookJsonUtilsTest.java index b5c7f885..811a7d24 100644 --- a/lib/src/test/java/growthbook/sdk/java/GrowthBookJsonUtilsTest.java +++ b/lib/src/test/java/growthbook/sdk/java/GrowthBookJsonUtilsTest.java @@ -4,6 +4,10 @@ import com.google.gson.Gson; import com.google.gson.JsonElement; +import growthbook.sdk.java.model.BucketRange; +import growthbook.sdk.java.model.DataType; +import growthbook.sdk.java.model.Namespace; +import growthbook.sdk.java.util.GrowthBookJsonUtils; import org.junit.jupiter.api.Test; class GrowthBookJsonUtilsTest { diff --git a/lib/src/test/java/growthbook/sdk/java/GrowthBookTest.java b/lib/src/test/java/growthbook/sdk/java/GrowthBookTest.java index 679b76ca..d53c6936 100644 --- a/lib/src/test/java/growthbook/sdk/java/GrowthBookTest.java +++ b/lib/src/test/java/growthbook/sdk/java/GrowthBookTest.java @@ -17,9 +17,20 @@ import com.google.gson.JsonPrimitive; import com.google.gson.annotations.SerializedName; import com.google.gson.reflect.TypeToken; +import growthbook.sdk.java.callback.ExperimentRunCallback; +import growthbook.sdk.java.callback.FeatureUsageCallback; +import growthbook.sdk.java.evaluators.ConditionEvaluator; +import growthbook.sdk.java.evaluators.ExperimentEvaluator; +import growthbook.sdk.java.evaluators.FeatureEvaluator; +import growthbook.sdk.java.model.Experiment; +import growthbook.sdk.java.model.ExperimentResult; +import growthbook.sdk.java.model.FeatureResult; +import growthbook.sdk.java.model.FeatureResultSource; +import growthbook.sdk.java.model.GBContext; import growthbook.sdk.java.testhelpers.PaperCupsConfig; import growthbook.sdk.java.testhelpers.TestCasesJsonHelper; import growthbook.sdk.java.testhelpers.TestContext; +import growthbook.sdk.java.util.GrowthBookJsonUtils; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; import java.lang.reflect.Type; @@ -1098,7 +1109,7 @@ void test_withUrl_evaluateFeature_forcesBooleanValue() { FeatureResult result = subject.evalFeature("dark_mode", Boolean.class); assertEquals(true, result.getValue()); - assertEquals(FeatureResultSource.URL_OVERRIDE, result.source); + assertEquals(FeatureResultSource.URL_OVERRIDE, result.getSource()); } @Test @@ -1118,7 +1129,7 @@ void test_withUrl_evaluateFeature_forcesStringValue() { FeatureResult result = subject.evalFeature("banner_text", String.class); assertEquals("Hello, everyone! I hope you are all doing well!", result.getValue()); - assertEquals(FeatureResultSource.URL_OVERRIDE, result.source); + assertEquals(FeatureResultSource.URL_OVERRIDE, result.getSource()); } @Test @@ -1138,7 +1149,7 @@ void test_withUrl_evaluateFeature_forcesFloatValue() { FeatureResult result = subject.evalFeature("donut_price", Float.class); assertEquals(3.33f, result.getValue()); - assertEquals(FeatureResultSource.URL_OVERRIDE, result.source); + assertEquals(FeatureResultSource.URL_OVERRIDE, result.getSource()); } @Test @@ -1158,7 +1169,7 @@ void test_withUrl_evaluateFeature_forcesIntegerValue() { FeatureResult result = subject.evalFeature("donut_price", Integer.class); assertEquals(4, result.getValue()); - assertEquals(FeatureResultSource.URL_OVERRIDE, result.source); + assertEquals(FeatureResultSource.URL_OVERRIDE, result.getSource()); } // endregion URL -> force features -> evaluateFeature diff --git a/lib/src/test/java/growthbook/sdk/java/GrowthBookUtilsTest.java b/lib/src/test/java/growthbook/sdk/java/GrowthBookUtilsTest.java index 79af4c57..5902c9fa 100644 --- a/lib/src/test/java/growthbook/sdk/java/GrowthBookUtilsTest.java +++ b/lib/src/test/java/growthbook/sdk/java/GrowthBookUtilsTest.java @@ -5,7 +5,11 @@ import com.google.gson.JsonArray; import com.google.gson.reflect.TypeToken; +import growthbook.sdk.java.model.BucketRange; +import growthbook.sdk.java.model.Namespace; import growthbook.sdk.java.testhelpers.TestCasesJsonHelper; +import growthbook.sdk.java.util.GrowthBookJsonUtils; +import growthbook.sdk.java.util.GrowthBookUtils; import org.junit.jupiter.api.Test; import javax.annotation.Nullable; import java.lang.reflect.Type; diff --git a/lib/src/test/java/growthbook/sdk/java/LocalGbFeatureRepositoryTest.java b/lib/src/test/java/growthbook/sdk/java/LocalGbFeatureRepositoryTest.java index 5039be13..67c560c4 100644 --- a/lib/src/test/java/growthbook/sdk/java/LocalGbFeatureRepositoryTest.java +++ b/lib/src/test/java/growthbook/sdk/java/LocalGbFeatureRepositoryTest.java @@ -6,6 +6,8 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; +import growthbook.sdk.java.exception.FeatureFetchException; +import growthbook.sdk.java.repository.LocalGbFeatureRepository; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/lib/src/test/java/growthbook/sdk/java/MathUtilsTest.java b/lib/src/test/java/growthbook/sdk/java/MathUtilsTest.java index 0ffb3de7..a8b57634 100644 --- a/lib/src/test/java/growthbook/sdk/java/MathUtilsTest.java +++ b/lib/src/test/java/growthbook/sdk/java/MathUtilsTest.java @@ -2,6 +2,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; +import growthbook.sdk.java.util.MathUtils; import org.junit.jupiter.api.Test; class MathUtilsTest { diff --git a/lib/src/test/java/growthbook/sdk/java/NamespaceTest.java b/lib/src/test/java/growthbook/sdk/java/NamespaceTest.java index bfebf873..d5f62c75 100644 --- a/lib/src/test/java/growthbook/sdk/java/NamespaceTest.java +++ b/lib/src/test/java/growthbook/sdk/java/NamespaceTest.java @@ -4,6 +4,7 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import growthbook.sdk.java.model.Namespace; import org.junit.jupiter.api.Test; class NamespaceTest { diff --git a/lib/src/test/java/growthbook/sdk/java/NativeJavaGbFeatureRepositoryTest.java b/lib/src/test/java/growthbook/sdk/java/NativeJavaGbFeatureRepositoryTest.java index 0393c4ce..4af37612 100644 --- a/lib/src/test/java/growthbook/sdk/java/NativeJavaGbFeatureRepositoryTest.java +++ b/lib/src/test/java/growthbook/sdk/java/NativeJavaGbFeatureRepositoryTest.java @@ -11,6 +11,10 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import growthbook.sdk.java.callback.FeatureRefreshCallback; +import growthbook.sdk.java.exception.FeatureFetchException; +import growthbook.sdk.java.repository.FeatureRefreshStrategy; +import growthbook.sdk.java.repository.NativeJavaGbFeatureRepository; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mock; diff --git a/lib/src/test/java/growthbook/sdk/java/OperatorTest.java b/lib/src/test/java/growthbook/sdk/java/OperatorTest.java index 30c26ed8..e899d314 100644 --- a/lib/src/test/java/growthbook/sdk/java/OperatorTest.java +++ b/lib/src/test/java/growthbook/sdk/java/OperatorTest.java @@ -3,6 +3,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; +import growthbook.sdk.java.model.Operator; import org.junit.jupiter.api.Test; class OperatorTest { diff --git a/lib/src/test/java/growthbook/sdk/java/StringUtilsTest.java b/lib/src/test/java/growthbook/sdk/java/StringUtilsTest.java index 0dca0d76..ea8603ff 100644 --- a/lib/src/test/java/growthbook/sdk/java/StringUtilsTest.java +++ b/lib/src/test/java/growthbook/sdk/java/StringUtilsTest.java @@ -2,6 +2,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; +import growthbook.sdk.java.util.StringUtils; import org.junit.jupiter.api.Test; class StringUtilsTest { diff --git a/lib/src/test/java/growthbook/sdk/java/TrackDataTest.java b/lib/src/test/java/growthbook/sdk/java/TrackDataTest.java index 15ab925b..beb7afc1 100644 --- a/lib/src/test/java/growthbook/sdk/java/TrackDataTest.java +++ b/lib/src/test/java/growthbook/sdk/java/TrackDataTest.java @@ -2,6 +2,10 @@ import static org.junit.jupiter.api.Assertions.assertEquals; +import growthbook.sdk.java.model.Experiment; +import growthbook.sdk.java.model.ExperimentResult; +import growthbook.sdk.java.model.FeatureResult; +import growthbook.sdk.java.model.TrackData; import org.junit.jupiter.api.Test; class TrackDataTest { diff --git a/lib/src/test/java/growthbook/sdk/java/UrlUtilsTest.java b/lib/src/test/java/growthbook/sdk/java/UrlUtilsTest.java index e6d430eb..5c757943 100644 --- a/lib/src/test/java/growthbook/sdk/java/UrlUtilsTest.java +++ b/lib/src/test/java/growthbook/sdk/java/UrlUtilsTest.java @@ -2,6 +2,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; +import growthbook.sdk.java.util.UrlUtils; import org.junit.jupiter.api.Test; import java.net.MalformedURLException; import java.net.URL; diff --git a/lib/src/test/java/growthbook/sdk/java/VariationMetaTest.java b/lib/src/test/java/growthbook/sdk/java/VariationMetaTest.java index 913f4e5c..5ef258b2 100644 --- a/lib/src/test/java/growthbook/sdk/java/VariationMetaTest.java +++ b/lib/src/test/java/growthbook/sdk/java/VariationMetaTest.java @@ -2,6 +2,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; +import growthbook.sdk.java.model.VariationMeta; import org.junit.jupiter.api.Test; class VariationMetaTest { diff --git a/lib/src/test/java/growthbook/sdk/java/multiusermode/GrowthBookClientTest.java b/lib/src/test/java/growthbook/sdk/java/multiusermode/GrowthBookClientTest.java index 9b312d40..c82fc41e 100644 --- a/lib/src/test/java/growthbook/sdk/java/multiusermode/GrowthBookClientTest.java +++ b/lib/src/test/java/growthbook/sdk/java/multiusermode/GrowthBookClientTest.java @@ -1,10 +1,15 @@ package growthbook.sdk.java.multiusermode; import com.google.gson.JsonObject; -import growthbook.sdk.java.*; +import growthbook.sdk.java.callback.FeatureRefreshCallback; +import growthbook.sdk.java.exception.FeatureFetchException; +import growthbook.sdk.java.model.FeatureResult; import growthbook.sdk.java.multiusermode.configurations.Options; import growthbook.sdk.java.multiusermode.configurations.UserContext; +import growthbook.sdk.java.repository.FeatureRefreshStrategy; +import growthbook.sdk.java.repository.GBFeaturesRepository; import growthbook.sdk.java.testhelpers.TestCasesJsonHelper; +import growthbook.sdk.java.util.GrowthBookJsonUtils; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; diff --git a/lib/src/test/java/growthbook/sdk/java/testhelpers/SSETestServer.java b/lib/src/test/java/growthbook/sdk/java/testhelpers/SSETestServer.java index 4e1c8ced..9e81d1b2 100644 --- a/lib/src/test/java/growthbook/sdk/java/testhelpers/SSETestServer.java +++ b/lib/src/test/java/growthbook/sdk/java/testhelpers/SSETestServer.java @@ -3,10 +3,10 @@ import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpServer; -import growthbook.sdk.java.FeatureFetchException; -import growthbook.sdk.java.FeatureRefreshStrategy; -import growthbook.sdk.java.GBContext; -import growthbook.sdk.java.GBFeaturesRepository; +import growthbook.sdk.java.exception.FeatureFetchException; +import growthbook.sdk.java.repository.FeatureRefreshStrategy; +import growthbook.sdk.java.model.GBContext; +import growthbook.sdk.java.repository.GBFeaturesRepository; import growthbook.sdk.java.GrowthBook; import java.io.IOException; import java.io.OutputStream; From 04f4490203aa0e645319410065553ffa252f629a Mon Sep 17 00:00:00 2001 From: Volodymyr Nazarkevych Date: Tue, 4 Feb 2025 21:10:09 +0200 Subject: [PATCH 2/4] Fix NPE by marking gate as nullable and using safe comparison --- lib/src/main/java/growthbook/sdk/java/Version.java | 2 +- .../java/growthbook/sdk/java/evaluators/FeatureEvaluator.java | 2 +- .../main/java/growthbook/sdk/java/model/ParentCondition.java | 4 +++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/src/main/java/growthbook/sdk/java/Version.java b/lib/src/main/java/growthbook/sdk/java/Version.java index 78ed1a6a..5d299029 100644 --- a/lib/src/main/java/growthbook/sdk/java/Version.java +++ b/lib/src/main/java/growthbook/sdk/java/Version.java @@ -4,5 +4,5 @@ * Tag for the published GrowthBook SDK version */ public interface Version { - static final String SDK_VERSION = "0.9.92"; + String SDK_VERSION = "0.9.92"; } diff --git a/lib/src/main/java/growthbook/sdk/java/evaluators/FeatureEvaluator.java b/lib/src/main/java/growthbook/sdk/java/evaluators/FeatureEvaluator.java index cc40cdb1..e512dcb0 100644 --- a/lib/src/main/java/growthbook/sdk/java/evaluators/FeatureEvaluator.java +++ b/lib/src/main/java/growthbook/sdk/java/evaluators/FeatureEvaluator.java @@ -206,7 +206,7 @@ public FeatureResult evaluateFeature( // blocking prerequisite eval failed: feature evaluation fails if (!evalCondition) { // blocking prerequisite eval failed: feature evaluation fails - if (parentCondition.getGate()) { + if (Boolean.TRUE.equals(parentCondition.getGate())) { log.info("Feature blocked by prerequisite"); FeatureResult featureResultWhenBlockedByPrerequisite = diff --git a/lib/src/main/java/growthbook/sdk/java/model/ParentCondition.java b/lib/src/main/java/growthbook/sdk/java/model/ParentCondition.java index e71c6449..598633c9 100644 --- a/lib/src/main/java/growthbook/sdk/java/model/ParentCondition.java +++ b/lib/src/main/java/growthbook/sdk/java/model/ParentCondition.java @@ -5,6 +5,8 @@ import lombok.Data; import lombok.RequiredArgsConstructor; +import javax.annotation.Nullable; + /** * A ParentCondition defines a prerequisite. It consists of a parent feature's id (string), * a condition (Condition),and an optional gate (boolean) flag. @@ -27,5 +29,5 @@ public class ParentCondition { * If gate is true, then this is a blocking feature-level prerequisite; * otherwise it applies to the current rule only */ - private Boolean gate; + @Nullable private Boolean gate; } From 6df76492964c1c21e299ff588291cc3c52547b6a Mon Sep 17 00:00:00 2001 From: Volodymyr Nazarkevych Date: Thu, 6 Feb 2025 13:00:58 +0200 Subject: [PATCH 3/4] Fix potential NPE with optional fields, refactor code style, and simplify logic in project --- README.md | 4 +- .../java/growthbook/sdk/java/GrowthBook.java | 6 +- .../java/evaluators/ConditionEvaluator.java | 10 ++-- .../java/evaluators/ExperimentEvaluator.java | 4 +- .../sdk/java/evaluators/FeatureEvaluator.java | 9 ++- .../growthbook/sdk/java/model/Experiment.java | 3 + .../sdk/java/model/ExperimentResult.java | 4 +- .../growthbook/sdk/java/model/Feature.java | 1 + .../sdk/java/model/FeatureRule.java | 3 +- .../growthbook/sdk/java/model/Filter.java | 1 + .../growthbook/sdk/java/model/GBContext.java | 7 +-- ...neratedStickyBucketAssignmentDocModel.java | 1 - .../StickyAssignmentsDocument.java | 2 +- .../configurations/UserContext.java | 2 +- .../java/repository/GBFeaturesRepository.java | 2 +- .../InMemoryStickyBucketServiceImpl.java | 2 + .../stickyBucketing/StickyBucketService.java | 2 + .../sdk/java/util/GrowthBookUtils.java | 16 +++--- .../growthbook/sdk/java/util/MathUtils.java | 2 +- .../growthbook/sdk/java/util/UrlUtils.java | 4 +- .../sdk/java/CachingManagerTest.java | 4 +- .../sdk/java/DecryptionUtilsTest.java | 16 ++---- ...FeatureWithStickyBucketingFeatureTest.java | 2 +- .../sdk/java/ExperimentResultTest.java | 2 +- .../growthbook/sdk/java/ExperimentTest.java | 6 +- .../growthbook/sdk/java/FeatureRuleTest.java | 17 +++--- .../growthbook/sdk/java/GBContextTest.java | 16 +++--- .../GBFeaturesRepositoryRefreshingTest.java | 6 +- .../sdk/java/GBFeaturesRepositoryTest.java | 4 +- .../growthbook/sdk/java/GrowthBookTest.java | 56 +++++++++---------- .../NativeJavaGbFeatureRepositoryTest.java | 20 +++---- .../multiusermode/GrowthBookClientTest.java | 6 +- .../java/testhelpers/TestCasesJsonHelper.java | 7 +-- 33 files changed, 123 insertions(+), 124 deletions(-) rename lib/src/main/java/growthbook/sdk/java/{stickyBucketing => model}/StickyAssignmentsDocument.java (94%) diff --git a/README.md b/README.md index 894d7e1f..3cfe38c9 100644 --- a/README.md +++ b/README.md @@ -131,7 +131,7 @@ The method returns a FeatureResult object, which contains the evaluated result o public FeatureResult evalFeature(String key, Class valueTypeClass, UserContext userContext); ``` -* `getFeatureValue()` the same purpose as in `evalFeature()` but have ability to provide default value) +* `getFeatureValue()` the same purpose as in `evalFeature()`, but have ability to provide default value ```java public ValueType getFeatureValue(String featureKey, ValueType defaultValue, Class gsonDeserializableClass, UserContext userContext); ``` @@ -270,7 +270,7 @@ public class InMemoryStickyBucketServiceImpl implements StickyBucketService { ### Releasing a new version -For now we are manually managing the version number. +For now, we are manually managing the version number. When making a new release, ensure the file `growthbook/sdk/java/Version.java` has the version matching the tag and release. For example, if you are releasing version `0.3.0`, the following criteria should be met: diff --git a/lib/src/main/java/growthbook/sdk/java/GrowthBook.java b/lib/src/main/java/growthbook/sdk/java/GrowthBook.java index e9fa5b95..71c98025 100644 --- a/lib/src/main/java/growthbook/sdk/java/GrowthBook.java +++ b/lib/src/main/java/growthbook/sdk/java/GrowthBook.java @@ -160,7 +160,7 @@ private EvaluationContext getEvaluationContext() { *

* There are a few ordered steps to evaluate a feature *

- * 1. If the key doesn't exist in context.features + * 1. If the key doesn't exist in context.getFeatures() * 1.1 Return getFeatureResult(null, "unknownFeature") * 2. Loop through the feature rules (if any) * 2.1 If the rule has parentConditions (prerequisites) defined, loop through each one: @@ -281,7 +281,7 @@ public void setInMemoryStickyBucketService() { * 4) 0 * Everything else is considered "truthy", including empty arrays and objects. * If the value is "truthy", then isOn() will return true and isOff() will return false. - * If the value is "falsy", then the opposite values will be returned. + * If the value is "false", then the opposite values will be returned. * * @param featureKey name of the feature * @return true if the value is a truthy value @@ -300,7 +300,7 @@ public Boolean isOn(String featureKey) { * 4) 0 * Everything else is considered "truthy", including empty arrays and objects. * If the value is "truthy", then isOn() will return true and isOff() will return false. - * If the value is "falsy", then the opposite values will be returned. + * If the value is "false", then the opposite values will be returned. * * @param featureKey name of the feature * @return true if the value is a truthy value diff --git a/lib/src/main/java/growthbook/sdk/java/evaluators/ConditionEvaluator.java b/lib/src/main/java/growthbook/sdk/java/evaluators/ConditionEvaluator.java index 3fd9e6db..e24d3f83 100644 --- a/lib/src/main/java/growthbook/sdk/java/evaluators/ConditionEvaluator.java +++ b/lib/src/main/java/growthbook/sdk/java/evaluators/ConditionEvaluator.java @@ -4,6 +4,7 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; +import com.google.gson.JsonSyntaxException; import com.google.gson.reflect.TypeToken; import growthbook.sdk.java.util.GrowthBookJsonUtils; import growthbook.sdk.java.model.Operator; @@ -19,6 +20,7 @@ import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; /** * INTERNAL: Implementation of condition evaluation @@ -93,10 +95,10 @@ public Boolean evaluateCondition(JsonObject attributes, JsonObject conditionJson } // If none of the entries failed their checks, `evalCondition` returns true return true; - } catch (com.google.gson.JsonSyntaxException jsonSyntaxException) { + } catch (JsonSyntaxException jsonSyntaxException) { log.error(jsonSyntaxException.getMessage(), jsonSyntaxException); return false; - } catch (java.util.regex.PatternSyntaxException patternSyntaxException) { + } catch (PatternSyntaxException patternSyntaxException) { log.error(patternSyntaxException.getMessage(), patternSyntaxException); return false; } catch (Exception exception) { // for the case if something was missed @@ -467,7 +469,7 @@ Boolean evalOperatorCondition(String operatorString, @Nullable JsonElement actua case IN_GROUP: if (actual != null && expected != null) { - JsonElement jsonElement = savedGroups.get(expected.getAsString()); + JsonElement jsonElement = savedGroups != null ? savedGroups.get(expected.getAsString()) : null; if (jsonElement != null) { return isIn(actual, jsonElement.getAsJsonArray()); } @@ -475,7 +477,7 @@ Boolean evalOperatorCondition(String operatorString, @Nullable JsonElement actua } case NOT_IN_GROUP: if (actual != null && expected != null) { - JsonElement jsonElement = savedGroups.get(expected.getAsString()); + JsonElement jsonElement = savedGroups != null ? savedGroups.get(expected.getAsString()) : null; if (jsonElement != null) { return !isIn(actual, jsonElement.getAsJsonArray()); } diff --git a/lib/src/main/java/growthbook/sdk/java/evaluators/ExperimentEvaluator.java b/lib/src/main/java/growthbook/sdk/java/evaluators/ExperimentEvaluator.java index 2e8f2883..de0f45b6 100644 --- a/lib/src/main/java/growthbook/sdk/java/evaluators/ExperimentEvaluator.java +++ b/lib/src/main/java/growthbook/sdk/java/evaluators/ExperimentEvaluator.java @@ -296,7 +296,9 @@ public ExperimentResult evaluateExperiment(Experiment FeatureResult evaluateFeature( // Loop through the feature rules (if any) List> featureRules = feature.getRules(); - for (int i = 0; i < featureRules.size(); i++) { - FeatureRule rule = featureRules.get(i); + for (FeatureRule rule : featureRules) { // If there are prerequisite flag(s), evaluate them if (rule.getParentConditions() != null) { for (ParentCondition parentCondition : rule.getParentConditions()) { @@ -238,7 +237,7 @@ public FeatureResult evaluateFeature( } // Feature value is being forced - if (rule.getForce().isPresent()) { + if (rule.getForce() != null && rule.getForce().isPresent()) { // If the rule has a condition, and it evaluates to false, skip this rule and continue to the next one if (rule.getCondition() != null) { @@ -299,7 +298,7 @@ public FeatureResult evaluateFeature( String attributeValue = context.getUser().getAttributes().get(ruleKey) == null ? null : context.getUser().getAttributes().get(ruleKey).getAsString(); - + if (attributeValue == null || attributeValue.isEmpty()) { continue; } @@ -326,7 +325,7 @@ public FeatureResult evaluateFeature( if (featureUsageCallbackWithUser != null) { featureUsageCallbackWithUser.onFeatureUsage(key, forcedRuleFeatureValue, context.getUser()); } - + return forcedRuleFeatureValue; } else { diff --git a/lib/src/main/java/growthbook/sdk/java/model/Experiment.java b/lib/src/main/java/growthbook/sdk/java/model/Experiment.java index deb953a4..281b370c 100644 --- a/lib/src/main/java/growthbook/sdk/java/model/Experiment.java +++ b/lib/src/main/java/growthbook/sdk/java/model/Experiment.java @@ -45,11 +45,13 @@ public class Experiment { /** * What percent of users should be included in the experiment (between 0 and 1, inclusive) */ + @Nullable Float coverage; /** * Optional targeting condition */ + @Nullable JsonObject conditionJson; /** @@ -70,6 +72,7 @@ public class Experiment { /** * All users included in the experiment will be forced into the specific variation index */ + @Nullable Integer force; /** diff --git a/lib/src/main/java/growthbook/sdk/java/model/ExperimentResult.java b/lib/src/main/java/growthbook/sdk/java/model/ExperimentResult.java index 386e8703..0995ee1a 100644 --- a/lib/src/main/java/growthbook/sdk/java/model/ExperimentResult.java +++ b/lib/src/main/java/growthbook/sdk/java/model/ExperimentResult.java @@ -120,11 +120,11 @@ public ExperimentResult( ) { this.value = value; this.variationId = variationId; - this.inExperiment = inExperiment == null ? false : inExperiment; + this.inExperiment = inExperiment != null && inExperiment; this.hashAttribute = hashAttribute == null ? "id" : hashAttribute; this.hashValue = hashValue; this.featureId = featureId; - this.hashUsed = hashUsed == null ? false : hashUsed; + this.hashUsed = hashUsed != null && hashUsed; this.key = key; if (this.key == null && variationId != null) { diff --git a/lib/src/main/java/growthbook/sdk/java/model/Feature.java b/lib/src/main/java/growthbook/sdk/java/model/Feature.java index 1b7c604f..d31a7730 100644 --- a/lib/src/main/java/growthbook/sdk/java/model/Feature.java +++ b/lib/src/main/java/growthbook/sdk/java/model/Feature.java @@ -26,5 +26,6 @@ public class Feature { /** * The default value (should use null if not specified) */ + @Nullable private final Object defaultValue = null; } diff --git a/lib/src/main/java/growthbook/sdk/java/model/FeatureRule.java b/lib/src/main/java/growthbook/sdk/java/model/FeatureRule.java index 55d50067..5c89ef13 100644 --- a/lib/src/main/java/growthbook/sdk/java/model/FeatureRule.java +++ b/lib/src/main/java/growthbook/sdk/java/model/FeatureRule.java @@ -57,6 +57,7 @@ public class FeatureRule implements JsonDeserializer force; /** @@ -162,7 +163,7 @@ public class FeatureRule implements JsonDeserializer() : forcedVariationsMap; this.trackingCallback = trackingCallback; diff --git a/lib/src/main/java/growthbook/sdk/java/model/GeneratedStickyBucketAssignmentDocModel.java b/lib/src/main/java/growthbook/sdk/java/model/GeneratedStickyBucketAssignmentDocModel.java index 716c1bb8..03205436 100644 --- a/lib/src/main/java/growthbook/sdk/java/model/GeneratedStickyBucketAssignmentDocModel.java +++ b/lib/src/main/java/growthbook/sdk/java/model/GeneratedStickyBucketAssignmentDocModel.java @@ -1,6 +1,5 @@ package growthbook.sdk.java.model; -import growthbook.sdk.java.stickyBucketing.StickyAssignmentsDocument; import lombok.AllArgsConstructor; import lombok.Data; import lombok.RequiredArgsConstructor; diff --git a/lib/src/main/java/growthbook/sdk/java/stickyBucketing/StickyAssignmentsDocument.java b/lib/src/main/java/growthbook/sdk/java/model/StickyAssignmentsDocument.java similarity index 94% rename from lib/src/main/java/growthbook/sdk/java/stickyBucketing/StickyAssignmentsDocument.java rename to lib/src/main/java/growthbook/sdk/java/model/StickyAssignmentsDocument.java index 4cd74256..37c3525e 100644 --- a/lib/src/main/java/growthbook/sdk/java/stickyBucketing/StickyAssignmentsDocument.java +++ b/lib/src/main/java/growthbook/sdk/java/model/StickyAssignmentsDocument.java @@ -1,4 +1,4 @@ -package growthbook.sdk.java.stickyBucketing; +package growthbook.sdk.java.model; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/lib/src/main/java/growthbook/sdk/java/multiusermode/configurations/UserContext.java b/lib/src/main/java/growthbook/sdk/java/multiusermode/configurations/UserContext.java index b5e665b6..a3887bb8 100644 --- a/lib/src/main/java/growthbook/sdk/java/multiusermode/configurations/UserContext.java +++ b/lib/src/main/java/growthbook/sdk/java/multiusermode/configurations/UserContext.java @@ -2,7 +2,7 @@ import com.google.gson.JsonObject; import growthbook.sdk.java.multiusermode.util.TransformationUtil; -import growthbook.sdk.java.stickyBucketing.StickyAssignmentsDocument; +import growthbook.sdk.java.model.StickyAssignmentsDocument; import lombok.Builder; import lombok.Data; import lombok.extern.slf4j.Slf4j; diff --git a/lib/src/main/java/growthbook/sdk/java/repository/GBFeaturesRepository.java b/lib/src/main/java/growthbook/sdk/java/repository/GBFeaturesRepository.java index b7d76c08..7720e55b 100644 --- a/lib/src/main/java/growthbook/sdk/java/repository/GBFeaturesRepository.java +++ b/lib/src/main/java/growthbook/sdk/java/repository/GBFeaturesRepository.java @@ -168,7 +168,7 @@ public void setCachingManager(CachingManager cachingManager) { * Endpoint for POST request */ @Getter - private String remoteEvalEndPoint; + private final String remoteEvalEndPoint; /** diff --git a/lib/src/main/java/growthbook/sdk/java/stickyBucketing/InMemoryStickyBucketServiceImpl.java b/lib/src/main/java/growthbook/sdk/java/stickyBucketing/InMemoryStickyBucketServiceImpl.java index 081fbc2f..17bb2de9 100644 --- a/lib/src/main/java/growthbook/sdk/java/stickyBucketing/InMemoryStickyBucketServiceImpl.java +++ b/lib/src/main/java/growthbook/sdk/java/stickyBucketing/InMemoryStickyBucketServiceImpl.java @@ -1,5 +1,7 @@ package growthbook.sdk.java.stickyBucketing; +import growthbook.sdk.java.model.StickyAssignmentsDocument; + import java.util.HashMap; import java.util.Map; diff --git a/lib/src/main/java/growthbook/sdk/java/stickyBucketing/StickyBucketService.java b/lib/src/main/java/growthbook/sdk/java/stickyBucketing/StickyBucketService.java index 0f6ad3d3..87f68908 100644 --- a/lib/src/main/java/growthbook/sdk/java/stickyBucketing/StickyBucketService.java +++ b/lib/src/main/java/growthbook/sdk/java/stickyBucketing/StickyBucketService.java @@ -1,5 +1,7 @@ package growthbook.sdk.java.stickyBucketing; +import growthbook.sdk.java.model.StickyAssignmentsDocument; + import java.util.Map; /** diff --git a/lib/src/main/java/growthbook/sdk/java/util/GrowthBookUtils.java b/lib/src/main/java/growthbook/sdk/java/util/GrowthBookUtils.java index 67a772e6..972e2ced 100644 --- a/lib/src/main/java/growthbook/sdk/java/util/GrowthBookUtils.java +++ b/lib/src/main/java/growthbook/sdk/java/util/GrowthBookUtils.java @@ -15,7 +15,7 @@ import growthbook.sdk.java.model.StickyBucketVariation; import growthbook.sdk.java.model.VariationMeta; import growthbook.sdk.java.multiusermode.configurations.EvaluationContext; -import growthbook.sdk.java.stickyBucketing.StickyAssignmentsDocument; +import growthbook.sdk.java.model.StickyAssignmentsDocument; import growthbook.sdk.java.stickyBucketing.StickyBucketService; import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; @@ -132,7 +132,7 @@ public static ArrayList getEqualWeights(Integer numberOfVariations) { } Float weight = 1f / numberOfVariations; - return new ArrayList(Collections.nCopies(size, weight)); + return new ArrayList<>(Collections.nCopies(size, weight)); } // region Experiment for query string @@ -141,7 +141,7 @@ public static ArrayList getEqualWeights(Integer numberOfVariations) { * This checks if an experiment variation is being forced via a URL query string. * This may not be applicable for all SDKs (e.g. mobile). *

- * As an example, if the id is my-test and url is http://localhost/?my-test=1, + * As an example, if the id is my-test and url is ..., * it would return 1. *

* Returns null if any of these are true: @@ -176,7 +176,7 @@ public static Integer getQueryStringOverride(String id, String urlString, Intege * This checks if an experiment variation is being forced via a URL query string. * This may not be applicable for all SDKs (e.g. mobile). *

- * As an example, if the id is my-test and url is http://localhost/?my-test=1, + * As an example, if the id is my-test and url is ..., * it would return 1. *

* Returns null if any of these are true: @@ -410,7 +410,7 @@ public static ArrayList getBucketRanges( adjustedWeights = getEqualWeights(numberOfVariations); } - float start = 0.0f; + float start; float cumulative = 0.0f; ArrayList bucketRanges = new ArrayList<>(); @@ -479,7 +479,7 @@ public static Boolean isFilteredOut(List filters, JsonObject attributes) JsonPrimitive hashValuePrimitive = hashValueElement.getAsJsonPrimitive(); String hashValue = hashValuePrimitive.getAsString(); - if (hashValue == null || hashValue.equals("")) return true; + if (hashValue == null || hashValue.isEmpty()) return true; Integer hashVersion = filter.getHashVersion(); if (hashVersion == null) { @@ -617,7 +617,7 @@ public static Map getStickyBucketAttributes(GBContext context, * @param Feature class * @return list of sticky bucket identifier */ - private static @Nullable List deriveStickyBucketIdentifierAttributes( + private static List deriveStickyBucketIdentifierAttributes( GBContext context, String featureDataModel ) { @@ -871,7 +871,7 @@ public static HashAttributeAndHashValue getHashAttribute( private static int findVariationIndex(List meta, String variationKey) { for (int i = 0; i < meta.size(); i++) { if (meta.get(i).getKey() != null) { - if (meta.get(i).getKey().equals(variationKey)) { + if (Objects.equals(meta.get(i).getKey(), variationKey)) { return i; } } diff --git a/lib/src/main/java/growthbook/sdk/java/util/MathUtils.java b/lib/src/main/java/growthbook/sdk/java/util/MathUtils.java index 8e9f03e1..3dd791c8 100644 --- a/lib/src/main/java/growthbook/sdk/java/util/MathUtils.java +++ b/lib/src/main/java/growthbook/sdk/java/util/MathUtils.java @@ -9,7 +9,7 @@ public class MathUtils { /** * Fowler-Noll-Vo algorithm - * fnv32a returns an long, so we convert that to a float using a modulus + * fnv32a returns a long, so we convert that to a float using a modulus * * @param data byte list * @return long diff --git a/lib/src/main/java/growthbook/sdk/java/util/UrlUtils.java b/lib/src/main/java/growthbook/sdk/java/util/UrlUtils.java index 19e0c4b9..198213dd 100644 --- a/lib/src/main/java/growthbook/sdk/java/util/UrlUtils.java +++ b/lib/src/main/java/growthbook/sdk/java/util/UrlUtils.java @@ -17,8 +17,8 @@ public class UrlUtils { * @return key/value pairs mapping to the items in the query string */ public static Map parseQueryString(String queryString) { - Map map = new HashMap(); - if ((queryString == null) || (queryString.equals(""))) { + Map map = new HashMap<>(); + if ((queryString == null) || (queryString.isEmpty())) { return map; } String[] params = queryString.split("&"); diff --git a/lib/src/test/java/growthbook/sdk/java/CachingManagerTest.java b/lib/src/test/java/growthbook/sdk/java/CachingManagerTest.java index 0711a170..be99a19a 100644 --- a/lib/src/test/java/growthbook/sdk/java/CachingManagerTest.java +++ b/lib/src/test/java/growthbook/sdk/java/CachingManagerTest.java @@ -56,9 +56,7 @@ void shouldThrowExceptionWhenWritingFails() { fail("Creating test file was not successful."); } - RuntimeException thrown = assertThrows(RuntimeException.class, () -> { - cachingManager.saveContent(fileName, "This should fail"); - }); + RuntimeException thrown = assertThrows(RuntimeException.class, () -> cachingManager.saveContent(fileName, "This should fail")); assertInstanceOf(IOException.class, thrown.getCause()); } diff --git a/lib/src/test/java/growthbook/sdk/java/DecryptionUtilsTest.java b/lib/src/test/java/growthbook/sdk/java/DecryptionUtilsTest.java index e064094b..851def2a 100644 --- a/lib/src/test/java/growthbook/sdk/java/DecryptionUtilsTest.java +++ b/lib/src/test/java/growthbook/sdk/java/DecryptionUtilsTest.java @@ -54,9 +54,7 @@ void test_throwsArgumentExceptionWhenPayloadInvalid() { String payload = "foobar"; String encryptionKey = "BhB1wORFmZLTDjbvstvS8w=="; - Exception exception = assertThrows(DecryptionUtils.DecryptionException.class, () -> { - DecryptionUtils.decrypt(payload, encryptionKey); - }); + Exception exception = assertThrows(DecryptionUtils.DecryptionException.class, () -> DecryptionUtils.decrypt(payload, encryptionKey)); assertTrue(exception.getMessage().contains("Invalid payload")); } @@ -66,9 +64,7 @@ void test_throwsArgumentExceptionWhenPayloadInvalid_decodingIv() { String payload = "foobar.bar"; String encryptionKey = "BhB1wORFmZLTDjbvstvS8w=="; - Exception exception = assertThrows(DecryptionUtils.DecryptionException.class, () -> { - DecryptionUtils.decrypt(payload, encryptionKey); - }); + Exception exception = assertThrows(DecryptionUtils.DecryptionException.class, () -> DecryptionUtils.decrypt(payload, encryptionKey)); assertTrue(exception.getMessage().contains("Invalid payload")); } @@ -78,9 +74,7 @@ void test_throwsArgumentExceptionWhenEncryptionKeyInvalid() { String payload = "7rvPA94JEsqRo9yPZsdsXg==.bJ8vtYvX+ur3cEUFVkYo1OyWb98oLnMlpeoO0Hs4YPc0EVb7oKX4KNz+Yt6GUMBsieXqtL7oaYzX+kMayZEtV+3bhyDYnS9QBrvalnfxbLExjtnsy8g0pPQHU/P/DPIzO0F+pphcahRfi+3AMTnIreqvkqrcX+MyOwHN56lqEs23Vp4Rsq2qDow/LZmn5kpwMNhMY0DBq7jC+lh2Oyly0g=="; String encryptionKey = "foobar"; - Exception exception = assertThrows(DecryptionUtils.DecryptionException.class, () -> { - DecryptionUtils.decrypt(payload, encryptionKey); - }); + Exception exception = assertThrows(DecryptionUtils.DecryptionException.class, () -> DecryptionUtils.decrypt(payload, encryptionKey)); assertTrue(exception.getMessage().contains("Invalid encryption key")); } @@ -100,9 +94,7 @@ void jsonTestCases_decrypt() throws DecryptionUtils.DecryptionException { JsonElement expectedElem = test.get(3); if (expectedElem.isJsonNull()) { // Null means no features can be parsed - Exception exception = assertThrows(DecryptionUtils.DecryptionException.class, () -> { - DecryptionUtils.decrypt(payload, key); - }); + Exception exception = assertThrows(DecryptionUtils.DecryptionException.class, () -> DecryptionUtils.decrypt(payload, key)); // System.out.printf("\n\nException thrown: %s", exception.getMessage()); } else { String expected = test.get(3).getAsString(); diff --git a/lib/src/test/java/growthbook/sdk/java/EvaluateFeatureWithStickyBucketingFeatureTest.java b/lib/src/test/java/growthbook/sdk/java/EvaluateFeatureWithStickyBucketingFeatureTest.java index a2f7d704..3347f8b5 100644 --- a/lib/src/test/java/growthbook/sdk/java/EvaluateFeatureWithStickyBucketingFeatureTest.java +++ b/lib/src/test/java/growthbook/sdk/java/EvaluateFeatureWithStickyBucketingFeatureTest.java @@ -10,7 +10,7 @@ import growthbook.sdk.java.model.FeatureResult; import growthbook.sdk.java.model.GBContext; import growthbook.sdk.java.stickyBucketing.InMemoryStickyBucketServiceImpl; -import growthbook.sdk.java.stickyBucketing.StickyAssignmentsDocument; +import growthbook.sdk.java.model.StickyAssignmentsDocument; import growthbook.sdk.java.stickyBucketing.StickyBucketService; import growthbook.sdk.java.testhelpers.TestCasesJsonHelper; import growthbook.sdk.java.util.GrowthBookJsonUtils; diff --git a/lib/src/test/java/growthbook/sdk/java/ExperimentResultTest.java b/lib/src/test/java/growthbook/sdk/java/ExperimentResultTest.java index a52b91a6..414ab888 100644 --- a/lib/src/test/java/growthbook/sdk/java/ExperimentResultTest.java +++ b/lib/src/test/java/growthbook/sdk/java/ExperimentResultTest.java @@ -54,7 +54,7 @@ void test_builderDefaultValues() { @Test void test_canBeConstructed() { - ExperimentResult subject = new ExperimentResult( + ExperimentResult subject = new ExperimentResult<>( "c", 2, true, diff --git a/lib/src/test/java/growthbook/sdk/java/ExperimentTest.java b/lib/src/test/java/growthbook/sdk/java/ExperimentTest.java index 5a71bd3e..87f46444 100644 --- a/lib/src/test/java/growthbook/sdk/java/ExperimentTest.java +++ b/lib/src/test/java/growthbook/sdk/java/ExperimentTest.java @@ -26,7 +26,7 @@ void canBeConstructed() { Namespace namespace = Namespace.builder().build(); - Experiment experiment = new Experiment( + Experiment experiment = new Experiment<>( "my_experiment", variations, weights, @@ -84,8 +84,8 @@ void canBeBuilt() { assertEquals(0.5f, experiment.getCoverage()); assertEquals(1, experiment.getForce()); assertEquals(1, experiment.getForce()); - assertEquals(0.3f, experiment.getWeights().get(0)); - assertEquals(0.7f, experiment.getWeights().get(1)); + assertEquals(0.3f, experiment.getWeights() != null ? experiment.getWeights().get(0) : null); + assertEquals(0.7f, experiment.getWeights() != null ? experiment.getWeights().get(1) : null); assertEquals("my_experiment", experiment.getKey()); assertEquals("my_experiment", experiment.getKey()); assertEquals("_id", experiment.getHashAttribute()); diff --git a/lib/src/test/java/growthbook/sdk/java/FeatureRuleTest.java b/lib/src/test/java/growthbook/sdk/java/FeatureRuleTest.java index 087c8e2c..725f21db 100644 --- a/lib/src/test/java/growthbook/sdk/java/FeatureRuleTest.java +++ b/lib/src/test/java/growthbook/sdk/java/FeatureRuleTest.java @@ -13,7 +13,7 @@ class FeatureRuleTest { @Test void canBeConstructed() { - ArrayList weights = new ArrayList(); + ArrayList weights = new ArrayList<>(); weights.add(0.3f); weights.add(0.7f); @@ -26,11 +26,11 @@ void canBeConstructed() { .rangeEnd(0.6f) .build(); - FeatureRule subject = new FeatureRule( + FeatureRule subject = new FeatureRule<>( null, "my-key", 0.5f, - new OptionalField<>(true,100), + new OptionalField<>(true, 100), variations, weights, namespace, @@ -54,8 +54,8 @@ void canBeConstructed() { assertEquals(0.5f, subject.getCoverage()); assertEquals(0.5f, subject.getCoverage()); - assertEquals(100, subject.getForce().getValue()); - assertEquals(100, subject.getForce().getValue()); + assertEquals(100, subject.getForce() != null ? subject.getForce().getValue() : null); + assertEquals(100, subject.getForce() != null ? subject.getForce().getValue() : null); assertEquals(namespace, subject.getNamespace()); assertEquals(namespace, subject.getNamespace()); assertEquals("_id", subject.getHashAttribute()); @@ -66,7 +66,7 @@ void canBeConstructed() { @Test void canBeBuilt() { - ArrayList weights = new ArrayList(); + ArrayList weights = new ArrayList<>(); weights.add(0.3f); weights.add(0.7f); @@ -85,13 +85,14 @@ void canBeBuilt() { .force(new OptionalField<>(true, "forced-value")) .namespace(namespace) .weights(weights) + .variations(variations) .hashAttribute("_id") .build(); assertEquals(0.5f, subject.getCoverage()); assertEquals(0.5f, subject.getCoverage()); - assertEquals("forced-value", subject.getForce().getValue()); - assertEquals("forced-value", subject.getForce().getValue()); + assertEquals("forced-value", subject.getForce() != null ? subject.getForce().getValue() : null); + assertEquals("forced-value", subject.getForce() != null ? subject.getForce().getValue() : null); assertEquals(namespace, subject.getNamespace()); assertEquals(namespace, subject.getNamespace()); assertEquals(weights, subject.getWeights()); diff --git a/lib/src/test/java/growthbook/sdk/java/GBContextTest.java b/lib/src/test/java/growthbook/sdk/java/GBContextTest.java index 01f972a1..7694131f 100644 --- a/lib/src/test/java/growthbook/sdk/java/GBContextTest.java +++ b/lib/src/test/java/growthbook/sdk/java/GBContextTest.java @@ -41,7 +41,7 @@ void canBeConstructed() { Boolean isQaMode = false; Boolean allowUrlOverride = false; String url = "http://localhost:3000"; - HashMap forcedVariations = new HashMap(); + HashMap forcedVariations = new HashMap<>(); forcedVariations.put("my-test", 0); forcedVariations.put("other-test", 1); String featuresJson = "{}"; @@ -112,7 +112,9 @@ void canExecuteATrackingCallback() { .builder() .value("Hello, world!") .build(); - subject.getTrackingCallback().onTrack(experiment, result); + if (subject.getTrackingCallback() != null) { + subject.getTrackingCallback().onTrack(experiment, result); + } verify(trackingCallback).onTrack(experiment, result); } @@ -123,7 +125,7 @@ void supportsEncryptedFeaturesUsingConstructor() { Boolean isQaMode = false; Boolean allowUrlOverride = false; String url = "http://localhost:3000"; - HashMap forcedVariations = new HashMap(); + HashMap forcedVariations = new HashMap<>(); forcedVariations.put("my-test", 0); forcedVariations.put("other-test", 1); String encryptedFeaturesJson = "7rvPA94JEsqRo9yPZsdsXg==.bJ8vtYvX+ur3cEUFVkYo1OyWb98oLnMlpeoO0Hs4YPc0EVb7oKX4KNz+Yt6GUMBsieXqtL7oaYzX+kMayZEtV+3bhyDYnS9QBrvalnfxbLExjtnsy8g0pPQHU/P/DPIzO0F+pphcahRfi+3AMTnIreqvkqrcX+MyOwHN56lqEs23Vp4Rsq2qDow/LZmn5kpwMNhMY0DBq7jC+lh2Oyly0g=="; @@ -150,7 +152,7 @@ void supportsEncryptedFeaturesUsingConstructor() { String expectedFeaturesJson = "{\"greeting\":{\"defaultValue\":\"hello\",\"rules\":[{\"condition\":{\"country\":\"france\"},\"force\":\"bonjour\"},{\"condition\":{\"country\":\"mexico\"},\"force\":\"hola\"}]}}"; assertNotNull(subject); - assertEquals(expectedFeaturesJson.trim(), subject.getFeatures().toString().trim()); + assertEquals(expectedFeaturesJson.trim(), subject.getFeatures() != null ? subject.getFeatures().toString().trim() : null); } @Test @@ -159,7 +161,7 @@ void supportsEncryptedFeaturesUsingBuilder() { Boolean isQaMode = false; Boolean allowUrlOverride = false; String url = "http://localhost:3000"; - HashMap forcedVariations = new HashMap(); + HashMap forcedVariations = new HashMap<>(); forcedVariations.put("my-test", 0); forcedVariations.put("other-test", 1); String encryptedFeaturesJson = "7rvPA94JEsqRo9yPZsdsXg==.bJ8vtYvX+ur3cEUFVkYo1OyWb98oLnMlpeoO0Hs4YPc0EVb7oKX4KNz+Yt6GUMBsieXqtL7oaYzX+kMayZEtV+3bhyDYnS9QBrvalnfxbLExjtnsy8g0pPQHU/P/DPIzO0F+pphcahRfi+3AMTnIreqvkqrcX+MyOwHN56lqEs23Vp4Rsq2qDow/LZmn5kpwMNhMY0DBq7jC+lh2Oyly0g=="; @@ -197,7 +199,7 @@ void whenEncryptionKeyInvalid_featuresStayEmpty() { .encryptionKey(encryptionKey) .build(); - assertEquals("{}", subject.getFeatures().toString()); + assertEquals("{}", subject.getFeatures() != null ? subject.getFeatures().toString() : null); } @Test @@ -212,6 +214,6 @@ void whenEncryptedPayloadMalformed_featuresStayEmpty() { .encryptionKey(encryptionKey) .build(); - assertEquals("{}", subject.getFeatures().toString()); + assertEquals("{}", subject.getFeatures() != null ? subject.getFeatures().toString() : null); } } diff --git a/lib/src/test/java/growthbook/sdk/java/GBFeaturesRepositoryRefreshingTest.java b/lib/src/test/java/growthbook/sdk/java/GBFeaturesRepositoryRefreshingTest.java index 41c551dd..36a91d8d 100644 --- a/lib/src/test/java/growthbook/sdk/java/GBFeaturesRepositoryRefreshingTest.java +++ b/lib/src/test/java/growthbook/sdk/java/GBFeaturesRepositoryRefreshingTest.java @@ -54,7 +54,7 @@ void refreshesFeaturesWhenGetFeaturesCalledAfterCacheExpired() throws IOExceptio ); subject.initialize(); - // Advance time 3 seconds. We are still within the cache TTL so it should not trigger a refresh. + // Advance time 3 seconds. We are still within the cache TTL, so it should not trigger a refresh. sleepSeconds(3); subject.getFeaturesJson(); @@ -92,7 +92,7 @@ void doesNotRefreshFeaturesWhenGetFeaturesCalledWithinCacheTime() throws IOExcep ); subject.initialize(); - // Advance time 2 seconds. We are still within the cache TTL so it should not trigger a refresh. + // Advance time 2 seconds. We are still within the cache TTL, so it should not trigger a refresh. sleepSeconds(2); subject.getFeaturesJson(); @@ -128,7 +128,7 @@ void refreshesFeaturesWhenGetFeaturesCalledAfterCacheExpired_multipleTimes() thr ); subject.initialize(); - // Advance time 3 seconds. We are still within the cache TTL so it should not trigger a refresh. + // Advance time 3 seconds. We are still within the cache TTL, so it should not trigger a refresh. sleepSeconds(3); subject.getFeaturesJson(); diff --git a/lib/src/test/java/growthbook/sdk/java/GBFeaturesRepositoryTest.java b/lib/src/test/java/growthbook/sdk/java/GBFeaturesRepositoryTest.java index c3ae59cf..5fa7cb82 100644 --- a/lib/src/test/java/growthbook/sdk/java/GBFeaturesRepositoryTest.java +++ b/lib/src/test/java/growthbook/sdk/java/GBFeaturesRepositoryTest.java @@ -419,7 +419,7 @@ void test_fetchForRemoteEval_requestBody() throws FeatureFetchException, IOExcep } @Test() - void testOnInitializeHttpError() throws FeatureFetchException, IOException { + void testOnInitializeHttpError() throws IOException { OkHttpClient mockOkHttpClient = mock(OkHttpClient.class); String errorResponseJson = "{\"status\": 400, \"error\": \"Invalid API Key\"}"; @@ -450,7 +450,7 @@ void testOnInitializeHttpError() throws FeatureFetchException, IOException { assertThrows( FeatureFetchException.class, - () -> subject.initialize(), + subject::initialize, "HTTP_RESPONSE_ERROR : responded with status 400" ); diff --git a/lib/src/test/java/growthbook/sdk/java/GrowthBookTest.java b/lib/src/test/java/growthbook/sdk/java/GrowthBookTest.java index d53c6936..2031b354 100644 --- a/lib/src/test/java/growthbook/sdk/java/GrowthBookTest.java +++ b/lib/src/test/java/growthbook/sdk/java/GrowthBookTest.java @@ -31,6 +31,7 @@ import growthbook.sdk.java.testhelpers.TestCasesJsonHelper; import growthbook.sdk.java.testhelpers.TestContext; import growthbook.sdk.java.util.GrowthBookJsonUtils; +import lombok.Getter; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; import java.lang.reflect.Type; @@ -93,21 +94,21 @@ void test_evalFeature() { // System.out.printf("\n\n Eval Feature actual: %s - JSON: %s", result, result.toJson()); // System.out.printf("\n\n Eval Feature expected: %s - JSON: %s", expectedResult, expectedResult.toJson()); - boolean valuePasses = Objects.equals(expectedResult.getValue(), result.getValue()); + boolean valuePasses = Objects.equals(expectedResult.getValue(), result != null ? result.getValue() : null); if (!valuePasses) { - System.out.printf("\n\nExpected value: %s, Actual value: %s", expectedResult.getValue(), result.getValue()); + System.out.printf("\n\nExpected value: %s, Actual value: %s", expectedResult.getValue(), result != null ? result.getValue() : null); } - boolean onPasses = Objects.equals(expectedResult.isOn(), result.isOn()); + boolean onPasses = Objects.equals(expectedResult.isOn(), result != null ? result.isOn() : null); if (!onPasses) { - System.out.printf("\n\nExpected isOn: %s, Actual isOn: %s", expectedResult.isOn(), result.isOn()); + System.out.printf("\n\nExpected isOn: %s, Actual isOn: %s", expectedResult.isOn(), result != null ? result.isOn() : null); } - boolean offPasses = Objects.equals(expectedResult.isOff(), result.isOff()); + boolean offPasses = Objects.equals(expectedResult.isOff(), result != null ? result.isOff() : null); if (!offPasses) { - System.out.printf("\n\nExpected isOff: %s, Actual isOff: %s", expectedResult.isOff(), result.isOff()); + System.out.printf("\n\nExpected isOff: %s, Actual isOff: %s", expectedResult.isOff(), result != null ? result.isOff() : null); } - boolean sourcePasses = Objects.equals(expectedResult.getSource(), result.getSource()); + boolean sourcePasses = Objects.equals(expectedResult.getSource(), result != null ? result.getSource() : null); if (!sourcePasses) { - System.out.printf("\n\nExpected getSource: %s, Actual getSource: %s", expectedResult.getSource(), result.getSource()); + System.out.printf("\n\nExpected getSource: %s, Actual getSource: %s", expectedResult.getSource(), result != null ? result.getSource() : null); } // Hash value on experiment @@ -116,7 +117,7 @@ void test_evalFeature() { boolean keyPasses = true; if (expectedResult.getExperimentResult() != null) { System.out.printf("\n\nHas an experiment result: %s (index = %s)", testDescription, i); - ExperimentResult actualResult = result.getExperimentResult(); + ExperimentResult actualResult = result != null ? result.getExperimentResult() : null; String actualHashValue = actualResult != null ? actualResult.getHashValue() : null; hashValuePasses = Objects.equals(expectedResult.getExperimentResult().getHashValue(), actualHashValue); if (!hashValuePasses) { @@ -416,8 +417,10 @@ void test_isOn_returns_true() { FeatureResult feature = subject.evalFeature(featureKey, Object.class); - assertTrue(feature.isOn()); - assertFalse(feature.isOff()); + if (feature != null) { + assertTrue(feature.isOn()); + assertFalse(feature.isOff()); + } } @Test @@ -1004,7 +1007,7 @@ void test_withUrl_getFeatureValue_jsonValueFromString() { .build(); GrowthBook subject = new GrowthBook(context); - String resultAsString = (String) subject.getFeatureValue("meal_overrides_gluten_free", "{\"meal_type\": \"standard\", \"dessert\": \"Donut\"}"); + String resultAsString = subject.getFeatureValue("meal_overrides_gluten_free", "{\"meal_type\": \"standard\", \"dessert\": \"Donut\"}"); // Custom deserialization example MealOrder result = jsonUtils.gson.fromJson(resultAsString, MealOrder.class); @@ -1027,7 +1030,7 @@ void test_withUrl_getFeatureValue_withForcedJsonValue_returnsDefaultValueWhenInv .build(); GrowthBook subject = new GrowthBook(context); - // We try to deserialize an unsupported class from the URL but it cannot deserialize properly, so we get the default value + // We try to deserialize an unsupported class from the URL, but it cannot deserialize properly, so we get the default value GBTestingFoo defaultFoo = new GBTestingFoo(); GBTestingFoo result = (GBTestingFoo) subject.getFeatureValue("meal_overrides_gluten_free", defaultFoo); @@ -1054,21 +1057,14 @@ public String toString() { } } + @Getter static class MealOrder { @SerializedName("meal_type") MealType mealType; - public MealType getMealType() { - return this.mealType; - } - @SerializedName("dessert") String dessert; - public String getDessert() { - return this.dessert; - } - public MealOrder(MealType mealType, String dessert) { this.mealType = mealType; this.dessert = dessert; @@ -1108,8 +1104,10 @@ void test_withUrl_evaluateFeature_forcesBooleanValue() { FeatureResult result = subject.evalFeature("dark_mode", Boolean.class); - assertEquals(true, result.getValue()); - assertEquals(FeatureResultSource.URL_OVERRIDE, result.getSource()); + if (result != null) { + assertEquals(true, result.getValue()); + assertEquals(FeatureResultSource.URL_OVERRIDE, result.getSource()); + } } @Test @@ -1128,8 +1126,8 @@ void test_withUrl_evaluateFeature_forcesStringValue() { FeatureResult result = subject.evalFeature("banner_text", String.class); - assertEquals("Hello, everyone! I hope you are all doing well!", result.getValue()); - assertEquals(FeatureResultSource.URL_OVERRIDE, result.getSource()); + assertEquals("Hello, everyone! I hope you are all doing well!", result != null ? result.getValue() : null); + assertEquals(FeatureResultSource.URL_OVERRIDE, result != null ? result.getSource() : null); } @Test @@ -1148,8 +1146,8 @@ void test_withUrl_evaluateFeature_forcesFloatValue() { FeatureResult result = subject.evalFeature("donut_price", Float.class); - assertEquals(3.33f, result.getValue()); - assertEquals(FeatureResultSource.URL_OVERRIDE, result.getSource()); + assertEquals(3.33f, result != null ? result.getValue() : null); + assertEquals(FeatureResultSource.URL_OVERRIDE, result != null ? result.getSource() : null); } @Test @@ -1168,8 +1166,8 @@ void test_withUrl_evaluateFeature_forcesIntegerValue() { FeatureResult result = subject.evalFeature("donut_price", Integer.class); - assertEquals(4, result.getValue()); - assertEquals(FeatureResultSource.URL_OVERRIDE, result.getSource()); + assertEquals(4, result != null ? result.getValue() : null); + assertEquals(FeatureResultSource.URL_OVERRIDE, result != null ? result.getSource() : null); } // endregion URL -> force features -> evaluateFeature diff --git a/lib/src/test/java/growthbook/sdk/java/NativeJavaGbFeatureRepositoryTest.java b/lib/src/test/java/growthbook/sdk/java/NativeJavaGbFeatureRepositoryTest.java index 4af37612..35669ca1 100644 --- a/lib/src/test/java/growthbook/sdk/java/NativeJavaGbFeatureRepositoryTest.java +++ b/lib/src/test/java/growthbook/sdk/java/NativeJavaGbFeatureRepositoryTest.java @@ -111,17 +111,15 @@ void canBeBuilt_withEncryptionKey() { @Test() void cannotBeBuild_withoutClientKey() { - assertThrows(IllegalArgumentException.class, () -> { - new NativeJavaGbFeatureRepository( - API_HOST, - null, - null, - null, - null, - null, - null - ); - }); + assertThrows(IllegalArgumentException.class, () -> new NativeJavaGbFeatureRepository( + API_HOST, + null, + null, + null, + null, + null, + null + )); } @Test diff --git a/lib/src/test/java/growthbook/sdk/java/multiusermode/GrowthBookClientTest.java b/lib/src/test/java/growthbook/sdk/java/multiusermode/GrowthBookClientTest.java index c82fc41e..1d5b1087 100644 --- a/lib/src/test/java/growthbook/sdk/java/multiusermode/GrowthBookClientTest.java +++ b/lib/src/test/java/growthbook/sdk/java/multiusermode/GrowthBookClientTest.java @@ -41,7 +41,7 @@ void tearDown() throws Exception { @Test void test_initialization_withValidConfiguration() throws FeatureFetchException { - mockRepository = createMockRepository("{}", "{}"); + mockRepository = createMockRepository(); mockBuilder = createMockBuilder(mockRepository); FeatureRefreshCallback mockCallback = mock(FeatureRefreshCallback.class); @@ -112,7 +112,7 @@ void test_initialization_withFailedFeatureFetch() throws FeatureFetchException { void test_evalFeature_withUserContext() { String attributes = "{ \"user_group\": \"subscriber\", \"beta_users\": true }"; - mockRepository = createMockRepository("{}", "{}"); + mockRepository = createMockRepository(); mockBuilder = createMockBuilder(mockRepository); FeatureRefreshCallback mockCallback = mock(FeatureRefreshCallback.class); @@ -134,7 +134,7 @@ void test_evalFeature_withUserContext() { } } - private GBFeaturesRepository createMockRepository(String features, String savedGroups) { + private GBFeaturesRepository createMockRepository() { GBFeaturesRepository repository = mock(GBFeaturesRepository.class); when(repository.getInitialized()).thenReturn(true); when(repository.getFeaturesJson()).thenReturn("{}"); diff --git a/lib/src/test/java/growthbook/sdk/java/testhelpers/TestCasesJsonHelper.java b/lib/src/test/java/growthbook/sdk/java/testhelpers/TestCasesJsonHelper.java index b3950e2c..3dfcc338 100644 --- a/lib/src/test/java/growthbook/sdk/java/testhelpers/TestCasesJsonHelper.java +++ b/lib/src/test/java/growthbook/sdk/java/testhelpers/TestCasesJsonHelper.java @@ -4,6 +4,8 @@ import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import lombok.Getter; + import java.io.FileNotFoundException; import java.io.FileReader; import java.nio.file.Path; @@ -78,12 +80,9 @@ public JsonArray getStickyBucketTestCases() { private final JsonObject testCases; + @Getter private final String demoFeaturesJson; - public String getDemoFeaturesJson() { - return this.demoFeaturesJson; - } - private static TestCasesJsonHelper instance = null; private TestCasesJsonHelper() { From bf2ece1ca4f913183043fb207309e43927c65ac7 Mon Sep 17 00:00:00 2001 From: Volodymyr Nazarkevych Date: Thu, 6 Feb 2025 16:38:42 +0200 Subject: [PATCH 4/4] update javadoc for GrowthBookUtils --- .../sdk/java/util/GrowthBookUtils.java | 82 +++++++++---------- 1 file changed, 40 insertions(+), 42 deletions(-) diff --git a/lib/src/main/java/growthbook/sdk/java/util/GrowthBookUtils.java b/lib/src/main/java/growthbook/sdk/java/util/GrowthBookUtils.java index 972e2ced..95fedb3f 100644 --- a/lib/src/main/java/growthbook/sdk/java/util/GrowthBookUtils.java +++ b/lib/src/main/java/growthbook/sdk/java/util/GrowthBookUtils.java @@ -445,21 +445,21 @@ public static Boolean inRange(Float n, BucketRange range) { } /** - * This is a helper method to evaluate filters for both feature flags and experiments. - * This method: + * Evaluates whether a user should be filtered out based on the given filters. + *

+ * This method processes each filter in the provided list and performs the following steps: *

    - *
  • Loop through filters array - *
  • Get the hashAttribute and hashValue
  • - *
  • If hashValue is empty, return true
  • - *
  • Determine the bucket for the user
  • - *
  • If inRange(n, range) is false for every range in filter.ranges, return true
  • - * - *
  • If you made it through the entire array without returning early, return false now
  • + *
  • Iterates through the list of filters.
  • + *
  • Retrieves the hash attribute and hash value from the user attributes.
  • + *
  • If the hash value is empty, the user is filtered out (returns {@code true}).
  • + *
  • Computes a hash-based bucket value for the user.
  • + *
  • If none of the specified bucket ranges match, the user is filtered out.
  • *
+ * If all filters are processed without an early return, the method returns {@code false}, meaning the user is not filtered out. * - * @param filters List - * @param attributes JsonObject - * @return check if user filtered + * @param filters The list of {@link Filter} objects that define filtering criteria. + * @param attributes A {@link JsonObject} containing user attributes. + * @return {@code true} if the user is filtered out, otherwise {@code false}. */ public static Boolean isFilteredOut(List filters, JsonObject attributes) { if (filters == null) return false; @@ -551,12 +551,11 @@ public static Boolean isIncludedInRollout( } /** - * Method that get cached assignments - * and set it to Context's Sticky Bucket Assignments documents + * Retrieves cached assignments and sets them in the context's Sticky Bucket Assignments documents. * - * @param context GBContext - * @param featuresDataModel String - * @param attributeOverrides JsonObject + * @param context {@link GBContext} that contains sticky bucketing attributes and sticky bucket service + * @param featuresDataModel A string representing the features data model. + * @param attributeOverrides {@link JsonObject} containing attribute overrides. */ public static void refreshStickyBuckets(GBContext context, String featuresDataModel, @@ -580,12 +579,12 @@ public static void refreshStickyBuckets(GBContext context, } /** - * Supportive method for get attribute value from Context + * Supportive method to get attribute values from the context. * - * @param context GBContext - * @param featuresDataModel String - * @param attributeOverrides JsonObject - * @return create a map of sticky bucket attributes + * @param context {@link GBContext} The context containing user attributes. + * @param featuresDataModel A string representing the features data model. + * @param attributeOverrides A {@link JsonObject} containing attribute overrides. + * @return {@code Map} A map of sticky bucket attributes. */ public static Map getStickyBucketAttributes(GBContext context, String featuresDataModel, @@ -610,12 +609,11 @@ public static Map getStickyBucketAttributes(GBContext context, } /** - * Supportive method for get attribute value from Context if identifiers missed + * Supportive method to get attribute values from the context if identifiers are missing. * - * @param context GBContext - * @param featureDataModel String - * @param Feature class - * @return list of sticky bucket identifier + * @param context {@link GBContext} The context containing user attributes. + * @param featureDataModel A string representing the feature data model. + * @return {@code List} A list of sticky bucket identifiers. */ private static List deriveStickyBucketIdentifierAttributes( GBContext context, @@ -660,12 +658,12 @@ private static List deriveStickyBucketIdentifierAttributes( /** * Method to get actual Sticky Bucket assignments. - * Also, this method handle if assignments belong to user + * Also, this method handles if assignments belong to the user. * - * @param context GBContext - * @param expHashAttribute String - * @param expFallbackAttribute String - * @return Map(StickyBucketAssignments) + * @param context {@link EvaluationContext} + * @param expHashAttribute String (nullable) + * @param expFallbackAttribute String (nullable) + * @return {@code Map} containing sticky bucket assignments. */ public static Map getStickyBucketAssignments( EvaluationContext context, @@ -732,15 +730,15 @@ public static Map getStickyBucketAssignments( } /** - * Method to get {@link StickyBucketVariation}: variation and versionIsBlocked + * Method to get {@link StickyBucketVariation}: variation and versionIsBlocked. * - * @param context GBContext + * @param context {@link EvaluationContext} * @param experimentKey String - * @param experimentHashAttribute String - * @param experimentFallbackAttribute String - * @param experimentBucketVersion Integer - * @param minExperimentBucketVersion Integer - * @param meta List + * @param experimentHashAttribute String (nullable) + * @param experimentFallbackAttribute String (nullable) + * @param experimentBucketVersion Integer (nullable) + * @param minExperimentBucketVersion Integer (nullable) + * @param meta {@code List<}{@link VariationMeta}{@code >} (nullable) * @return {@link StickyBucketVariation} */ public static StickyBucketVariation getStickyBucketVariation( @@ -807,12 +805,12 @@ public static String getStickyBucketExperimentKey( } /** - * Method for generate Sticky Bucket Assignment document + * Method for generating a Sticky Bucket Assignment document. * - * @param stickyBucketAssignmentDocs Map + * @param stickyBucketAssignmentDocs {@code Map} * @param attributeName String * @param attributeValue String - * @param assignments Map + * @param assignments {@code Map} * @return {@link GeneratedStickyBucketAssignmentDocModel} */ public static GeneratedStickyBucketAssignmentDocModel generateStickyBucketAssignmentDoc(