Skip to content

feat: long support; safe delegation to int#1985

Open
toddbaert wants to merge 5 commits into
mainfrom
feat/long
Open

feat: long support; safe delegation to int#1985
toddbaert wants to merge 5 commits into
mainfrom
feat/long

Conversation

@toddbaert

Copy link
Copy Markdown
Member
  • adds long support to client/provider
  • delegates to provider int resolver by default
    • widens, rejecting unsafe defaults
    • providers supporting Long should implement manually

Closes: #501

@toddbaert toddbaert requested review from a team as code owners July 3, 2026 17:47
@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@toddbaert, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 43 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 696b7054-c6cb-493c-b963-54af20986ff0

📥 Commits

Reviewing files that changed from the base of the PR and between bdbe524 and c931153.

📒 Files selected for processing (1)
  • src/main/java/dev/openfeature/sdk/FeatureProvider.java
📝 Walkthrough

Walkthrough

This PR adds LONG support across the SDK: public API additions, Value wrapping and conversion, provider delegation from getDoubleEvaluation, client routing, memory-provider coercion, hook support, and test coverage for long-valued flags and safe conversion behavior.

Changes

Long Flag Value Type Support

Layer / File(s) Summary
LONG type, Value wrapping, and public API declarations
src/main/java/dev/openfeature/sdk/FlagValueType.java, src/main/java/dev/openfeature/sdk/Value.java, src/main/java/dev/openfeature/sdk/LongHook.java, src/main/java/dev/openfeature/sdk/Client.java, src/main/java/dev/openfeature/sdk/Features.java, src/test/java/dev/openfeature/sdk/fixtures/HookFixtures.java, src/test/java/dev/openfeature/sdk/LongHookTest.java
Adds LONG, Value(Long)/asLong()/objectToValue support, LongHook, API-note Javadocs, getLongValue/getLongDetails declarations, a mockLongHook() fixture, and hook support tests.
FeatureProvider default getLongEvaluation delegation
src/main/java/dev/openfeature/sdk/FeatureProvider.java, src/test/java/dev/openfeature/sdk/LongDefaultDelegationTest.java
Adds MAX_SAFE_INTEGER, default getLongEvaluation delegation and conversion logic, helper methods for safe-range and mismatch handling, and tests for conversion, delegation, and mismatch cases.
OpenFeatureClient LONG routing and accessor methods
src/main/java/dev/openfeature/sdk/OpenFeatureClient.java, src/test/java/dev/openfeature/sdk/FlagEvaluationSpecTest.java, src/test/java/dev/openfeature/sdk/HookSupportTest.java
Routes LONG through provider evaluation and adds getLongValue/getLongDetails overloads with coverage for long flag evaluation and hook default values.
InMemoryProvider/TestProvider Long support and type coercion
src/main/java/dev/openfeature/sdk/providers/memory/InMemoryProvider.java, src/test/java/dev/openfeature/sdk/testutils/testProvider/TestProvider.java, src/test/java/dev/openfeature/sdk/providers/memory/InMemoryProviderTest.java
Adds long evaluation overrides and type-coercion helpers, plus tests for native Long, widened Integer, rejected incompatible values, and context-evaluator fallback behavior.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant OpenFeatureClient
  participant FeatureProvider
  participant DoubleEvaluationSource
  Caller->>OpenFeatureClient: getLongValue(key, default, ctx, options)
  OpenFeatureClient->>OpenFeatureClient: evaluateFlag(FlagValueType.LONG, ...)
  OpenFeatureClient->>FeatureProvider: getLongEvaluation(key, default, ctx)
  alt provider overrides getLongEvaluation
    FeatureProvider-->>OpenFeatureClient: ProviderEvaluation<Long>
  else default delegation
    FeatureProvider->>DoubleEvaluationSource: getDoubleEvaluation(key, doubleDefault, ctx)
    DoubleEvaluationSource-->>FeatureProvider: ProviderEvaluation<Double>
    FeatureProvider->>FeatureProvider: validate finite/integral/safe-range
    FeatureProvider-->>OpenFeatureClient: ProviderEvaluation<Long>
  end
  OpenFeatureClient-->>Caller: Long value
Loading

Related issues: #501 — requests a way to fetch Long-typed flag values, addressed by the new getLongValue and getLongDetails APIs.

Suggested labels: enhancement, api

Suggested reviewers: none identified from provided context

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and clearly reflects the main change: adding Long support with safe delegation behavior.
Description check ✅ Passed The description is directly related to the PR and accurately summarizes the Long support changes.
Linked Issues check ✅ Passed The PR fulfills issue #501 by adding Long retrieval support to the SDK APIs and provider flow.
Out of Scope Changes check ✅ Passed The changes shown are all aligned with Long support, delegation, and related test/documentation updates.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/main/java/dev/openfeature/sdk/providers/memory/InMemoryProvider.java (1)

159-176: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Validate the context-evaluator result before returning it. The targeting path still returns flag.getContextEvaluator().evaluate(...) directly, so an Integer can escape as the value of a ProviderEvaluation<Long> without the isAssignableTo/coerceVariant widening used on the default-variant path. Apply the same check/coercion here or fail with TypeMismatchError.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/dev/openfeature/sdk/providers/memory/InMemoryProvider.java`
around lines 159 - 176, The targeting branch in InMemoryProvider’s evaluation
logic returns the raw result from flag.getContextEvaluator().evaluate(...)
without validating or widening it like the default-variant path. Update the
context-evaluator flow to run the same isAssignableTo check and coerceVariant
conversion before assigning value, or throw TypeMismatchError when the evaluated
variant cannot satisfy the expected type. Use the evaluate helper path and the
existing type-handling logic in InMemoryProvider to keep behavior consistent
across targeting and default resolution.
🧹 Nitpick comments (1)
src/main/java/dev/openfeature/sdk/FeatureProvider.java (1)

130-155: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Minor duplication: reuse isWithinSafeRange and consolidate longError overloads.

Math.abs(value) > MAX_SAFE_INTEGER re-implements the same range check as isWithinSafeRange(long) (once value is confirmed integral, (long) value is safe to pass). Also, the two longError overloads duplicate most builder fields, differing only in variant/flagMetadata.

♻️ Optional consolidation
-            if (Math.abs(value) > MAX_SAFE_INTEGER) {
+            if (!isWithinSafeRange((long) value)) {
                 return longError(
                         defaultValue,
                         "Value " + value + " exceeds safe integer range [-(2^53 - 1), 2^53 - 1] for long",
                         result);
             }
...
-    private static ProviderEvaluation<Long> longError(Long defaultValue, String message) {
-        return ProviderEvaluation.<Long>builder()
-                .value(defaultValue)
-                .reason(Reason.ERROR.toString())
-                .errorCode(ErrorCode.TYPE_MISMATCH)
-                .errorMessage(message)
-                .build();
-    }
-
-    // preserve upstream metadata/variant; override with type error
-    private static ProviderEvaluation<Long> longError(
-            Long defaultValue, String message, ProviderEvaluation<Double> upstream) {
-        return ProviderEvaluation.<Long>builder()
-                .value(defaultValue)
-                .reason(Reason.ERROR.toString())
-                .errorCode(ErrorCode.TYPE_MISMATCH)
-                .errorMessage(message)
-                .variant(upstream.getVariant())
-                .flagMetadata(upstream.getFlagMetadata())
-                .build();
-    }
+    private static ProviderEvaluation<Long> longError(Long defaultValue, String message) {
+        return longError(defaultValue, message, null);
+    }
+
+    // preserve upstream metadata/variant when available; override with type error
+    private static ProviderEvaluation<Long> longError(
+            Long defaultValue, String message, ProviderEvaluation<Double> upstream) {
+        var builder = ProviderEvaluation.<Long>builder()
+                .value(defaultValue)
+                .reason(Reason.ERROR.toString())
+                .errorCode(ErrorCode.TYPE_MISMATCH)
+                .errorMessage(message);
+        if (upstream != null) {
+            builder.variant(upstream.getVariant()).flagMetadata(upstream.getFlagMetadata());
+        }
+        return builder.build();
+    }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/dev/openfeature/sdk/FeatureProvider.java` around lines 130 -
155, The `FeatureProvider` helpers duplicate range and error-building logic.
Update the integral conversion path to call `isWithinSafeRange(long)` instead of
rechecking with `Math.abs`, and consolidate the two `longError` overloads by
sharing the common `ProviderEvaluation` builder setup in one helper while
preserving the optional `variant` and `flagMetadata` from the upstream value.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/main/java/dev/openfeature/sdk/providers/memory/InMemoryProvider.java`:
- Line 173: The error message in InMemoryProvider’s type mismatch path is
missing a space before “is”, causing malformed output. Update the
TypeMismatchError message in the relevant flag-checking logic so the
concatenated text reads naturally, using the same key variable and error
construction in InMemoryProvider.

---

Outside diff comments:
In `@src/main/java/dev/openfeature/sdk/providers/memory/InMemoryProvider.java`:
- Around line 159-176: The targeting branch in InMemoryProvider’s evaluation
logic returns the raw result from flag.getContextEvaluator().evaluate(...)
without validating or widening it like the default-variant path. Update the
context-evaluator flow to run the same isAssignableTo check and coerceVariant
conversion before assigning value, or throw TypeMismatchError when the evaluated
variant cannot satisfy the expected type. Use the evaluate helper path and the
existing type-handling logic in InMemoryProvider to keep behavior consistent
across targeting and default resolution.

---

Nitpick comments:
In `@src/main/java/dev/openfeature/sdk/FeatureProvider.java`:
- Around line 130-155: The `FeatureProvider` helpers duplicate range and
error-building logic. Update the integral conversion path to call
`isWithinSafeRange(long)` instead of rechecking with `Math.abs`, and consolidate
the two `longError` overloads by sharing the common `ProviderEvaluation` builder
setup in one helper while preserving the optional `variant` and `flagMetadata`
from the upstream value.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 56880d00-46b7-4979-b108-be72f986954a

📥 Commits

Reviewing files that changed from the base of the PR and between a7d4e8a and 835784e.

📒 Files selected for processing (15)
  • src/main/java/dev/openfeature/sdk/Client.java
  • src/main/java/dev/openfeature/sdk/FeatureProvider.java
  • src/main/java/dev/openfeature/sdk/Features.java
  • src/main/java/dev/openfeature/sdk/FlagValueType.java
  • src/main/java/dev/openfeature/sdk/LongHook.java
  • src/main/java/dev/openfeature/sdk/OpenFeatureClient.java
  • src/main/java/dev/openfeature/sdk/Value.java
  • src/main/java/dev/openfeature/sdk/providers/memory/InMemoryProvider.java
  • src/test/java/dev/openfeature/sdk/FlagEvaluationSpecTest.java
  • src/test/java/dev/openfeature/sdk/HookSupportTest.java
  • src/test/java/dev/openfeature/sdk/LongDefaultDelegationTest.java
  • src/test/java/dev/openfeature/sdk/LongHookTest.java
  • src/test/java/dev/openfeature/sdk/fixtures/HookFixtures.java
  • src/test/java/dev/openfeature/sdk/providers/memory/InMemoryProviderTest.java
  • src/test/java/dev/openfeature/sdk/testutils/testProvider/TestProvider.java

Comment thread src/main/java/dev/openfeature/sdk/providers/memory/InMemoryProvider.java Outdated
Comment thread src/main/java/dev/openfeature/sdk/providers/memory/InMemoryProvider.java Outdated
@toddbaert

Copy link
Copy Markdown
Member Author

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)

src/main/java/dev/openfeature/sdk/providers/memory/InMemoryProvider.java (1)> 159-176: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Validate the context-evaluator result before returning it. The targeting path still returns flag.getContextEvaluator().evaluate(...) directly, so an Integer can escape as the value of a ProviderEvaluation<Long> without the isAssignableTo/coerceVariant widening used on the default-variant path. Apply the same check/coercion here or fail with TypeMismatchError.

🤖 Prompt for AI Agents

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/dev/openfeature/sdk/providers/memory/InMemoryProvider.java`
around lines 159 - 176, The targeting branch in InMemoryProvider’s evaluation
logic returns the raw result from flag.getContextEvaluator().evaluate(...)
without validating or widening it like the default-variant path. Update the
context-evaluator flow to run the same isAssignableTo check and coerceVariant
conversion before assigning value, or throw TypeMismatchError when the evaluated
variant cannot satisfy the expected type. Use the evaluate helper path and the
existing type-handling logic in InMemoryProvider to keep behavior consistent
across targeting and default resolution.

🧹 Nitpick comments (1)

src/main/java/dev/openfeature/sdk/FeatureProvider.java (1)> 130-155: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Minor duplication: reuse isWithinSafeRange and consolidate longError overloads.
Math.abs(value) > MAX_SAFE_INTEGER re-implements the same range check as isWithinSafeRange(long) (once value is confirmed integral, (long) value is safe to pass). Also, the two longError overloads duplicate most builder fields, differing only in variant/flagMetadata.

♻️ Optional consolidation

-            if (Math.abs(value) > MAX_SAFE_INTEGER) {
+            if (!isWithinSafeRange((long) value)) {
                 return longError(
                         defaultValue,
                         "Value " + value + " exceeds safe integer range [-(2^53 - 1), 2^53 - 1] for long",
                         result);
             }
...
-    private static ProviderEvaluation<Long> longError(Long defaultValue, String message) {
-        return ProviderEvaluation.<Long>builder()
-                .value(defaultValue)
-                .reason(Reason.ERROR.toString())
-                .errorCode(ErrorCode.TYPE_MISMATCH)
-                .errorMessage(message)
-                .build();
-    }
-
-    // preserve upstream metadata/variant; override with type error
-    private static ProviderEvaluation<Long> longError(
-            Long defaultValue, String message, ProviderEvaluation<Double> upstream) {
-        return ProviderEvaluation.<Long>builder()
-                .value(defaultValue)
-                .reason(Reason.ERROR.toString())
-                .errorCode(ErrorCode.TYPE_MISMATCH)
-                .errorMessage(message)
-                .variant(upstream.getVariant())
-                .flagMetadata(upstream.getFlagMetadata())
-                .build();
-    }
+    private static ProviderEvaluation<Long> longError(Long defaultValue, String message) {
+        return longError(defaultValue, message, null);
+    }
+
+    // preserve upstream metadata/variant when available; override with type error
+    private static ProviderEvaluation<Long> longError(
+            Long defaultValue, String message, ProviderEvaluation<Double> upstream) {
+        var builder = ProviderEvaluation.<Long>builder()
+                .value(defaultValue)
+                .reason(Reason.ERROR.toString())
+                .errorCode(ErrorCode.TYPE_MISMATCH)
+                .errorMessage(message);
+        if (upstream != null) {
+            builder.variant(upstream.getVariant()).flagMetadata(upstream.getFlagMetadata());
+        }
+        return builder.build();
+    }

🤖 Prompt for AI Agents

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/dev/openfeature/sdk/FeatureProvider.java` around lines 130 -
155, The `FeatureProvider` helpers duplicate range and error-building logic.
Update the integral conversion path to call `isWithinSafeRange(long)` instead of
rechecking with `Math.abs`, and consolidate the two `longError` overloads by
sharing the common `ProviderEvaluation` builder setup in one helper while
preserving the optional `variant` and `flagMetadata` from the upstream value.

🤖 Prompt for all review comments with AI agents

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/main/java/dev/openfeature/sdk/providers/memory/InMemoryProvider.java`:
- Line 173: The error message in InMemoryProvider’s type mismatch path is
missing a space before “is”, causing malformed output. Update the
TypeMismatchError message in the relevant flag-checking logic so the
concatenated text reads naturally, using the same key variable and error
construction in InMemoryProvider.

---

Outside diff comments:
In `@src/main/java/dev/openfeature/sdk/providers/memory/InMemoryProvider.java`:
- Around line 159-176: The targeting branch in InMemoryProvider’s evaluation
logic returns the raw result from flag.getContextEvaluator().evaluate(...)
without validating or widening it like the default-variant path. Update the
context-evaluator flow to run the same isAssignableTo check and coerceVariant
conversion before assigning value, or throw TypeMismatchError when the evaluated
variant cannot satisfy the expected type. Use the evaluate helper path and the
existing type-handling logic in InMemoryProvider to keep behavior consistent
across targeting and default resolution.

---

Nitpick comments:
In `@src/main/java/dev/openfeature/sdk/FeatureProvider.java`:
- Around line 130-155: The `FeatureProvider` helpers duplicate range and
error-building logic. Update the integral conversion path to call
`isWithinSafeRange(long)` instead of rechecking with `Math.abs`, and consolidate
the two `longError` overloads by sharing the common `ProviderEvaluation` builder
setup in one helper while preserving the optional `variant` and `flagMetadata`
from the upstream value.

🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info

Added fix and related test.

toddbaert added 2 commits July 3, 2026 14:21
* adds long support to client/provider
* delegates to provider int resolver by default
  * widens, rejecting unsafe defaults
  * providers supporting Long should implement manually

Signed-off-by: Todd Baert <todd.baert@dynatrace.com>
Signed-off-by: Todd Baert <todd.baert@dynatrace.com>
@codecov

codecov Bot commented Jul 3, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 85.52632% with 11 lines in your changes missing coverage. Please review.
✅ Project coverage is 92.84%. Comparing base (a7d4e8a) to head (c931153).

Files with missing lines Patch % Lines
src/main/java/dev/openfeature/sdk/Value.java 0.00% 7 Missing and 1 partial ⚠️
...feature/sdk/providers/memory/InMemoryProvider.java 85.00% 1 Missing and 2 partials ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##               main    #1985      +/-   ##
============================================
+ Coverage     92.23%   92.84%   +0.61%     
- Complexity      669      707      +38     
============================================
  Files            59       60       +1     
  Lines          1635     1705      +70     
  Branches        186      195       +9     
============================================
+ Hits           1508     1583      +75     
+ Misses           80       74       -6     
- Partials         47       48       +1     
Flag Coverage Δ
unittests 92.84% <85.52%> (+0.61%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Comment thread src/main/java/dev/openfeature/sdk/FeatureProvider.java Outdated
justinabrahms added a commit to justinabrahms/ncr that referenced this pull request Jul 4, 2026
Makes `ncr serve` an actual review tool (docs/design-review-comments.md).

Phase 2 — anchors: the indexer records both old/new line numbers per line
(Block.Lines / DiffLine); the renderer emits data-path/side/line/text on every
diff line so a click maps to a GitHub review position. buildAnchorSet validates
that a comment lands on a real diff line.

Phase 3 — commenting UI + queue: web/review.js (+ .css) adds line/range selection
(shift-click), an inline composer, editable/deletable comment threads, and a
bottom-right tray. Backed by /api/comments CRUD in reviewserver.go, persisted to
~/.ncr/reviews/<owner>__<repo>__<pr>.json (state.go).

Phase 4 — submit: the "Review done" modal is the composer — summary + verdict
(Comment/Approve/Request-changes) — with an up-front dry-run that blocks on any
unanchorable comment. Confirm posts ONE review via `gh api`, then archives the
round and clears the queue. gh call is injectable (submitFn) for testing.

Serve is now the default; --static writes the file. Data attributes are emitted in
both, but the review JS/CSS only load when serving.

Tests: renderer anchors + anchor-set (anchors_test.go); comment CRUD + persistence,
dry-run flagging, submit/archive, and empty-review rules (reviewserver_test.go).
All green; verified live against open-feature/java-sdk#1985 with a cached plan
(post comment → persist → dry-run ok).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
long MAX_SAFE_INTEGER = 9_007_199_254_740_991L;

/**
* Returns provider-identifying metadata (typically the provider name).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we add all that Java Doc?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as #1985 (comment)

Comment thread src/main/java/dev/openfeature/sdk/FeatureProvider.java Outdated
* flags, or the SDK is shut down.
* Providers can overwrite this method, if they have special shutdown actions
* needed.
* Called when a provider is about to be replaced or the SDK is shutting down. Providers can

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we rewrite all the docs?

@toddbaert toddbaert Jul 6, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed a lot of the Java-docs were missing, even for public APIs (for example here) so I took this chance to update them. I can revert it if you want, or do it in a separate PR.

toddbaert and others added 2 commits July 6, 2026 12:10
Co-authored-by: chrfwow <christian.lutnik@dynatrace.com>
Signed-off-by: Todd Baert <todd.baert@dynatrace.com>
Co-authored-by: Justin Abrahms <justin@abrah.ms>
Signed-off-by: Todd Baert <todd.baert@dynatrace.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/test/java/dev/openfeature/sdk/providers/memory/InMemoryProviderTest.java (1)

134-219: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Solid coverage for widening/rejection behavior; one gap remains.

The new tests correctly validate Long/Integer widening and rejection (native long, int→long widening, double/long rejection) and the contextEvaluator direct-result paths. However, contextEvaluator_nullResultFallsBackToDefaultVariantWithTypeCheck (lines 205-218) only exercises the fallback path where the default variant's type already matches the expected type (7L expected as Long). It doesn't cover the scenario that motivated the original review comment — a contextEvaluator returning null while the fallback default variant is of a mismatched type (e.g., a Double default variant requested as Long) — which is the exact case the fix (shared isAssignableTo/coerceVariant check on the reassigned raw) was meant to address.

Consider adding a test asserting TypeMismatchError for that combination to fully close the loop on the fixed defect.

`@SneakyThrows`
`@Test`
void contextEvaluator_nullResultWithMismatchedDefaultVariantThrows() {
    Flag<Object> flag = Flag.<Object>builder()
            .variant("v", 3.14)
            .defaultVariant("v")
            .contextEvaluator((f, ctx) -> null)
            .build();
    InMemoryProvider local = new InMemoryProvider(Map.of("targeted", flag));
    local.initialize(new ImmutableContext());
    assertThrows(TypeMismatchError.class, () -> local.getLongEvaluation("targeted", 0L, new ImmutableContext()));
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/test/java/dev/openfeature/sdk/providers/memory/InMemoryProviderTest.java`
around lines 134 - 219, Add a test in InMemoryProviderTest that covers the null
contextEvaluator fallback when the default variant type does not match the
requested type: create a Flag with contextEvaluator returning null, a Double
default variant, and assert getLongEvaluation on InMemoryProvider throws
TypeMismatchError. This should exercise the same fallback/type-check path as
contextEvaluator_nullResultFallsBackToDefaultVariantWithTypeCheck and confirm
the reassigned raw value is still validated by the shared
isAssignableTo/coerceVariant logic.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In
`@src/test/java/dev/openfeature/sdk/providers/memory/InMemoryProviderTest.java`:
- Around line 134-219: Add a test in InMemoryProviderTest that covers the null
contextEvaluator fallback when the default variant type does not match the
requested type: create a Flag with contextEvaluator returning null, a Double
default variant, and assert getLongEvaluation on InMemoryProvider throws
TypeMismatchError. This should exercise the same fallback/type-check path as
contextEvaluator_nullResultFallsBackToDefaultVariantWithTypeCheck and confirm
the reassigned raw value is still validated by the shared
isAssignableTo/coerceVariant logic.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: a57356b1-a859-413a-86af-19814f56ae4e

📥 Commits

Reviewing files that changed from the base of the PR and between 835784e and 20653c2.

📒 Files selected for processing (15)
  • src/main/java/dev/openfeature/sdk/Client.java
  • src/main/java/dev/openfeature/sdk/FeatureProvider.java
  • src/main/java/dev/openfeature/sdk/Features.java
  • src/main/java/dev/openfeature/sdk/FlagValueType.java
  • src/main/java/dev/openfeature/sdk/LongHook.java
  • src/main/java/dev/openfeature/sdk/OpenFeatureClient.java
  • src/main/java/dev/openfeature/sdk/Value.java
  • src/main/java/dev/openfeature/sdk/providers/memory/InMemoryProvider.java
  • src/test/java/dev/openfeature/sdk/FlagEvaluationSpecTest.java
  • src/test/java/dev/openfeature/sdk/HookSupportTest.java
  • src/test/java/dev/openfeature/sdk/LongDefaultDelegationTest.java
  • src/test/java/dev/openfeature/sdk/LongHookTest.java
  • src/test/java/dev/openfeature/sdk/fixtures/HookFixtures.java
  • src/test/java/dev/openfeature/sdk/providers/memory/InMemoryProviderTest.java
  • src/test/java/dev/openfeature/sdk/testutils/testProvider/TestProvider.java
✅ Files skipped from review due to trivial changes (1)
  • src/main/java/dev/openfeature/sdk/Client.java
🚧 Files skipped from review as they are similar to previous changes (12)
  • src/main/java/dev/openfeature/sdk/FlagValueType.java
  • src/test/java/dev/openfeature/sdk/testutils/testProvider/TestProvider.java
  • src/main/java/dev/openfeature/sdk/LongHook.java
  • src/test/java/dev/openfeature/sdk/HookSupportTest.java
  • src/test/java/dev/openfeature/sdk/FlagEvaluationSpecTest.java
  • src/test/java/dev/openfeature/sdk/LongHookTest.java
  • src/main/java/dev/openfeature/sdk/providers/memory/InMemoryProvider.java
  • src/main/java/dev/openfeature/sdk/Features.java
  • src/main/java/dev/openfeature/sdk/Value.java
  • src/test/java/dev/openfeature/sdk/fixtures/HookFixtures.java
  • src/main/java/dev/openfeature/sdk/OpenFeatureClient.java
  • src/main/java/dev/openfeature/sdk/FeatureProvider.java

Signed-off-by: Todd Baert <todd.baert@dynatrace.com>
@sonarqubecloud

sonarqubecloud Bot commented Jul 6, 2026

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Why the SDK does not provide a way to fetch Long value?

3 participants