diff --git a/pom.xml b/pom.xml index e572a4c..d062c9c 100644 --- a/pom.xml +++ b/pom.xml @@ -11,259 +11,266 @@ the License. --> - - 4.0.0 - com.fleetpin - graphql-builder - 3.1.0-SNAPSHOT + + 4.0.0 + com.fleetpin + graphql-builder + 3.1.0-SNAPSHOT - GraphQL Builder - Builds a graphql schema from a model using reflection - https://github.com/ashley-taylor/graphql-builder + GraphQL Builder + Builds a graphql schema from a model using reflection + https://github.com/ashley-taylor/graphql-builder - - 5.11.2 - UTF-8 - 2.18.0 - 1.17.0 - 1.2.1 - 22.3 - + + 5.11.2 + UTF-8 + 2.18.0 + 1.17.0 + 1.2.1 + 22.3 + - - - sonatype - central snapshot - https://oss.sonatype.org/content/repositories/snapshots - - - sonatype - central release - https://oss.sonatype.org/service/local/staging/deploy/maven2 - - + + + sonatype + central snapshot + https://oss.sonatype.org/content/repositories/snapshots + + + sonatype + central release + https://oss.sonatype.org/service/local/staging/deploy/maven2 + + - - https://github.com/ashley-taylor/graphql-builder - scm:git:https://github.com/ashley-taylor/graphql-builder.git - scm:git:https://github.com/ashley-taylor/graphql-builder.git - HEAD - + + https://github.com/ashley-taylor/graphql-builder + scm:git:https://github.com/ashley-taylor/graphql-builder.git + scm:git:https://github.com/ashley-taylor/graphql-builder.git + HEAD + - - - Apache License, Version 2.0 - http://www.apache.org/licenses/LICENSE-2.0.txt - repo - - + + + Apache License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + repo + + - - - Ashley Taylor - ashley.taylor@fleetpin.co.nz - Fleetpin - http://www.fleetpin.co.nz - - + + + Ashley Taylor + ashley.taylor@fleetpin.co.nz + Fleetpin + http://www.fleetpin.co.nz + + - - - - org.apache.maven.plugins - maven-compiler-plugin - - 21 - 21 - -parameters - - - - org.apache.maven.plugins - maven-release-plugin - 3.1.1 - - - org.apache.maven.plugins - maven-source-plugin - - - attach-sources - - jar-no-fork - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - 3.10.1 - - - attach-javadocs - - jar - - - - - - com.hubspot.maven.plugins - prettier-maven-plugin - 0.22 - - 1.4.0 - 160 - 4 - true - true - true - - - - validate - - - - - org.pitest - pitest-maven - ${pitest.version} - - - org.pitest - pitest-junit5-plugin - ${pitest-junit5-plugin.version} - - - - 4 - false - false - - STRONGER - - - - - com.mycila - license-maven-plugin - 4.6 - - - -
src/license/license.txt
-
-
-
-
+ + + + org.apache.maven.plugins + maven-compiler-plugin + + 21 + 21 + -parameters + + + + org.apache.maven.plugins + maven-release-plugin + 3.1.1 + + + org.apache.maven.plugins + maven-source-plugin + + + attach-sources + + jar-no-fork + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.10.1 + + + attach-javadocs + + jar + + + + + + com.hubspot.maven.plugins + prettier-maven-plugin + 0.22 + + 1.4.0 + 160 + 4 + true + true + true + + + + validate + + + + + org.pitest + pitest-maven + ${pitest.version} + + + org.pitest + pitest-junit5-plugin + ${pitest-junit5-plugin.version} + + + + 4 + false + false + + STRONGER + + + + + com.mycila + license-maven-plugin + 4.6 + + + +
src/license/license.txt
+
+
+
+
-
-
+
+
- - - com.graphql-java - graphql-java - ${graphql.version} - - - com.graphql-java - graphql-java-extended-scalars - 21.0 - test - - - org.reflections - reflections - 0.10.2 - - - jakarta.annotation - jakarta.annotation-api - 3.0.0 - - - com.fasterxml.jackson.core - jackson-databind - ${jackson.version} - test - - - com.fasterxml.jackson.module - jackson-module-parameter-names - ${jackson.version} - test - - - com.fasterxml.jackson.datatype - jackson-datatype-jdk8 - ${jackson.version} - test - - - com.fasterxml.jackson.datatype - jackson-datatype-jsr310 - ${jackson.version} - test - - - io.reactivex.rxjava3 - rxjava - 3.1.9 - test - + + + com.graphql-java + graphql-java + ${graphql.version} + + + com.graphql-java + graphql-java-extended-scalars + 21.0 + test + + + org.reflections + reflections + 0.10.2 + + + jakarta.annotation + jakarta.annotation-api + 3.0.0 + + + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} + test + + + com.fasterxml.jackson.module + jackson-module-parameter-names + ${jackson.version} + test + + + com.fasterxml.jackson.datatype + jackson-datatype-jdk8 + ${jackson.version} + test + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + ${jackson.version} + test + + + io.reactivex.rxjava3 + rxjava + 3.1.9 + test + - - org.junit.jupiter - junit-jupiter - ${junit.jupiter.version} - test - - - - org.skyscreamer - jsonassert - 1.5.3 - test - + + org.junit.jupiter + junit-jupiter + ${junit.jupiter.version} + test + - + + org.skyscreamer + jsonassert + 1.5.3 + test + + + jakarta.validation + jakarta.validation-api + 3.1.0 + - - - sonatype - - - - org.apache.maven.plugins - maven-gpg-plugin - 3.2.7 - - - sign-artifacts - verify - - sign - - - - - - org.sonatype.plugins - nexus-staging-maven-plugin - 1.7.0 - true - - sonatype - https://oss.sonatype.org/ - true - - - - - - + + + + + + sonatype + + + + org.apache.maven.plugins + maven-gpg-plugin + 3.2.7 + + + sign-artifacts + verify + + sign + + + + + + org.sonatype.plugins + nexus-staging-maven-plugin + 1.7.0 + true + + sonatype + https://oss.sonatype.org/ + true + + + + + +
diff --git a/src/main/java/com/fleetpin/graphql/builder/DirectiveCaller.java b/src/main/java/com/fleetpin/graphql/builder/DirectiveCaller.java index 73b3bd9..6ea1125 100644 --- a/src/main/java/com/fleetpin/graphql/builder/DirectiveCaller.java +++ b/src/main/java/com/fleetpin/graphql/builder/DirectiveCaller.java @@ -13,8 +13,9 @@ import graphql.schema.DataFetcher; import graphql.schema.DataFetchingEnvironment; + import java.lang.annotation.Annotation; public interface DirectiveCaller extends DirectiveOperation { public Object process(T annotation, DataFetchingEnvironment env, DataFetcher fetcher) throws Exception; -} +} \ No newline at end of file diff --git a/src/main/java/com/fleetpin/graphql/builder/DirectiveProcessor.java b/src/main/java/com/fleetpin/graphql/builder/DirectiveProcessor.java index 18d429d..a772d28 100644 --- a/src/main/java/com/fleetpin/graphql/builder/DirectiveProcessor.java +++ b/src/main/java/com/fleetpin/graphql/builder/DirectiveProcessor.java @@ -2,11 +2,17 @@ import com.fleetpin.graphql.builder.annotations.Directive; import graphql.introspection.Introspection; -import graphql.schema.*; +import graphql.schema.GraphQLAppliedDirective; +import graphql.schema.GraphQLAppliedDirectiveArgument; +import graphql.schema.GraphQLArgument; +import graphql.schema.GraphQLDirective; +import jakarta.validation.Constraint; + import java.lang.annotation.Annotation; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.util.*; +import java.util.HashMap; +import java.util.Map; import java.util.function.Consumer; import java.util.function.Function; @@ -22,15 +28,22 @@ public DirectiveProcessor(GraphQLDirective directive, Map directive) { var builder = GraphQLDirective.newDirective().name(directive.getSimpleName()); - var validLocations = directive.getAnnotation(Directive.class).value(); + Introspection.DirectiveLocation[] validLocations = null; + + if (!directive.isAnnotationPresent(Directive.class) && directive == Constraint.class) { + validLocations = new Introspection.DirectiveLocation[] { Introspection.DirectiveLocation.ARGUMENT_DEFINITION }; + } else { + validLocations = directive.getAnnotation(Directive.class).value(); + + // Check for repeatable tag in annotation and add it + builder.repeatable(directive.getAnnotation(Directive.class).repeatable()); + } + // loop through and add valid locations for (Introspection.DirectiveLocation location : validLocations) { builder.validLocation(location); } - // Check for repeatable tag in annotation and add it - builder.repeatable(directive.getAnnotation(Directive.class).repeatable()); - // Go through each argument and add name/type to directive var methods = directive.getDeclaredMethods(); Map> builders = new HashMap<>(); diff --git a/src/main/java/com/fleetpin/graphql/builder/DirectivesSchema.java b/src/main/java/com/fleetpin/graphql/builder/DirectivesSchema.java index ce6e59e..ad2e302 100644 --- a/src/main/java/com/fleetpin/graphql/builder/DirectivesSchema.java +++ b/src/main/java/com/fleetpin/graphql/builder/DirectivesSchema.java @@ -13,23 +13,22 @@ import com.fleetpin.graphql.builder.annotations.DataFetcherWrapper; import com.fleetpin.graphql.builder.annotations.Directive; -import graphql.schema.DataFetcher; -import graphql.schema.DataFetchingEnvironment; -import graphql.schema.GraphQLAppliedDirective; -import graphql.schema.GraphQLDirective; +import graphql.schema.*; +import jakarta.validation.Constraint; +import jakarta.validation.constraints.Size; +import org.reactivestreams.Publisher; + import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.lang.reflect.ParameterizedType; import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; -import java.util.concurrent.ExecutionException; import java.util.function.Consumer; -import java.util.stream.Collectors; import java.util.stream.Stream; -import org.reactivestreams.Publisher; + +import static graphql.Scalars.GraphQLInt; class DirectivesSchema { @@ -63,7 +62,7 @@ public static DirectivesSchema build(List> globalDirectiv } continue; } - if (!directiveType.isAnnotationPresent(Directive.class)) { + if (!directiveType.isAnnotationPresent(Directive.class) && directiveType != Constraint.class) { continue; } if (!directiveType.isAnnotation()) { @@ -179,25 +178,10 @@ private CompletableFuture applyRestrict(RestrictType restrict, Objec } } - private static CompletableFuture> all(List> toReturn) { - return CompletableFuture - .allOf(toReturn.toArray(CompletableFuture[]::new)) - .thenApply(__ -> - toReturn - .stream() - .map(m -> { - try { - return m.get(); - } catch (InterruptedException | ExecutionException e) { - throw new RuntimeException(e); - } - }) - .collect(Collectors.toList()) - ); - } - public void addSchemaDirective(AnnotatedElement element, Class location, Consumer builder) { for (Annotation annotation : element.getAnnotations()) { + convertJakartaAnnotationsToConstraintDirectives(builder, annotation); + var processor = this.directiveProcessors.get(annotation.annotationType()); if (processor != null) { try { @@ -209,10 +193,18 @@ public void addSchemaDirective(AnnotatedElement element, Class location, Cons } } + private static void convertJakartaAnnotationsToConstraintDirectives(Consumer builder, Annotation annotation) { + // convert all jakarta validation annotations to a corresponding constraint directive + if (annotation instanceof Size size) { + builder.accept(GraphQLAppliedDirective.newDirective().name("Constraint").argument(GraphQLAppliedDirectiveArgument + .newArgument().name("min").type(GraphQLInt).valueProgrammatic(size.min())).build()); + } + } + public void processDirectives(EntityProcessor ep) { // Replacement of processSDL - Map, DirectiveProcessor> directiveProcessors = new HashMap<>(); + Map, DirectiveProcessor> directiveProcessorsMap = new HashMap<>(); - this.directives.forEach(dir -> directiveProcessors.put(dir, DirectiveProcessor.build(ep, dir))); - this.directiveProcessors = directiveProcessors; + this.directives.forEach(dir -> directiveProcessorsMap.put(dir, DirectiveProcessor.build(ep, dir))); + this.directiveProcessors = directiveProcessorsMap; } } diff --git a/src/main/java/com/fleetpin/graphql/builder/MethodProcessor.java b/src/main/java/com/fleetpin/graphql/builder/MethodProcessor.java index 8bef984..6b002a8 100644 --- a/src/main/java/com/fleetpin/graphql/builder/MethodProcessor.java +++ b/src/main/java/com/fleetpin/graphql/builder/MethodProcessor.java @@ -1,30 +1,18 @@ package com.fleetpin.graphql.builder; -import static com.fleetpin.graphql.builder.EntityUtil.isContext; - -import com.fleetpin.graphql.builder.annotations.Directive; -import com.fleetpin.graphql.builder.annotations.GraphQLDeprecated; -import com.fleetpin.graphql.builder.annotations.GraphQLDescription; -import com.fleetpin.graphql.builder.annotations.Mutation; -import com.fleetpin.graphql.builder.annotations.Query; -import com.fleetpin.graphql.builder.annotations.Subscription; +import com.fleetpin.graphql.builder.annotations.*; import graphql.GraphQLContext; -import graphql.schema.DataFetcher; -import graphql.schema.DataFetchingEnvironment; -import graphql.schema.FieldCoordinates; -import graphql.schema.GraphQLAppliedDirective; -import graphql.schema.GraphQLAppliedDirectiveArgument; -import graphql.schema.GraphQLArgument; -import graphql.schema.GraphQLCodeRegistry; -import graphql.schema.GraphQLFieldDefinition; +import graphql.schema.*; import graphql.schema.GraphQLFieldDefinition.Builder; -import graphql.schema.GraphQLObjectType; + import java.lang.annotation.Annotation; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.function.Function; +import static com.fleetpin.graphql.builder.EntityUtil.isContext; + class MethodProcessor { private final DataFetcherRunner dataFetcherRunner; @@ -109,19 +97,7 @@ Builder process(AuthorizerSchema authorizer, FieldCoordinates coordinates, TypeM argument.description(description.value()); } - for (Annotation annotation : parameter.getAnnotations()) { - // Check to see if the annotation is a directive - if (!annotation.annotationType().isAnnotationPresent(Directive.class)) { - continue; - } - var annotationType = annotation.annotationType(); - // Get the values out of the directive annotation - var methods = annotationType.getDeclaredMethods(); - - // Get the applied directive and add it to the argument - var appliedDirective = getAppliedDirective(annotation, annotationType, methods); - argument.withAppliedDirective(appliedDirective); - } + entityProcessor.addSchemaDirective(parameter, method.getDeclaringClass(), argument::withAppliedDirective); argument.name(EntityUtil.getName(parameter.getName(), parameter)); // TODO: argument.defaultValue(defaultValue) @@ -133,23 +109,6 @@ Builder process(AuthorizerSchema authorizer, FieldCoordinates coordinates, TypeM return field; } - private GraphQLAppliedDirective getAppliedDirective(Annotation annotation, Class annotationType, Method[] methods) - throws IllegalAccessException, InvocationTargetException { - var appliedDirective = new GraphQLAppliedDirective.Builder().name(annotationType.getSimpleName()); - for (var definedMethod : methods) { - var name = definedMethod.getName(); - var value = definedMethod.invoke(annotation); - if (value == null) { - continue; - } - - TypeMeta innerMeta = new TypeMeta(null, definedMethod.getReturnType(), definedMethod.getGenericReturnType()); - var argumentType = entityProcessor.getEntity(innerMeta).getInputType(innerMeta, definedMethod.getAnnotations()); - appliedDirective.argument(GraphQLAppliedDirectiveArgument.newArgument().name(name).type(argumentType).valueProgrammatic(value).build()); - } - return appliedDirective.build(); - } - private DataFetcher buildFetcher(DirectivesSchema diretives, AuthorizerSchema authorizer, Method method, TypeMeta meta) { DataFetcher fetcher = buildDataFetcher(meta, method); fetcher = diretives.wrap(method, meta, fetcher); diff --git a/src/main/java/com/fleetpin/graphql/builder/SchemaBuilder.java b/src/main/java/com/fleetpin/graphql/builder/SchemaBuilder.java index 24bf2fc..e80a4ac 100644 --- a/src/main/java/com/fleetpin/graphql/builder/SchemaBuilder.java +++ b/src/main/java/com/fleetpin/graphql/builder/SchemaBuilder.java @@ -14,13 +14,16 @@ import com.fleetpin.graphql.builder.annotations.*; import graphql.schema.GraphQLScalarType; import graphql.schema.GraphQLSchema; +import jakarta.validation.Constraint; +import org.reflections.Reflections; +import org.reflections.scanners.Scanners; + +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; -import org.reflections.Reflections; -import org.reflections.scanners.Scanners; public class SchemaBuilder { @@ -75,7 +78,7 @@ private graphql.schema.GraphQLSchema.Builder build(Set builder.additionalDirective(directive)); + directives.getSchemaDirective().forEach(builder::additionalDirective); for (var schema : schemaConfiguration) { this.directives.addSchemaDirective(schema, schema, builder::withSchemaAppliedDirective); @@ -131,41 +134,7 @@ public GraphQLSchema.Builder build() { Set> schemaConfiguration = reflections.getSubTypesOf(SchemaConfiguration.class); - Set> directivesTypes = reflections.getTypesAnnotatedWith(Directive.class); - directivesTypes.addAll(reflections.getTypesAnnotatedWith(DataFetcherWrapper.class)); - - Set> restrict = reflections.getTypesAnnotatedWith(Restrict.class); - Set> restricts = reflections.getTypesAnnotatedWith(Restricts.class); - List> globalRestricts = new ArrayList<>(); - - for (var r : restrict) { - Restrict annotation = EntityUtil.getAnnotation(r, Restrict.class); - var factoryClass = annotation.value(); - var factory = factoryClass.getConstructor().newInstance(); - if (!factory.extractType().isAssignableFrom(r)) { - throw new RuntimeException( - "Restrict annotation does match class applied to targets" + factory.extractType() + " but was on class " + r - ); - } - globalRestricts.add(factory); - } - - for (var r : restricts) { - Restricts annotations = EntityUtil.getAnnotation(r, Restricts.class); - for (Restrict annotation : annotations.value()) { - var factoryClass = annotation.value(); - var factory = factoryClass.getConstructor().newInstance(); - - if (!factory.extractType().isAssignableFrom(r)) { - throw new RuntimeException( - "Restrict annotation does match class applied to targets" + factory.extractType() + " but was on class " + r - ); - } - globalRestricts.add(factory); - } - } - - DirectivesSchema directivesSchema = DirectivesSchema.build(globalRestricts, directivesTypes); // Entry point for directives + DirectivesSchema directivesSchema = getDirectivesSchema(reflections); Set> types = reflections.getTypesAnnotatedWith(Entity.class); @@ -178,7 +147,7 @@ public GraphQLSchema.Builder build() { endPoints.addAll(queries); types.removeIf(t -> t.getDeclaredAnnotation(Entity.class) == null); - types.removeIf(t -> t.isAnonymousClass()); + types.removeIf(Class::isAnonymousClass); return new SchemaBuilder(dataFetcherRunner, scalars, directivesSchema, authorizer) .processTypes(types) @@ -188,5 +157,56 @@ public GraphQLSchema.Builder build() { throw new RuntimeException(e); } } + + private static DirectivesSchema getDirectivesSchema(Reflections reflections) throws ReflectiveOperationException { + Set> directivesTypes = reflections.getTypesAnnotatedWith(Directive.class); + directivesTypes.addAll(reflections.getTypesAnnotatedWith(DataFetcherWrapper.class)); + + addAllJakartaAnnotations(directivesTypes); + + List> globalRestricts = getGlobalRestricts(reflections); + + return DirectivesSchema.build(globalRestricts, directivesTypes); // Entry point for directives + } + + private static void addAllJakartaAnnotations(Set> directivesTypes) { + // make sure the Constraint directive is added to the schema + directivesTypes.add(Constraint.class); + } + + private static List> getGlobalRestricts(Reflections reflections) + throws InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException { + Set> restrict = reflections.getTypesAnnotatedWith(Restrict.class); + Set> restricts = reflections.getTypesAnnotatedWith(Restricts.class); + List> globalRestricts = new ArrayList<>(); + + for (var r : restrict) { + Restrict annotation = EntityUtil.getAnnotation(r, Restrict.class); + var factoryClass = annotation.value(); + var factory = factoryClass.getConstructor().newInstance(); + if (!factory.extractType().isAssignableFrom(r)) { + throw new RuntimeException( + "Restrict annotation does match class applied to targets" + factory.extractType() + " but was on class " + r + ); + } + globalRestricts.add(factory); + } + + for (var r : restricts) { + Restricts annotations = EntityUtil.getAnnotation(r, Restricts.class); + for (Restrict annotation : annotations.value()) { + var factoryClass = annotation.value(); + var factory = factoryClass.getConstructor().newInstance(); + + if (!factory.extractType().isAssignableFrom(r)) { + throw new RuntimeException( + "Restrict annotation does match class applied to targets" + factory.extractType() + " but was on class " + r + ); + } + globalRestricts.add(factory); + } + } + return globalRestricts; + } } } diff --git a/src/test/java/com/fleetpin/graphql/builder/JakartaValidationDirectiveTest.java b/src/test/java/com/fleetpin/graphql/builder/JakartaValidationDirectiveTest.java new file mode 100644 index 0000000..5854002 --- /dev/null +++ b/src/test/java/com/fleetpin/graphql/builder/JakartaValidationDirectiveTest.java @@ -0,0 +1,66 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package com.fleetpin.graphql.builder; + +import graphql.ExecutionInput; +import graphql.ExecutionResult; +import graphql.GraphQL; +import graphql.introspection.IntrospectionWithDirectivesSupport; +import graphql.schema.FieldCoordinates; +import graphql.schema.GraphQLSchema; +import org.junit.jupiter.api.Test; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class JakartaValidationDirectiveTest { + @Test + public void testJakartaArgumentAnnotationChangedToConstraint() { + GraphQL schema = GraphQL.newGraphQL(SchemaBuilder.build("com.fleetpin.graphql.builder.type.directive")).build(); + var name = schema.getGraphQLSchema().getFieldDefinition(FieldCoordinates.coordinates(schema.getGraphQLSchema().getMutationType(), "setName")); + var constraint = name.getArgument("name").getAppliedDirective("Constraint"); + var argument = constraint.getArgument("min"); + var min = argument.getValue(); + assertEquals(3, min); + } + + @Test + public void testDirectiveArgumentDefinition() { + Map response = execute("query IntrospectionQuery { __schema { directives { name locations args { name } } } }", null).getData(); + List> dir = (List>) ((Map) response.get("__schema")).get("directives"); + LinkedHashMap constraint = dir.stream().filter(map -> map.get("name").equals("Constraint")).collect(Collectors.toList()).get(0); + + assertEquals(9, dir.size()); + assertEquals("ARGUMENT_DEFINITION", ((List) constraint.get("locations")).get(0)); + assertEquals(1, ((List) constraint.get("args")).size()); + assertEquals("{name=validatedBy}", ((List) constraint.get("args")).getFirst().toString()); + //setName(name: String! @Size(min : 3)): Int! + //directive @Constraint(name: String!) on ARGUMENT_DEFINITION + } + + private ExecutionResult execute(String query, Map variables) { + GraphQLSchema preSchema = SchemaBuilder.builder().classpath("com.fleetpin.graphql.builder.type.directive").build().build(); + GraphQL schema = GraphQL.newGraphQL(new IntrospectionWithDirectivesSupport().apply(preSchema)).build(); + + var input = ExecutionInput.newExecutionInput(); + input.query(query); + if (variables != null) { + input.variables(variables); + } + ExecutionResult result = schema.execute(input); + return result; + } +} diff --git a/src/test/java/com/fleetpin/graphql/builder/type/directive/Cat.java b/src/test/java/com/fleetpin/graphql/builder/type/directive/Cat.java index 9935400..a5eac53 100644 --- a/src/test/java/com/fleetpin/graphql/builder/type/directive/Cat.java +++ b/src/test/java/com/fleetpin/graphql/builder/type/directive/Cat.java @@ -12,11 +12,12 @@ package com.fleetpin.graphql.builder.type.directive; import com.fleetpin.graphql.builder.annotations.Entity; +import com.fleetpin.graphql.builder.annotations.Mutation; import com.fleetpin.graphql.builder.annotations.Query; +import jakarta.validation.constraints.Size; @Entity public class Cat { - public boolean isCalico() { return true; } @@ -35,6 +36,11 @@ public static Cat getCat() { return new Cat(); } + @Mutation + public static String setName(@Size(min = 3) String name) { + return name; + } + @Query @Uppercase public static Cat getUpper() {