v22.0
版本发布时间: 2024-04-16 13:06:13
graphql-java/graphql-java最新发布版本:v22.3(2024-09-05 11:15:52)
We are pleased to announce the release of graphql-java v22.0.
Thanks to everyone in the community who contributed to the release, whether that was code, helping to report issues, or participating in discussions.
This is a breaking change release.
The graphql-java team takes breaking changes very seriously but in the name of performance we have made some significant breaking changes in this release.
Major Performance Changes
Past releases have been very much performance focused and this one is no different. However, this release is aiming to reduce memory pressure more than reduce pure CPU usage. When the graphql-java engine is running, if it produces less objects it will ultimately run faster because of reduced memory pressure and less garbage to collect.
The engine has been changed in two major ways that reduce memory pressure.
ExecutionResult wrapping
The first was that all values that come back got wrapped internally into a ExecutionResult
object where the data
attribute was the value. This was a carry over from some very early GraphQL code but was unnecessary and hence has been removed. The follow on effect of this is that some graphql.execution.ExecutionStrategy
protected methods and graphql.execution.instrumentation.Instrumentation
methods used to receive and return ExecutionResult
values and no longer do, which is an API breaking change. We have made this breaking changes in the name of memory pressure performance.
CompletableFuture wrapping
The second major change is that the engine no longer exclusively uses java.util.concurrent.CompletableFuture
s when composing together results. Let us explain the past code first so we can discuss the new code.
CompletableFuture
is a fantastic construct because it represents a promise to a value and it can also hold an exceptional state inside itself. Async programming with CompletableFuture
is viral. If stage 1 of some compute process returns a CompletableFuture
then stage 2 and 3 and 4 are likely to as well to ensure everything is asynchronous.
We use to take values that were not asynchronous (such as DataFetcher that returned a simple in memory object) and wrap them in a CompletableFuture
so that all of the other code composed together using CompletableFuture
methods like .thenApply()
and .thenCompose
and so on. The code is cleaner if you use all CompletableFuture
code patterns.
However many objects in a GraphQL request are not asynchronous but rather materialised objects in memory. Scalars, enums and list are often just values immediately available to be used and allocating a CompletableFuture
makes the code easier to write but it has a memory pressure cost.
So we have sacrificed cleaner code for more memory performant code.
graphql-java engine graphql.execution.ExecutionStrategy
methods now just return Object
where that object might be either a CompletableFuture
or a materialised value.
private Object /*CompletableFuture<FetchedValue> | FetchedValue>*/
fetchField(GraphQLFieldDefinition fieldDef, ExecutionContext executionContext, ExecutionStrategyParameters parameters) {
Notice we have lost type safety here. In the past this would have only been CompletableFuture<FetchedValue>
and hence been both type safe and async composable.
Now the caller of that method has to handle the async case where it might be a CompletableFuture<FetchedValue>
AND the materialised value case where it might be a FetchedValue
but as most simple fields in GraphQL are in fact materialised values, this is worth the less clean code.
DataFetchers
can of course continue to return CompletableFuture
values and they will be handled in a polymorphic manner.
The upshot of all this work is that the graphql-java engine allocated way less CompletableFuture
values and hence reduces the amount of memory used.
Instrumentation Changes
The above changes now mean means that before graphql.execution.instrumentation.InstrumentationContext
used to be given a CompletableFuture
but now no longer does
void onDispatched(CompletableFuture<T> result);
is now
void onDispatched();
if you previously used the CompletableFuture
to know when something was completed, well InstrumentationContext
has the same semantics because it's completed method is similar in that it presents a value or an exception
void onCompleted(T result, Throwable t);
graphql.execution.instrumentation.Instrumentation
also had a lot of deprecated methods in place and these have been removed since the more performant shape of passing in graphql.execution.instrumentation.InstrumentationState
has been in place for quite a few releases.
Some of the methods that received ExecutionResult
wrapped values have also changed as mentioned above.
Instrumentation
is probably the area that needs the most attention in terms of breaking changes. If you have not moved off the deprecated methods, your custom Instrumentation
s will no longer compile or run.
Interning key strings
Our friends at Netflix provided a PR that interns certain key strings like "field names" so that we create less String instances when processing field names in queries that we know must be previously interned in the schema.
https://github.com/graphql-java/graphql-java/pull/3504
The full list of performance related changes
Major Changes
@defer Experimental Support
Support for the @defer
directive has been added in an experimental fashion. While @defer
is still not in the released GraphQL specification, we have judged it mature enough to support at this stage and the graphql-js
reference implementation has support for it.
https://github.com/graphql/graphql-wg/blob/main/rfcs/DeferStream.md
At this stage we have not yet supported @stream
but this is likely to be included in a future release.
Breaking Changes
There are quite a few API breaking changes in this release. In fact there are 22 PRs containing breaking API changes.
Stricter parseValue coercion: Aligning with JS reference implementation
We have made changes to String, Boolean, Float, and Int parseValue
coercion, to be consistent with the reference JS implementation. The key change is parseValue
is now stricter on accepted inputs.
- String
parseValue
now requires input of typeString
. For example, aNumber
input123
or aBoolean
inputtrue
will no longer be accepted. - Boolean
parseValue
now requires input of typeBoolean
. For example, aString
input"true"
will no longer be accepted. - Float
parseValue
now requires input of typeNumber
. For example, aString
input"3.14"
will no longer be accepted. - Int
parseValue
now requires input of typeNumber
. For example, aString
input"42"
will no longer be accepted.
This is a breaking change. To help you migrate, in version 21.0, we introduced the InputInterceptor https://github.com/graphql-java/graphql-java/pull/3188 (and an implementation LegacyCoercingInputInterceptor https://github.com/graphql-java/graphql-java/pull/3218) to provide a migration pathway. You can use this interceptor to monitor and modify values.
For more, see https://github.com/graphql-java/graphql-java/pull/3553 JS reference implementation: https://github.com/graphql/graphql-js/blob/main/src/type/scalars.ts
Removing deprecated methods
Many methods that have been deprecated for a long time, sometimes even up to 6 years, have finally been removed.
The CompletableFuture
unwrapping work mentioned above changed many methods in the graphql.execution.ExecutionStrategy
classes but we don't expect this affect many people since very few people write their own engines.
That CompletableFuture
unwrapping work also had knock on effects as mentioned above on graphql.execution.instrumentation.Instrumentation
and hence this is the most likely place for there to be compatibility challenges in existing code.
DataLoaderDispatcherInstrumentation has been removed and is now built into the engine
The code to dispatch org.dataloader.DataLoader
s used to be an instrumentation called DataLoadersDataLoaderDispatcherInstrumentation
and it was automatically added at runtime. This approach has been removed.
The equivalent code is now built into the graphql-java engine itself. DataLoader
s can now always be used without any special setup. This also allows the code to be more performant in how DataLoader
s are dispatched.
SL4J logging has been removed
Previously, the graphql-java engine would log at DEBUG level certain errors or when fields get fetched. This has not proven used for from a support point to the graphql-java team and also has a compliance cost in that user generated content (UGC) and personally identifying information (PII) could end up being logged, which may not be allowed under regimes like European General Data Protection Regulation (GDPR).
If you want to log now we suggest you invest in a Instrumentation
that logs key events and you can there for log what you want and in a compliant manner of your choosing.
https://github.com/graphql-java/graphql-java/pull/3403
The full list of API breaking changes
Other changes
- Optional strict mode for RuntimeWiring and TypeRuntimeWiring, to avoid accidentally having multiple datafetchers on the same element #3565
What's Changed
- OneOf validation not being applied to nested inputs by @felipe-gdr in https://github.com/graphql-java/graphql-java/pull/3365
- Bump me.champeau.jmh from 0.7.1 to 0.7.2 by @dependabot in https://github.com/graphql-java/graphql-java/pull/3371
- Dutch translations for GraphQL Java by @jord1e in https://github.com/graphql-java/graphql-java/pull/3031
- Add 'compute' family of methods to GraphQLContext by @salvoilmiosi in https://github.com/graphql-java/graphql-java/pull/3364
- Handle list of @oneOf input objects by @bbakerman in https://github.com/graphql-java/graphql-java/pull/3370
- Bump com.graphql-java:java-dataloader from 3.2.1 to 3.2.2 by @dependabot in https://github.com/graphql-java/graphql-java/pull/3375
- Bump com.fasterxml.jackson.core:jackson-databind from 2.15.3 to 2.16.0 by @dependabot in https://github.com/graphql-java/graphql-java/pull/3376
- Bump org.jetbrains:annotations from 24.0.1 to 24.1.0 by @dependabot in https://github.com/graphql-java/graphql-java/pull/3377
- Add GitHub action to manage stale PRs and issues by @dondonz in https://github.com/graphql-java/graphql-java/pull/3359
- Bump actions/setup-node from 3 to 4 by @dependabot in https://github.com/graphql-java/graphql-java/pull/3358
- Bump google-github-actions/auth from 1.1.1 to 1.2.0 by @dependabot in https://github.com/graphql-java/graphql-java/pull/3381
- Update German translations by @jord1e in https://github.com/graphql-java/graphql-java/pull/3368
- Bump google-github-actions/auth from 1.2.0 to 2.0.0 by @dependabot in https://github.com/graphql-java/graphql-java/pull/3389
- Bump actions/setup-java from 3 to 4 by @dependabot in https://github.com/graphql-java/graphql-java/pull/3390
- Add tag to exempt PRs and issues from the stale bot by @dondonz in https://github.com/graphql-java/graphql-java/pull/3391
- Bump org.codehaus.groovy:groovy from 3.0.19 to 3.0.20 by @dependabot in https://github.com/graphql-java/graphql-java/pull/3402
- Bump com.fasterxml.jackson.core:jackson-databind from 2.16.0 to 2.16.1 by @dependabot in https://github.com/graphql-java/graphql-java/pull/3400
- Bump actions/stale from 8 to 9 by @dependabot in https://github.com/graphql-java/graphql-java/pull/3393
- Bump org.testng:testng from 7.8.0 to 7.9.0 by @dependabot in https://github.com/graphql-java/graphql-java/pull/3407
- Cleaning up ValidationError constructors by @dondonz in https://github.com/graphql-java/graphql-java/pull/3405
- Refactor ENF Factory by @felipe-gdr in https://github.com/graphql-java/graphql-java/pull/3410
- upgrade gradle to 8.5 by @andimarek in https://github.com/graphql-java/graphql-java/pull/3412
- Java 9 @Deprecated annotation by @dondonz in https://github.com/graphql-java/graphql-java/pull/3406
- Defer support on ENFs by @felipe-gdr in https://github.com/graphql-java/graphql-java/pull/3395
- Bump google-github-actions/auth from 2.0.0 to 2.0.1 by @dependabot in https://github.com/graphql-java/graphql-java/pull/3416
- 3385 - fix for the turkish eye 🧿 by @bbakerman in https://github.com/graphql-java/graphql-java/pull/3388
- Update deprecated methods in scalar coercion documentation example by @dondonz in https://github.com/graphql-java/graphql-java/pull/3413
- Propagate GraphQLContext when completing fields - fix missing ConditionalNodesDecision issue by @dondonz in https://github.com/graphql-java/graphql-java/pull/3411
- This removes SLF4J from the code base by @bbakerman in https://github.com/graphql-java/graphql-java/pull/3403
- Check in Gradle files for Gradle 8.5 by @dondonz in https://github.com/graphql-java/graphql-java/pull/3419
- Bump google-github-actions/auth from 2.0.1 to 2.1.0 by @dependabot in https://github.com/graphql-java/graphql-java/pull/3420
- Bump gradle/wrapper-validation-action from 1 to 2 by @dependabot in https://github.com/graphql-java/graphql-java/pull/3437
- Skip signing for local and upgrade to Gradle 8.6 by @dondonz in https://github.com/graphql-java/graphql-java/pull/3441
- ExecutionResult wrapping can be avoided - reduces memory allocations and GC by @bbakerman in https://github.com/graphql-java/graphql-java/pull/3330
- Bump org.eclipse.jetty:jetty-server from 11.0.15 to 11.0.20 by @dependabot in https://github.com/graphql-java/graphql-java/pull/3445
- Bump google-github-actions/auth from 2.1.0 to 2.1.1 by @dependabot in https://github.com/graphql-java/graphql-java/pull/3446
- Defer execution 2024 by @felipe-gdr in https://github.com/graphql-java/graphql-java/pull/3421
- Add class hierarchy for incremental execution result by @felipe-gdr in https://github.com/graphql-java/graphql-java/pull/3414
- ensure that instrumentations get an executionid by @jbellenger in https://github.com/graphql-java/graphql-java/pull/3448
- handle more Schema diff applied directives cases by @andimarek in https://github.com/graphql-java/graphql-java/pull/3451
- Defer execution refactoring after first merge by @felipe-gdr in https://github.com/graphql-java/graphql-java/pull/3450
- Fix bug where deferred payloads were not using field aliases by @felipe-gdr in https://github.com/graphql-java/graphql-java/pull/3449
- Fix invalid AST printer: add escape characters to single line descriptions by @dondonz in https://github.com/graphql-java/graphql-java/pull/3443
- Fix flaky defer test by @felipe-gdr in https://github.com/graphql-java/graphql-java/pull/3455
- Native DataLoader dispatch strategy without Instrumentation by @andimarek in https://github.com/graphql-java/graphql-java/pull/3447
- Avoid repeated Map lookups in SimpleFieldValidation by @kilink in https://github.com/graphql-java/graphql-java/pull/3461
- Fix oneOf bug when variables is empty by @felipe-gdr in https://github.com/graphql-java/graphql-java/pull/3430
- Avoid Map for instrumentation state by @DanielThomas in https://github.com/graphql-java/graphql-java/pull/3459
- Small code tweaks on recent PR by @bbakerman in https://github.com/graphql-java/graphql-java/pull/3463
- Use String concatenation instead of StringBuilder by @kilink in https://github.com/graphql-java/graphql-java/pull/3464
- Added Async benchmark for future changes by @bbakerman in https://github.com/graphql-java/graphql-java/pull/3467
- cleaning up the jhm benchmarks by @andimarek in https://github.com/graphql-java/graphql-java/pull/3468
- fixed async benchmark - it was nonsensical before by @bbakerman in https://github.com/graphql-java/graphql-java/pull/3469
- andis suggestions on batch size by @bbakerman in https://github.com/graphql-java/graphql-java/pull/3472
- Fix schema builder to copy extensionDefinitions by @dondonz in https://github.com/graphql-java/graphql-java/pull/3470
- Added an id generator that's more performant by @bbakerman in https://github.com/graphql-java/graphql-java/pull/3466
- Bump google-github-actions/auth from 2.1.1 to 2.1.2 by @dependabot in https://github.com/graphql-java/graphql-java/pull/3473
- Tweaked id generator name by @bbakerman in https://github.com/graphql-java/graphql-java/pull/3474
- Using object instead of CF in DispatcherStrategy interface by @bbakerman in https://github.com/graphql-java/graphql-java/pull/3479
- Added a more complex query benchmark by @bbakerman in https://github.com/graphql-java/graphql-java/pull/3476
- Now allows the benchmark to go into profiling mode by @bbakerman in https://github.com/graphql-java/graphql-java/pull/3485
- Now allows the benchmark to go into profiling mode - 2 by @bbakerman in https://github.com/graphql-java/graphql-java/pull/3486
- Avoid repeated calls to getFieldDef and unnecessary immutable builders/collections by @DanielThomas in https://github.com/graphql-java/graphql-java/pull/3478
- This removes the CompletableFuture signature from InstrumentationContext by @bbakerman in https://github.com/graphql-java/graphql-java/pull/3457
- Don't build a builder object and then turn it into the actual object by @bbakerman in https://github.com/graphql-java/graphql-java/pull/3465
- directive filtering during printing by @bbakerman in https://github.com/graphql-java/graphql-java/pull/3387
- Updated helper code for profiler attachment by @bbakerman in https://github.com/graphql-java/graphql-java/pull/3491
- Combined benchmark runner by @bbakerman in https://github.com/graphql-java/graphql-java/pull/3493
- Defer validation by @Juliano-Prado in https://github.com/graphql-java/graphql-java/pull/3439
- Does not allocate a default deferred context that is thrown away on transform by @bbakerman in https://github.com/graphql-java/graphql-java/pull/3484
- Bump org.codehaus.groovy:groovy from 3.0.20 to 3.0.21 by @dependabot in https://github.com/graphql-java/graphql-java/pull/3497
- Get fieldDef improvements from Netflix by @bbakerman in https://github.com/graphql-java/graphql-java/pull/3499
- recreating the netflix Intern field names PR by @bbakerman in https://github.com/graphql-java/graphql-java/pull/3503
- adding a tracking agent by @andimarek in https://github.com/graphql-java/graphql-java/pull/3433
- Map benchmarks by @bbakerman in https://github.com/graphql-java/graphql-java/pull/3488
- A CompleteableFuture benchmark by @bbakerman in https://github.com/graphql-java/graphql-java/pull/3492
- Fix printing of union types by @bhabegger in https://github.com/graphql-java/graphql-java/pull/3506
- SubscriptionUniqueRootField validation to check multiple fragments - Validation Bug fix by @Juliano-Prado in https://github.com/graphql-java/graphql-java/pull/3481
- Return empty singleton DirectivesHolder if directives are empty by @gnawf in https://github.com/graphql-java/graphql-java/pull/3518
- Bump org.junit.jupiter:junit-jupiter from 5.7.1 to 5.10.2 by @dependabot in https://github.com/graphql-java/graphql-java/pull/3523
- Bump org.assertj:assertj-core from 3.25.1 to 3.25.3 by @dependabot in https://github.com/graphql-java/graphql-java/pull/3521
- Bump net.bytebuddy:byte-buddy from 1.14.11 to 1.14.12 by @dependabot in https://github.com/graphql-java/graphql-java/pull/3522
- Bump com.fasterxml.jackson.core:jackson-databind from 2.16.1 to 2.16.2 by @dependabot in https://github.com/graphql-java/graphql-java/pull/3519
- Bump net.bytebuddy:byte-buddy-agent from 1.14.11 to 1.14.12 by @dependabot in https://github.com/graphql-java/graphql-java/pull/3520
- allow for a max result nodes limit for execution by @andimarek in https://github.com/graphql-java/graphql-java/pull/3525
- This provides and ability to disable Introspection by @bbakerman in https://github.com/graphql-java/graphql-java/pull/3526
- This provides GoodFaithIntrospection by @bbakerman in https://github.com/graphql-java/graphql-java/pull/3527
- Bump com.fasterxml.jackson.core:jackson-databind from 2.16.2 to 2.17.0 by @dependabot in https://github.com/graphql-java/graphql-java/pull/3534
- adding a cycle schema analyzer by @andimarek in https://github.com/graphql-java/graphql-java/pull/3533
- Restrict the number of ENFs created and take advantage in GoodFaith introspection by @andimarek in https://github.com/graphql-java/graphql-java/pull/3539
- Interning fieldnames (from netflix) by @bbakerman in https://github.com/graphql-java/graphql-java/pull/3504
- Cheaper assertions with constant strings by @bbakerman in https://github.com/graphql-java/graphql-java/pull/3507
- Small tweaks to not allocate objects for lambda closures by @bbakerman in https://github.com/graphql-java/graphql-java/pull/3508
- Removed the deprecated Instrumentation methods and removes ER wrapping by @bbakerman in https://github.com/graphql-java/graphql-java/pull/3460
- Removed deprecated methods in parsing by @bbakerman in https://github.com/graphql-java/graphql-java/pull/3509
- Removed deprecated methods in doc providers by @bbakerman in https://github.com/graphql-java/graphql-java/pull/3510
- Removed deprecated methods in ExecutionInput by @bbakerman in https://github.com/graphql-java/graphql-java/pull/3511
- Removed deprecated methods in ExecutionContext by @bbakerman in https://github.com/graphql-java/graphql-java/pull/3512
- Removed deprecated methods in GraphQLSchema by @bbakerman in https://github.com/graphql-java/graphql-java/pull/3515
- Removed deprecated methods and SchemaGeneratorPostProcessing by @bbakerman in https://github.com/graphql-java/graphql-java/pull/3516
- Removed deprecated methods in ValidationError by @bbakerman in https://github.com/graphql-java/graphql-java/pull/3517
- cleanup ExecutableNormalizedOperationFactory by @andimarek in https://github.com/graphql-java/graphql-java/pull/3544
- Made the field definition lookup more optimised by @bbakerman in https://github.com/graphql-java/graphql-java/pull/3494
- Removed deprecated methods in code registry by @bbakerman in https://github.com/graphql-java/graphql-java/pull/3514
- Improve Good faith introspection error handling by @andimarek in https://github.com/graphql-java/graphql-java/pull/3546
- Reduce the usage of CompletableFutures in graphql-java - scalars / enums and lists by @bbakerman in https://github.com/graphql-java/graphql-java/pull/3480
- add a default max nodes count for the ExecutableNormalizedFactory by @andimarek in https://github.com/graphql-java/graphql-java/pull/3547
- Reduce the usage of CompletableFutures in graphql-java - now with objects by @bbakerman in https://github.com/graphql-java/graphql-java/pull/3490
- Bump net.bytebuddy:byte-buddy from 1.14.12 to 1.14.13 by @dependabot in https://github.com/graphql-java/graphql-java/pull/3554
- Bump net.bytebuddy:byte-buddy-agent from 1.14.12 to 1.14.13 by @dependabot in https://github.com/graphql-java/graphql-java/pull/3555
- Stricter parseValue coercion for String, Int, Float, Boolean by @dondonz in https://github.com/graphql-java/graphql-java/pull/3553
- require non-empty directive locations by @jbellenger in https://github.com/graphql-java/graphql-java/pull/3552
- Putting createState back into Instrumentation by @bbakerman in https://github.com/graphql-java/graphql-java/pull/3557
- Bump org.testng:testng from 7.9.0 to 7.10.0 by @dependabot in https://github.com/graphql-java/graphql-java/pull/3559
- Bump io.github.gradle-nexus.publish-plugin from 1.3.0 to 2.0.0 by @dependabot in https://github.com/graphql-java/graphql-java/pull/3560
- fix incremental partial result builder by @sbarker2 in https://github.com/graphql-java/graphql-java/pull/3562
- Dataloader 3.3.0 upgrade by @bbakerman in https://github.com/graphql-java/graphql-java/pull/3564
- strictMode for RuntimeWiring and TypeRuntimeWiring by @bbakerman in https://github.com/graphql-java/graphql-java/pull/3565
- Bump org.testng:testng from 7.10.0 to 7.10.1 by @dependabot in https://github.com/graphql-java/graphql-java/pull/3566
- Bump gradle/wrapper-validation-action from 2 to 3 by @dependabot in https://github.com/graphql-java/graphql-java/pull/3567
- validate non-nullable directive args by @jbellenger in https://github.com/graphql-java/graphql-java/pull/3551
New Contributors
- @salvoilmiosi made their first contribution in https://github.com/graphql-java/graphql-java/pull/3364
- @Juliano-Prado made their first contribution in https://github.com/graphql-java/graphql-java/pull/3439
- @bhabegger made their first contribution in https://github.com/graphql-java/graphql-java/pull/3506
- @sbarker2 made their first contribution in https://github.com/graphql-java/graphql-java/pull/3562
Full Changelog: https://github.com/graphql-java/graphql-java/compare/v21.5...v22.0