Migrating the Java SDK for Featurevisor v4
- Minimal migration path
- Breaking changes
- Root condition reasonBreaking
- Datafile update resultBreaking
- Module callbacksBreaking
- Evaluation detailsBreaking
- Removed Java compatibility typesBreaking
- Language differences
- OpenFeature
- Migration checklist
Upgrade Java applications to SDK 5.0.0 for Featurevisor v4 support. This guide also covers Kotlin and Android applications using the Java SDK.
Follow the shared migration order: prepare canonical prerequisite datafiles, upgrade consumers, then upgrade the project CLI. Before publishing new runtime fields, follow Adopt new syntax safely.
Convert Groups before upgrading
This SDK silently ignores legacy feature ranges, with no compatibility handling or warning. Convert Groups to flat list requirements while still on the previous compatible SDK and v3 CLI, then publish all datafiles, caches and bundled copies before upgrading. Unconverted files can change cohorts or enable features without a variation. Old cohorts are not guaranteed. Follow Groups removed.
Minimal migration path#
Most Java application code does not change. These APIs were already available in the previous SDK line and keep the same role:
Featurevisor.createFeaturevisor(...)isEnabled(...),getVariation(...), and feature variable getters- overloaded global variable getters such as
getVariableString(variableKey, context, options) evaluateFlag(...),evaluateVariation(...), andevaluateVariable(...)stickyFeatures,stickyVariables,setStickyFeatures(...), andsetStickyVariables(...)getFeatureEvaluations(...),getVariableEvaluations(...), and child instancesdatafile_set,context_set,sticky_features_set, andsticky_variables_setevents
If an application already uses the canonical module callbacks and does not inspect legacy evaluation fields or import the removed compatibility classes, its source migration can be limited to updating the SDK and testing its datafiles.
See the Java SDK guide for the complete current API.
Breaking changes#
Root condition reason Breaking#
An unmet root gate reports conditions_unmet for feature flags and global variables, replacing the v3 required reason for feature flags and required_features_unmet for global variables. This applies to attribute, segment, feature and variable leaves in root conditions. Update callbacks, analytics and test expectations. Variation and feature variable evaluations retain their disabled reasons. See the shared migration guidance.
boolean unmetRequirement = Evaluation.REASON_REQUIRED.equals(evaluation.getReason());boolean unmetRequirement = Evaluation.REASON_CONDITIONS_UNMET.equals(evaluation.getReason());Datafile update result Breaking#
All setDatafile overloads now return boolean instead of void: true for accepted updates, including unchanged content, and false for rejected updates or closed instances. Calls can ignore it, but recompile consumers and providers against the new SDK. Rejection keeps the previous valid datafile, with details in diagnostics. Merge remains the default.
f.setDatafile(datafile);boolean accepted = f.setDatafile(datafile);if (!accepted) { System.err.println("Datafile rejected. Check diagnostics.");}Module callbacks Breaking#
The deprecated feature only before and after callbacks are removed. beforeEvaluation and afterEvaluation were already available in the previous SDK line, so applications can adopt them before the breaking upgrade.
FeaturevisorModule module = new FeaturevisorModule("context") .before(options -> options.copy().context(addCountry(options.getContext()))) .bucketValue(options -> options.getBucketValue()) .after((evaluation, options) -> evaluation);Featurevisor f = Featurevisor.createFeaturevisor( new Featurevisor.FeaturevisorOptions().datafile(datafile).modules(List.of(module)));FeaturevisorModule module = new FeaturevisorModule("context") .beforeEvaluation(options -> options.copy().context(addCountry(options.getContext()))) .bucketValue(options -> options.getBucketValue()) .afterEvaluation((evaluation, options) -> evaluation);Featurevisor f = Featurevisor.createFeaturevisor( new Featurevisor.FeaturevisorOptions().datafile(datafile).modules(List.of(module)));The canonical callbacks run for feature and global variable evaluations, including prerequisite evaluations. If callback logic is feature specific, check options.getFeatureKey() before applying it. setup, bucketKey, bucketValue, and close are unchanged.
Evaluation details Breaking#
Read failed root gates with getConditions(), replacing the prerequisite specific accessor. getStickyFeature() is the replacement after migration for getSticky():
Evaluation evaluation = f.evaluateVariable("checkout", "colour");var prerequisites = evaluation.getRequired();var sticky = evaluation.getSticky();Evaluation evaluation = f.evaluateVariable("checkout", "colour");var prerequisites = evaluation.getConditions();var sticky = evaluation.getStickyFeature();Use evaluation.getReason().equals(Evaluation.REASON_STICKY) to identify sticky results. getStickyFeature() is optional metadata and is not present for every sticky result.
The deprecated Evaluation.REASON_VARIABLE_OVERRIDE constant is removed. Use REASON_VARIABLE_OVERRIDE_RULE or REASON_VARIABLE_OVERRIDE_VARIATION, matching the detailed result already returned by the runtime.
Accumulating global variable evaluations add getVariableOverridePaths(). It records every matched authored path in execution order. Existing singular override accessors describe the final match.
Removed Java compatibility types Breaking#
| Previous type | After migration |
|---|---|
VariableKey | Pass the variable key as a String |
RequiredWithVariation | Author conditions with { feature, variation }. Java datafile models expose the resulting object form |
There is no new Java requirement key wrapper to instantiate. Most applications load generated datafiles and never reference these model types directly.
Language differences#
Java and Kotlin consumers should update the same model imports and datafile expectations. Android consumers must also check bundled fallbacks before changing SDKs.
Native date inputs#
Date comparisons also accept OffsetDateTime and ZonedDateTime, alongside Instant and java.util.Date. They compare the represented instant at millisecond precision. This is an addition, not a breaking change. LocalDate and LocalDateTime remain rejected because they do not identify an instant. See native date values.
OpenFeature #
com.featurevisor:featurevisor-openfeature remains separate from com.featurevisor:featurevisor-java. The provider depends on the matching core package version and dev.openfeature:sdk version 1.23.0 in the current Maven manifest. Upgrade both Featurevisor artifacts to 5.0.0 together. Check that the application's OpenFeature dependency resolves compatibly. The upstream OpenFeature version is not the Featurevisor release version.
The provider constructor, key mapping, and resolver usage remain unchanged. The updated provider maps conditions_unmet to OpenFeature's disabled reason, so keeping provider and core versions aligned also preserves reason and notification behaviour.
An empty targeting key received by the provider now replaces an existing userId or configured targeting field with "". An omitted key preserves that field. Verify the final context delivered by your OpenFeature client when contexts are merged.
See Java OpenFeature usage and the shared OpenFeature provider guide.
Migration checklist#
Required for the migration#
- Prepare and deploy canonical
conditionsdatafiles before changing the runtime. - Replace module
beforeandaftercallbacks with their canonical evaluation callbacks. - Replace legacy evaluation metadata accessors and remove obsolete model imports.
- Upgrade the core SDK and OpenFeature provider together when used.
- Test feature, variation, feature variable, global variable, sticky, child, and module behaviour.
- Upgrade the project CLI last, review mutation order and date and regex comparisons, and keep a compatible rollback datafile.
Only if adopting optional features#
Follow Adopt new syntax safely before publishing new datafile syntax. Upgrade every CLI runner before adding checks or scenarios.

