Skip to content

feat(10.x.x): @oneOf input directive support - #2193

Merged
samuelAndalon merged 1 commit into
10.x.xfrom
feat/10.x.x/one-of
Jun 26, 2026
Merged

feat(10.x.x): @oneOf input directive support #2193
samuelAndalon merged 1 commit into
10.x.xfrom
feat/10.x.x/one-of

Conversation

@samuelAndalon

Copy link
Copy Markdown
Contributor

📝 Description

cherry pick #2183

### 📝 Description
Add support for GraphQL `@oneOf` directive for input objects .

See: 
https://graphql.org/blog/2025-09-04-multioption-inputs-with-oneof/
https://spec.graphql.org/September2025/#sec-OneOf-Input-Objects


#### What graphql-java provides
graphql-java owns the directive definition and all input validation—
runs before our convertArgumentValue:

- Directive def — @OneOf SDL definition baked into
[graphql-java](https://github.com/graphql-java/graphql-java/blob/master/src/main/java/graphql/Directives.java#L244).
- Input validation/coercion — ValuesResolverOneOfValidation (source)
enforces oneOf rules at execution time, per spec:
- exactly one field supplied,
- [that field's value
non-null](https://github.com/graphql-java/graphql-java/blob/master/src/main/java/graphql/execution/OneOfNullValueException.java),
- [rejects map with 0 or 2+ keys -> error before resolver
runs](https://github.com/graphql-java/graphql-java/blob/master/src/main/java/graphql/execution/OneOfTooManyKeysException.java).

So by the time graphql-kotlin runtime code sees the argument map, it is
already validated: guaranteed single non-null entry. That's why
mapToOneOfKotlinObject can safely
  do input.entries.single() — no defensive count check needed.

#### What graphql-java does NOT cover

graphql-java works in graphql land. It knows nothing about Kotlin sealed
types. It does not:

- generate the @OneOf input object from Kotlin types
- know which sealed subtype a given field maps to
- construct the Kotlin instance at runtime during operation execution

#### What graphql-kotlin adds
1. Schema generation (generateOneOfInputObject /
generateOneOfInputProperty)
    - Kotlin sealed interface -> @OneOf input object.
    - Each subtype (@GraphQLOneOfField) -> one input field
2. Argument mapping (mapToOneOfKotlinObject in convertArgumentValue)
    - Takes the already-validated single-entry map from graphql-java.
    - Matches fieldName -> sealed subtype via @GraphQLOneOfField.

### 🔗 Related Issues
#1891


### Examples
<img width="929" height="613" alt="image"
src="https://github.com/user-attachments/assets/9517a631-cad5-4cbe-9ef6-e25daee7965e"
/>
<img width="937" height="569" alt="image"
src="https://github.com/user-attachments/assets/3e7feb91-1409-441d-88f2-fb8fef8cdae2"
/>

---------

Co-authored-by: Samuel Vazquez <samvazquez@expediagroup.com>
@samuelAndalon
samuelAndalon merged commit 681dca9 into 10.x.x Jun 26, 2026
17 checks passed
@samuelAndalon
samuelAndalon deleted the feat/10.x.x/one-of branch June 26, 2026 16:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants