Skip to content

Conversation

khvn26
Copy link
Member

@khvn26 khvn26 commented Sep 16, 2025

Contributes to #179.

In this PR, we:

  • Add EvaluationResult getEvaluationResult(EvaluationContext context) and remove all of the old engine APIs.
  • Add support for JSONPath-enabled context values.
  • Add EngineMappers class for engine-API data interop.
  • Breaking change: EnvironmentModel class, used by IOfflineHandler, is no longer part of com.flagsmith.flagengine package. Methods carrying the engine business logic and sub-models/fields not relevant to the SDK are removed.
  • Breaking change: drop Java 8 support.

@khvn26 khvn26 requested a review from Copilot September 16, 2025 20:58
Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR introduces support for context values and adds a new getEvaluationResult API while removing legacy engine APIs. The changes involve a breaking refactor from Java 8 to Java 11 and introduces JSONPath-enabled context value evaluation.

Key changes:

  • Introduces EvaluationResult getEvaluationResult(EvaluationContext context) API replacing old model-based APIs
  • Adds JSONPath support for context value evaluation and removes model-based segment evaluation
  • Drops Java 8 support in favor of Java 11 minimum requirement

Reviewed Changes

Copilot reviewed 58 out of 58 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
pom.xml Updates Java version from 8 to 11, adds JsonPath dependency and code generation plugin
src/main/java/com/flagsmith/flagengine/Engine.java Replaces model-based feature evaluation with context-based evaluation using new API
src/main/java/com/flagsmith/flagengine/segments/SegmentEvaluator.java Refactors from model-based to context-based segment evaluation with JSONPath support
src/main/java/com/flagsmith/mappers/EngineMappers.java New mapper utility for converting JSON documents to engine contexts
src/main/java/com/flagsmith/interfaces/IOfflineHandler.java Breaking change: replaces EnvironmentModel with EvaluationContext
src/test/java/com/flagsmith/flagengine/unit/segments/SegmentModelTest.java Updates test to use new context-based evaluation instead of model-based

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

@khvn26 khvn26 requested a review from a team as a code owner October 10, 2025 10:33
@khvn26 khvn26 requested review from gagantrivedi and removed request for a team October 10, 2025 10:33
@khvn26 khvn26 requested review from Zaimwa9 and emyller October 15, 2025 16:04

@ParameterizedTest
@MethodSource("identitiesInSegmentsPercentageSplit")
public void testIdentityInSegmentPercentageSplitUsesDjangoId(Integer djangoId, String identifier,
Copy link
Member Author

Choose a reason for hiding this comment

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

Copy link

@emyller emyller left a comment

Choose a reason for hiding this comment

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

Non blocking comments, since engine tests pass. These comments may or may not require attention.

P.S. Reviewing this on the iPad was frustratingly difficult, as is reading this Java codebase sometimes. I’m sorry for the somewhat poor review compared to my standards.

Comment on lines +91 to +92
.filter(String.class::isInstance)
.map(Object::toString)
Copy link

Choose a reason for hiding this comment

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

Is .map here for typing? It looks redundant given the .filter above.

Comment on lines +106 to +108
if (!(contextValue instanceof Boolean) && contextValue != null) {
contextValue = String.valueOf(contextValue);
}
Copy link

Choose a reason for hiding this comment

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

I don't understand why booleans are left out of the party here. 😞 Will .contains below compare "true" == true / "false" == false? Sorry I don't follow. Our whole boolean thing is already a bit of a party pooper.

Comment on lines +167 to +168
Double divisor = Double.parseDouble(parts[0]);
Double remainder = Double.parseDouble(parts[1]);
Copy link

Choose a reason for hiding this comment

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

Do we need to worry divisor and remainder could be non-numeric strings?

|| Boolean.FALSE.toString().equalsIgnoreCase(((String) str));
|| Boolean.TRUE.toString().equalsIgnoreCase((String.valueOf(str)))
|| Boolean.FALSE.toString().equalsIgnoreCase((String.valueOf(str)))
|| "1".equals(String.valueOf(str));
Copy link

Choose a reason for hiding this comment

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

This final proposition here looks like cheating some specific test to pass. 😆
I admit I'm even more confused now. Sorry this may be correct as is and I just don't follow the "true" and "false" strings on steroids above.

(I don't mean to insult your code, or the previous author's)

Copy link

Choose a reason for hiding this comment

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

(maybe lowkey I do but I don't mean any disrespect)


return segment;
}).collect(Collectors.toList());
}).filter(Objects::nonNull).collect(Collectors.toList());
Copy link

Choose a reason for hiding this comment

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

Is this to support typing?

}

@Override
public int hashCode() {
Copy link

Choose a reason for hiding this comment

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

}

@Override
public boolean equals(Object other) {
Copy link

Choose a reason for hiding this comment

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

metadata = MapperFactory.getMapper()
.convertValue(flagResult.getMetadata(), FeatureMetadata.class);

if (metadata == null || metadata.getFlagsmithId() == null) {
Copy link

Choose a reason for hiding this comment

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

Do we expect metadata not to exist in a FlagResult?

Copy link

Choose a reason for hiding this comment

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

I second that, as it's used internally and we seem to have an agreement on using them, I could see it required.

if (traits != null && !traits.isEmpty()) {
for (Map.Entry<String, Object> entry : traits.entrySet()) {
Object traitValue = entry.getValue();
// Handle TraitConfig-like objects (maps with "value" key)
Copy link

Choose a reason for hiding this comment

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

Just wondering: do we cover this in engine test data?

* @param environmentModel the environment model
* @return the evaluation context
*/
public static EvaluationContext mapEnvironmentToContext(
Copy link

Choose a reason for hiding this comment

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

Why is this a separate function?

Copy link

@Zaimwa9 Zaimwa9 left a comment

Choose a reason for hiding this comment

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

Looks good to me overall. I share Evandro's confusion surrounding boolean management - some clarification could help, also to have other implementations ISO.
I added a comment on the modulo evaluator

return false;

case MODULO:
if (contextValue instanceof Number && conditionValue instanceof String) {
Copy link

Choose a reason for hiding this comment

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

Don't we want to try parsing context value in case it's a numerical string ?

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.

3 participants