Releases · graphql-java/graphql-java · GitHub
Skip to content

Releases: graphql-java/graphql-java

26.0

23 Apr 01:20

Choose a tag to compare

This is the 26.0 release of graphql-java. Highlights are summarized below; the full list of merged PRs is at the end.

⚠️ Breaking Changes

Query complexity limits are now enforced by default

New QueryComplexityLimits validation checks maxDepth (default 100) and maxFieldsCount (default 100,000) as part of standard validation. Queries exceeding these limits will now fail with new MaxQueryDepthExceeded / MaxQueryFieldsExceeded validation errors.

  • Set custom limits via GraphQLContext using QueryComplexityLimits.KEY.
  • Disable entirely with QueryComplexityLimits.NONE.

Introduced in #4256.

Validation rule filtering API changed

In #4228 the rule-filter predicate changed from Predicate<Class<?>> to Predicate<OperationValidationRule> in Validator.validateDocument(...) and ParseAndValidate.parseAndValidate(...). Callers that filtered by class (e.g. rule -> rule != NoUnusedFragments.class) must migrate to the enum (rule -> rule != OperationValidationRule.NO_UNUSED_FRAGMENTS). The @Internal classes AbstractRule and RulesVisitor were removed.

Built-in directive handling consolidated (#4229)

  • DirectiveInfo was removed. Replace usages:
    • DirectiveInfo.isGraphqlSpecifiedDirective(...)Directives.isBuiltInDirective(...)
    • DirectiveInfo.GRAPHQL_SPECIFICATION_DIRECTIVESDirectives.BUILT_IN_DIRECTIVES
    • DirectiveInfo.GRAPHQL_SPECIFICATION_DIRECTIVE_MAPDirectives.BUILT_IN_DIRECTIVES_MAP
  • Directive ordering is now consistent: all 7 built-in directives appear first, followed by user-defined directives.
  • GraphQLSchema.Builder.clearDirectives() was initially removed then re-added in #4276 with new semantics — it clears all additionalDirectives, but built-in directives are always re-added automatically at build time.

OneOf inhabitability validation (#4248)

New validator rejects OneOf input types that cannot be populated with a finite value (e.g. input A @oneOf { a: A }). Schemas that previously validated may now be rejected.

Non-null field validation for code-built schemas (#4194)

Code-built schemas now perform the same deprecated-on-non-null field validation as SDL-built ones. Schemas relying on the gap may now fail validation.

GraphQLSchema.getCodeRegistry() is no longer @Nullable (#4247)

The return type was incorrectly annotated nullable. Callers may now drop redundant null checks; downstream nullness tooling will reflect the change.

JSpecify nullability annotations rolled out broadly

Waves 2 and 3 (#4184, #4274) plus many individual PRs annotated hundreds of classes across graphql.analysis, graphql.execution, graphql.language, graphql.schema and others with @NullMarked/@NullUnmarked/@Nullable. Kotlin and other null-aware callers will now see stricter nullability contracts; code that relied on previously-permissive signatures may need adjustment.

✨ New Features

  • GraphQLSchema.FastBuilder (#4197) — a more restrictive but ~5× faster schema builder that reduces both time and memory for large schemas.
  • Query complexity limits (#4256) — depth/field-count guardrails baked into validation (see breaking changes above for the enforcement side).
  • QueryAppliedDirective on operations and documents (#4297) — directives applied at the operation/document level are now exposed as QueryAppliedDirectives.
  • New instrumentation hook for post-exception-handling results (#4206, #4207) — observe the DataFetcherResult after DataFetcherExceptionHandler has mapped exceptions to errors. ChainedInstrumentation delegates the new hook correctly.
  • Generic DataFetcherResult.newBuilder(T data) (#4254) — removes the need for explicit type witnesses on the common DataFetcherResult.<T>newResult().data(x)... pattern.
  • Re-added GraphQLSchema.Builder.clearDirectives() (#4276) — useful with GraphQLSchema.transform to rewrite non-built-in directives; built-ins are always re-added.
  • toString() on AST directives holders (#4195).

⚡ Performance

  • Incremental @defer execution starts earlier (#4174) — begins processing deferred payloads as soon as the first incremental call is detected instead of waiting for the initial result to complete.
  • Validation consolidation (#4228) — all operation validation rules run in a single OperationValidator pass, significantly cutting validation overhead.
  • Reduced allocations on the execution hot path (#4252):
    • Async$Many.materialisedList() — replaced ArrayList copy with a zero-copy Arrays.asList() wrapper.
    • ResultPath.toStringValue — lazy computation; the string form is only built on first toString() (typically only during error reporting).
    • New GraphQLCodeRegistry.getDataFetcher(String, String, GraphQLFieldDefinition) overload avoiding per-fetch FieldCoordinates allocations (~54 KB/op reduction).
  • FastBuilder for schema construction (#4197) — see New Features.
  • Fixed ShallowTypeRefCollector to also resolve type refs inside applied directive arguments and enum value definitions (#4288) — correctness fix enabling FastBuilder to be used on more schemas.

🐛 Other Noteworthy Changes

Execution / data fetching

  • DataLoader dispatch with multiple @defer fragments (#4270) — fixes a case where DataLoaders were not dispatched correctly when multiple deferred fragments were in play.
  • CompletionStageSubscriber race condition (#4296) — completion signal could be lost if an in-flight CompletionStage resolved concurrently. Fix is backed by new jcstress stress tests.
  • PropertyDataFetcher on non-public classes (#4287) — properties on non-public classes that implement public interfaces (e.g. TreeMap.Entry) now fetch correctly on Java 16+ by searching public interfaces.
  • ExecutableNormalizedField respects GraphqlFieldVisibility (#4204) — selection-set APIs now use the schema's configured visibility instead of going straight to the type.
  • ScheduledDataLoaderRegistry "dispatch all" fix (#4164).
  • ChainedInstrumentation onExceptionHandled delegation (#4207).

Schema / field visibility

  • Fixes for complex field-visibility transformer cases and schema transformation when deletions cascade (#4203, #4205, #4208, #4209, #4212, #4213, #4275).
  • Overlapping-fields null-type regression fixed (#4291).
  • GraphQLTypeCollectingVisitor now recursively traverses indirect strong references (#4213).
  • SchemaTraverser::depthFirst overload signature fix (#4165).

Build / packaging / security

  • Bytecode-modified classes no longer ship in published JARs (#4343) — the @Generated annotation injected for coverage reporting was leaking into published artifacts. JARs now contain pristine compiler output.
  • Trojan Source / glassworm Unicode detection (#4344) — pre-commit hook and CI workflow now reject dangerous BiDi/zero-width/control characters in source.
  • Windows compatibility (#4239) — removed colons from performance-results/ filenames, split the oversized large-schema-5.graphqls, added pre-commit + CI checks.

Tooling / DX

  • getDataLoader type bounds improved (#4180).
  • Build and test on Java 25 (#4173, #4330).
  • Many dependency updates (Reactor, Jackson, Kotlin, Groovy, Gradle, ByteBuddy, errorprone, etc.) across the release.

Full PR list

Expand to see all merged PRs
Read more

26.0.beta-2

19 Feb 22:54
9ae83ab

Choose a tag to compare

26.0.beta-2 Pre-release
Pre-release

A word of warning

While all features are tested and we consider them ready to be used, we don't guarantee that this is a stable version: this means there will be more breaking changes until we reach 26.0.

This version is intended for testing and providing feedback to the GraphQL Java team.

What's Changed

Breaking Changes

  • Validation rules consolidated into single OperationValidator — The 31 individual rule classes in graphql.validation.rules.*, AbstractRule, and RulesVisitor have been removed. The rule filtering predicate type changed from Predicate<Class<?>> to Predicate<OperationValidationRule> (a new @PublicApi enum). Code that filters rules by class reference must migrate to the enum. (#4228)

  • DirectiveInfo class removed — Use Directives.isBuiltInDirective() and Directives.BUILT_IN_DIRECTIVES instead. GraphQLSchema.Builder.clearDirectives() has also been removed — all 7 built-in directives are now always present. Built-in directives now consistently appear first in schema.getDirectives(). (#4229)

  • JSpecify nullability annotations — big wave 2 — ~50 classes annotated with @NullMarked and @Nullable. This may surface new warnings or errors in projects using NullAway or Kotlin. (#4184)

Performance

  • 23-39% execution throughput improvement — Reduce allocations in Async$Many (zero-copy list), ResultPath (lazy toString()), and GraphQLCodeRegistry (fast-path DataFetcher lookup avoiding throwaway FieldCoordinates allocation). (#4252)

  • 14-40% faster validation — Single OperationValidator eliminates per-rule visitor overhead and reduces collection allocations on hot paths. (#4228)

New Features

  • feat: GraphQLSchema.FastBuilder for high-performance schema construction by @rstata in #4197
  • Add OneOf inhabitability validation by @jbellenger in #4248
  • Call onExceptionHandled in ChainedInstrumentation by @tinnou in #4207
  • New transformSchemaWithDeletes method for complex deletion cases in #4209

Bug Fixes

  • Fix ExecutableNormalizedField to respect GraphqlFieldVisibility by @Samjin in #4204
  • Fix type collecting for indirect references in #4213
  • Fix and improve field visibility in #4212
  • Code-built schemas now perform deprecated non-null field validations (same as SDL-built) in #4194
  • Remove incorrect @Nullable from GraphQLSchema.getCodeRegistry() in #4247

Other Improvements

  • AST directives holder has a toString() in #4195
  • Add documentation and test for additionalTypes in GraphQLSchema in #4208
  • Build and test using Java 25 by @yeikel in #4173
  • Update Objenesis, Spock and Groovy by @m1ngyuan in #4240
  • Bump Gradle wrapper to 9.3.1, Shadow to 9.3.1, Kotlin to 2.3.0

New Contributors

Full Changelog: v26.0.beta-1...v26.0.beta-2

26.0.beta-1

14 Jan 03:25
c465601

Choose a tag to compare

26.0.beta-1 Pre-release
Pre-release

This is a beta release for the upcoming version 26.

A word of warning

While all features are tested and we consider them ready to be used, we don't guarantee that this is a stable version: this means there will be more breaking changes until we reach 26.0.

This version is intended for testing and providing feedback to the GraphQL Java team.

What's Changed

  • use dispatch all to not break ScheduledDataLoaderRegistry by @andimarek in #4164
  • Upgrade to Gradle 9.2.0 by @Copilot in #4171
  • fix build after gradle 9 upgrade by @andimarek in #4175
  • GQLGW-5297-optimise-incremental-part-execution-for-defer-requests by @llin2 in #4174
  • Bump actions/checkout from 5 to 6 by @dependabot[bot] in #4178
  • Bump net.bytebuddy:byte-buddy from 1.17.8 to 1.18.1 by @dependabot[bot] in #4176
  • Bump io.projectreactor:reactor-core from 3.7.12 to 3.8.0 by @dependabot[bot] in #4168
  • Bump com.google.errorprone:error_prone_core from 2.43.0 to 2.44.0 by @dependabot[bot] in #4167
  • Fix error: Unusable type signature for overload of graphql.schema.SchemaTraverser::depthFirst #4147 by @marktech0813 in #4165
  • Getdataloader type bounds by @ctbarbour in #4180
  • All fields removed from object/interface via field visibility transformer which is reachable via additional types by @andimarek in #4203
  • fixes complex case for Field visibility transformer. See test case by @andimarek in #4205
  • Proposal for an additional instrumentation hook point by @tinnou in #4206

New Contributors

Full Changelog: v25.0...v26.0.beta-1

25.0

10 Nov 01:21

Choose a tag to compare

Key changes

Dataloader

Refactoring strategy

The existing PerLevelDataLoaderStrategy has been refactored which lead to simplifications and performance improvements.

New strategies

Two new strategies were introduced: CHAINED and EXHAUSTED. Both can be configured via UnusalConfiguration (see next section).

CHAINED allow for chained DataLoaders to be used while keeping a per level dispatch strategies.

EXHAUSTED is a completely new strategy that works on the basis to dispatch once the engine is not busy. It mirrors the JS data loader dispatch strategy, but for a multi threaded system.

Unusual Configuration

A more generalised configuration mechanism has been added for "unusual configuration". By that we mean configuation we dont expect many people to use but if they do its now in a more common place

For example if you wanted to change the maximum depth the document parser will accept you could call the following methods.

        var parserOptions = newParserOptions().maxRuleDepth(99).build()
        GraphQL.unusualConfiguration().parsing().setDefaultParserOptions(parserOptions)

JSpecify Annotations

The team are starting to embrace https://jspecify.dev/ annotations as the way to indicate nullable and non nullable fields. Many important classes have had these annotations added to help make it more semantically clear when a value can be null or not.

Breaking Changes

A wrapping FetchedValue object is not always returned on field fetchers for performance reasons. This means that graphql.execution.instrumentation.parameters.InstrumentationFieldCompleteParameters#getFetchedObject was created to replace the older getFetchedValue method and the returns object can sometimes be a FetchedValue or sometimes a simple POJO value.

Performance improvements

A series of performance improvements have been made to reduce the memory footprint of the library. Also the Java .stream() operator can be slower than a more direct loop and many of these calls have been changed for performance reasons.

  • avoid wrapping materialized fieldValueObject in a CompletableFuture by @samuelAndalon in #3943
  • ExecutionStrategyParameters now has a direct transform without a Builder by @bbakerman in #3935
  • ExecutionStepInfo now has a direct transform without a Builder by @bbakerman in #3934
  • FpKit now longer uses streams for performance reasons by @bbakerman in #3932
  • Implement toString/hashCode/equals for DataFetcherResult by @AlexandreCarlton in #3964
  • Introduce a filter and map imperative method to replace .stream() calls by @bbakerman in #3931
  • Removing some of the Optional.map() and .stream() for performance reasons by @bbakerman in #3930
  • Stop creating NonNullableFieldValidator every for every object or list field by @bbakerman in #3929

What's Changed

Read more

25.0.beta-9

12 Oct 21:04

Choose a tag to compare

25.0.beta-9 Pre-release
Pre-release

This is another beta release for the upcoming version 25.

A word of warning

While all features are tested and we consider them ready to be used, we don't guarantee that this is a stable version: this means there will be more breaking changes until we reach 25.0.

This version is intended for testing and providing feedback to the GraphQL Java team.

What's Changed

Full Changelog: v25.0.beta-7...v25.0.beta-9

25.0.beta-8

28 Sep 12:10
45a7d59

Choose a tag to compare

25.0.beta-8 Pre-release
Pre-release

This is another beta release for the upcoming version 25.

It contains a new Data Loader dispatching strategy ... see #4130

A word of warning

While all features are tested and we consider them ready to be used, we don't guarantee that this is a stable version: this means there will be more breaking changes until we reach 25.0.

This version is intended for testing and providing feedback to the GraphQL Java team.

What's Changed

  • Bump com.google.errorprone:error_prone_core from 2.41.0 to 2.42.0 by @dependabot[bot] in #4125
  • 5.0.3 version of dataloader by @bbakerman in #4126
  • Per level tracking simplification and performance improvements by @andimarek in #4128
  • cleanup and comments for dataloader tracking by @andimarek in #4129
  • Bump com.uber.nullaway:nullaway from 0.12.9 to 0.12.10 by @dependabot[bot] in #4124
  • New Exhaustion based data loader dispatching strategy by @andimarek in #4130

Full Changelog: 25.0.beta-6...v25.0.beta-8

25.0.beta-7

28 Sep 12:08
45a7d59

Choose a tag to compare

25.0.beta-7 Pre-release
Pre-release

This is another beta release for the upcoming version 25.

24.3

23 Sep 06:13
ca269f2

Choose a tag to compare

This small bug fix brings in java-dataloader 5.0.3 which itself has a fix such that the Kotlin stdlib is not included a POM dependency

See https://github.com/graphql-java/java-dataloader/releases/tag/v5.0.3 for more details

What's Changed

Full Changelog: v24.2...v24.3

25.0.beta-6

22 Sep 06:21
e6ca15a

Choose a tag to compare

25.0.beta-6 Pre-release
Pre-release

This is another beta release for the upcoming version 25.

It contains various changes, specifically performance improvements for the new chained dataloader feature.

A word of warning

While all features are tested and we consider them ready to be used, we don't guarantee that this is a stable version: this means there will be more breaking changes until we reach 25.0.

This version is intended for testing and providing feedback to the GraphQL Java team.

What's Changed

New Contributors

Full Changelog: v25.0.beta-5...25.0.beta-6

25.0.beta-5

01 Aug 00:17

Choose a tag to compare

25.0.beta-5 Pre-release
Pre-release

This is another beta release for the upcoming version 25.

This beta-5 release includes improvements to the Profiler to make it easier to use and analyse. More documentation on the Profiler is to come.

A word of warning

While all features are tested and we consider them ready to be used, we don't guarantee that this is a stable version: this means there will be more breaking changes until we reach 25.0.

This version is intended for testing and providing feedback to the GraphQL Java team.

What's Changed

Full Changelog: v25.0.beta-4...v25.0.beta-5