Skip to content

feat: long support; safe delegation to int#1985

Merged
toddbaert merged 5 commits into
mainfrom
feat/long
Jul 13, 2026
Merged

feat: long support; safe delegation to int#1985
toddbaert merged 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

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: a2236796-4981-49fc-a04a-7c5608165c99

📥 Commits

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

📒 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 as they are similar to previous changes (14)
  • src/main/java/dev/openfeature/sdk/LongHook.java
  • src/test/java/dev/openfeature/sdk/LongHookTest.java
  • src/test/java/dev/openfeature/sdk/testutils/testProvider/TestProvider.java
  • src/test/java/dev/openfeature/sdk/HookSupportTest.java
  • src/test/java/dev/openfeature/sdk/fixtures/HookFixtures.java
  • src/main/java/dev/openfeature/sdk/Client.java
  • src/main/java/dev/openfeature/sdk/providers/memory/InMemoryProvider.java
  • src/main/java/dev/openfeature/sdk/OpenFeatureClient.java
  • src/main/java/dev/openfeature/sdk/FlagValueType.java
  • src/main/java/dev/openfeature/sdk/Features.java
  • src/test/java/dev/openfeature/sdk/providers/memory/InMemoryProviderTest.java
  • src/main/java/dev/openfeature/sdk/Value.java
  • src/test/java/dev/openfeature/sdk/LongDefaultDelegationTest.java
  • src/main/java/dev/openfeature/sdk/FeatureProvider.java

📝 Walkthrough

Walkthrough

This PR adds LONG support across the SDK through new APIs, value conversion, provider evaluation, client routing, hook support, memory-provider coercion, and comprehensive tests for conversion and type handling.

Changes

Long Flag Value Support

Layer / File(s) Summary
LONG type and public API contracts
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 typing, Long value wrapping, LongHook support, Long accessor declarations, API notes, fixtures, and hook tests.
Default Long provider evaluation
src/main/java/dev/openfeature/sdk/FeatureProvider.java, src/test/java/dev/openfeature/sdk/LongDefaultDelegationTest.java
Adds double-to-long delegation with safe-range and integral checks, mismatch handling, metadata propagation, and conversion tests.
Client LONG routing and accessors
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 evaluations through the provider and adds value/detail overloads with evaluation and hook coverage.
Provider implementations and 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, Integer-to-Long widening, type validation, and provider fallback tests.

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->>FeatureProvider: getLongEvaluation(key, default, ctx)
  FeatureProvider->>DoubleEvaluationSource: getDoubleEvaluation(key, doubleDefault, ctx)
  DoubleEvaluationSource-->>FeatureProvider: ProviderEvaluation<Double>
  FeatureProvider->>FeatureProvider: validate and convert value
  FeatureProvider-->>OpenFeatureClient: ProviderEvaluation<Long>
  OpenFeatureClient-->>Caller: Long value
Loading

Suggested reviewers: beeme1mr, justinabrahms, kinyoklion, nicklasl, aepfli

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 6.94% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the main change: adding long support with safe delegation.
Description check ✅ Passed The description clearly matches the changeset by describing long support and safe delegation behavior.
Linked Issues check ✅ Passed The PR fulfills issue #501 by adding Long retrieval support to the SDK APIs and provider path.
Out of Scope Changes check ✅ Passed The added docs and tests are directly tied to the long-support feature and do not appear out of scope.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

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.

@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 (3ac32f3) to head (d71830d).

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.

@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

@lukas-reining lukas-reining left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM

toddbaert and others added 5 commits July 13, 2026 12:39
* 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>
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>
Signed-off-by: Todd Baert <todd.baert@dynatrace.com>
@sonarqubecloud

Copy link
Copy Markdown

@toddbaert toddbaert merged commit f630089 into main Jul 13, 2026
10 of 11 checks passed
@toddbaert toddbaert deleted the feat/long branch July 13, 2026 16:51
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?

4 participants