Pewarta Proxy

📋 Server Request & Proxy Logs

Loading active proxy settings...
Developed by Khairul Adha (adhexa.id)
Mengambil log server...

⚙️ Pengaturan Proxy Target

Skip to content

Skip OneOf input validation walk when no @oneOf type is reachable - #4516

Draft
joshgord wants to merge 5 commits into
graphql-java:masterfrom
joshgord:oneof-validation-short-circuit
Draft

joshgord wants to merge 5 commits into
graphql-java:masterfrom
joshgord:oneof-validation-short-circuit

Conversation

@joshgord

@joshgord joshgord commented Oct 27, 2026 •

Copy link
Copy Markdown

ValuesResolverOneOfValidation recursively inspects coerced input values even when their types cannot reach an @oneOf input object. Schema-aware argument and variable coercion can skip that dedicated walk for those types.

The schema now owns an immutable reachability map, computed during schema construction. Reverse traversal from OneOf types handles recursive input graphs and unresolved type references. Type-changing builds recompute the map; transformWithoutTypes shares it. Both the standard builder and FastBuilder are covered. There is no JVM-wide cache that retains discarded schema types.

Existing resolver signatures remain available. Schema-less calls and detached input types retain the original validation walk. Code registry field visibility and the existing OneOf error behavior remain unchanged.

The JMH benchmark separates cached-document execution, direct variable coercion, and schema construction. Its parameters select absent, unrelated, or reachable OneOf types and recursive input graphs of depth 1 or 8.

ValuesResolverOneOfValidation walks the full input object tree of every
argument on every argument coercion and every variable coercion, and
allocates a stream pipeline plus a collected list per input object
field, solely to find @OneOf types and enforce their single-key
constraint. On schemas that use no @OneOf types this walk can never do
anything but still runs for every input argument of every field of
every request.

Memoize per GraphQLInputObjectType whether its transitively reachable
input types include a @OneOf type, and skip the walk when none is
reachable. The check is cycle-safe for self-referencing input types.
When a @OneOf type is reachable the existing walk runs unchanged.

Synthetic execution benchmark (5.5k fetched fields/op, 501 fields/op
carrying nested input-object arguments, ThreadMXBean allocated bytes):
-3.6% bytes/op with default instrumentation, -1.6% bytes/op with 8
chained instrumentations.

Generated by Josh-Bot 9000
* Per input object type: true if the type itself or any transitively reachable input object type is a
* @oneOf type. Input types are immutable once built, so this answer is stable for a given type instance.
*/
private static final Map<GraphQLInputObjectType, Boolean> CONTAINS_ONE_OF = new ConcurrentHashMap<>();

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.

While the idea here has merit I think the static is the wrong place to cache the object types.

A graphql server MAY use many different schemas over its life time. However map is cached JVM wide. So its every growing.

I think this question (does an input type have the @OneOf directive would be better cached inside the schema

schema.inputTypeContainsOneOf( inputType)

This could then be computed at schema build time and cached in a map that does not change.

That way if the schema goes away - the knowledge of the types goes with it.

As it stands today if the schema goes away, the static map here conitnues to have a reference to the object type and hence the schema.

So the schema can never be garbage collected and schemas are very large objects

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.

Ahh just saw

If that is a concern I can switch to weak keys or compute the flag at schema build time instead — happy to take guidance on the preferred form.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I understand the concerns @bbakerman, I'm still running through some performance tests on my side before I move this out of draft at which point I'll also address the concerns about a static cache

@bbakerman bbakerman 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.

This needs to cache to be inside the schema object - not in a JVM static

@github-actions

Copy link
Copy Markdown
Contributor

Test Report

Test Results

Java Version Total Passed Failed Errors Skipped
Java 11 6053 (+2 🟢) 5997 (+2 🟢) 0 (±0) 0 (±0) 56 (±0)
Java 17 6053 (+2 🟢) 5996 (+2 🟢) 0 (±0) 0 (±0) 57 (±0)
Java 21 6053 (+2 🟢) 5996 (+2 🟢) 0 (±0) 0 (±0) 57 (±0)
Java 25 6053 (+2 🟢) 5996 (+2 🟢) 0 (±0) 0 (±0) 57 (±0)
jcstress 32 (±0) 32 (±0) 0 (±0) 0 (±0) 0 (±0)
Total 24244 (+8 🟢) 24017 (+8 🟢) 0 (±0) 0 (±0) 227 (±0)

Code Coverage (Java 25)

Metric Covered Missed Coverage vs Master
Lines 30229 3087 90.7% ±0.0%
Branches 8877 1511 85.5% ±0.0%
Methods 8076 1188 87.2% ±0.0%

Changed Class Coverage (1 class)

Class Line Branch Method
g.e.ValuesResolverOneOfValidation +0.4% 🟢 -1.8% 🔴 +8.3% 🟢
ValuesResolverOneOfValidation — method details
Method Line Branch
validateOneOfInputTypes 100.0% (+2.8% 🟢) 100.0% (+7.7% 🟢)
mayContainOneOf new 100.0% 100.0%
computeContainsOneOf new 100.0% —
containsOneOf new 100.0% 100.0%
unwrapToNamed new 100.0% 100.0%
validateOneOfInputTypesImpl new 91.7% 84.6%
lambda$validateOneOfInputTypesImpl$0 new 100.0% —
<clinit> new 100.0% —
lambda$validateOneOfInputTypes$0 removed removed

Full HTML report: build artifact jacoco-html-report

Updated: 2026-10-28 03:37:54 UTC

Josh Gordineer added 4 commits October 31, 2026 02:31
Compute immutable input-type reachability during schema construction and
use it for schema-aware coercion. Remove the JVM-wide cache so discarded
schemas do not leave their input types retained.

Preserve the original validation path for schema-less calls and detached
types. Cover recursive and wrapped inputs, both builders, schema
transforms, and resolver fallbacks.
Mark optional schema metadata explicitly nullable and keep the conversion
overload private to its class. Group argument resolver overloads together
and use the existing test import convention.
Parameterize absent, unrelated, and reachable OneOf types across recursive
input graphs. Separate cached-document execution, variable coercion, and
schema construction, with parsing outside the measured paths.

Use existing execution APIs so the benchmark can run on both sides of the
optimization, and check that the fixtures exercise the intended inputs.

This branch has not been deployed

No deployments
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.

2 participants