From 4f37774736e4f31b9188bd1985bd6109485b67cb Mon Sep 17 00:00:00 2001 From: Ruediger zu Dohna Date: Wed, 4 Jan 2023 11:15:50 +0100 Subject: [PATCH 01/11] maven-cache the github setup-java action --- .github/workflows/build.yml | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 284918059..da9918465 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -33,6 +33,7 @@ jobs: with: java-version: ${{matrix.java}} distribution: 'temurin' + cache: 'maven' - name: Install graphviz run: sudo apt install graphviz @@ -58,19 +59,12 @@ jobs: ref: main path: wildfly-graphql-feature-pack - - name: Cache local Maven repository - uses: actions/cache@v2 - with: - path: ~/.m2/repository - key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} - restore-keys: | - ${{ runner.os }}-maven- - - uses: actions/setup-java@v3.0.0 name: set up jdk ${{matrix.java}} with: java-version: ${{matrix.java}} distribution: 'temurin' + cache: 'maven' - name: build with maven run: mvn -B install -DskipTests --file pom.xml @@ -104,19 +98,12 @@ jobs: ref: jakarta-rewrite path: quarkus - - name: Cache local Maven repository - uses: actions/cache@v2 - with: - path: ~/.m2/repository - key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} - restore-keys: | - ${{ runner.os }}-maven- - - uses: actions/setup-java@v3.0.0 name: set up jdk ${{matrix.java}} with: java-version: ${{matrix.java}} distribution: 'temurin' + cache: 'maven' - name: build with maven run: mvn -B install -DskipTests --file smallrye-graphql/pom.xml @@ -145,6 +132,7 @@ jobs: with: java-version: 11 distribution: 'temurin' + cache: 'maven' - name: sonar env: From ee87e35517710c978f475d3e67f464a375375a9d Mon Sep 17 00:00:00 2001 From: Sascha Dais <41467575+roggenbrot@users.noreply.github.com> Date: Wed, 4 Jan 2023 17:08:39 +0100 Subject: [PATCH 02/11] Throw exception on unknown input to prevent invalid json --- .../impl/core/utils/ValueFormatter.java | 46 +++++++-- .../impl/core/utils/ValueFormatterTest.java | 28 ++++++ .../tck/graphql/dynamic/core/ArraysTest.java | 14 ++- .../graphql/dynamic/core/IterableTest.java | 94 +++++++++++++++++++ .../src/main/resources/core/arrays.graphql | 4 + .../src/main/resources/core/iterable.graphql | 53 +++++++++++ 6 files changed, 230 insertions(+), 9 deletions(-) create mode 100644 client/implementation/src/test/java/io/smallrye/graphql/client/impl/core/utils/ValueFormatterTest.java create mode 100644 client/tck/src/main/java/tck/graphql/dynamic/core/IterableTest.java create mode 100644 client/tck/src/main/resources/core/iterable.graphql diff --git a/client/implementation/src/main/java/io/smallrye/graphql/client/impl/core/utils/ValueFormatter.java b/client/implementation/src/main/java/io/smallrye/graphql/client/impl/core/utils/ValueFormatter.java index e0d810cf3..924627bb8 100644 --- a/client/implementation/src/main/java/io/smallrye/graphql/client/impl/core/utils/ValueFormatter.java +++ b/client/implementation/src/main/java/io/smallrye/graphql/client/impl/core/utils/ValueFormatter.java @@ -2,6 +2,7 @@ import java.lang.reflect.Array; import java.time.LocalDate; +import java.util.UUID; import io.smallrye.graphql.client.core.exceptions.BuildException; import io.smallrye.graphql.client.impl.core.EnumImpl; @@ -10,6 +11,18 @@ public class ValueFormatter { + private final static Class[] QUOTED_VALUES = new Class[] { String.class, Character.class, LocalDate.class, UUID.class }; + private final static Class[] UNQUOTED_VALUES = new Class[] { Number.class, Boolean.class }; + + public static boolean assignableFrom(Class clazz, Class[] candidates) { + for (Class candidate : candidates) { + if (candidate.isAssignableFrom(clazz)) { + return true; + } + } + return false; + } + public static String format(Object value) throws BuildException { if (value == null) { return "null"; @@ -24,17 +37,36 @@ public static String format(Object value) throws BuildException { return gqlEnum.build(); } else if (value.getClass().isArray()) { return _processArray(value); - } else if (value instanceof String) { - return _getAsQuotedString(String.valueOf(value)); - } else if (value instanceof Character) { - return _getAsQuotedString(String.valueOf(value)); - } else if (value instanceof LocalDate) { - return _getAsQuotedString(String.valueOf(value)); + } else if (value instanceof Iterable) { + return _processIterable((Iterable) value); } else { - return value.toString(); + if (assignableFrom(value.getClass(), QUOTED_VALUES)) { + return _getAsQuotedString(String.valueOf(value)); + } else if (assignableFrom(value.getClass(), UNQUOTED_VALUES)) { + return value.toString(); + } + throw new IllegalStateException("Could not format " + value.getClass() + ": Unsupported type."); } } + private static String _processIterable(Iterable iterable) throws BuildException { + StringBuilder builder = new StringBuilder(); + + boolean first = true; + builder.append("["); + for (Object v : iterable) { + if (first) { + first = false; + } else { + builder.append(","); + } + builder.append(format(v)); + } + builder.append("]"); + + return builder.toString(); + } + private static String _processArray(Object array) throws BuildException { StringBuilder builder = new StringBuilder(); diff --git a/client/implementation/src/test/java/io/smallrye/graphql/client/impl/core/utils/ValueFormatterTest.java b/client/implementation/src/test/java/io/smallrye/graphql/client/impl/core/utils/ValueFormatterTest.java new file mode 100644 index 000000000..10914f9f7 --- /dev/null +++ b/client/implementation/src/test/java/io/smallrye/graphql/client/impl/core/utils/ValueFormatterTest.java @@ -0,0 +1,28 @@ +package io.smallrye.graphql.client.impl.core.utils; + +import org.junit.jupiter.api.Test; + +import java.util.Date; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +class ValueFormatterTest { + + @Test + public void testUnsupportedInput() { + + assertThrows(IllegalStateException.class, () -> { + ValueFormatter.format(new Object()); + }); + + assertThrows(IllegalStateException.class, () -> { + ValueFormatter.format(Map.of("test", "value")); + }); + + assertThrows(IllegalStateException.class, () -> { + ValueFormatter.format(new Date()); + }); + } + +} \ No newline at end of file diff --git a/client/tck/src/main/java/tck/graphql/dynamic/core/ArraysTest.java b/client/tck/src/main/java/tck/graphql/dynamic/core/ArraysTest.java index aeab064ee..1bbe582c4 100644 --- a/client/tck/src/main/java/tck/graphql/dynamic/core/ArraysTest.java +++ b/client/tck/src/main/java/tck/graphql/dynamic/core/ArraysTest.java @@ -13,6 +13,9 @@ import java.math.BigDecimal; import java.math.BigInteger; import java.net.URISyntaxException; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; import org.junit.jupiter.api.Test; @@ -61,7 +64,11 @@ public void arraysTest() throws IOException, URISyntaxException { prop("charPrimitiveArray", new char[] { 'f', 'o', 'o' }), prop("charObjectArray", new Character[] { 'f', 'o', 'o' }), - prop("stringArray", new String[] { "foo", "bar", "baz" })))), + prop("stringArray", new String[] { "foo", "bar", "baz" }), + + prop("uuidArray", new UUID[]{UUID.fromString("fc4bb4f4-13fe-4908-8d6a-afa64f1b56c9"), + UUID.fromString("863c9e3c-7538-41b9-9d63-0852f6a50815")}) + ))), field("boolPrimitiveArray"), field("boolObjectArray"), @@ -89,7 +96,10 @@ public void arraysTest() throws IOException, URISyntaxException { field("charPrimitiveArray"), field("charObjectArray"), - field("stringArray")))); + field("stringArray"), + + field("uuidArray") + ))); String generatedRequest = document.build(); AssertGraphQL.assertEquivalentGraphQLRequest(expectedRequest, generatedRequest); diff --git a/client/tck/src/main/java/tck/graphql/dynamic/core/IterableTest.java b/client/tck/src/main/java/tck/graphql/dynamic/core/IterableTest.java new file mode 100644 index 000000000..d7eba23f6 --- /dev/null +++ b/client/tck/src/main/java/tck/graphql/dynamic/core/IterableTest.java @@ -0,0 +1,94 @@ +package tck.graphql.dynamic.core; + +import io.smallrye.graphql.client.core.Document; +import org.junit.jupiter.api.Test; +import tck.graphql.dynamic.helper.AssertGraphQL; +import tck.graphql.dynamic.helper.Utils; + +import java.io.IOException; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.net.URISyntaxException; +import java.util.List; +import java.util.Set; +import java.util.UUID; + +import static io.smallrye.graphql.client.core.Argument.arg; +import static io.smallrye.graphql.client.core.Argument.args; +import static io.smallrye.graphql.client.core.Document.document; +import static io.smallrye.graphql.client.core.Field.field; +import static io.smallrye.graphql.client.core.InputObject.inputObject; +import static io.smallrye.graphql.client.core.InputObjectField.prop; +import static io.smallrye.graphql.client.core.Operation.operation; +import static io.smallrye.graphql.client.core.OperationType.QUERY; + +public class IterableTest { + + @Test + public void iterableTest() throws IOException, URISyntaxException { + String expectedRequest = Utils.getResourceFileContent("core/iterable.graphql"); + + Document document = document( + operation(QUERY, "iterableHolderQuery", + field("iterableHolder", + args( + arg("iterableHolder", inputObject( + + prop("boolObjectList", List.of(true, false)), + + prop("byteObjectList", List.of( (byte)0, (byte)2, (byte)3)), + + prop("shortObjectList", List.of( (short)78,(short) 789,(short) 645 )), + + prop("intObjectList", List.of( 78, 65, 12354 )), + + prop("longObjectList", List.of( 789L, 947894L, 1874448L )), + + prop("floatObjectList", List.of( 1567.654f, 8765f, 123789456.1851f )), + + prop("doubleObjectList", List.of( 789.3242d, 1815d, 98765421.654897d )), + + prop("bigIntegerList", + List.of( BigInteger.ZERO, BigInteger.ONE, BigInteger.TEN )), + + prop("bigDecimalList", + List.of( BigDecimal.ZERO, BigDecimal.ONE, BigDecimal.TEN )), + + prop("charObjectList", List.of( 'f', 'o', 'o' )), + + prop("stringList", List.of( "foo", "bar", "baz" )), + + prop("uuidList", + List.of(UUID.fromString("fc4bb4f4-13fe-4908-8d6a-afa64f1b56c9"), + UUID.fromString("863c9e3c-7538-41b9-9d63-0852f6a50815"))) + + ))), + field("boolObjectList"), + + field("byteObjectList"), + + field("shortObjectList"), + + field("intObjectList"), + + field("longObjectList"), + + field("floatObjectList"), + + field("doubleObjectList"), + + field("bigIntegerList"), + + field("bigDecimalList"), + + field("charObjectList"), + + field("stringList"), + + field("uuidList") + ))); + + String generatedRequest = document.build(); + AssertGraphQL.assertEquivalentGraphQLRequest(expectedRequest, generatedRequest); + } +} diff --git a/client/tck/src/main/resources/core/arrays.graphql b/client/tck/src/main/resources/core/arrays.graphql index 4b306d724..c35c0e521 100644 --- a/client/tck/src/main/resources/core/arrays.graphql +++ b/client/tck/src/main/resources/core/arrays.graphql @@ -28,6 +28,8 @@ query arrayHolderQuery { charObjectArray: ["f", "o", "o"], stringArray: ["foo", "bar", "baz"], + + uuidArray: ["fc4bb4f4-13fe-4908-8d6a-afa64f1b56c9", "863c9e3c-7538-41b9-9d63-0852f6a50815"] }) { boolPrimitiveArray boolObjectArray @@ -57,5 +59,7 @@ query arrayHolderQuery { charObjectArray stringArray + + uuidArray } } \ No newline at end of file diff --git a/client/tck/src/main/resources/core/iterable.graphql b/client/tck/src/main/resources/core/iterable.graphql new file mode 100644 index 000000000..a1265df45 --- /dev/null +++ b/client/tck/src/main/resources/core/iterable.graphql @@ -0,0 +1,53 @@ +query iterableHolderQuery { + iterableHolder(iterableHolder:{ + + boolObjectList: [true, false] + + byteObjectList: [0, 2, 3] + + shortObjectList: [78, 789, 645] + + intObjectList: [78, 65, 12354] + + longObjectList: [789, 947894, 1874448] + + floatObjectList: [1567.654, 8765.0, 1.23789456E8] + + doubleObjectList: [789.3242, 1815.0, 9.8765421654897E7] + + bigIntegerList: [0, 1, 10] + + bigDecimalList: [0, 1, 10] + + charObjectList: ["f", "o", "o"] + + stringList: ["foo", "bar", "baz"] + + uuidList: ["fc4bb4f4-13fe-4908-8d6a-afa64f1b56c9", "863c9e3c-7538-41b9-9d63-0852f6a50815"] + + }) { + boolObjectList + + byteObjectList + + shortObjectList + + intObjectList + + longObjectList + + floatObjectList + + doubleObjectList + + bigIntegerList + + bigDecimalList + + charObjectList + + stringList + + uuidList + } +} \ No newline at end of file From 310712f6e8d4b7de9511b134afd4062c783712c1 Mon Sep 17 00:00:00 2001 From: Jan Martiska Date: Thu, 5 Jan 2023 09:26:58 +0100 Subject: [PATCH 03/11] Fix formatting --- .../impl/core/utils/ValueFormatterTest.java | 6 +-- .../tck/graphql/dynamic/core/ArraysTest.java | 11 ++-- .../graphql/dynamic/core/IterableTest.java | 53 +++++++++---------- 3 files changed, 33 insertions(+), 37 deletions(-) diff --git a/client/implementation/src/test/java/io/smallrye/graphql/client/impl/core/utils/ValueFormatterTest.java b/client/implementation/src/test/java/io/smallrye/graphql/client/impl/core/utils/ValueFormatterTest.java index 10914f9f7..2b5af4897 100644 --- a/client/implementation/src/test/java/io/smallrye/graphql/client/impl/core/utils/ValueFormatterTest.java +++ b/client/implementation/src/test/java/io/smallrye/graphql/client/impl/core/utils/ValueFormatterTest.java @@ -1,11 +1,11 @@ package io.smallrye.graphql.client.impl.core.utils; -import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertThrows; import java.util.Date; import java.util.Map; -import static org.junit.jupiter.api.Assertions.assertThrows; +import org.junit.jupiter.api.Test; class ValueFormatterTest { @@ -25,4 +25,4 @@ public void testUnsupportedInput() { }); } -} \ No newline at end of file +} diff --git a/client/tck/src/main/java/tck/graphql/dynamic/core/ArraysTest.java b/client/tck/src/main/java/tck/graphql/dynamic/core/ArraysTest.java index 1bbe582c4..2c93a7179 100644 --- a/client/tck/src/main/java/tck/graphql/dynamic/core/ArraysTest.java +++ b/client/tck/src/main/java/tck/graphql/dynamic/core/ArraysTest.java @@ -13,8 +13,6 @@ import java.math.BigDecimal; import java.math.BigInteger; import java.net.URISyntaxException; -import java.util.Arrays; -import java.util.List; import java.util.UUID; import org.junit.jupiter.api.Test; @@ -66,9 +64,9 @@ public void arraysTest() throws IOException, URISyntaxException { prop("stringArray", new String[] { "foo", "bar", "baz" }), - prop("uuidArray", new UUID[]{UUID.fromString("fc4bb4f4-13fe-4908-8d6a-afa64f1b56c9"), - UUID.fromString("863c9e3c-7538-41b9-9d63-0852f6a50815")}) - ))), + prop("uuidArray", + new UUID[] { UUID.fromString("fc4bb4f4-13fe-4908-8d6a-afa64f1b56c9"), + UUID.fromString("863c9e3c-7538-41b9-9d63-0852f6a50815") })))), field("boolPrimitiveArray"), field("boolObjectArray"), @@ -98,8 +96,7 @@ public void arraysTest() throws IOException, URISyntaxException { field("stringArray"), - field("uuidArray") - ))); + field("uuidArray")))); String generatedRequest = document.build(); AssertGraphQL.assertEquivalentGraphQLRequest(expectedRequest, generatedRequest); diff --git a/client/tck/src/main/java/tck/graphql/dynamic/core/IterableTest.java b/client/tck/src/main/java/tck/graphql/dynamic/core/IterableTest.java index d7eba23f6..5a45dfcd0 100644 --- a/client/tck/src/main/java/tck/graphql/dynamic/core/IterableTest.java +++ b/client/tck/src/main/java/tck/graphql/dynamic/core/IterableTest.java @@ -1,18 +1,5 @@ package tck.graphql.dynamic.core; -import io.smallrye.graphql.client.core.Document; -import org.junit.jupiter.api.Test; -import tck.graphql.dynamic.helper.AssertGraphQL; -import tck.graphql.dynamic.helper.Utils; - -import java.io.IOException; -import java.math.BigDecimal; -import java.math.BigInteger; -import java.net.URISyntaxException; -import java.util.List; -import java.util.Set; -import java.util.UUID; - import static io.smallrye.graphql.client.core.Argument.arg; import static io.smallrye.graphql.client.core.Argument.args; import static io.smallrye.graphql.client.core.Document.document; @@ -22,6 +9,19 @@ import static io.smallrye.graphql.client.core.Operation.operation; import static io.smallrye.graphql.client.core.OperationType.QUERY; +import java.io.IOException; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.net.URISyntaxException; +import java.util.List; +import java.util.UUID; + +import org.junit.jupiter.api.Test; + +import io.smallrye.graphql.client.core.Document; +import tck.graphql.dynamic.helper.AssertGraphQL; +import tck.graphql.dynamic.helper.Utils; + public class IterableTest { @Test @@ -36,31 +36,31 @@ public void iterableTest() throws IOException, URISyntaxException { prop("boolObjectList", List.of(true, false)), - prop("byteObjectList", List.of( (byte)0, (byte)2, (byte)3)), + prop("byteObjectList", List.of((byte) 0, (byte) 2, (byte) 3)), - prop("shortObjectList", List.of( (short)78,(short) 789,(short) 645 )), + prop("shortObjectList", List.of((short) 78, (short) 789, (short) 645)), - prop("intObjectList", List.of( 78, 65, 12354 )), + prop("intObjectList", List.of(78, 65, 12354)), - prop("longObjectList", List.of( 789L, 947894L, 1874448L )), + prop("longObjectList", List.of(789L, 947894L, 1874448L)), - prop("floatObjectList", List.of( 1567.654f, 8765f, 123789456.1851f )), + prop("floatObjectList", List.of(1567.654f, 8765f, 123789456.1851f)), - prop("doubleObjectList", List.of( 789.3242d, 1815d, 98765421.654897d )), + prop("doubleObjectList", List.of(789.3242d, 1815d, 98765421.654897d)), prop("bigIntegerList", - List.of( BigInteger.ZERO, BigInteger.ONE, BigInteger.TEN )), + List.of(BigInteger.ZERO, BigInteger.ONE, BigInteger.TEN)), prop("bigDecimalList", - List.of( BigDecimal.ZERO, BigDecimal.ONE, BigDecimal.TEN )), + List.of(BigDecimal.ZERO, BigDecimal.ONE, BigDecimal.TEN)), - prop("charObjectList", List.of( 'f', 'o', 'o' )), + prop("charObjectList", List.of('f', 'o', 'o')), - prop("stringList", List.of( "foo", "bar", "baz" )), + prop("stringList", List.of("foo", "bar", "baz")), prop("uuidList", - List.of(UUID.fromString("fc4bb4f4-13fe-4908-8d6a-afa64f1b56c9"), - UUID.fromString("863c9e3c-7538-41b9-9d63-0852f6a50815"))) + List.of(UUID.fromString("fc4bb4f4-13fe-4908-8d6a-afa64f1b56c9"), + UUID.fromString("863c9e3c-7538-41b9-9d63-0852f6a50815"))) ))), field("boolObjectList"), @@ -85,8 +85,7 @@ public void iterableTest() throws IOException, URISyntaxException { field("stringList"), - field("uuidList") - ))); + field("uuidList")))); String generatedRequest = document.build(); AssertGraphQL.assertEquivalentGraphQLRequest(expectedRequest, generatedRequest); From 690bbe352eb33c7dc065d561b1b9348f2f891f93 Mon Sep 17 00:00:00 2001 From: Jan Martiska Date: Thu, 5 Jan 2023 18:43:19 +0100 Subject: [PATCH 04/11] Increase timeouts in DynamicClientSSLTestCase, use try-with-resources --- .../vertx/test/ssl/DynamicClientSSLTest.java | 51 ++++++++----------- 1 file changed, 20 insertions(+), 31 deletions(-) diff --git a/client/implementation-vertx/src/test/java/io/smallrye/graphql/client/vertx/test/ssl/DynamicClientSSLTest.java b/client/implementation-vertx/src/test/java/io/smallrye/graphql/client/vertx/test/ssl/DynamicClientSSLTest.java index 78ba46ac0..ba46ca245 100644 --- a/client/implementation-vertx/src/test/java/io/smallrye/graphql/client/vertx/test/ssl/DynamicClientSSLTest.java +++ b/client/implementation-vertx/src/test/java/io/smallrye/graphql/client/vertx/test/ssl/DynamicClientSSLTest.java @@ -13,6 +13,7 @@ public class DynamicClientSSLTest { + public static final Duration TIMEOUT = Duration.ofSeconds(20); private SSLTestingTools tools = new SSLTestingTools(); /** @@ -25,12 +26,12 @@ public void serverAuthentication_correctTruststore() throws Exception { System.setProperty("myclient1/mp-graphql/truststore", "classpath:ssl/client.pkcs12.truststore"); System.setProperty("myclient1/mp-graphql/truststorePassword", "clienttruststorepassword"); System.setProperty("myclient1/mp-graphql/truststoreType", "PKCS12"); - DynamicGraphQLClient client = DynamicGraphQLClientBuilder.newBuilder() + try (DynamicGraphQLClient client = DynamicGraphQLClientBuilder.newBuilder() .configKey("myclient1") .url("https://127.0.0.1:" + server.actualPort()) - .build(); - client.executeAsync("asd").await().atMost(Duration.ofSeconds(1)); - client.close(); + .build()) { + client.executeAsync("asd").await().atMost(TIMEOUT); + } } finally { server.close(); } @@ -47,21 +48,15 @@ public void serverAuthentication_badKeystoreOnServer() throws Exception { System.setProperty("myclient2/mp-graphql/truststore", "classpath:ssl/client.pkcs12.truststore"); System.setProperty("myclient2/mp-graphql/truststorePassword", "clienttruststorepassword"); System.setProperty("myclient2/mp-graphql/truststoreType", "PKCS12"); - DynamicGraphQLClient client = null; - try { - client = DynamicGraphQLClientBuilder.newBuilder() - .configKey("myclient2") - .url("https://127.0.0.1:" + server.actualPort()) - .build(); - client.executeAsync("asd").await().atMost(Duration.ofSeconds(1)); + try (DynamicGraphQLClient client = DynamicGraphQLClientBuilder.newBuilder() + .configKey("myclient2") + .url("https://127.0.0.1:" + server.actualPort()) + .build()) { + client.executeAsync("asd").await().atMost(TIMEOUT); Assertions.fail("Connection to server should fail"); } catch (Exception e) { // verify that the client rejected the server's certificate assertHasCauseContainingMessage(e, "unable to find valid certification path to requested target"); - } finally { - if (client != null) { - client.close(); - } } } finally { server.close(); @@ -81,13 +76,13 @@ public void clientAuthentication_correctKeystore() throws Exception { System.setProperty("myclient3/mp-graphql/keystoreType", "PKCS12"); WebClientOptions options = new WebClientOptions(); options.setTrustAll(true); // don't require server auth - DynamicGraphQLClient client = new VertxDynamicGraphQLClientBuilder() + try (DynamicGraphQLClient client = new VertxDynamicGraphQLClientBuilder() .configKey("myclient3") .options(options) .url("https://127.0.0.1:" + server.actualPort()) - .build(); - client.executeAsync("asd").await().atMost(Duration.ofSeconds(1)); - client.close(); + .build()) { + client.executeAsync("asd").await().atMost(TIMEOUT); + } } finally { server.close(); } @@ -106,22 +101,16 @@ public void clientAuthentication_badKeystore() throws Exception { System.setProperty("myclient4/mp-graphql/keystoreType", "PKCS12"); WebClientOptions options = new WebClientOptions(); options.setTrustAll(true); // don't require server auth - DynamicGraphQLClient client = null; - try { - client = new VertxDynamicGraphQLClientBuilder() - .configKey("myclient4") - .options(options) - .url("https://127.0.0.1:" + server.actualPort()) - .build(); - client.executeAsync("asd").await().atMost(Duration.ofSeconds(1)); + try (DynamicGraphQLClient client = new VertxDynamicGraphQLClientBuilder() + .configKey("myclient4") + .options(options) + .url("https://127.0.0.1:" + server.actualPort()) + .build()) { + client.executeAsync("asd").await().atMost(TIMEOUT); Assertions.fail("Connection to server should fail"); } catch (Exception e) { // verify that the server rejected the client's certificate assertHasCauseContainingMessage(e, "Received fatal alert: bad_certificate"); - } finally { - if (client != null) { - client.close(); - } } } finally { server.close(); From 2c0a6d09a7cd8987b52d6d07624d1a62298294be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=BCdiger=20zu=20Dohna?= Date: Fri, 6 Jan 2023 12:05:12 +0100 Subject: [PATCH 05/11] 1670 repeatable directives (#1675) * maven-cache the github setup-java action * fix #1670: make `@Key` and `@Provides` repeatable and allow directives to be repeatable. Update the federation annotation documentation and fix some deprecations. * #1670: make `@Key` and `@Provides` repeatable and allow directives to be repeatable. Update the federation annotation documentation and fix some deprecations. (squashed) * #1670: update documentation --- .../smallrye/graphql/schema/Annotations.java | 29 +++- .../schema/creator/DirectiveTypeCreator.java | 3 +- .../graphql/schema/creator/ModelCreator.java | 8 +- .../schema/creator/type/AbstractCreator.java | 6 +- .../schema/creator/type/EnumCreator.java | 2 +- .../schema/creator/type/InputTypeCreator.java | 4 +- .../graphql/schema/helper/Directives.java | 21 +-- docs/directives.md | 17 +- docs/federation.md | 8 +- .../graphql/api/federation/Extends.java | 11 +- .../graphql/api/federation/External.java | 16 +- .../smallrye/graphql/api/federation/Key.java | 27 ++- .../graphql/api/federation/Provides.java | 24 ++- .../graphql/api/federation/Requires.java | 14 +- .../graphql/entry/http/IndexInitializer.java | 2 + .../smallrye/graphql/schema/SchemaTest.java | 161 +++++++++++------- .../schema/TestTypeWithFederation.java | 19 +++ 17 files changed, 260 insertions(+), 112 deletions(-) diff --git a/common/schema-builder/src/main/java/io/smallrye/graphql/schema/Annotations.java b/common/schema-builder/src/main/java/io/smallrye/graphql/schema/Annotations.java index a0c88dc72..25f2636ff 100644 --- a/common/schema-builder/src/main/java/io/smallrye/graphql/schema/Annotations.java +++ b/common/schema-builder/src/main/java/io/smallrye/graphql/schema/Annotations.java @@ -9,6 +9,7 @@ import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; +import java.util.stream.Stream; import org.jboss.jandex.AnnotationInstance; import org.jboss.jandex.AnnotationTarget; @@ -76,7 +77,7 @@ private static Map getParentAnnotations(FieldInfo f private static Map getParentAnnotations(ClassInfo classInfo) { Map parentAnnotations = new HashMap<>(); - for (AnnotationInstance classAnnotation : classInfo.classAnnotations()) { + for (AnnotationInstance classAnnotation : classInfo.declaredAnnotations()) { parentAnnotations.putIfAbsent(classAnnotation.name(), classAnnotation); } @@ -95,7 +96,7 @@ private static Map getPackageAnnotations(ClassInfo if (packageName != null) { ClassInfo packageInfo = ScanningContext.getIndex().getClassByName(packageName); if (packageInfo != null) { - for (AnnotationInstance packageAnnotation : packageInfo.classAnnotations()) { + for (AnnotationInstance packageAnnotation : packageInfo.declaredAnnotations()) { packageAnnotations.putIfAbsent(packageAnnotation.name(), packageAnnotation); } } @@ -178,7 +179,7 @@ public static Annotations getAnnotationsForClass(ClassInfo classInfo) { Map annotationMap = new HashMap<>(); - for (AnnotationInstance annotationInstance : classInfo.classAnnotations()) { + for (AnnotationInstance annotationInstance : classInfo.declaredAnnotations()) { DotName name = annotationInstance.name(); annotationMap.put(name, annotationInstance); } @@ -390,6 +391,25 @@ public Optional getOneOfTheseMethodParameterAnnotationsValue(DotName... return Optional.empty(); } + /** + * Get a stream of that annotation, maybe empty if not present, maybe a stream of one, or maybe several, if it's repeatable. + */ + public Stream resolve(DotName name) { + var annotationInstance = annotationsMap.get(name); + if (annotationInstance == null) { + var repeatableType = ScanningContext.getIndex().getClassByName(name); + if (repeatableType.hasAnnotation(REPEATABLE)) { + DotName containerName = repeatableType.annotation(REPEATABLE).value().asClass().name(); + AnnotationInstance containerAnnotation = annotationsMap.get(containerName); + if (containerAnnotation != null) { + return Stream.of(containerAnnotation.value().asNestedArray()); + } + } + return Stream.of(); + } + return Stream.of(annotationInstance); + } + @Override public String toString() { return annotationsMap.toString(); @@ -558,6 +578,8 @@ private static Map getAnnotationsWithFilter(org.jbo private static final short ZERO = 0; + public static final DotName REPEATABLE = DotName.createSimple("java.lang.annotation.Repeatable"); + // SmallRye Common Annotations public static final DotName BLOCKING = DotName.createSimple("io.smallrye.common.annotation.Blocking"); public static final DotName NON_BLOCKING = DotName.createSimple("io.smallrye.common.annotation.NonBlocking"); @@ -629,5 +651,4 @@ private static Map getAnnotationsWithFilter(org.jbo //Kotlin NotNull public static final DotName KOTLIN_NOT_NULL = DotName.createSimple("org.jetbrains.annotations.NotNull"); - } diff --git a/common/schema-builder/src/main/java/io/smallrye/graphql/schema/creator/DirectiveTypeCreator.java b/common/schema-builder/src/main/java/io/smallrye/graphql/schema/creator/DirectiveTypeCreator.java index 630766edb..f60ceb07c 100644 --- a/common/schema-builder/src/main/java/io/smallrye/graphql/schema/creator/DirectiveTypeCreator.java +++ b/common/schema-builder/src/main/java/io/smallrye/graphql/schema/creator/DirectiveTypeCreator.java @@ -34,7 +34,8 @@ public DirectiveType create(ClassInfo classInfo) { directiveType.setClassName(classInfo.name().toString()); directiveType.setName(toDirectiveName(classInfo, annotations)); directiveType.setDescription(DescriptionHelper.getDescriptionForType(annotations).orElse(null)); - directiveType.setLocations(getLocations(classInfo.classAnnotation(DIRECTIVE))); + directiveType.setLocations(getLocations(classInfo.declaredAnnotation(DIRECTIVE))); + directiveType.setRepeatable(classInfo.hasAnnotation(Annotations.REPEATABLE)); for (MethodInfo method : classInfo.methods()) { DirectiveArgument argument = new DirectiveArgument(); diff --git a/common/schema-builder/src/main/java/io/smallrye/graphql/schema/creator/ModelCreator.java b/common/schema-builder/src/main/java/io/smallrye/graphql/schema/creator/ModelCreator.java index 7b27d67e8..7c07851b8 100644 --- a/common/schema-builder/src/main/java/io/smallrye/graphql/schema/creator/ModelCreator.java +++ b/common/schema-builder/src/main/java/io/smallrye/graphql/schema/creator/ModelCreator.java @@ -53,10 +53,7 @@ protected static Type getReturnType(MethodInfo methodInfo) { } /** - * The the return type.This is usually the method return type, but can also be adapted to something else - * - * @param fieldInfo - * @return the return type + * The return type. This is usually the method return type, but can also be adapted to something else */ protected static Type getReturnType(FieldInfo fieldInfo) { return fieldInfo.type(); @@ -100,8 +97,7 @@ private void doPopulateField(Direction direction, Field field, Type type, Annota // Directives if (directives != null) { // this happens while scanning for the directive types - field.addDirectiveInstances( - directives.buildDirectiveInstances(name -> annotations.getOneOfTheseAnnotations(name).orElse(null))); + field.addDirectiveInstances(directives.buildDirectiveInstances(annotations)); } } } diff --git a/common/schema-builder/src/main/java/io/smallrye/graphql/schema/creator/type/AbstractCreator.java b/common/schema-builder/src/main/java/io/smallrye/graphql/schema/creator/type/AbstractCreator.java index ce5a2e944..4d6e662b8 100644 --- a/common/schema-builder/src/main/java/io/smallrye/graphql/schema/creator/type/AbstractCreator.java +++ b/common/schema-builder/src/main/java/io/smallrye/graphql/schema/creator/type/AbstractCreator.java @@ -74,15 +74,15 @@ public Type create(ClassInfo classInfo, Reference reference) { addOperations(type, classInfo); // Directives - addDirectives(type, classInfo); + addDirectives(type, annotations); return type; } protected abstract void addFields(Type type, ClassInfo classInfo, Reference reference); - private void addDirectives(Type type, ClassInfo classInfo) { - type.setDirectiveInstances(directives.buildDirectiveInstances(classInfo::classAnnotation)); + private void addDirectives(Type type, Annotations annotations) { + type.setDirectiveInstances(directives.buildDirectiveInstances(annotations)); } private void addPolymorphicTypes(Type type, ClassInfo classInfo, Reference reference) { diff --git a/common/schema-builder/src/main/java/io/smallrye/graphql/schema/creator/type/EnumCreator.java b/common/schema-builder/src/main/java/io/smallrye/graphql/schema/creator/type/EnumCreator.java index d352b1eec..fb8e854f9 100644 --- a/common/schema-builder/src/main/java/io/smallrye/graphql/schema/creator/type/EnumCreator.java +++ b/common/schema-builder/src/main/java/io/smallrye/graphql/schema/creator/type/EnumCreator.java @@ -78,7 +78,7 @@ public EnumType create(ClassInfo classInfo, Reference reference) { } private List getDirectiveInstances(Annotations annotations) { - return directives.buildDirectiveInstances(dotName -> annotations.getOneOfTheseAnnotations(dotName).orElse(null)); + return directives.buildDirectiveInstances(annotations); } } diff --git a/common/schema-builder/src/main/java/io/smallrye/graphql/schema/creator/type/InputTypeCreator.java b/common/schema-builder/src/main/java/io/smallrye/graphql/schema/creator/type/InputTypeCreator.java index d8c3c80b0..f99358bd1 100644 --- a/common/schema-builder/src/main/java/io/smallrye/graphql/schema/creator/type/InputTypeCreator.java +++ b/common/schema-builder/src/main/java/io/smallrye/graphql/schema/creator/type/InputTypeCreator.java @@ -29,7 +29,7 @@ /** * This creates an input type object. - * + * * The input object has fields that might reference other types * that should still be created. * @@ -138,7 +138,7 @@ public void setDirectives(Directives directives) { } private List getDirectiveInstances(Annotations annotations) { - return directives.buildDirectiveInstances(dotName -> annotations.getOneOfTheseAnnotations(dotName).orElse(null)); + return directives.buildDirectiveInstances(annotations); } private void addFields(InputType inputType, ClassInfo classInfo, Reference reference) { diff --git a/common/schema-builder/src/main/java/io/smallrye/graphql/schema/helper/Directives.java b/common/schema-builder/src/main/java/io/smallrye/graphql/schema/helper/Directives.java index a008e1e4d..df781c129 100644 --- a/common/schema-builder/src/main/java/io/smallrye/graphql/schema/helper/Directives.java +++ b/common/schema-builder/src/main/java/io/smallrye/graphql/schema/helper/Directives.java @@ -1,17 +1,18 @@ package io.smallrye.graphql.schema.helper; +import static java.util.stream.Collectors.toList; import static org.jboss.jandex.AnnotationValue.Kind.ARRAY; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.function.Function; import org.jboss.jandex.AnnotationInstance; import org.jboss.jandex.AnnotationValue; import org.jboss.jandex.DotName; +import io.smallrye.graphql.schema.Annotations; import io.smallrye.graphql.schema.model.DirectiveInstance; import io.smallrye.graphql.schema.model.DirectiveType; @@ -37,21 +38,13 @@ public Directives(List directiveTypes) { } } - public List buildDirectiveInstances(Function getAnnotation) { - List result = null; + public List buildDirectiveInstances(Annotations annotations) { // only build directive instances from `@Directive` annotations here (that means the `directiveTypes` map), // because `directiveTypesOther` directives get their instances added on-the-go by classes that extend `ModelCreator` - for (DotName directiveTypeName : directiveTypes.keySet()) { - AnnotationInstance annotationInstance = getAnnotation.apply(directiveTypeName); - if (annotationInstance == null) { - continue; - } - if (result == null) { - result = new ArrayList<>(); - } - result.add(toDirectiveInstance(annotationInstance)); - } - return result; + return directiveTypes.keySet().stream() + .flatMap(annotations::resolve) + .map(this::toDirectiveInstance) + .collect(toList()); } private DirectiveInstance toDirectiveInstance(AnnotationInstance annotationInstance) { diff --git a/docs/directives.md b/docs/directives.md index 139e1e2a4..8902f10e4 100644 --- a/docs/directives.md +++ b/docs/directives.md @@ -1,5 +1,20 @@ # Directives +## Custom Directives + +You can add your own [GraphQL Directives](https://spec.graphql.org/draft/#sec-Language.Directives) by writing +a corresponding Java Annotation and annotate it as `@Directive`, e.g.: + +```java +@Directive(on = { OBJECT, INTERFACE }) +@Description("Just a test") +@Retention(RUNTIME) +public @interface MyDirective { +} +``` + +Directives can be repeatable, see the `@Key` annotation for an example. + ## Directives generated from Bean Validation annotations If your project uses Bean Validation to validate fields on input types and operation arguments, and you enable @@ -23,4 +38,4 @@ BV annotations are listed here): Note: The `@NotNull` annotation does not map to a directive, instead it makes the GraphQL type non-nullable. -Constraints will only appear on fields of input types and operation arguments. \ No newline at end of file +Constraints will only appear on fields of input types and operation arguments. diff --git a/docs/federation.md b/docs/federation.md index e7ee83088..7fbee7f22 100644 --- a/docs/federation.md +++ b/docs/federation.md @@ -1,6 +1,6 @@ # Federation -To enable support for [GraphQL Federation](https://www.apollographql.com/docs/federation), simply set the `smallrye.graphql.federation.enabled` config key to `true`. +Support for [GraphQL Federation](https://www.apollographql.com/docs/federation) is enabled by default. If you add one of the federation annotations, the corresponding directives will be declared to your schema and the additional Federation queries will be added automatically. You can also disable Federation completely by setting the `smallrye.graphql.federation.enabled` config key to `false`. You can add the Federation directives by using the equivalent Java annotation, e.g. to extend a `Product` entity with a `price` field, you can write a class: @@ -37,7 +37,7 @@ import org.eclipse.microprofile.graphql.Query; public class Prices { @Query public Product product(@Id String id) { - return ...; + return ... } } ``` @@ -45,7 +45,7 @@ public class Prices { The GraphQL Schema then contains: ```graphql -type Product @extends @key(fields : ["id"]) { +type Product @extends @key(fields : "id") { id: ID price: Int } @@ -58,3 +58,5 @@ type Query { product(id: ID): Product } ``` + +If you can resolve, e.g., the product with different types of ids, you can add multiple `@Key` annotations. diff --git a/server/api/src/main/java/io/smallrye/graphql/api/federation/Extends.java b/server/api/src/main/java/io/smallrye/graphql/api/federation/Extends.java index 2220567f0..49b3cdfa1 100644 --- a/server/api/src/main/java/io/smallrye/graphql/api/federation/Extends.java +++ b/server/api/src/main/java/io/smallrye/graphql/api/federation/Extends.java @@ -11,10 +11,15 @@ import io.smallrye.common.annotation.Experimental; import io.smallrye.graphql.api.Directive; -/** directive @extends on OBJECT | INTERFACE */ +/** + * directive @extends on OBJECT | INTERFACE + * + * @see federation + * spec + */ @Directive(on = { OBJECT, INTERFACE }) -@Description("Some libraries such as graphql-java don't have native support for type extensions in their printer. " + - "Apollo Federation supports using an @extends directive in place of extend type to annotate type references.") +@Description("Indicates that an object or interface definition is an extension of another definition of that same type.\n" + + "If your subgraph library supports GraphQL's built-in extend keyword, do not use this directive! Instead, use extend.") @Retention(RUNTIME) @Experimental("SmallRye GraphQL Federation is still subject to change. " + "Additionally, this annotation is currently only a directive without explicit support from the extension.") diff --git a/server/api/src/main/java/io/smallrye/graphql/api/federation/External.java b/server/api/src/main/java/io/smallrye/graphql/api/federation/External.java index 431a906cd..0bd2d3fd8 100644 --- a/server/api/src/main/java/io/smallrye/graphql/api/federation/External.java +++ b/server/api/src/main/java/io/smallrye/graphql/api/federation/External.java @@ -1,6 +1,7 @@ package io.smallrye.graphql.api.federation; import static io.smallrye.graphql.api.DirectiveLocation.FIELD_DEFINITION; +import static io.smallrye.graphql.api.DirectiveLocation.OBJECT; import static java.lang.annotation.RetentionPolicy.RUNTIME; import java.lang.annotation.Retention; @@ -10,10 +11,17 @@ import io.smallrye.common.annotation.Experimental; import io.smallrye.graphql.api.Directive; -/** directive @external on FIELD_DEFINITION */ -@Directive(on = FIELD_DEFINITION) -@Description("The @external directive is used to mark a field as owned by another service. " + - "This allows service A to use fields from service B while also knowing at runtime the types of that field.") +/** + * directive @external on FIELD_DEFINITION | OBJECT + * + * @see federation + * spec + */ +@Directive(on = { FIELD_DEFINITION, OBJECT }) +@Description("Indicates that this subgraph usually can't resolve a particular object field, but it still needs to define " + + "that field for other purposes.\n" + + "This directive is always used in combination with another directive that references object fields, " + + "such as @provides or @requires.") @Retention(RUNTIME) @Experimental("SmallRye GraphQL Federation is still subject to change.") public @interface External { diff --git a/server/api/src/main/java/io/smallrye/graphql/api/federation/Key.java b/server/api/src/main/java/io/smallrye/graphql/api/federation/Key.java index 6ae31a6df..4015e642a 100644 --- a/server/api/src/main/java/io/smallrye/graphql/api/federation/Key.java +++ b/server/api/src/main/java/io/smallrye/graphql/api/federation/Key.java @@ -4,6 +4,7 @@ import static io.smallrye.graphql.api.DirectiveLocation.OBJECT; import static java.lang.annotation.RetentionPolicy.RUNTIME; +import java.lang.annotation.Repeatable; import java.lang.annotation.Retention; import org.eclipse.microprofile.graphql.Description; @@ -11,14 +12,32 @@ import io.smallrye.common.annotation.Experimental; import io.smallrye.graphql.api.Directive; +import io.smallrye.graphql.api.federation.Key.Keys; -/** directive @key(fields: _FieldSet!) on OBJECT | INTERFACE */ +/** + * directive @key(fields: FieldSet!) repeatable on OBJECT | INTERFACE + * + * @see federation spec + */ @Directive(on = { OBJECT, INTERFACE }) -@Description("The @key directive is used to indicate a combination of fields that can be used to uniquely identify " + - "and fetch an object or interface.") +@Description("Designates an object type as an entity and specifies its key fields (a set of fields that the subgraph " + + "can use to uniquely identify any instance of the entity). You can apply multiple @key directives to " + + "a single entity (to specify multiple valid sets of key fields).") @Retention(RUNTIME) +@Repeatable(Keys.class) @Experimental("SmallRye GraphQL Federation is still subject to change.") public @interface Key { @NonNull - String[] fields(); + @Description("A GraphQL selection set (provided as a string) of fields and subfields that contribute " + + "to the entity's primary key.\n" + + "Examples:\n" + + "\"id\"\n" + + "\"username region\"\n" + + "\"name organization { id }\"") + String fields(); + + @Retention(RUNTIME) + @interface Keys { + Key[] value(); + } } diff --git a/server/api/src/main/java/io/smallrye/graphql/api/federation/Provides.java b/server/api/src/main/java/io/smallrye/graphql/api/federation/Provides.java index df63a6d2d..458622e13 100644 --- a/server/api/src/main/java/io/smallrye/graphql/api/federation/Provides.java +++ b/server/api/src/main/java/io/smallrye/graphql/api/federation/Provides.java @@ -11,13 +11,27 @@ import io.smallrye.common.annotation.Experimental; import io.smallrye.graphql.api.Directive; -/** directive @provides(fields: _FieldSet!) on FIELD_DEFINITION */ +/** + * directive @provides(fields: FieldSet!) on FIELD_DEFINITION + * + * @see federation + * spec + */ @Directive(on = FIELD_DEFINITION) -@Description("When resolving the annotated field, this service can provide additional, normally `@external` fields.") +@Description("Specifies a set of entity fields that a subgraph can resolve, but only at a particular schema path " + + "(at other paths, the subgraph can't resolve those fields).\n" + + "If a subgraph can always resolve a particular entity field, do not apply this directive.\n" + + "Using this directive is always an optional optimization. It can reduce the total number of subgraphs " + + "that your graph router needs to communicate with to resolve certain operations, which can improve performance.") @Retention(RUNTIME) -@Experimental("SmallRye GraphQL Federation is still subject to change. " + - "Additionally, this annotation is currently only a directive without explicit support from the extension.") +@Experimental("SmallRye GraphQL Federation is still subject to change.") public @interface Provides { @NonNull - String[] fields(); + @Description("A GraphQL selection set (provided as a string) of object fields and subfields that the subgraph " + + "can resolve only at this query path.\n" + + "Examples:\n" + + "\"name\"\n" + + "\"name address\"\n" + + "\"... on Person { name address }\" (valid for fields that return a union or interface)") + String fields(); } diff --git a/server/api/src/main/java/io/smallrye/graphql/api/federation/Requires.java b/server/api/src/main/java/io/smallrye/graphql/api/federation/Requires.java index 90cce5924..a4e81b0fd 100644 --- a/server/api/src/main/java/io/smallrye/graphql/api/federation/Requires.java +++ b/server/api/src/main/java/io/smallrye/graphql/api/federation/Requires.java @@ -11,14 +11,20 @@ import io.smallrye.common.annotation.Experimental; import io.smallrye.graphql.api.Directive; -/** directive @requires(fields: _FieldSet!) on FIELD_DEFINITION */ +/** + * directive @requires(fields: FieldSet!) on FIELD_DEFINITION + * + * @see federation + * spec + */ @Directive(on = FIELD_DEFINITION) -@Description("In order to resolve the annotated field, this service needs these additional `@external` fields, " + - "even when the client didn't request them.") +@Description("Indicates that the resolver for a particular entity field depends on the values of other entity fields " + + "that are resolved by other subgraphs. This tells the graph router that it needs to fetch the values " + + "of those externally defined fields first, even if the original client query didn't request them.") @Retention(RUNTIME) @Experimental("SmallRye GraphQL Federation is still subject to change. " + "Additionally, this annotation is currently only a directive without explicit support from the extension.") public @interface Requires { @NonNull - String[] fields(); + String fields(); } diff --git a/server/implementation-servlet/src/main/java/io/smallrye/graphql/entry/http/IndexInitializer.java b/server/implementation-servlet/src/main/java/io/smallrye/graphql/entry/http/IndexInitializer.java index 6a360b923..f9f6f1093 100644 --- a/server/implementation-servlet/src/main/java/io/smallrye/graphql/entry/http/IndexInitializer.java +++ b/server/implementation-servlet/src/main/java/io/smallrye/graphql/entry/http/IndexInitializer.java @@ -2,6 +2,7 @@ import java.io.IOException; import java.io.InputStream; +import java.lang.annotation.Repeatable; import java.net.MalformedURLException; import java.net.URISyntaxException; import java.net.URL; @@ -78,6 +79,7 @@ private IndexView createCustomIndex() { try { indexer.index(convertClassToInputStream(Map.class)); indexer.index(convertClassToInputStream(Entry.class)); + indexer.index(convertClassToInputStream(Repeatable.class)); // things from the API module indexer.index(convertClassToInputStream(Extends.class)); diff --git a/server/implementation/src/test/java/io/smallrye/graphql/schema/SchemaTest.java b/server/implementation/src/test/java/io/smallrye/graphql/schema/SchemaTest.java index becceb117..35272bc27 100644 --- a/server/implementation/src/test/java/io/smallrye/graphql/schema/SchemaTest.java +++ b/server/implementation/src/test/java/io/smallrye/graphql/schema/SchemaTest.java @@ -1,5 +1,9 @@ package io.smallrye.graphql.schema; +import static graphql.Scalars.GraphQLString; +import static graphql.introspection.Introspection.DirectiveLocation.INTERFACE; +import static graphql.introspection.Introspection.DirectiveLocation.OBJECT; +import static java.util.Objects.requireNonNull; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; @@ -9,8 +13,10 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.lang.annotation.Repeatable; import java.net.URISyntaxException; import java.nio.file.Files; +import java.util.EnumSet; import java.util.stream.Stream; import org.jboss.jandex.IndexView; @@ -25,9 +31,12 @@ import graphql.schema.GraphQLFieldDefinition; import graphql.schema.GraphQLInputObjectType; import graphql.schema.GraphQLObjectType; +import graphql.schema.GraphQLScalarType; import graphql.schema.GraphQLSchema; +import graphql.schema.GraphQLUnionType; import io.smallrye.graphql.api.Directive; import io.smallrye.graphql.api.federation.Key; +import io.smallrye.graphql.api.federation.Key.Keys; import io.smallrye.graphql.bootstrap.Bootstrap; import io.smallrye.graphql.execution.SchemaPrinter; import io.smallrye.graphql.execution.TestConfig; @@ -76,8 +85,8 @@ void testSchemaWithDirectives() throws URISyntaxException, IOException { assertOperationWithDirectives(graphQLSchema.getSubscriptionType().getField("subscriptionWithDirectives")); String actualSchema = new SchemaPrinter().print(graphQLSchema); - String expectedSchema = Files - .readString(new File(SchemaTest.class.getResource("/schemaTest.graphql").toURI()).toPath()); + var schemaUri = requireNonNull(SchemaTest.class.getResource("/schemaTest.graphql")).toURI(); + String expectedSchema = Files.readString(new File(schemaUri).toPath()); Assertions.assertEquals(expectedSchema, actualSchema); } @@ -91,12 +100,8 @@ void schemaWithEnumDirectives() { "Enum EnumWithDirectives should have directive @enumDirective"); assertNotNull(enumWithDirectives.getValue("A").getDirective("enumDirective"), "Enum value EnumWithDirectives.A should have directive @enumDirective"); - - assertSchemaEndsWith(graphQLSchema, "" + - "enum EnumWithDirectives @enumDirective {\n" + - " A @enumDirective\n" + - " B\n" + - "}\n"); + assertNull(enumWithDirectives.getValue("B").getDirective("enumDirective"), + "Enum value EnumWithDirectives.B should not have directive @enumDirective"); } @Test @@ -111,53 +116,105 @@ void schemaWithInputDirectives() { "Input type field InputWithDirectivesInput.foo should have directive @inputDirective"); assertNotNull(inputWithDirectives.getField("bar").getDirective("inputDirective"), "Input type field InputWithDirectivesInput.bar should have directive @inputDirective"); - - assertSchemaEndsWith(graphQLSchema, "" + - "input InputWithDirectivesInput @inputDirective {\n" + - " bar: Int! @inputDirective\n" + - " foo: Int! @inputDirective\n" + - "}\n"); } @Test void testSchemaWithFederationDisabled() { - GraphQLSchema graphQLSchema = createGraphQLSchema(Directive.class, Key.class, TestTypeWithFederation.class, - FederationTestApi.class); - - assertSchemaEndsWith(graphQLSchema, "\n" + - "\"Query root\"\n" + - "type Query {\n" + - " testTypeWithFederation(arg: String): TestTypeWithFederation\n" + - "}\n" + - "\n" + - "type TestTypeWithFederation @key(fields : [\"id\"]) {\n" + - " id: String\n" + - "}\n"); + GraphQLSchema graphQLSchema = createGraphQLSchema(Directive.class, Key.class, Keys.class, + TestTypeWithFederation.class, FederationTestApi.class); + + assertNotNull(graphQLSchema.getDirective("key")); + assertNull(graphQLSchema.getType("_Entity")); + + GraphQLObjectType queryRoot = graphQLSchema.getQueryType(); + assertEquals(1, queryRoot.getFields().size()); + assertNull(queryRoot.getField("_entities")); + assertNull(queryRoot.getField("_service")); + + GraphQLFieldDefinition query = queryRoot.getField("testTypeWithFederation"); + assertEquals(1, query.getArguments().size()); + assertEquals(GraphQLString, query.getArgument("arg").getType()); + assertEquals("TestTypeWithFederation", ((GraphQLObjectType) query.getType()).getName()); + + GraphQLObjectType type = graphQLSchema.getObjectType("TestTypeWithFederation"); + assertEquals(2, type.getDirectives().size()); + assertKeyDirective(type.getDirectives().get(0), "id"); + assertKeyDirective(type.getDirectives().get(1), "type id"); + assertEquals(3, type.getFields().size()); + assertEquals("id", type.getFields().get(0).getName()); + assertEquals(GraphQLString, type.getFields().get(0).getType()); + assertEquals("type", type.getFields().get(1).getName()); + assertEquals(GraphQLString, type.getFields().get(1).getType()); + assertEquals("value", type.getFields().get(2).getName()); + assertEquals(GraphQLString, type.getFields().get(2).getType()); + + assertNull(graphQLSchema.getObjectType("_Service")); } @Test - void testSchemaWithFederation() { + void testSchemaWithFederationEnabled() { config.federationEnabled = true; - GraphQLSchema graphQLSchema = createGraphQLSchema(Directive.class, Key.class, TestTypeWithFederation.class, - FederationTestApi.class); - - assertSchemaEndsWith(graphQLSchema, "\n" + - "union _Entity = TestTypeWithFederation\n" + - "\n" + - "\"Query root\"\n" + - "type Query {\n" + - " _entities(representations: [_Any!]!): [_Entity]!\n" + - " _service: _Service!\n" + - " testTypeWithFederation(arg: String): TestTypeWithFederation\n" + - "}\n" + - "\n" + - "type TestTypeWithFederation @key(fields : [\"id\"]) {\n" + - " id: String\n" + - "}\n" + - "\n" + - "type _Service {\n" + - " sdl: String!\n" + - "}\n"); + GraphQLSchema graphQLSchema = createGraphQLSchema(Repeatable.class, Directive.class, Key.class, Keys.class, + TestTypeWithFederation.class, FederationTestApi.class); + + GraphQLDirective keyDirective = graphQLSchema.getDirective("key"); + assertEquals("key", keyDirective.getName()); + assertTrue(keyDirective.isRepeatable()); + assertEquals( + "Designates an object type as an entity and specifies its key fields " + + "(a set of fields that the subgraph can use to uniquely identify any instance " + + "of the entity). You can apply multiple @key directives to a single entity " + + "(to specify multiple valid sets of key fields).", + keyDirective.getDescription()); + assertEquals(EnumSet.of(OBJECT, INTERFACE), keyDirective.validLocations()); + assertEquals(1, keyDirective.getArguments().size()); + assertEquals("String", ((GraphQLScalarType) keyDirective.getArgument("fields").getType()).getName()); + + GraphQLUnionType entityType = (GraphQLUnionType) graphQLSchema.getType("_Entity"); + assertNotNull(entityType); + assertEquals(1, entityType.getTypes().size()); + assertEquals(TestTypeWithFederation.class.getSimpleName(), entityType.getTypes().get(0).getName()); + + GraphQLObjectType queryRoot = graphQLSchema.getQueryType(); + assertEquals(3, queryRoot.getFields().size()); + + GraphQLFieldDefinition entities = queryRoot.getField("_entities"); + assertEquals(1, entities.getArguments().size()); + assertEquals("[_Any!]!", entities.getArgument("representations").getType().toString()); + assertEquals("[_Entity]!", entities.getType().toString()); + + GraphQLFieldDefinition service = queryRoot.getField("_service"); + assertEquals(0, service.getArguments().size()); + assertEquals("_Service!", service.getType().toString()); + + GraphQLFieldDefinition query = queryRoot.getField("testTypeWithFederation"); + assertEquals(1, query.getArguments().size()); + assertEquals(GraphQLString, query.getArgument("arg").getType()); + assertEquals("TestTypeWithFederation", ((GraphQLObjectType) query.getType()).getName()); + + GraphQLObjectType type = graphQLSchema.getObjectType("TestTypeWithFederation"); + assertEquals(2, type.getDirectives().size()); + assertKeyDirective(type.getDirectives().get(0), "id"); + assertKeyDirective(type.getDirectives().get(1), "type id"); + assertEquals(3, type.getFields().size()); + assertEquals("id", type.getFields().get(0).getName()); + assertEquals(GraphQLString, type.getFields().get(0).getType()); + assertEquals("type", type.getFields().get(1).getName()); + assertEquals(GraphQLString, type.getFields().get(1).getType()); + assertEquals("value", type.getFields().get(2).getName()); + assertEquals(GraphQLString, type.getFields().get(2).getType()); + + GraphQLObjectType serviceType = graphQLSchema.getObjectType("_Service"); + assertEquals(1, serviceType.getFields().size()); + assertEquals("sdl", serviceType.getFields().get(0).getName()); + assertEquals("String!", serviceType.getFields().get(0).getType().toString()); + } + + private static void assertKeyDirective(GraphQLDirective graphQLDirective, String value) { + assertEquals("key", graphQLDirective.getName()); + assertEquals(1, graphQLDirective.getArguments().size()); + assertEquals("fields", graphQLDirective.getArguments().get(0).getName()); + assertEquals(value, graphQLDirective.getArguments().get(0).toAppliedArgument().getArgumentValue().getValue()); } private GraphQLSchema createGraphQLSchema(Class... api) { @@ -168,16 +225,6 @@ private GraphQLSchema createGraphQLSchema(Class... api) { return graphQLSchema; } - private static void assertSchemaEndsWith(GraphQLSchema schema, String end) { - String schemaString = new SchemaPrinter().print(schema); - assertSchemaEndsWith(schemaString, end); - } - - private static void assertSchemaEndsWith(String schema, String end) { - // assertEquals(schema, end); // this is convenient for debugging, as the IDE can show the diff - assertTrue(schema.endsWith(end), () -> "<<<\n" + schema + "\n>>> does not end with <<<\n" + end + "\n>>>"); - } - private void assertOperationWithDirectives(GraphQLFieldDefinition operation) { String name = operation.getName(); GraphQLDirective operationDirective = operation.getDirective("operationDirective"); diff --git a/server/implementation/src/test/java/io/smallrye/graphql/schema/TestTypeWithFederation.java b/server/implementation/src/test/java/io/smallrye/graphql/schema/TestTypeWithFederation.java index a9d85d831..b7bad7272 100644 --- a/server/implementation/src/test/java/io/smallrye/graphql/schema/TestTypeWithFederation.java +++ b/server/implementation/src/test/java/io/smallrye/graphql/schema/TestTypeWithFederation.java @@ -3,8 +3,19 @@ import io.smallrye.graphql.api.federation.Key; @Key(fields = "id") +@Key(fields = "type id") public class TestTypeWithFederation { + private String type; private String id; + private String value; + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } public String getId() { return id; @@ -13,4 +24,12 @@ public String getId() { public void setId(String id) { this.id = id; } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } } From b5c31126a923688f03c399ae99cb15e1ba7734af Mon Sep 17 00:00:00 2001 From: Jan Martiska Date: Fri, 6 Jan 2023 10:14:04 +0100 Subject: [PATCH 06/11] Only add Federation-related directive types to the schema if Federation is enabled --- .../graphql/schema/SchemaBuilder.java | 10 +- .../smallrye/graphql/schema/SchemaTest.java | 124 ++++++++++-------- server/tck/pom.xml | 3 + 3 files changed, 78 insertions(+), 59 deletions(-) diff --git a/common/schema-builder/src/main/java/io/smallrye/graphql/schema/SchemaBuilder.java b/common/schema-builder/src/main/java/io/smallrye/graphql/schema/SchemaBuilder.java index f9b382c24..4cc790c13 100644 --- a/common/schema-builder/src/main/java/io/smallrye/graphql/schema/SchemaBuilder.java +++ b/common/schema-builder/src/main/java/io/smallrye/graphql/schema/SchemaBuilder.java @@ -69,6 +69,8 @@ public class SchemaBuilder { private final DirectiveTypeCreator directiveTypeCreator; private final UnionCreator unionCreator; + private final DotName FEDERATION_ANNOTATIONS_PACKAGE = DotName.createSimple("io.smallrye.graphql.api.federation"); + /** * This builds the Schema from Jandex * @@ -160,7 +162,13 @@ private void addDirectiveTypes(Schema schema) { // custom directives from annotations for (AnnotationInstance annotationInstance : ScanningContext.getIndex().getAnnotations(DIRECTIVE)) { ClassInfo classInfo = annotationInstance.target().asClass(); - schema.addDirectiveType(directiveTypeCreator.create(classInfo)); + boolean federationEnabled = Boolean.getBoolean("smallrye.graphql.federation.enabled"); + // only add federation-related directive types to the schema if federation is enabled + DotName packageName = classInfo.name().packagePrefixName(); + if (packageName == null || !packageName.equals(FEDERATION_ANNOTATIONS_PACKAGE) || federationEnabled) { + schema.addDirectiveType(directiveTypeCreator.create(classInfo)); + } + } // bean validation directives schema.addDirectiveType(BeanValidationDirectivesHelper.CONSTRAINT_DIRECTIVE_TYPE); diff --git a/server/implementation/src/test/java/io/smallrye/graphql/schema/SchemaTest.java b/server/implementation/src/test/java/io/smallrye/graphql/schema/SchemaTest.java index 35272bc27..1eb3dea3b 100644 --- a/server/implementation/src/test/java/io/smallrye/graphql/schema/SchemaTest.java +++ b/server/implementation/src/test/java/io/smallrye/graphql/schema/SchemaTest.java @@ -120,10 +120,14 @@ void schemaWithInputDirectives() { @Test void testSchemaWithFederationDisabled() { + config.federationEnabled = false; + // need to set it as system property because the SchemaBuilder doesn't have access to the Config object + System.setProperty("smallrye.graphql.federation.enabled", "false"); + GraphQLSchema graphQLSchema = createGraphQLSchema(Directive.class, Key.class, Keys.class, TestTypeWithFederation.class, FederationTestApi.class); - assertNotNull(graphQLSchema.getDirective("key")); + assertNull(graphQLSchema.getDirective("key")); assertNull(graphQLSchema.getType("_Entity")); GraphQLObjectType queryRoot = graphQLSchema.getQueryType(); @@ -137,9 +141,7 @@ void testSchemaWithFederationDisabled() { assertEquals("TestTypeWithFederation", ((GraphQLObjectType) query.getType()).getName()); GraphQLObjectType type = graphQLSchema.getObjectType("TestTypeWithFederation"); - assertEquals(2, type.getDirectives().size()); - assertKeyDirective(type.getDirectives().get(0), "id"); - assertKeyDirective(type.getDirectives().get(1), "type id"); + assertEquals(0, type.getDirectives().size()); assertEquals(3, type.getFields().size()); assertEquals("id", type.getFields().get(0).getName()); assertEquals(GraphQLString, type.getFields().get(0).getType()); @@ -154,60 +156,66 @@ void testSchemaWithFederationDisabled() { @Test void testSchemaWithFederationEnabled() { config.federationEnabled = true; - GraphQLSchema graphQLSchema = createGraphQLSchema(Repeatable.class, Directive.class, Key.class, Keys.class, - TestTypeWithFederation.class, FederationTestApi.class); - - GraphQLDirective keyDirective = graphQLSchema.getDirective("key"); - assertEquals("key", keyDirective.getName()); - assertTrue(keyDirective.isRepeatable()); - assertEquals( - "Designates an object type as an entity and specifies its key fields " + - "(a set of fields that the subgraph can use to uniquely identify any instance " + - "of the entity). You can apply multiple @key directives to a single entity " + - "(to specify multiple valid sets of key fields).", - keyDirective.getDescription()); - assertEquals(EnumSet.of(OBJECT, INTERFACE), keyDirective.validLocations()); - assertEquals(1, keyDirective.getArguments().size()); - assertEquals("String", ((GraphQLScalarType) keyDirective.getArgument("fields").getType()).getName()); - - GraphQLUnionType entityType = (GraphQLUnionType) graphQLSchema.getType("_Entity"); - assertNotNull(entityType); - assertEquals(1, entityType.getTypes().size()); - assertEquals(TestTypeWithFederation.class.getSimpleName(), entityType.getTypes().get(0).getName()); - - GraphQLObjectType queryRoot = graphQLSchema.getQueryType(); - assertEquals(3, queryRoot.getFields().size()); - - GraphQLFieldDefinition entities = queryRoot.getField("_entities"); - assertEquals(1, entities.getArguments().size()); - assertEquals("[_Any!]!", entities.getArgument("representations").getType().toString()); - assertEquals("[_Entity]!", entities.getType().toString()); - - GraphQLFieldDefinition service = queryRoot.getField("_service"); - assertEquals(0, service.getArguments().size()); - assertEquals("_Service!", service.getType().toString()); - - GraphQLFieldDefinition query = queryRoot.getField("testTypeWithFederation"); - assertEquals(1, query.getArguments().size()); - assertEquals(GraphQLString, query.getArgument("arg").getType()); - assertEquals("TestTypeWithFederation", ((GraphQLObjectType) query.getType()).getName()); - - GraphQLObjectType type = graphQLSchema.getObjectType("TestTypeWithFederation"); - assertEquals(2, type.getDirectives().size()); - assertKeyDirective(type.getDirectives().get(0), "id"); - assertKeyDirective(type.getDirectives().get(1), "type id"); - assertEquals(3, type.getFields().size()); - assertEquals("id", type.getFields().get(0).getName()); - assertEquals(GraphQLString, type.getFields().get(0).getType()); - assertEquals("type", type.getFields().get(1).getName()); - assertEquals(GraphQLString, type.getFields().get(1).getType()); - assertEquals("value", type.getFields().get(2).getName()); - assertEquals(GraphQLString, type.getFields().get(2).getType()); - - GraphQLObjectType serviceType = graphQLSchema.getObjectType("_Service"); - assertEquals(1, serviceType.getFields().size()); - assertEquals("sdl", serviceType.getFields().get(0).getName()); - assertEquals("String!", serviceType.getFields().get(0).getType().toString()); + // need to set it as system property because the SchemaBuilder doesn't have access to the Config object + System.setProperty("smallrye.graphql.federation.enabled", "true"); + try { + GraphQLSchema graphQLSchema = createGraphQLSchema(Repeatable.class, Directive.class, Key.class, Keys.class, + TestTypeWithFederation.class, FederationTestApi.class); + + GraphQLDirective keyDirective = graphQLSchema.getDirective("key"); + assertEquals("key", keyDirective.getName()); + assertTrue(keyDirective.isRepeatable()); + assertEquals( + "Designates an object type as an entity and specifies its key fields " + + "(a set of fields that the subgraph can use to uniquely identify any instance " + + "of the entity). You can apply multiple @key directives to a single entity " + + "(to specify multiple valid sets of key fields).", + keyDirective.getDescription()); + assertEquals(EnumSet.of(OBJECT, INTERFACE), keyDirective.validLocations()); + assertEquals(1, keyDirective.getArguments().size()); + assertEquals("String", ((GraphQLScalarType) keyDirective.getArgument("fields").getType()).getName()); + + GraphQLUnionType entityType = (GraphQLUnionType) graphQLSchema.getType("_Entity"); + assertNotNull(entityType); + assertEquals(1, entityType.getTypes().size()); + assertEquals(TestTypeWithFederation.class.getSimpleName(), entityType.getTypes().get(0).getName()); + + GraphQLObjectType queryRoot = graphQLSchema.getQueryType(); + assertEquals(3, queryRoot.getFields().size()); + + GraphQLFieldDefinition entities = queryRoot.getField("_entities"); + assertEquals(1, entities.getArguments().size()); + assertEquals("[_Any!]!", entities.getArgument("representations").getType().toString()); + assertEquals("[_Entity]!", entities.getType().toString()); + + GraphQLFieldDefinition service = queryRoot.getField("_service"); + assertEquals(0, service.getArguments().size()); + assertEquals("_Service!", service.getType().toString()); + + GraphQLFieldDefinition query = queryRoot.getField("testTypeWithFederation"); + assertEquals(1, query.getArguments().size()); + assertEquals(GraphQLString, query.getArgument("arg").getType()); + assertEquals("TestTypeWithFederation", ((GraphQLObjectType) query.getType()).getName()); + + GraphQLObjectType type = graphQLSchema.getObjectType("TestTypeWithFederation"); + assertEquals(2, type.getDirectives().size()); + assertKeyDirective(type.getDirectives().get(0), "id"); + assertKeyDirective(type.getDirectives().get(1), "type id"); + assertEquals(3, type.getFields().size()); + assertEquals("id", type.getFields().get(0).getName()); + assertEquals(GraphQLString, type.getFields().get(0).getType()); + assertEquals("type", type.getFields().get(1).getName()); + assertEquals(GraphQLString, type.getFields().get(1).getType()); + assertEquals("value", type.getFields().get(2).getName()); + assertEquals(GraphQLString, type.getFields().get(2).getType()); + + GraphQLObjectType serviceType = graphQLSchema.getObjectType("_Service"); + assertEquals(1, serviceType.getFields().size()); + assertEquals("sdl", serviceType.getFields().get(0).getName()); + assertEquals("String!", serviceType.getFields().get(0).getType().toString()); + } finally { + System.clearProperty("smallrye.graphql.federation.enabled"); + } } private static void assertKeyDirective(GraphQLDirective graphQLDirective, String value) { diff --git a/server/tck/pom.xml b/server/tck/pom.xml index 8fb7b9bb9..c034a978d 100644 --- a/server/tck/pom.xml +++ b/server/tck/pom.xml @@ -132,6 +132,9 @@ testng.xml + + true + From 4580cd15d616fc9572dbfaa3a5105be6aae653e8 Mon Sep 17 00:00:00 2001 From: Jan Martiska Date: Fri, 6 Jan 2023 13:41:44 +0100 Subject: [PATCH 07/11] Release 2.0.1 --- .github/project.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/project.yml b/.github/project.yml index bfe950f37..0f7f3e0ca 100644 --- a/.github/project.yml +++ b/.github/project.yml @@ -1,4 +1,4 @@ name: SmallRye GraphQL release: - current-version: 2.0.0 - next-version: 2.0.1-SNAPSHOT + current-version: 2.0.1 + next-version: 2.0.2-SNAPSHOT From 3fb15f5069dd6e4c7039972cc46b247e2901932d Mon Sep 17 00:00:00 2001 From: SmallRye CI Date: Fri, 6 Jan 2023 12:46:43 +0000 Subject: [PATCH 08/11] Update Gradle plugin version --- tools/gradle-plugin/gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/gradle-plugin/gradle.properties b/tools/gradle-plugin/gradle.properties index 97d695b3d..332be4061 100644 --- a/tools/gradle-plugin/gradle.properties +++ b/tools/gradle-plugin/gradle.properties @@ -1 +1 @@ -version=2.0.0 +version=2.0.1 From d0e61f05f32515c177c54c60953e9a0f3b5dd149 Mon Sep 17 00:00:00 2001 From: SmallRye CI Date: Fri, 6 Jan 2023 12:50:26 +0000 Subject: [PATCH 09/11] [maven-release-plugin] prepare release 2.0.1 --- client/api/pom.xml | 2 +- client/generator-test/pom.xml | 2 +- client/generator/pom.xml | 2 +- client/implementation-vertx/pom.xml | 2 +- client/implementation/pom.xml | 2 +- client/pom.xml | 2 +- client/tck/pom.xml | 2 +- common/pom.xml | 2 +- common/schema-builder/pom.xml | 2 +- common/schema-model/pom.xml | 2 +- docs/pom.xml | 2 +- pom.xml | 4 ++-- release/pom.xml | 2 +- server/api/pom.xml | 2 +- server/implementation-cdi/pom.xml | 2 +- server/implementation-servlet/pom.xml | 2 +- server/implementation/pom.xml | 2 +- server/integration-tests-jdk16/pom.xml | 2 +- server/integration-tests/pom.xml | 2 +- server/pom.xml | 2 +- server/runner/pom.xml | 2 +- server/tck/pom.xml | 2 +- tools/gradle-plugin/pom.xml | 2 +- tools/maven-plugin-tests/pom.xml | 2 +- tools/maven-plugin/pom.xml | 2 +- tools/pom.xml | 2 +- ui/graphiql/pom.xml | 2 +- ui/pom.xml | 2 +- 28 files changed, 29 insertions(+), 29 deletions(-) diff --git a/client/api/pom.xml b/client/api/pom.xml index 9e4dd282b..5acdda12f 100644 --- a/client/api/pom.xml +++ b/client/api/pom.xml @@ -5,7 +5,7 @@ io.smallrye smallrye-graphql-client-parent - 2.0.1-SNAPSHOT + 2.0.1 smallrye-graphql-client-api diff --git a/client/generator-test/pom.xml b/client/generator-test/pom.xml index 2e5f11db0..bb7cea153 100644 --- a/client/generator-test/pom.xml +++ b/client/generator-test/pom.xml @@ -4,7 +4,7 @@ io.smallrye smallrye-graphql-client-parent - 2.0.1-SNAPSHOT + 2.0.1 smallrye-graphql-client-generator-test diff --git a/client/generator/pom.xml b/client/generator/pom.xml index d8b8e4b86..9ec825379 100644 --- a/client/generator/pom.xml +++ b/client/generator/pom.xml @@ -4,7 +4,7 @@ io.smallrye smallrye-graphql-client-parent - 2.0.1-SNAPSHOT + 2.0.1 smallrye-graphql-client-generator diff --git a/client/implementation-vertx/pom.xml b/client/implementation-vertx/pom.xml index 9a2677773..bcae57c91 100644 --- a/client/implementation-vertx/pom.xml +++ b/client/implementation-vertx/pom.xml @@ -5,7 +5,7 @@ io.smallrye smallrye-graphql-client-parent - 2.0.1-SNAPSHOT + 2.0.1 smallrye-graphql-client-implementation-vertx diff --git a/client/implementation/pom.xml b/client/implementation/pom.xml index b57b38cf7..54c5ff3ab 100644 --- a/client/implementation/pom.xml +++ b/client/implementation/pom.xml @@ -5,7 +5,7 @@ io.smallrye smallrye-graphql-client-parent - 2.0.1-SNAPSHOT + 2.0.1 smallrye-graphql-client diff --git a/client/pom.xml b/client/pom.xml index 51d56ece0..289f12b8c 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -5,7 +5,7 @@ io.smallrye smallrye-graphql-parent - 2.0.1-SNAPSHOT + 2.0.1 smallrye-graphql-client-parent diff --git a/client/tck/pom.xml b/client/tck/pom.xml index d6cc50617..29ea92f24 100644 --- a/client/tck/pom.xml +++ b/client/tck/pom.xml @@ -5,7 +5,7 @@ io.smallrye smallrye-graphql-client-parent - 2.0.1-SNAPSHOT + 2.0.1 smallrye-graphql-client-tck diff --git a/common/pom.xml b/common/pom.xml index aacab4f99..83f597722 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -5,7 +5,7 @@ io.smallrye smallrye-graphql-parent - 2.0.1-SNAPSHOT + 2.0.1 smallrye-graphql-common-parent diff --git a/common/schema-builder/pom.xml b/common/schema-builder/pom.xml index e89f94568..05f1f957d 100644 --- a/common/schema-builder/pom.xml +++ b/common/schema-builder/pom.xml @@ -5,7 +5,7 @@ io.smallrye smallrye-graphql-common-parent - 2.0.1-SNAPSHOT + 2.0.1 smallrye-graphql-schema-builder diff --git a/common/schema-model/pom.xml b/common/schema-model/pom.xml index 594afbb8a..71b4735c8 100644 --- a/common/schema-model/pom.xml +++ b/common/schema-model/pom.xml @@ -4,7 +4,7 @@ io.smallrye smallrye-graphql-common-parent - 2.0.1-SNAPSHOT + 2.0.1 smallrye-graphql-schema-model diff --git a/docs/pom.xml b/docs/pom.xml index 5f2e9a20a..b08e1e3e9 100644 --- a/docs/pom.xml +++ b/docs/pom.xml @@ -5,7 +5,7 @@ io.smallrye smallrye-graphql-parent - 2.0.1-SNAPSHOT + 2.0.1 smallrye-graphql-documentation diff --git a/pom.xml b/pom.xml index d840f671b..2b56b4477 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ smallrye-graphql-parent - 2.0.1-SNAPSHOT + 2.0.1 pom SmallRye: GraphQL Parent @@ -78,7 +78,7 @@ scm:git:git@github.com:smallrye/smallrye-graphql.git scm:git:git@github.com:smallrye/smallrye-graphql.git https://github.com/smallrye/smallrye-graphql/ - HEAD + 2.0.1 diff --git a/release/pom.xml b/release/pom.xml index 464e3050b..66821246f 100644 --- a/release/pom.xml +++ b/release/pom.xml @@ -5,7 +5,7 @@ io.smallrye smallrye-graphql-parent - 2.0.1-SNAPSHOT + 2.0.1 smallrye-graphql-release diff --git a/server/api/pom.xml b/server/api/pom.xml index 37e7ae851..4672fca18 100644 --- a/server/api/pom.xml +++ b/server/api/pom.xml @@ -5,7 +5,7 @@ io.smallrye smallrye-graphql-server-parent - 2.0.1-SNAPSHOT + 2.0.1 smallrye-graphql-api diff --git a/server/implementation-cdi/pom.xml b/server/implementation-cdi/pom.xml index 40306e766..d3c9959bc 100644 --- a/server/implementation-cdi/pom.xml +++ b/server/implementation-cdi/pom.xml @@ -5,7 +5,7 @@ io.smallrye smallrye-graphql-server-parent - 2.0.1-SNAPSHOT + 2.0.1 smallrye-graphql-cdi diff --git a/server/implementation-servlet/pom.xml b/server/implementation-servlet/pom.xml index 46f5ef775..c1c15508c 100644 --- a/server/implementation-servlet/pom.xml +++ b/server/implementation-servlet/pom.xml @@ -5,7 +5,7 @@ io.smallrye smallrye-graphql-server-parent - 2.0.1-SNAPSHOT + 2.0.1 smallrye-graphql-servlet diff --git a/server/implementation/pom.xml b/server/implementation/pom.xml index 53884db5a..cbb84ff07 100644 --- a/server/implementation/pom.xml +++ b/server/implementation/pom.xml @@ -5,7 +5,7 @@ io.smallrye smallrye-graphql-server-parent - 2.0.1-SNAPSHOT + 2.0.1 smallrye-graphql diff --git a/server/integration-tests-jdk16/pom.xml b/server/integration-tests-jdk16/pom.xml index 4e1504083..fa62565cc 100644 --- a/server/integration-tests-jdk16/pom.xml +++ b/server/integration-tests-jdk16/pom.xml @@ -3,7 +3,7 @@ smallrye-graphql-server-parent io.smallrye - 2.0.1-SNAPSHOT + 2.0.1 4.0.0 diff --git a/server/integration-tests/pom.xml b/server/integration-tests/pom.xml index ac18dd4ff..c5cba529f 100644 --- a/server/integration-tests/pom.xml +++ b/server/integration-tests/pom.xml @@ -4,7 +4,7 @@ io.smallrye smallrye-graphql-server-parent - 2.0.1-SNAPSHOT + 2.0.1 4.0.0 diff --git a/server/pom.xml b/server/pom.xml index 43705492a..4dd83634e 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -5,7 +5,7 @@ io.smallrye smallrye-graphql-parent - 2.0.1-SNAPSHOT + 2.0.1 smallrye-graphql-server-parent diff --git a/server/runner/pom.xml b/server/runner/pom.xml index a3b3dda1c..54755e6a5 100644 --- a/server/runner/pom.xml +++ b/server/runner/pom.xml @@ -5,7 +5,7 @@ io.smallrye smallrye-graphql-server-parent - 2.0.1-SNAPSHOT + 2.0.1 smallrye-graphql-runner diff --git a/server/tck/pom.xml b/server/tck/pom.xml index c034a978d..7615a3310 100644 --- a/server/tck/pom.xml +++ b/server/tck/pom.xml @@ -4,7 +4,7 @@ io.smallrye smallrye-graphql-server-parent - 2.0.1-SNAPSHOT + 2.0.1 smallrye-graphql-tck diff --git a/tools/gradle-plugin/pom.xml b/tools/gradle-plugin/pom.xml index 3bcc811e7..0c5129d1a 100644 --- a/tools/gradle-plugin/pom.xml +++ b/tools/gradle-plugin/pom.xml @@ -4,7 +4,7 @@ io.smallrye smallrye-graphql-tools-parent - 2.0.1-SNAPSHOT + 2.0.1 4.0.0 diff --git a/tools/maven-plugin-tests/pom.xml b/tools/maven-plugin-tests/pom.xml index 423c6e961..de3a9db4b 100644 --- a/tools/maven-plugin-tests/pom.xml +++ b/tools/maven-plugin-tests/pom.xml @@ -3,7 +3,7 @@ io.smallrye smallrye-graphql-tools-parent - 2.0.1-SNAPSHOT + 2.0.1 4.0.0 diff --git a/tools/maven-plugin/pom.xml b/tools/maven-plugin/pom.xml index 997991e99..ef38490d6 100644 --- a/tools/maven-plugin/pom.xml +++ b/tools/maven-plugin/pom.xml @@ -3,7 +3,7 @@ io.smallrye smallrye-graphql-tools-parent - 2.0.1-SNAPSHOT + 2.0.1 4.0.0 diff --git a/tools/pom.xml b/tools/pom.xml index 8d31e6b53..7d334ffae 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -5,7 +5,7 @@ io.smallrye smallrye-graphql-parent - 2.0.1-SNAPSHOT + 2.0.1 smallrye-graphql-tools-parent diff --git a/ui/graphiql/pom.xml b/ui/graphiql/pom.xml index eb3dc14f9..e649c13db 100644 --- a/ui/graphiql/pom.xml +++ b/ui/graphiql/pom.xml @@ -5,7 +5,7 @@ io.smallrye smallrye-graphql-ui-parent - 2.0.1-SNAPSHOT + 2.0.1 smallrye-graphql-ui-graphiql diff --git a/ui/pom.xml b/ui/pom.xml index d56208918..ac2d11c35 100644 --- a/ui/pom.xml +++ b/ui/pom.xml @@ -5,7 +5,7 @@ io.smallrye smallrye-graphql-parent - 2.0.1-SNAPSHOT + 2.0.1 smallrye-graphql-ui-parent From b1181bdf58fd4f5fd518ae586a084c6791f090b8 Mon Sep 17 00:00:00 2001 From: SmallRye CI Date: Fri, 6 Jan 2023 12:50:26 +0000 Subject: [PATCH 10/11] [maven-release-plugin] prepare for next development iteration --- client/api/pom.xml | 2 +- client/generator-test/pom.xml | 2 +- client/generator/pom.xml | 2 +- client/implementation-vertx/pom.xml | 2 +- client/implementation/pom.xml | 2 +- client/pom.xml | 2 +- client/tck/pom.xml | 2 +- common/pom.xml | 2 +- common/schema-builder/pom.xml | 2 +- common/schema-model/pom.xml | 2 +- docs/pom.xml | 2 +- pom.xml | 4 ++-- release/pom.xml | 2 +- server/api/pom.xml | 2 +- server/implementation-cdi/pom.xml | 2 +- server/implementation-servlet/pom.xml | 2 +- server/implementation/pom.xml | 2 +- server/integration-tests-jdk16/pom.xml | 2 +- server/integration-tests/pom.xml | 2 +- server/pom.xml | 2 +- server/runner/pom.xml | 2 +- server/tck/pom.xml | 2 +- tools/gradle-plugin/pom.xml | 2 +- tools/maven-plugin-tests/pom.xml | 2 +- tools/maven-plugin/pom.xml | 2 +- tools/pom.xml | 2 +- ui/graphiql/pom.xml | 2 +- ui/pom.xml | 2 +- 28 files changed, 29 insertions(+), 29 deletions(-) diff --git a/client/api/pom.xml b/client/api/pom.xml index 5acdda12f..89512fdd6 100644 --- a/client/api/pom.xml +++ b/client/api/pom.xml @@ -5,7 +5,7 @@ io.smallrye smallrye-graphql-client-parent - 2.0.1 + 2.0.2-SNAPSHOT smallrye-graphql-client-api diff --git a/client/generator-test/pom.xml b/client/generator-test/pom.xml index bb7cea153..429fa6f76 100644 --- a/client/generator-test/pom.xml +++ b/client/generator-test/pom.xml @@ -4,7 +4,7 @@ io.smallrye smallrye-graphql-client-parent - 2.0.1 + 2.0.2-SNAPSHOT smallrye-graphql-client-generator-test diff --git a/client/generator/pom.xml b/client/generator/pom.xml index 9ec825379..5d84a79af 100644 --- a/client/generator/pom.xml +++ b/client/generator/pom.xml @@ -4,7 +4,7 @@ io.smallrye smallrye-graphql-client-parent - 2.0.1 + 2.0.2-SNAPSHOT smallrye-graphql-client-generator diff --git a/client/implementation-vertx/pom.xml b/client/implementation-vertx/pom.xml index bcae57c91..f4943e0a5 100644 --- a/client/implementation-vertx/pom.xml +++ b/client/implementation-vertx/pom.xml @@ -5,7 +5,7 @@ io.smallrye smallrye-graphql-client-parent - 2.0.1 + 2.0.2-SNAPSHOT smallrye-graphql-client-implementation-vertx diff --git a/client/implementation/pom.xml b/client/implementation/pom.xml index 54c5ff3ab..10ef213bc 100644 --- a/client/implementation/pom.xml +++ b/client/implementation/pom.xml @@ -5,7 +5,7 @@ io.smallrye smallrye-graphql-client-parent - 2.0.1 + 2.0.2-SNAPSHOT smallrye-graphql-client diff --git a/client/pom.xml b/client/pom.xml index 289f12b8c..539af5262 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -5,7 +5,7 @@ io.smallrye smallrye-graphql-parent - 2.0.1 + 2.0.2-SNAPSHOT smallrye-graphql-client-parent diff --git a/client/tck/pom.xml b/client/tck/pom.xml index 29ea92f24..ed1574d61 100644 --- a/client/tck/pom.xml +++ b/client/tck/pom.xml @@ -5,7 +5,7 @@ io.smallrye smallrye-graphql-client-parent - 2.0.1 + 2.0.2-SNAPSHOT smallrye-graphql-client-tck diff --git a/common/pom.xml b/common/pom.xml index 83f597722..8dc9ad235 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -5,7 +5,7 @@ io.smallrye smallrye-graphql-parent - 2.0.1 + 2.0.2-SNAPSHOT smallrye-graphql-common-parent diff --git a/common/schema-builder/pom.xml b/common/schema-builder/pom.xml index 05f1f957d..86c222691 100644 --- a/common/schema-builder/pom.xml +++ b/common/schema-builder/pom.xml @@ -5,7 +5,7 @@ io.smallrye smallrye-graphql-common-parent - 2.0.1 + 2.0.2-SNAPSHOT smallrye-graphql-schema-builder diff --git a/common/schema-model/pom.xml b/common/schema-model/pom.xml index 71b4735c8..e77045514 100644 --- a/common/schema-model/pom.xml +++ b/common/schema-model/pom.xml @@ -4,7 +4,7 @@ io.smallrye smallrye-graphql-common-parent - 2.0.1 + 2.0.2-SNAPSHOT smallrye-graphql-schema-model diff --git a/docs/pom.xml b/docs/pom.xml index b08e1e3e9..bf7ae58f7 100644 --- a/docs/pom.xml +++ b/docs/pom.xml @@ -5,7 +5,7 @@ io.smallrye smallrye-graphql-parent - 2.0.1 + 2.0.2-SNAPSHOT smallrye-graphql-documentation diff --git a/pom.xml b/pom.xml index 2b56b4477..6fb121921 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ smallrye-graphql-parent - 2.0.1 + 2.0.2-SNAPSHOT pom SmallRye: GraphQL Parent @@ -78,7 +78,7 @@ scm:git:git@github.com:smallrye/smallrye-graphql.git scm:git:git@github.com:smallrye/smallrye-graphql.git https://github.com/smallrye/smallrye-graphql/ - 2.0.1 + HEAD diff --git a/release/pom.xml b/release/pom.xml index 66821246f..fb61daa22 100644 --- a/release/pom.xml +++ b/release/pom.xml @@ -5,7 +5,7 @@ io.smallrye smallrye-graphql-parent - 2.0.1 + 2.0.2-SNAPSHOT smallrye-graphql-release diff --git a/server/api/pom.xml b/server/api/pom.xml index 4672fca18..09fc7d537 100644 --- a/server/api/pom.xml +++ b/server/api/pom.xml @@ -5,7 +5,7 @@ io.smallrye smallrye-graphql-server-parent - 2.0.1 + 2.0.2-SNAPSHOT smallrye-graphql-api diff --git a/server/implementation-cdi/pom.xml b/server/implementation-cdi/pom.xml index d3c9959bc..a524c4891 100644 --- a/server/implementation-cdi/pom.xml +++ b/server/implementation-cdi/pom.xml @@ -5,7 +5,7 @@ io.smallrye smallrye-graphql-server-parent - 2.0.1 + 2.0.2-SNAPSHOT smallrye-graphql-cdi diff --git a/server/implementation-servlet/pom.xml b/server/implementation-servlet/pom.xml index c1c15508c..cc8eb60be 100644 --- a/server/implementation-servlet/pom.xml +++ b/server/implementation-servlet/pom.xml @@ -5,7 +5,7 @@ io.smallrye smallrye-graphql-server-parent - 2.0.1 + 2.0.2-SNAPSHOT smallrye-graphql-servlet diff --git a/server/implementation/pom.xml b/server/implementation/pom.xml index cbb84ff07..7a320f613 100644 --- a/server/implementation/pom.xml +++ b/server/implementation/pom.xml @@ -5,7 +5,7 @@ io.smallrye smallrye-graphql-server-parent - 2.0.1 + 2.0.2-SNAPSHOT smallrye-graphql diff --git a/server/integration-tests-jdk16/pom.xml b/server/integration-tests-jdk16/pom.xml index fa62565cc..87f62e920 100644 --- a/server/integration-tests-jdk16/pom.xml +++ b/server/integration-tests-jdk16/pom.xml @@ -3,7 +3,7 @@ smallrye-graphql-server-parent io.smallrye - 2.0.1 + 2.0.2-SNAPSHOT 4.0.0 diff --git a/server/integration-tests/pom.xml b/server/integration-tests/pom.xml index c5cba529f..7dd6de23c 100644 --- a/server/integration-tests/pom.xml +++ b/server/integration-tests/pom.xml @@ -4,7 +4,7 @@ io.smallrye smallrye-graphql-server-parent - 2.0.1 + 2.0.2-SNAPSHOT 4.0.0 diff --git a/server/pom.xml b/server/pom.xml index 4dd83634e..95e24bd6e 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -5,7 +5,7 @@ io.smallrye smallrye-graphql-parent - 2.0.1 + 2.0.2-SNAPSHOT smallrye-graphql-server-parent diff --git a/server/runner/pom.xml b/server/runner/pom.xml index 54755e6a5..700561cc5 100644 --- a/server/runner/pom.xml +++ b/server/runner/pom.xml @@ -5,7 +5,7 @@ io.smallrye smallrye-graphql-server-parent - 2.0.1 + 2.0.2-SNAPSHOT smallrye-graphql-runner diff --git a/server/tck/pom.xml b/server/tck/pom.xml index 7615a3310..7255c8be4 100644 --- a/server/tck/pom.xml +++ b/server/tck/pom.xml @@ -4,7 +4,7 @@ io.smallrye smallrye-graphql-server-parent - 2.0.1 + 2.0.2-SNAPSHOT smallrye-graphql-tck diff --git a/tools/gradle-plugin/pom.xml b/tools/gradle-plugin/pom.xml index 0c5129d1a..32cac9835 100644 --- a/tools/gradle-plugin/pom.xml +++ b/tools/gradle-plugin/pom.xml @@ -4,7 +4,7 @@ io.smallrye smallrye-graphql-tools-parent - 2.0.1 + 2.0.2-SNAPSHOT 4.0.0 diff --git a/tools/maven-plugin-tests/pom.xml b/tools/maven-plugin-tests/pom.xml index de3a9db4b..804ebd866 100644 --- a/tools/maven-plugin-tests/pom.xml +++ b/tools/maven-plugin-tests/pom.xml @@ -3,7 +3,7 @@ io.smallrye smallrye-graphql-tools-parent - 2.0.1 + 2.0.2-SNAPSHOT 4.0.0 diff --git a/tools/maven-plugin/pom.xml b/tools/maven-plugin/pom.xml index ef38490d6..ab2309e79 100644 --- a/tools/maven-plugin/pom.xml +++ b/tools/maven-plugin/pom.xml @@ -3,7 +3,7 @@ io.smallrye smallrye-graphql-tools-parent - 2.0.1 + 2.0.2-SNAPSHOT 4.0.0 diff --git a/tools/pom.xml b/tools/pom.xml index 7d334ffae..481898594 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -5,7 +5,7 @@ io.smallrye smallrye-graphql-parent - 2.0.1 + 2.0.2-SNAPSHOT smallrye-graphql-tools-parent diff --git a/ui/graphiql/pom.xml b/ui/graphiql/pom.xml index e649c13db..b17eb4eb9 100644 --- a/ui/graphiql/pom.xml +++ b/ui/graphiql/pom.xml @@ -5,7 +5,7 @@ io.smallrye smallrye-graphql-ui-parent - 2.0.1 + 2.0.2-SNAPSHOT smallrye-graphql-ui-graphiql diff --git a/ui/pom.xml b/ui/pom.xml index ac2d11c35..344f77f86 100644 --- a/ui/pom.xml +++ b/ui/pom.xml @@ -5,7 +5,7 @@ io.smallrye smallrye-graphql-parent - 2.0.1 + 2.0.2-SNAPSHOT smallrye-graphql-ui-parent From ef13e39bbdc6981dca09def4b3d45c9001050614 Mon Sep 17 00:00:00 2001 From: Ruediger zu Dohna Date: Sun, 8 Jan 2023 15:35:46 +0100 Subject: [PATCH 11/11] fix #1689: properly add/remove federation directives --- .../graphql/schema/SchemaBuilder.java | 10 +- .../graphql/schema/model/DirectiveType.java | 4 + .../smallrye/graphql/bootstrap/Bootstrap.java | 46 ++++--- .../smallrye/graphql/schema/SchemaTest.java | 123 +++++++++--------- 4 files changed, 92 insertions(+), 91 deletions(-) diff --git a/common/schema-builder/src/main/java/io/smallrye/graphql/schema/SchemaBuilder.java b/common/schema-builder/src/main/java/io/smallrye/graphql/schema/SchemaBuilder.java index 4cc790c13..f9b382c24 100644 --- a/common/schema-builder/src/main/java/io/smallrye/graphql/schema/SchemaBuilder.java +++ b/common/schema-builder/src/main/java/io/smallrye/graphql/schema/SchemaBuilder.java @@ -69,8 +69,6 @@ public class SchemaBuilder { private final DirectiveTypeCreator directiveTypeCreator; private final UnionCreator unionCreator; - private final DotName FEDERATION_ANNOTATIONS_PACKAGE = DotName.createSimple("io.smallrye.graphql.api.federation"); - /** * This builds the Schema from Jandex * @@ -162,13 +160,7 @@ private void addDirectiveTypes(Schema schema) { // custom directives from annotations for (AnnotationInstance annotationInstance : ScanningContext.getIndex().getAnnotations(DIRECTIVE)) { ClassInfo classInfo = annotationInstance.target().asClass(); - boolean federationEnabled = Boolean.getBoolean("smallrye.graphql.federation.enabled"); - // only add federation-related directive types to the schema if federation is enabled - DotName packageName = classInfo.name().packagePrefixName(); - if (packageName == null || !packageName.equals(FEDERATION_ANNOTATIONS_PACKAGE) || federationEnabled) { - schema.addDirectiveType(directiveTypeCreator.create(classInfo)); - } - + schema.addDirectiveType(directiveTypeCreator.create(classInfo)); } // bean validation directives schema.addDirectiveType(BeanValidationDirectivesHelper.CONSTRAINT_DIRECTIVE_TYPE); diff --git a/common/schema-model/src/main/java/io/smallrye/graphql/schema/model/DirectiveType.java b/common/schema-model/src/main/java/io/smallrye/graphql/schema/model/DirectiveType.java index 0127e92c7..4b519b3a4 100644 --- a/common/schema-model/src/main/java/io/smallrye/graphql/schema/model/DirectiveType.java +++ b/common/schema-model/src/main/java/io/smallrye/graphql/schema/model/DirectiveType.java @@ -69,6 +69,10 @@ public void setRepeatable(boolean repeatable) { this.repeatable = repeatable; } + public boolean isFederation() { + return className != null && className.startsWith("io.smallrye.graphql.api.federation"); + } + /** * Helper 'getter' methods, but DON'T add 'get' into their names, otherwise it breaks Quarkus bytecode recording, * because they would be detected as actual property getters while they are actually not diff --git a/server/implementation/src/main/java/io/smallrye/graphql/bootstrap/Bootstrap.java b/server/implementation/src/main/java/io/smallrye/graphql/bootstrap/Bootstrap.java index 912225a0d..e803acf85 100644 --- a/server/implementation/src/main/java/io/smallrye/graphql/bootstrap/Bootstrap.java +++ b/server/implementation/src/main/java/io/smallrye/graphql/bootstrap/Bootstrap.java @@ -220,11 +220,17 @@ private TypeResolver fetchEntityType() { private void createGraphQLDirectiveTypes() { if (schema.hasDirectiveTypes()) { for (DirectiveType directiveType : schema.getDirectiveTypes()) { - createGraphQLDirectiveType(directiveType); + if (enabled(directiveType)) { + createGraphQLDirectiveType(directiveType); + } } } } + private static boolean enabled(DirectiveType directiveType) { + return Config.get().isFederationEnabled() || !directiveType.isFederation(); + } + private void createGraphQLDirectiveType(DirectiveType directiveType) { GraphQLDirective.Builder directiveBuilder = GraphQLDirective.newDirective() .name(directiveType.getName()) @@ -372,7 +378,8 @@ private void createGraphQLEnumType(EnumType enumType) { .description(enumType.getDescription()); // Directives if (enumType.hasDirectiveInstances()) { - enumBuilder = enumBuilder.withDirectives(createGraphQLDirectives(enumType.getDirectiveInstances())); + enumBuilder = enumBuilder + .withDirectives(createGraphQLDirectives(enumType.getDirectiveInstances())); } // Values for (EnumValue value : enumType.getValues()) { @@ -381,7 +388,8 @@ private void createGraphQLEnumType(EnumType enumType) { .value(value.getValue()) .description(value.getDescription()); if (value.hasDirectiveInstances()) { - definitionBuilder = definitionBuilder.withDirectives(createGraphQLDirectives(value.getDirectiveInstances())); + definitionBuilder = definitionBuilder + .withDirectives(createGraphQLDirectives(value.getDirectiveInstances())); } enumBuilder = enumBuilder.value(definitionBuilder.build()); } @@ -411,9 +419,8 @@ private void createGraphQLInterfaceType(Type interfaceType) { // Directives if (interfaceType.hasDirectiveInstances()) { - for (DirectiveInstance directiveInstance : interfaceType.getDirectiveInstances()) { - interfaceTypeBuilder.withDirective(createGraphQLDirectiveFrom(directiveInstance)); - } + interfaceTypeBuilder = interfaceTypeBuilder + .withDirectives(createGraphQLDirectives(interfaceType.getDirectiveInstances())); } // Interfaces @@ -535,9 +542,8 @@ private void createGraphQLObjectType(Type type) { // Directives if (type.hasDirectiveInstances()) { - for (DirectiveInstance directiveInstance : type.getDirectiveInstances()) { - objectTypeBuilder.withDirective(createGraphQLDirectiveFrom(directiveInstance)); - } + objectTypeBuilder = objectTypeBuilder + .withDirectives(createGraphQLDirectives(type.getDirectiveInstances())); } // Fields @@ -657,7 +663,8 @@ private GraphQLFieldDefinition createGraphQLFieldDefinitionFromOperation(String // Directives if (operation.hasDirectiveInstances()) { - fieldBuilder = fieldBuilder.withDirectives(createGraphQLDirectives(operation.getDirectiveInstances())); + fieldBuilder = fieldBuilder + .withDirectives(createGraphQLDirectives(operation.getDirectiveInstances())); } GraphQLFieldDefinition graphQLFieldDefinition = fieldBuilder.build(); @@ -673,6 +680,7 @@ private GraphQLFieldDefinition createGraphQLFieldDefinitionFromOperation(String private GraphQLDirective[] createGraphQLDirectives(Collection directiveInstances) { return directiveInstances.stream() + .filter(directiveInstance -> enabled(directiveInstance.getType())) .map(this::createGraphQLDirectiveFrom) .toArray(GraphQLDirective[]::new); } @@ -695,9 +703,8 @@ private GraphQLFieldDefinition createGraphQLFieldDefinitionFromField(Reference o // Directives if (field.hasDirectiveInstances()) { - for (DirectiveInstance directiveInstance : field.getDirectiveInstances()) { - fieldBuilder.withDirective(createGraphQLDirectiveFrom(directiveInstance)); - } + fieldBuilder = fieldBuilder + .withDirectives(createGraphQLDirectives(field.getDirectiveInstances())); } // Auto Map argument @@ -770,10 +777,10 @@ private GraphQLInputObjectField createGraphQLInputObjectFieldFromField(Field fie // Type inputFieldBuilder = inputFieldBuilder.type(createGraphQLInputType(field)); + // Directives if (field.hasDirectiveInstances()) { - for (DirectiveInstance directiveInstance : field.getDirectiveInstances()) { - inputFieldBuilder.withDirective(createGraphQLDirectiveFrom(directiveInstance)); - } + inputFieldBuilder = inputFieldBuilder + .withDirectives(createGraphQLDirectives(field.getDirectiveInstances())); } // Default value (on method) @@ -942,12 +949,13 @@ private GraphQLArgument createGraphQLArgument(Argument argument) { graphQLInputType = GraphQLNonNull.nonNull(graphQLInputType); } + // Type argumentBuilder = argumentBuilder.type(graphQLInputType); + // Directives if (argument.hasDirectiveInstances()) { - for (DirectiveInstance directiveInstance : argument.getDirectiveInstances()) { - argumentBuilder.withDirective(createGraphQLDirectiveFrom(directiveInstance)); - } + argumentBuilder = argumentBuilder + .withDirectives(createGraphQLDirectives(argument.getDirectiveInstances())); } return argumentBuilder.build(); diff --git a/server/implementation/src/test/java/io/smallrye/graphql/schema/SchemaTest.java b/server/implementation/src/test/java/io/smallrye/graphql/schema/SchemaTest.java index 1eb3dea3b..92611e17b 100644 --- a/server/implementation/src/test/java/io/smallrye/graphql/schema/SchemaTest.java +++ b/server/implementation/src/test/java/io/smallrye/graphql/schema/SchemaTest.java @@ -4,6 +4,7 @@ import static graphql.introspection.Introspection.DirectiveLocation.INTERFACE; import static graphql.introspection.Introspection.DirectiveLocation.OBJECT; import static java.util.Objects.requireNonNull; +import static java.util.stream.Collectors.toSet; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; @@ -17,6 +18,7 @@ import java.net.URISyntaxException; import java.nio.file.Files; import java.util.EnumSet; +import java.util.Set; import java.util.stream.Stream; import org.jboss.jandex.IndexView; @@ -121,14 +123,15 @@ void schemaWithInputDirectives() { @Test void testSchemaWithFederationDisabled() { config.federationEnabled = false; - // need to set it as system property because the SchemaBuilder doesn't have access to the Config object - System.setProperty("smallrye.graphql.federation.enabled", "false"); GraphQLSchema graphQLSchema = createGraphQLSchema(Directive.class, Key.class, Keys.class, TestTypeWithFederation.class, FederationTestApi.class); - assertNull(graphQLSchema.getDirective("key")); + assertEquals(Set.of("include", "specifiedBy", "deprecated", "skip", "constraint"), + graphQLSchema.getDirectives().stream().map(GraphQLDirective::getName).collect(toSet())); + assertNull(graphQLSchema.getDirective("key")); // esp. NOT this one assertNull(graphQLSchema.getType("_Entity")); + assertNull(graphQLSchema.getType("_Service")); GraphQLObjectType queryRoot = graphQLSchema.getQueryType(); assertEquals(1, queryRoot.getFields().size()); @@ -156,66 +159,60 @@ void testSchemaWithFederationDisabled() { @Test void testSchemaWithFederationEnabled() { config.federationEnabled = true; - // need to set it as system property because the SchemaBuilder doesn't have access to the Config object - System.setProperty("smallrye.graphql.federation.enabled", "true"); - try { - GraphQLSchema graphQLSchema = createGraphQLSchema(Repeatable.class, Directive.class, Key.class, Keys.class, - TestTypeWithFederation.class, FederationTestApi.class); - - GraphQLDirective keyDirective = graphQLSchema.getDirective("key"); - assertEquals("key", keyDirective.getName()); - assertTrue(keyDirective.isRepeatable()); - assertEquals( - "Designates an object type as an entity and specifies its key fields " + - "(a set of fields that the subgraph can use to uniquely identify any instance " + - "of the entity). You can apply multiple @key directives to a single entity " + - "(to specify multiple valid sets of key fields).", - keyDirective.getDescription()); - assertEquals(EnumSet.of(OBJECT, INTERFACE), keyDirective.validLocations()); - assertEquals(1, keyDirective.getArguments().size()); - assertEquals("String", ((GraphQLScalarType) keyDirective.getArgument("fields").getType()).getName()); - - GraphQLUnionType entityType = (GraphQLUnionType) graphQLSchema.getType("_Entity"); - assertNotNull(entityType); - assertEquals(1, entityType.getTypes().size()); - assertEquals(TestTypeWithFederation.class.getSimpleName(), entityType.getTypes().get(0).getName()); - - GraphQLObjectType queryRoot = graphQLSchema.getQueryType(); - assertEquals(3, queryRoot.getFields().size()); - - GraphQLFieldDefinition entities = queryRoot.getField("_entities"); - assertEquals(1, entities.getArguments().size()); - assertEquals("[_Any!]!", entities.getArgument("representations").getType().toString()); - assertEquals("[_Entity]!", entities.getType().toString()); - - GraphQLFieldDefinition service = queryRoot.getField("_service"); - assertEquals(0, service.getArguments().size()); - assertEquals("_Service!", service.getType().toString()); - - GraphQLFieldDefinition query = queryRoot.getField("testTypeWithFederation"); - assertEquals(1, query.getArguments().size()); - assertEquals(GraphQLString, query.getArgument("arg").getType()); - assertEquals("TestTypeWithFederation", ((GraphQLObjectType) query.getType()).getName()); - - GraphQLObjectType type = graphQLSchema.getObjectType("TestTypeWithFederation"); - assertEquals(2, type.getDirectives().size()); - assertKeyDirective(type.getDirectives().get(0), "id"); - assertKeyDirective(type.getDirectives().get(1), "type id"); - assertEquals(3, type.getFields().size()); - assertEquals("id", type.getFields().get(0).getName()); - assertEquals(GraphQLString, type.getFields().get(0).getType()); - assertEquals("type", type.getFields().get(1).getName()); - assertEquals(GraphQLString, type.getFields().get(1).getType()); - assertEquals("value", type.getFields().get(2).getName()); - assertEquals(GraphQLString, type.getFields().get(2).getType()); - - GraphQLObjectType serviceType = graphQLSchema.getObjectType("_Service"); - assertEquals(1, serviceType.getFields().size()); - assertEquals("sdl", serviceType.getFields().get(0).getName()); - assertEquals("String!", serviceType.getFields().get(0).getType().toString()); - } finally { - System.clearProperty("smallrye.graphql.federation.enabled"); - } + GraphQLSchema graphQLSchema = createGraphQLSchema(Repeatable.class, Directive.class, Key.class, Keys.class, + TestTypeWithFederation.class, FederationTestApi.class); + + GraphQLDirective keyDirective = graphQLSchema.getDirective("key"); + assertEquals("key", keyDirective.getName()); + assertTrue(keyDirective.isRepeatable()); + assertEquals( + "Designates an object type as an entity and specifies its key fields " + + "(a set of fields that the subgraph can use to uniquely identify any instance " + + "of the entity). You can apply multiple @key directives to a single entity " + + "(to specify multiple valid sets of key fields).", + keyDirective.getDescription()); + assertEquals(EnumSet.of(OBJECT, INTERFACE), keyDirective.validLocations()); + assertEquals(1, keyDirective.getArguments().size()); + assertEquals("String", ((GraphQLScalarType) keyDirective.getArgument("fields").getType()).getName()); + + GraphQLUnionType entityType = (GraphQLUnionType) graphQLSchema.getType("_Entity"); + assertNotNull(entityType); + assertEquals(1, entityType.getTypes().size()); + assertEquals(TestTypeWithFederation.class.getSimpleName(), entityType.getTypes().get(0).getName()); + + GraphQLObjectType queryRoot = graphQLSchema.getQueryType(); + assertEquals(3, queryRoot.getFields().size()); + + GraphQLFieldDefinition entities = queryRoot.getField("_entities"); + assertEquals(1, entities.getArguments().size()); + assertEquals("[_Any!]!", entities.getArgument("representations").getType().toString()); + assertEquals("[_Entity]!", entities.getType().toString()); + + GraphQLFieldDefinition service = queryRoot.getField("_service"); + assertEquals(0, service.getArguments().size()); + assertEquals("_Service!", service.getType().toString()); + + GraphQLFieldDefinition query = queryRoot.getField("testTypeWithFederation"); + assertEquals(1, query.getArguments().size()); + assertEquals(GraphQLString, query.getArgument("arg").getType()); + assertEquals("TestTypeWithFederation", ((GraphQLObjectType) query.getType()).getName()); + + GraphQLObjectType type = graphQLSchema.getObjectType("TestTypeWithFederation"); + assertEquals(2, type.getDirectives().size()); + assertKeyDirective(type.getDirectives().get(0), "id"); + assertKeyDirective(type.getDirectives().get(1), "type id"); + assertEquals(3, type.getFields().size()); + assertEquals("id", type.getFields().get(0).getName()); + assertEquals(GraphQLString, type.getFields().get(0).getType()); + assertEquals("type", type.getFields().get(1).getName()); + assertEquals(GraphQLString, type.getFields().get(1).getType()); + assertEquals("value", type.getFields().get(2).getName()); + assertEquals(GraphQLString, type.getFields().get(2).getType()); + + GraphQLObjectType serviceType = graphQLSchema.getObjectType("_Service"); + assertEquals(1, serviceType.getFields().size()); + assertEquals("sdl", serviceType.getFields().get(0).getName()); + assertEquals("String!", serviceType.getFields().get(0).getType().toString()); } private static void assertKeyDirective(GraphQLDirective graphQLDirective, String value) {