Skip to content

Commit a79bebf

Browse files
committed
Merge commit '42efd9b23ef9ae7ba862d9affefe04a03a9b99cb' into 21.x-pull-in-21.3-commits
# Conflicts: # build.gradle # src/test/groovy/graphql/introspection/IntrospectionTest.groovy # src/test/groovy/graphql/schema/idl/SchemaPrinterTest.groovy
2 parents ddc53be + 42efd9b commit a79bebf

File tree

82 files changed

+3341
-553
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

82 files changed

+3341
-553
lines changed

.github/workflows/invoke_test_runner.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ jobs:
3434
if: github.repository == 'graphql-java/graphql-java'
3535
runs-on: ubuntu-latest
3636
steps:
37-
- uses: actions/checkout@v3
37+
- uses: actions/checkout@v4
3838
- uses: actions/setup-node@v3
3939
with:
4040
node-version: '14'

.github/workflows/master.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ jobs:
1313
MAVEN_CENTRAL_PGP_KEY: ${{ secrets.MAVEN_CENTRAL_PGP_KEY }}
1414

1515
steps:
16-
- uses: actions/checkout@v3
16+
- uses: actions/checkout@v4
1717
- uses: gradle/wrapper-validation-action@v1
1818
- name: Set up JDK 11
1919
uses: actions/setup-java@v3

.github/workflows/pull_request.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
buildAndTest:
1717
runs-on: ubuntu-latest
1818
steps:
19-
- uses: actions/checkout@v3
19+
- uses: actions/checkout@v4
2020
- uses: gradle/wrapper-validation-action@v1
2121
- name: Set up JDK 11
2222
uses: actions/setup-java@v3

.github/workflows/release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ jobs:
1717
RELEASE_VERSION: ${{ github.event.inputs.version }}
1818

1919
steps:
20-
- uses: actions/checkout@v3
20+
- uses: actions/checkout@v4
2121
- uses: gradle/wrapper-validation-action@v1
2222
- name: Set up JDK 11
2323
uses: actions/setup-java@v3

README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,17 @@ Discuss and ask questions in our Discussions: https://github.com/graphql-java/gr
55
This is a [GraphQL](https://github.com/graphql/graphql-spec) Java implementation.
66

77
[![Build](https://github.com/graphql-java/graphql-java/actions/workflows/master.yml/badge.svg)](https://github.com/graphql-java/graphql-java/actions/workflows/master.yml)
8-
[![Latest Release](https://img.shields.io/maven-central/v/com.graphql-java/graphql-java?versionPrefix=20.)](https://maven-badges.herokuapp.com/maven-central/com.graphql-java/graphql-java/)
8+
[![Latest Release](https://img.shields.io/maven-central/v/com.graphql-java/graphql-java?versionPrefix=21.)](https://maven-badges.herokuapp.com/maven-central/com.graphql-java/graphql-java/)
99
[![Latest Snapshot](https://img.shields.io/maven-central/v/com.graphql-java/graphql-java?label=maven-central%20snapshot&versionPrefix=0)](https://maven-badges.herokuapp.com/maven-central/com.graphql-java/graphql-java/)
1010
[![MIT licensed](https://img.shields.io/badge/license-MIT-green)](https://github.com/graphql-java/graphql-java/blob/master/LICENSE.md)
1111

1212
### Documentation
1313

14-
We have a tutorial for beginners: [Getting started with GraphQL Java and Spring Boot](https://www.graphql-java.com/tutorials/getting-started-with-spring-boot/)
14+
See our tutorial for beginners: [Getting started with GraphQL Java and Spring Boot](https://www.graphql-java.com/tutorials/getting-started-with-spring-boot/)
1515

16-
For details how to use `graphql-java` please look at the documentation: https://www.graphql-java.com/documentation/getting-started
16+
For further details, please see the documentation: https://www.graphql-java.com/documentation/getting-started
17+
18+
If you're looking to learn more, we (the maintainers) have written a book! [GraphQL with Java and Spring](https://leanpub.com/graphql-java) includes everything you need to know to build a production ready GraphQL service. The book is available on [Leanpub](https://leanpub.com/graphql-java) and [Amazon](https://www.amazon.com/GraphQL-Java-Spring-Andreas-Marek-ebook/dp/B0C96ZYWPF/).
1719

1820
Please take a look at our [list of releases](https://github.com/graphql-java/graphql-java/releases) if you want to learn more about new releases and the changelog.
1921

SECURITY.md

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,7 @@
22

33
## Supported Versions
44

5-
We support the latest release with security updates.
6-
7-
We retain the discretion to backport security updates, this is decided on a case-by-case basis.
8-
9-
| Version | Supported |
10-
| ------- | ------------------ |
11-
| v20.x | :white_check_mark: |
5+
As stated in our [Release Policy](https://www.graphql-java.com/blog/release-policy/), we will backport critical bugfixes and security fixes for versions dating back 18 months. These fixes will be backported depending on severity and demand.
126

137
## Reporting a Vulnerability
148

build.gradle

Lines changed: 44 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -20,37 +20,52 @@ java {
2020
}
2121
}
2222

23+
def makeDevelopmentVersion(parts) {
24+
def version = String.join("-", parts)
25+
println "created development version: $version"
26+
return version
27+
}
28+
2329
def getDevelopmentVersion() {
30+
def dateTime = new SimpleDateFormat('yyyy-MM-dd\'T\'HH-mm-ss').format(new Date())
2431
def gitCheckOutput = new StringBuilder()
2532
def gitCheckError = new StringBuilder()
26-
def gitCheck = ["git", "rev-parse", "--is-inside-work-tree"].execute()
33+
def gitCheck = ["git", "-C", projectDir.toString(), "rev-parse", "--is-inside-work-tree"].execute()
2734
gitCheck.waitForProcessOutput(gitCheckOutput, gitCheckError)
2835
def isGit = gitCheckOutput.toString().trim()
2936
if (isGit != "true") {
30-
def version = "0.0.0-" + new SimpleDateFormat('yyyy-MM-dd\'T\'HH-mm-ss').format(new Date()) + "-no-git"
31-
println "created development version: $version"
32-
return version
37+
return makeDevelopmentVersion(["0.0.0", dateTime, "no-git"])
3338
}
3439

35-
def gitHashOutput = new StringBuilder()
36-
def gitHashError = new StringBuilder()
37-
def gitShortHash = ["git", "-C", projectDir.toString(), "rev-parse", "--short", "HEAD"].execute()
38-
gitShortHash.waitForProcessOutput(gitHashOutput, gitHashError)
39-
def gitHash = gitHashOutput.toString().trim()
40-
if (gitHash.isEmpty()) {
41-
println "git hash is empty: error: ${error.toString()}"
42-
throw new IllegalStateException("git hash could not be determined")
40+
def isCi = Boolean.parseBoolean(System.env.CI)
41+
if (isCi) {
42+
def gitHashOutput = new StringBuilder()
43+
def gitHashError = new StringBuilder()
44+
def gitShortHash = ["git", "-C", projectDir.toString(), "rev-parse", "--short", "HEAD"].execute()
45+
gitShortHash.waitForProcessOutput(gitHashOutput, gitHashError)
46+
def gitHash = gitHashOutput.toString().trim()
47+
if (gitHash.isEmpty()) {
48+
println "git hash is empty: error: ${gitHashError.toString()}"
49+
throw new IllegalStateException("git hash could not be determined")
50+
}
51+
52+
return makeDevelopmentVersion(["0.0.0", dateTime, gitHash])
4353
}
44-
def version = "0.0.0-" + new SimpleDateFormat('yyyy-MM-dd\'T\'HH-mm-ss').format(new Date()) + "-" + gitHash
45-
println "created development version: $version"
46-
version
54+
55+
def gitRevParseOutput = new StringBuilder()
56+
def gitRevParseError = new StringBuilder()
57+
def gitRevParse = ["git", "-C", projectDir.toString(), "rev-parse", "--abbrev-ref", "HEAD"].execute()
58+
gitRevParse.waitForProcessOutput(gitRevParseOutput, gitRevParseError)
59+
def branchName = gitRevParseOutput.toString().trim()
60+
61+
return makeDevelopmentVersion(["0.0.0", branchName, "SNAPSHOT"])
4762
}
4863

4964
def reactiveStreamsVersion = '1.0.3'
5065
def slf4jVersion = '2.0.7'
5166
def releaseVersion = System.env.RELEASE_VERSION
5267
def antlrVersion = '4.11.1' // https://mvnrepository.com/artifact/org.antlr/antlr4-runtime
53-
def guavaVersion = '32.1.1-jre'
68+
def guavaVersion = '32.1.2-jre'
5469
version = releaseVersion ? releaseVersion : getDevelopmentVersion()
5570
group = 'com.graphql-java'
5671

@@ -87,17 +102,17 @@ dependencies {
87102
compileOnly 'org.jetbrains:annotations:24.0.1'
88103
implementation 'org.antlr:antlr4-runtime:' + antlrVersion
89104
implementation 'org.slf4j:slf4j-api:' + slf4jVersion
90-
api 'com.graphql-java:java-dataloader:3.2.0'
105+
api 'com.graphql-java:java-dataloader:3.2.1'
91106
api 'org.reactivestreams:reactive-streams:' + reactiveStreamsVersion
92107
antlr 'org.antlr:antlr4:' + antlrVersion
93108
implementation 'com.google.guava:guava:' + guavaVersion
94109
testImplementation group: 'junit', name: 'junit', version: '4.13.2'
95110
testImplementation 'org.spockframework:spock-core:2.0-groovy-3.0'
96-
testImplementation 'org.codehaus.groovy:groovy:3.0.18'
97-
testImplementation 'org.codehaus.groovy:groovy-json:3.0.18'
111+
testImplementation 'org.codehaus.groovy:groovy:3.0.19'
112+
testImplementation 'org.codehaus.groovy:groovy-json:3.0.19'
98113
testImplementation 'com.google.code.gson:gson:2.10.1'
99114
testImplementation 'org.eclipse.jetty:jetty-server:11.0.15'
100-
testImplementation 'com.fasterxml.jackson.core:jackson-databind:2.15.2'
115+
testImplementation 'com.fasterxml.jackson.core:jackson-databind:2.15.3'
101116
testImplementation 'org.slf4j:slf4j-simple:' + slf4jVersion
102117
testImplementation 'org.awaitility:awaitility-groovy:4.2.0'
103118
testImplementation 'com.github.javafaker:javafaker:1.0.2'
@@ -107,10 +122,10 @@ dependencies {
107122

108123
testImplementation 'org.testng:testng:7.8.0' // use for reactive streams test inheritance
109124

110-
testImplementation 'org.openjdk.jmh:jmh-core:1.36'
111-
testAnnotationProcessor 'org.openjdk.jmh:jmh-generator-annprocess:1.36'
112-
jmh 'org.openjdk.jmh:jmh-core:1.36'
113-
jmh 'org.openjdk.jmh:jmh-generator-annprocess:1.36'
125+
testImplementation 'org.openjdk.jmh:jmh-core:1.37'
126+
testAnnotationProcessor 'org.openjdk.jmh:jmh-generator-annprocess:1.37'
127+
jmh 'org.openjdk.jmh:jmh-core:1.37'
128+
jmh 'org.openjdk.jmh:jmh-generator-annprocess:1.37'
114129
}
115130

116131
shadowJar {
@@ -155,7 +170,7 @@ shadowJar {
155170
bnd('''
156171
-exportcontents: graphql.*
157172
-removeheaders: Private-Package
158-
Import-Package: !com.google.*,!org.checkerframework.*,!javax.annotation.*,!graphql.com.google.*,!org.antlr.*,!graphql.org.antlr.*,!sun.misc.*,*
173+
Import-Package: !android.os.*,!com.google.*,!org.checkerframework.*,!javax.annotation.*,!graphql.com.google.*,!org.antlr.*,!graphql.org.antlr.*,!sun.misc.*,*
159174
''')
160175
}
161176

@@ -203,7 +218,10 @@ generateGrammarSource {
203218
arguments += ["-visitor"]
204219
outputDirectory = file("${project.buildDir}/generated-src/antlr/main/graphql/parser/antlr")
205220
}
206-
generateGrammarSource.inputs.dir('src/main/antlr')
221+
generateGrammarSource.inputs
222+
.dir('src/main/antlr')
223+
.withPropertyName('sourceDir')
224+
.withPathSensitivity(PathSensitivity.RELATIVE)
207225

208226

209227
task sourcesJar(type: Jar) {

src/main/java/graphql/Directives.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import static graphql.introspection.Introspection.DirectiveLocation.FRAGMENT_SPREAD;
1616
import static graphql.introspection.Introspection.DirectiveLocation.INLINE_FRAGMENT;
1717
import static graphql.introspection.Introspection.DirectiveLocation.INPUT_FIELD_DEFINITION;
18+
import static graphql.introspection.Introspection.DirectiveLocation.INPUT_OBJECT;
1819
import static graphql.introspection.Introspection.DirectiveLocation.SCALAR;
1920
import static graphql.language.DirectiveLocation.newDirectiveLocation;
2021
import static graphql.language.InputValueDefinition.newInputValueDefinition;
@@ -31,10 +32,13 @@ public class Directives {
3132

3233
private static final String SPECIFIED_BY = "specifiedBy";
3334
private static final String DEPRECATED = "deprecated";
35+
private static final String ONE_OF = "oneOf";
3436

3537
public static final String NO_LONGER_SUPPORTED = "No longer supported";
3638
public static final DirectiveDefinition DEPRECATED_DIRECTIVE_DEFINITION;
3739
public static final DirectiveDefinition SPECIFIED_BY_DIRECTIVE_DEFINITION;
40+
@ExperimentalApi
41+
public static final DirectiveDefinition ONE_OF_DIRECTIVE_DEFINITION;
3842

3943

4044
static {
@@ -65,6 +69,12 @@ public class Directives {
6569
.type(newNonNullType(newTypeName().name("String").build()).build())
6670
.build())
6771
.build();
72+
73+
ONE_OF_DIRECTIVE_DEFINITION = DirectiveDefinition.newDirectiveDefinition()
74+
.name(ONE_OF)
75+
.directiveLocation(newDirectiveLocation().name(INPUT_OBJECT.name()).build())
76+
.description(createDescription("Indicates an Input Object is a OneOf Input Object."))
77+
.build();
6878
}
6979

7080
public static final GraphQLDirective IncludeDirective = GraphQLDirective.newDirective()
@@ -119,6 +129,14 @@ public class Directives {
119129
.definition(SPECIFIED_BY_DIRECTIVE_DEFINITION)
120130
.build();
121131

132+
@ExperimentalApi
133+
public static final GraphQLDirective OneOfDirective = GraphQLDirective.newDirective()
134+
.name(ONE_OF)
135+
.description("Indicates an Input Object is a OneOf Input Object.")
136+
.validLocations(INPUT_OBJECT)
137+
.definition(ONE_OF_DIRECTIVE_DEFINITION)
138+
.build();
139+
122140
private static Description createDescription(String s) {
123141
return new Description(s, null, false);
124142
}

src/main/java/graphql/GraphQL.java

Lines changed: 27 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package graphql;
22

33
import graphql.execution.AbortExecutionException;
4+
import graphql.execution.Async;
45
import graphql.execution.AsyncExecutionStrategy;
56
import graphql.execution.AsyncSerialExecutionStrategy;
67
import graphql.execution.DataFetcherExceptionHandler;
@@ -421,31 +422,33 @@ public CompletableFuture<ExecutionResult> executeAsync(ExecutionInput executionI
421422
if (logNotSafe.isDebugEnabled()) {
422423
logNotSafe.debug("Executing request. operation name: '{}'. query: '{}'. variables '{}'", executionInput.getOperationName(), executionInput.getQuery(), executionInput.getVariables());
423424
}
424-
executionInput = ensureInputHasId(executionInput);
425+
ExecutionInput executionInputWithId = ensureInputHasId(executionInput);
425426

426-
InstrumentationState instrumentationState = instrumentation.createState(new InstrumentationCreateStateParameters(this.graphQLSchema, executionInput));
427-
try {
428-
InstrumentationExecutionParameters inputInstrumentationParameters = new InstrumentationExecutionParameters(executionInput, this.graphQLSchema, instrumentationState);
429-
executionInput = instrumentation.instrumentExecutionInput(executionInput, inputInstrumentationParameters, instrumentationState);
430-
431-
CompletableFuture<ExecutionResult> beginExecutionCF = new CompletableFuture<>();
432-
InstrumentationExecutionParameters instrumentationParameters = new InstrumentationExecutionParameters(executionInput, this.graphQLSchema, instrumentationState);
433-
InstrumentationContext<ExecutionResult> executionInstrumentation = nonNullCtx(instrumentation.beginExecution(instrumentationParameters, instrumentationState));
434-
executionInstrumentation.onDispatched(beginExecutionCF);
435-
436-
GraphQLSchema graphQLSchema = instrumentation.instrumentSchema(this.graphQLSchema, instrumentationParameters, instrumentationState);
437-
438-
CompletableFuture<ExecutionResult> executionResult = parseValidateAndExecute(executionInput, graphQLSchema, instrumentationState);
439-
//
440-
// finish up instrumentation
441-
executionResult = executionResult.whenComplete(completeInstrumentationCtxCF(executionInstrumentation, beginExecutionCF));
442-
//
443-
// allow instrumentation to tweak the result
444-
executionResult = executionResult.thenCompose(result -> instrumentation.instrumentExecutionResult(result, instrumentationParameters, instrumentationState));
445-
return executionResult;
446-
} catch (AbortExecutionException abortException) {
447-
return handleAbortException(executionInput, instrumentationState, abortException);
448-
}
427+
CompletableFuture<InstrumentationState> instrumentationStateCF = instrumentation.createStateAsync(new InstrumentationCreateStateParameters(this.graphQLSchema, executionInput));
428+
return Async.orNullCompletedFuture(instrumentationStateCF).thenCompose(instrumentationState -> {
429+
try {
430+
InstrumentationExecutionParameters inputInstrumentationParameters = new InstrumentationExecutionParameters(executionInputWithId, this.graphQLSchema, instrumentationState);
431+
ExecutionInput instrumentedExecutionInput = instrumentation.instrumentExecutionInput(executionInputWithId, inputInstrumentationParameters, instrumentationState);
432+
433+
CompletableFuture<ExecutionResult> beginExecutionCF = new CompletableFuture<>();
434+
InstrumentationExecutionParameters instrumentationParameters = new InstrumentationExecutionParameters(instrumentedExecutionInput, this.graphQLSchema, instrumentationState);
435+
InstrumentationContext<ExecutionResult> executionInstrumentation = nonNullCtx(instrumentation.beginExecution(instrumentationParameters, instrumentationState));
436+
executionInstrumentation.onDispatched(beginExecutionCF);
437+
438+
GraphQLSchema graphQLSchema = instrumentation.instrumentSchema(this.graphQLSchema, instrumentationParameters, instrumentationState);
439+
440+
CompletableFuture<ExecutionResult> executionResult = parseValidateAndExecute(instrumentedExecutionInput, graphQLSchema, instrumentationState);
441+
//
442+
// finish up instrumentation
443+
executionResult = executionResult.whenComplete(completeInstrumentationCtxCF(executionInstrumentation, beginExecutionCF));
444+
//
445+
// allow instrumentation to tweak the result
446+
executionResult = executionResult.thenCompose(result -> instrumentation.instrumentExecutionResult(result, instrumentationParameters, instrumentationState));
447+
return executionResult;
448+
} catch (AbortExecutionException abortException) {
449+
return handleAbortException(executionInput, instrumentationState, abortException);
450+
}
451+
});
449452
}
450453

451454
private CompletableFuture<ExecutionResult> handleAbortException(ExecutionInput executionInput, InstrumentationState instrumentationState, AbortExecutionException abortException) {

src/main/java/graphql/execution/Async.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
import graphql.Assert;
44
import graphql.Internal;
5+
import org.jetbrains.annotations.NotNull;
6+
import org.jetbrains.annotations.Nullable;
57

68
import java.util.ArrayList;
79
import java.util.Collection;
@@ -207,4 +209,15 @@ public static <T> CompletableFuture<T> exceptionallyCompletedFuture(Throwable ex
207209
return result;
208210
}
209211

212+
/**
213+
* If the passed in CompletableFuture is null then it creates a CompletableFuture that resolves to null
214+
*
215+
* @param completableFuture the CF to use
216+
* @param <T> for two
217+
*
218+
* @return the completableFuture if it's not null or one that always resoles to null
219+
*/
220+
public static <T> @NotNull CompletableFuture<T> orNullCompletedFuture(@Nullable CompletableFuture<T> completableFuture) {
221+
return completableFuture != null ? completableFuture : CompletableFuture.completedFuture(null);
222+
}
210223
}

0 commit comments

Comments
 (0)