Skip to content

Stop creating NonNullableFieldValidator every for every object or list field #3929

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

bbakerman
Copy link
Member

Today we create a NonNullableFieldValidator for every list item and every object we encounter. We do this because the constructor took a ExecutionStepInfo which IF there was a problem was used say what field was in error

BUT we dont need this. It is passed into the validate method via the ExecutionStrategyParameters anyway

So we can create 1 at execution time and use it through out

This save nemory allocation for cases where you have lots of object fields and / or lost of list fields.

This is NOT a breaking change - NonNullableFieldValidator is a internal class and this only changes the constructor shape

@@ -187,7 +187,7 @@ private CompletableFuture<ExecutionResult> executeOperation(ExecutionContext exe

ResultPath path = ResultPath.rootPath();
ExecutionStepInfo executionStepInfo = newExecutionStepInfo().type(operationRootType).path(path).build();
NonNullableFieldValidator nonNullableFieldValidator = new NonNullableFieldValidator(executionContext, executionStepInfo);
NonNullableFieldValidator nonNullableFieldValidator = new NonNullableFieldValidator(executionContext);
Copy link
Member Author

Choose a reason for hiding this comment

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

No need for the executionStepInfo here. Its passed in during validate

So this instance gets used for the entirety of the operation

@@ -625,13 +625,10 @@ private FieldValueInfo completeField(GraphQLFieldDefinition fieldDef, ExecutionC
instrumentationParams, executionContext.getInstrumentationState()
));

NonNullableFieldValidator nonNullableFieldValidator = new NonNullableFieldValidator(executionContext, executionStepInfo);
Copy link
Member Author

Choose a reason for hiding this comment

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

no need to recreate it

@@ -625,13 +625,10 @@ private FieldValueInfo completeField(GraphQLFieldDefinition fieldDef, ExecutionC
instrumentationParams, executionContext.getInstrumentationState()
));

NonNullableFieldValidator nonNullableFieldValidator = new NonNullableFieldValidator(executionContext, executionStepInfo);

ExecutionStrategyParameters newParameters = parameters.transform(builder ->
builder.executionStepInfo(executionStepInfo)
Copy link
Member Author

Choose a reason for hiding this comment

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

see - executionStepInfo is in the ExecutionStrategyParameters always

@@ -786,13 +783,10 @@ protected FieldValueInfo completeValueForList(ExecutionContext executionContext,

ExecutionStepInfo stepInfoForListElement = executionStepInfoFactory.newExecutionStepInfoForListElement(executionStepInfo, indexedPath);

NonNullableFieldValidator nonNullableFieldValidator = new NonNullableFieldValidator(executionContext, stepInfoForListElement);

Copy link
Member Author

Choose a reason for hiding this comment

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

No need - same reason

@@ -37,7 +37,7 @@ private ExecutionStrategyParameters(ExecutionStepInfo executionStepInfo,
this.localContext = localContext;
this.fields = assertNotNull(fields, () -> "fields is null");
this.source = source;
this.nonNullableFieldValidator = nonNullableFieldValidator;
this.nonNullableFieldValidator = assertNotNull(nonNullableFieldValidator, () -> "requires a NonNullValidator");;
Copy link
Member Author

Choose a reason for hiding this comment

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

Just to be more specific - this helped find tests that "half create" objects for testing reasons

return parameters.transform(builder -> builder.field(firstField).path(fieldPath));
NonNullableFieldValidator nonNullableFieldValidator = new NonNullableFieldValidator(executionContext);
return parameters.transform(builder ->
builder.field(firstField).path(fieldPath).nonNullFieldValidator(nonNullableFieldValidator));
Copy link
Member Author

Choose a reason for hiding this comment

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

Subscriptions is a special case - because it starts a new ExecutionContext instance - So we do re-create it here - but only once - not per published message

@@ -117,6 +117,7 @@ abstract class AsyncExecutionStrategyTest extends Specification {
.newParameters()
.executionStepInfo(typeInfo)
.fields(mergedSelectionSet(['hello': mergedField([Field.newField('hello').build()]), 'hello2': mergedField([Field.newField('hello2').build()])]))
.nonNullFieldValidator(new NonNullableFieldValidator(executionContext))
Copy link
Member Author

Choose a reason for hiding this comment

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

The rest of the changes are test fixups where they half create support objects with just enough brains to work

Copy link
Contributor

Test Results

  312 files    312 suites   54s ⏱️
3 581 tests 3 576 ✅ 5 💤 0 ❌
3 670 runs  3 665 ✅ 5 💤 0 ❌

Results for commit d472058.

@bbakerman bbakerman added the performance work that is primarily targeted as performance improvements label Apr 24, 2025
@bbakerman bbakerman requested review from andimarek and dondonz April 27, 2025 06:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
performance work that is primarily targeted as performance improvements
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant