From 4d9b6428f4c29f577747a206d5f42d31b4b74cc3 Mon Sep 17 00:00:00 2001 From: amatiushkin Date: Thu, 14 Jun 2018 17:58:38 -0700 Subject: [PATCH 01/13] Add visitor for types and use generic traversal --- .../java/graphql/schema/GraphQLArgument.java | 17 + .../java/graphql/schema/GraphQLEnumType.java | 7 + .../schema/GraphQLEnumValueDefinition.java | 8 + .../schema/GraphQLFieldDefinition.java | 20 + .../schema/GraphQLInputObjectField.java | 17 + .../schema/GraphQLInputObjectType.java | 12 + .../graphql/schema/GraphQLInterfaceType.java | 12 + src/main/java/graphql/schema/GraphQLList.java | 19 + .../java/graphql/schema/GraphQLNonNull.java | 19 + .../graphql/schema/GraphQLObjectType.java | 20 + .../graphql/schema/GraphQLScalarType.java | 7 + src/main/java/graphql/schema/GraphQLType.java | 12 + .../graphql/schema/GraphQLTypeReference.java | 8 + .../java/graphql/schema/GraphQLUnionType.java | 17 + src/main/java/graphql/schema/SchemaUtil.java | 353 ++++++++++++------ .../java/graphql/schema/TypeTraverser.java | 62 +++ src/main/java/graphql/schema/TypeVisitor.java | 59 +++ .../java/graphql/schema/TypeVisitorStub.java | 76 ++++ .../graphql/StarWarsIntrospectionTests.groovy | 21 +- src/test/groovy/graphql/UnionTest.groovy | 2 +- 20 files changed, 635 insertions(+), 133 deletions(-) create mode 100644 src/main/java/graphql/schema/TypeTraverser.java create mode 100644 src/main/java/graphql/schema/TypeVisitor.java create mode 100644 src/main/java/graphql/schema/TypeVisitorStub.java diff --git a/src/main/java/graphql/schema/GraphQLArgument.java b/src/main/java/graphql/schema/GraphQLArgument.java index 95495fb8d7..2238f3782b 100644 --- a/src/main/java/graphql/schema/GraphQLArgument.java +++ b/src/main/java/graphql/schema/GraphQLArgument.java @@ -4,6 +4,8 @@ import graphql.PublicApi; import graphql.language.InputValueDefinition; import graphql.util.FpKit; +import graphql.util.TraversalControl; +import graphql.util.TraverserContext; import java.util.ArrayList; import java.util.Collections; @@ -71,11 +73,16 @@ private GraphQLArgument(String name, String description, GraphQLInputType type, } + @Deprecated void replaceTypeReferences(Map typeMap) { type = (GraphQLInputType) new SchemaUtil().resolveTypeReference(type, typeMap); } @Override + void replaceType(GraphQLInputType type) { + this.type = type; + } + public String getName() { return name; } @@ -140,6 +147,16 @@ public static Builder newArgument(GraphQLArgument existing) { return new Builder(existing); } + @Override + public TraversalControl accept(TraverserContext context, TypeVisitor visitor) { + return visitor.visitGraphQLArgument(this, context); + } + + @Override + public List getChildren() { + return Collections.singletonList(type); + } + public static class Builder { private String name; diff --git a/src/main/java/graphql/schema/GraphQLEnumType.java b/src/main/java/graphql/schema/GraphQLEnumType.java index 8277740fef..7320c25064 100644 --- a/src/main/java/graphql/schema/GraphQLEnumType.java +++ b/src/main/java/graphql/schema/GraphQLEnumType.java @@ -6,6 +6,8 @@ import graphql.PublicApi; import graphql.language.EnumTypeDefinition; import graphql.language.EnumValue; +import graphql.util.TraversalControl; +import graphql.util.TraverserContext; import java.util.ArrayList; import java.util.LinkedHashMap; @@ -175,6 +177,11 @@ public GraphQLEnumType transform(Consumer builderConsumer) { return builder.build(); } + @Override + public TraversalControl accept(TraverserContext context, TypeVisitor visitor) { + return visitor.visitGraphQLEnumType(this, context); + } + public static Builder newEnum() { return new Builder(); } diff --git a/src/main/java/graphql/schema/GraphQLEnumValueDefinition.java b/src/main/java/graphql/schema/GraphQLEnumValueDefinition.java index 322d3af809..41facc24b9 100644 --- a/src/main/java/graphql/schema/GraphQLEnumValueDefinition.java +++ b/src/main/java/graphql/schema/GraphQLEnumValueDefinition.java @@ -4,6 +4,8 @@ import graphql.DirectivesUtil; import graphql.Internal; import graphql.PublicApi; +import graphql.util.TraversalControl; +import graphql.util.TraverserContext; import java.util.ArrayList; import java.util.LinkedHashMap; @@ -105,6 +107,12 @@ public GraphQLEnumValueDefinition transform(Consumer builderConsumer) { return builder.build(); } + @Override + public TraversalControl accept(TraverserContext context, TypeVisitor visitor) { + return visitor.visitGraphQLEnumValueDefinition(this, context); + } + + public static Builder newEnumValueDefinition() { return new Builder(); } diff --git a/src/main/java/graphql/schema/GraphQLFieldDefinition.java b/src/main/java/graphql/schema/GraphQLFieldDefinition.java index d01eafca67..17a115bed1 100644 --- a/src/main/java/graphql/schema/GraphQLFieldDefinition.java +++ b/src/main/java/graphql/schema/GraphQLFieldDefinition.java @@ -4,6 +4,8 @@ import graphql.Internal; import graphql.PublicApi; import graphql.language.FieldDefinition; +import graphql.util.TraversalControl; +import graphql.util.TraverserContext; import java.util.ArrayList; import java.util.Collections; @@ -69,6 +71,11 @@ void replaceTypeReferences(Map typeMap) { this.type = (GraphQLOutputType) new SchemaUtil().resolveTypeReference(this.type, typeMap); } + + void replaceType(GraphQLOutputType type) { + this.type = type; + } + @Override public String getName() { return name; @@ -144,6 +151,19 @@ public GraphQLFieldDefinition transform(Consumer builderConsumer) { return builder.build(); } + @Override + public TraversalControl accept(TraverserContext context, TypeVisitor visitor) { + return visitor.visitGraphQLFieldDefinition(this, context); + } + + @Override + public List getChildren() { + List children = new ArrayList<>(); + children.add(type); + children.addAll(arguments); + return children; + } + public static Builder newFieldDefinition(GraphQLFieldDefinition existing) { return new Builder(existing); } diff --git a/src/main/java/graphql/schema/GraphQLInputObjectField.java b/src/main/java/graphql/schema/GraphQLInputObjectField.java index a25c7b1de8..c1e42d38f8 100644 --- a/src/main/java/graphql/schema/GraphQLInputObjectField.java +++ b/src/main/java/graphql/schema/GraphQLInputObjectField.java @@ -4,8 +4,11 @@ import graphql.Internal; import graphql.PublicApi; import graphql.language.InputValueDefinition; +import graphql.util.TraversalControl; +import graphql.util.TraverserContext; import java.util.ArrayList; +import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -63,6 +66,10 @@ void replaceTypeReferences(Map typeMap) { type = (GraphQLInputType) new SchemaUtil().resolveTypeReference(type, typeMap); } + void replaceType(GraphQLInputType type) { + this.type = type; + } + @Override public String getName() { return name; @@ -103,6 +110,16 @@ public GraphQLInputObjectField transform(Consumer builderConsumer) { return builder.build(); } + @Override + public TraversalControl accept(TraverserContext context, TypeVisitor visitor) { + return visitor.visitGraphQLInputObjectField(this, context); + } + + @Override + public List getChildren() { + return Collections.singletonList(type); + } + public static Builder newInputObjectField(GraphQLInputObjectField existing) { return new Builder(existing); } diff --git a/src/main/java/graphql/schema/GraphQLInputObjectType.java b/src/main/java/graphql/schema/GraphQLInputObjectType.java index e5abbaf340..0257af0fab 100644 --- a/src/main/java/graphql/schema/GraphQLInputObjectType.java +++ b/src/main/java/graphql/schema/GraphQLInputObjectType.java @@ -4,6 +4,8 @@ import graphql.Internal; import graphql.PublicApi; import graphql.language.InputObjectTypeDefinition; +import graphql.util.TraversalControl; +import graphql.util.TraverserContext; import java.util.ArrayList; import java.util.LinkedHashMap; @@ -110,6 +112,16 @@ public GraphQLInputObjectType transform(Consumer builderConsumer) { return builder.build(); } + @Override + public TraversalControl accept(TraverserContext context, TypeVisitor visitor) { + return visitor.visitGraphQLInputObjectType(this, context); + } + + @Override + public List getChildren() { + return new ArrayList<>(fieldMap.values()); + } + public static Builder newInputObject(GraphQLInputObjectType existing) { return new Builder(existing); } diff --git a/src/main/java/graphql/schema/GraphQLInterfaceType.java b/src/main/java/graphql/schema/GraphQLInterfaceType.java index b800ce15d2..b509033b22 100644 --- a/src/main/java/graphql/schema/GraphQLInterfaceType.java +++ b/src/main/java/graphql/schema/GraphQLInterfaceType.java @@ -4,6 +4,8 @@ import graphql.Internal; import graphql.PublicApi; import graphql.language.InterfaceTypeDefinition; +import graphql.util.TraversalControl; +import graphql.util.TraverserContext; import java.util.ArrayList; import java.util.Collections; @@ -125,6 +127,16 @@ public GraphQLInterfaceType transform(Consumer builderConsumer) { return builder.build(); } + @Override + public TraversalControl accept(TraverserContext context, TypeVisitor visitor) { + return visitor.visitGraphQLInterfaceType(this, context); + } + + @Override + public List getChildren() { + return new ArrayList<>(fieldDefinitionsByName.values()); + } + public static Builder newInterface() { return new Builder(); } diff --git a/src/main/java/graphql/schema/GraphQLList.java b/src/main/java/graphql/schema/GraphQLList.java index 12dd5de2cc..de340ca7d7 100644 --- a/src/main/java/graphql/schema/GraphQLList.java +++ b/src/main/java/graphql/schema/GraphQLList.java @@ -2,7 +2,11 @@ import graphql.PublicApi; +import graphql.util.TraversalControl; +import graphql.util.TraverserContext; +import java.util.Collections; +import java.util.List; import java.util.Map; import static graphql.Assert.assertNotNull; @@ -41,10 +45,15 @@ public GraphQLType getWrappedType() { return wrappedType; } + @Deprecated void replaceTypeReferences(Map typeMap) { wrappedType = new SchemaUtil().resolveTypeReference(wrappedType, typeMap); } + void replaceType(GraphQLType type) { + wrappedType = type; + } + @Override public boolean equals(Object o) { if (this == o) return true; @@ -65,4 +74,14 @@ public int hashCode() { public String getName() { return null; } + + @Override + public TraversalControl accept(TraverserContext context, TypeVisitor visitor) { + return visitor.visitGraphQLList(this, context); + } + + @Override + public List getChildren() { + return Collections.singletonList(wrappedType); + } } diff --git a/src/main/java/graphql/schema/GraphQLNonNull.java b/src/main/java/graphql/schema/GraphQLNonNull.java index 1a7d0193a7..5a7e7dfad9 100644 --- a/src/main/java/graphql/schema/GraphQLNonNull.java +++ b/src/main/java/graphql/schema/GraphQLNonNull.java @@ -2,7 +2,11 @@ import graphql.PublicApi; +import graphql.util.TraversalControl; +import graphql.util.TraverserContext; +import java.util.Collections; +import java.util.List; import java.util.Map; import static graphql.Assert.assertNotNull; @@ -41,10 +45,15 @@ public GraphQLType getWrappedType() { return wrappedType; } + @Deprecated void replaceTypeReferences(Map typeMap) { wrappedType = new SchemaUtil().resolveTypeReference(wrappedType, typeMap); } + void replaceType(GraphQLType type) { + wrappedType = type; + } + @Override public boolean equals(Object o) { if (this == o) return true; @@ -72,4 +81,14 @@ public String toString() { public String getName() { return null; } + + @Override + public TraversalControl accept(TraverserContext context, TypeVisitor visitor) { + return visitor.visitGraphQLNonNull(this, context); + } + + @Override + public List getChildren() { + return Collections.singletonList(wrappedType); + } } diff --git a/src/main/java/graphql/schema/GraphQLObjectType.java b/src/main/java/graphql/schema/GraphQLObjectType.java index 62f9ff9453..9f3188db9f 100644 --- a/src/main/java/graphql/schema/GraphQLObjectType.java +++ b/src/main/java/graphql/schema/GraphQLObjectType.java @@ -4,11 +4,14 @@ import graphql.Internal; import graphql.PublicApi; import graphql.language.ObjectTypeDefinition; +import graphql.util.TraversalControl; +import graphql.util.TraverserContext; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.UnaryOperator; import java.util.stream.Collectors; @@ -60,12 +63,17 @@ public GraphQLObjectType(String name, String description, List typeMap) { this.interfaces = this.interfaces.stream() .map(type -> (GraphQLOutputType) new SchemaUtil().resolveTypeReference(type, typeMap)) .collect(Collectors.toList()); } + void replaceInterfaces(List interfaces) { + this.interfaces = interfaces; + } + private void buildDefinitionMap(List fieldDefinitions) { for (GraphQLFieldDefinition fieldDefinition : fieldDefinitions) { String name = fieldDefinition.getName(); @@ -138,6 +146,18 @@ public GraphQLObjectType transform(Consumer builderConsumer) { return builder.build(); } + @Override + public TraversalControl accept(TraverserContext context, TypeVisitor visitor) { + return visitor.visitGraphQLObjectType(this, context); + } + + @Override + public List getChildren() { + List children = new ArrayList<>(fieldDefinitionsByName.values()); + children.addAll(interfaces); + return children; + } + public static Builder newObject() { return new Builder(); } diff --git a/src/main/java/graphql/schema/GraphQLScalarType.java b/src/main/java/graphql/schema/GraphQLScalarType.java index ee1a160806..13b9bafb68 100644 --- a/src/main/java/graphql/schema/GraphQLScalarType.java +++ b/src/main/java/graphql/schema/GraphQLScalarType.java @@ -4,6 +4,8 @@ import graphql.Internal; import graphql.PublicApi; import graphql.language.ScalarTypeDefinition; +import graphql.util.TraversalControl; +import graphql.util.TraverserContext; import java.util.ArrayList; import java.util.LinkedHashMap; @@ -105,6 +107,11 @@ public GraphQLScalarType transform(Consumer builderConsumer) { return builder.build(); } + @Override + public TraversalControl accept(TraverserContext context, TypeVisitor visitor) { + return visitor.visitGraphQLScalarType(this, context); + } + public static Builder newScalar() { return new Builder(); } diff --git a/src/main/java/graphql/schema/GraphQLType.java b/src/main/java/graphql/schema/GraphQLType.java index 0b3f3a67cd..bcc76f9aaa 100644 --- a/src/main/java/graphql/schema/GraphQLType.java +++ b/src/main/java/graphql/schema/GraphQLType.java @@ -2,6 +2,11 @@ import graphql.PublicApi; +import graphql.util.TraversalControl; +import graphql.util.TraverserContext; + +import java.util.Collections; +import java.util.List; /** * All types in graphql have a name @@ -12,4 +17,11 @@ public interface GraphQLType { * @return the name of the type which MUST fit within the regular expression {@code [_A-Za-z][_0-9A-Za-z]*} */ String getName(); + + /** + * @return returns all types directly associated with this node + */ + default List getChildren() { return Collections.emptyList(); } + + TraversalControl accept(TraverserContext context, TypeVisitor visitor); } diff --git a/src/main/java/graphql/schema/GraphQLTypeReference.java b/src/main/java/graphql/schema/GraphQLTypeReference.java index c97a215ae2..79006ef997 100644 --- a/src/main/java/graphql/schema/GraphQLTypeReference.java +++ b/src/main/java/graphql/schema/GraphQLTypeReference.java @@ -3,6 +3,9 @@ import graphql.PublicApi; +import graphql.util.TraversalControl; +import graphql.util.TraverserContext; + import static graphql.Assert.assertValidName; /** @@ -36,4 +39,9 @@ public GraphQLTypeReference(String name) { public String getName() { return name; } + + @Override + public TraversalControl accept(TraverserContext context, TypeVisitor visitor) { + return visitor.visitGraphQLTypeReference(this, context); + } } diff --git a/src/main/java/graphql/schema/GraphQLUnionType.java b/src/main/java/graphql/schema/GraphQLUnionType.java index a8a86cb10b..f035752ef9 100644 --- a/src/main/java/graphql/schema/GraphQLUnionType.java +++ b/src/main/java/graphql/schema/GraphQLUnionType.java @@ -4,6 +4,8 @@ import graphql.Internal; import graphql.PublicApi; import graphql.language.UnionTypeDefinition; +import graphql.util.TraversalControl; +import graphql.util.TraverserContext; import java.util.ArrayList; import java.util.LinkedHashMap; @@ -61,12 +63,17 @@ public GraphQLUnionType(String name, String description, List this.directives = directives; } + @Deprecated void replaceTypeReferences(Map typeMap) { this.types = this.types.stream() .map(type -> (GraphQLOutputType) new SchemaUtil().resolveTypeReference(type, typeMap)) .collect(Collectors.toList()); } + void replaceTypes(List types) { + this.types = types; + } + /** * @return This returns GraphQLObjectType or GraphQLTypeReference instances, if the type * references are not resolved yet. After they are resolved it contains only GraphQLObjectType. @@ -112,6 +119,16 @@ public GraphQLUnionType transform(Consumer builderConsumer) { return builder.build(); } + @Override + public TraversalControl accept(TraverserContext context, TypeVisitor visitor) { + return visitor.visitGraphQLUnionType(this, context); + } + + @Override + public List getChildren() { + return new ArrayList<>(types); + } + public static Builder newUnionType() { return new Builder(); } diff --git a/src/main/java/graphql/schema/SchemaUtil.java b/src/main/java/graphql/schema/SchemaUtil.java index 98faf2a7bc..a10844aae5 100644 --- a/src/main/java/graphql/schema/SchemaUtil.java +++ b/src/main/java/graphql/schema/SchemaUtil.java @@ -5,13 +5,17 @@ import graphql.AssertException; import graphql.Internal; import graphql.introspection.Introspection; +import graphql.util.TraversalControl; +import static graphql.util.TraversalControl.QUIT; +import graphql.util.TraverserContext; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; -import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; import static graphql.schema.GraphQLTypeUtil.isList; import static graphql.schema.GraphQLTypeUtil.isNonNull; @@ -21,31 +25,31 @@ @Internal public class SchemaUtil { - @SuppressWarnings("StatementWithEmptyBody") - private void collectTypes(GraphQLType root, Map result) { - if (isNonNull(root)) { - collectTypes(unwrapOne(root), result); - } else if (isList(root)) { - collectTypes(unwrapOne(root), result); - } else if (root instanceof GraphQLEnumType) { - assertTypeUniqueness(root, result); - result.put(root.getName(), root); - } else if (root instanceof GraphQLScalarType) { - assertTypeUniqueness(root, result); - result.put(root.getName(), root); - } else if (root instanceof GraphQLObjectType) { - collectTypesForObjects((GraphQLObjectType) root, result); - } else if (root instanceof GraphQLInterfaceType) { - collectTypesForInterfaces((GraphQLInterfaceType) root, result); - } else if (root instanceof GraphQLUnionType) { - collectTypesForUnions((GraphQLUnionType) root, result); - } else if (root instanceof GraphQLInputObjectType) { - collectTypesForInputObjects((GraphQLInputObjectType) root, result); - } else if (root instanceof GraphQLTypeReference) { - // nothing to do - } else { - Assert.assertShouldNeverHappen("Unknown type %s", root); + public Boolean isLeafType(GraphQLType graphQLType) { + return (Boolean) SHALLOW_TRAVERSER.depthFirst(new LeafVisitor(), graphQLType).getResult(); + } + + public boolean isInputType(GraphQLType graphQLType) { + return (Boolean) SHALLOW_TRAVERSER.depthFirst(new LeafVisitor() { + @Override + public TraversalControl visitGraphQLInputObjectType(GraphQLInputObjectType node, TraverserContext context) { + context.setResult(true); + return QUIT; + } + }, graphQLType).getResult(); + } + + + /** + * Use custom visitor + */ + @Deprecated + public GraphQLUnmodifiedType getUnmodifiedType(GraphQLType graphQLType) { + if (graphQLType instanceof GraphQLModifiedType) { + return getUnmodifiedType(((GraphQLModifiedType) graphQLType).getWrappedType()); } + return (GraphQLUnmodifiedType) graphQLType; + } /* @@ -72,82 +76,31 @@ private void assertTypeUniqueness(GraphQLType type, Map res } } - private void collectTypesForUnions(GraphQLUnionType unionType, Map result) { - assertTypeUniqueness(unionType, result); - - result.put(unionType.getName(), unionType); - for (GraphQLType type : unionType.getTypes()) { - collectTypes(type, result); - } + Map allTypes(final GraphQLSchema schema,final Set additionalTypes) { + List roots = new ArrayList() {{ + add(schema.getQueryType()); - } - - private void collectTypesForInterfaces(GraphQLInterfaceType interfaceType, Map result) { - if (result.containsKey(interfaceType.getName()) && !(result.get(interfaceType.getName()) instanceof GraphQLTypeReference)) { - assertTypeUniqueness(interfaceType, result); - return; - } - result.put(interfaceType.getName(), interfaceType); - - // this deliberately has open field visibility as its collecting on the whole schema - for (GraphQLFieldDefinition fieldDefinition : interfaceType.getFieldDefinitions()) { - collectTypes(fieldDefinition.getType(), result); - for (GraphQLArgument fieldArgument : fieldDefinition.getArguments()) { - collectTypes(fieldArgument.getType(), result); + if(schema.isSupportingMutations()) { + add(schema.getMutationType()); } - } - } - - private void collectTypesForObjects(GraphQLObjectType objectType, Map result) { - if (result.containsKey(objectType.getName()) && !(result.get(objectType.getName()) instanceof GraphQLTypeReference)) { - assertTypeUniqueness(objectType, result); - return; - } - result.put(objectType.getName(), objectType); + if(schema.isSupportingSubscriptions()) { + add(schema.getSubscriptionType()); + } - // this deliberately has open field visibility as its collecting on the whole schema - for (GraphQLFieldDefinition fieldDefinition : objectType.getFieldDefinitions()) { - collectTypes(fieldDefinition.getType(), result); - for (GraphQLArgument fieldArgument : fieldDefinition.getArguments()) { - collectTypes(fieldArgument.getType(), result); + if(additionalTypes != null) { + addAll(additionalTypes); } - } - for (GraphQLOutputType interfaceType : objectType.getInterfaces()) { - collectTypes(interfaceType, result); - } - } - private void collectTypesForInputObjects(GraphQLInputObjectType objectType, Map result) { - if (result.containsKey(objectType.getName()) && !(result.get(objectType.getName()) instanceof GraphQLTypeReference)) { - assertTypeUniqueness(objectType, result); - return; - } - result.put(objectType.getName(), objectType); + add(Introspection.__Schema); + }}; - for (GraphQLInputObjectField fieldDefinition : objectType.getFields()) { - collectTypes(fieldDefinition.getType(), result); - } + CollectingVisitor visitor = new CollectingVisitor(); + TRAVERSER.depthFirst(visitor, roots); + return visitor.getResult(); } - Map allTypes(GraphQLSchema schema, Set additionalTypes) { - Map typesByName = new LinkedHashMap<>(); - collectTypes(schema.getQueryType(), typesByName); - if (schema.isSupportingMutations()) { - collectTypes(schema.getMutationType(), typesByName); - } - if (schema.isSupportingSubscriptions()) { - collectTypes(schema.getSubscriptionType(), typesByName); - } - if (additionalTypes != null) { - for (GraphQLType type : additionalTypes) { - collectTypes(type, typesByName); - } - } - collectTypes(Introspection.__Schema, typesByName); - return typesByName; - } /* * Indexes GraphQLObject types registered with the provided schema by implemented GraphQLInterface name @@ -204,52 +157,208 @@ public List findImplementations(GraphQLSchema schema, GraphQL return result; } - void replaceTypeReferences(GraphQLSchema schema) { - Map typeMap = schema.getTypeMap(); - for (GraphQLType type : typeMap.values()) { - if (type instanceof GraphQLFieldsContainer) { - resolveTypeReferencesForFieldsContainer((GraphQLFieldsContainer) type, typeMap); - } - if (type instanceof GraphQLInputFieldsContainer) { - resolveTypeReferencesForInputFieldsContainer((GraphQLInputFieldsContainer) type, typeMap); - } - if (type instanceof GraphQLObjectType) { - ((GraphQLObjectType) type).replaceTypeReferences(typeMap); + + final Map typeMap = schema.getTypeMap(); + + TRAVERSER.depthFirst(new TypeVisitorStub() { + + @Override + public TraversalControl visitGraphQLObjectType(GraphQLObjectType node, TraverserContext context) { + + node.replaceInterfaces(node.getInterfaces().stream() + .map(type -> (GraphQLOutputType)typeMap.get(type.getName())) + .collect(Collectors.toList())); + return super.visitGraphQLObjectType(node, context); } - if (type instanceof GraphQLUnionType) { - ((GraphQLUnionType) type).replaceTypeReferences(typeMap); + + @Override + public TraversalControl visitGraphQLUnionType(GraphQLUnionType node, TraverserContext context) { + + node.replaceTypes(node.getTypes().stream() + .map(type -> (GraphQLOutputType)typeMap.get(type.getName())) + .collect(Collectors.toList())); + return super.visitGraphQLUnionType(node, context); } - } - } - private void resolveTypeReferencesForFieldsContainer(GraphQLFieldsContainer fieldsContainer, Map typeMap) { - for (GraphQLFieldDefinition fieldDefinition : fieldsContainer.getFieldDefinitions()) { - fieldDefinition.replaceTypeReferences(typeMap); - for (GraphQLArgument argument : fieldDefinition.getArguments()) { - argument.replaceTypeReferences(typeMap); + @Override + public TraversalControl visitGraphQLTypeReference(GraphQLTypeReference node, TraverserContext context) { + + final GraphQLType resolvedType = typeMap.get(node.getName()); + Assert.assertTrue(resolvedType != null, "type %s not found in schema", node.getName()); + context.getParentContext().thisNode().accept(context, new RefResolvingVisitor(resolvedType) ); + return super.visitGraphQLTypeReference(node, context); } - } - } + },typeMap.values()); - private void resolveTypeReferencesForInputFieldsContainer(GraphQLInputFieldsContainer fieldsContainer, Map typeMap) { - for (GraphQLInputObjectField fieldDefinition : fieldsContainer.getFieldDefinitions()) { - fieldDefinition.replaceTypeReferences(typeMap); - } } + @Deprecated GraphQLType resolveTypeReference(GraphQLType type, Map typeMap) { if (type instanceof GraphQLTypeReference || typeMap.containsKey(type.getName())) { GraphQLType resolvedType = typeMap.get(type.getName()); Assert.assertTrue(resolvedType != null, "type %s not found in schema", type.getName()); return resolvedType; } - if (isList(type)) { - ((GraphQLList) type).replaceTypeReferences(typeMap); + return type; + } + + + class RefResolvingVisitor extends TypeVisitorStub { + + final private GraphQLType resolvedType; + public RefResolvingVisitor(GraphQLType resolvedType) { + this.resolvedType = resolvedType; + } + + @Override + public TraversalControl visitGraphQLFieldDefinition(GraphQLFieldDefinition node, TraverserContext context) { + node.replaceType((GraphQLOutputType) resolvedType); + return super.visitGraphQLFieldDefinition(node, context); } - if (isNonNull(type)) { - ((GraphQLNonNull) type).replaceTypeReferences(typeMap); + + @Override + public TraversalControl visitGraphQLArgument(GraphQLArgument node, TraverserContext context) { + node.replaceType((GraphQLInputType) resolvedType); + return super.visitGraphQLArgument(node, context); } - return type; + + @Override + public TraversalControl visitGraphQLInputObjectField(GraphQLInputObjectField node, TraverserContext context) { + node.replaceType((GraphQLInputType) resolvedType); + return super.visitGraphQLInputObjectField(node, context); + } + + @Override + public TraversalControl visitGraphQLList(GraphQLList node, TraverserContext context) { + node.replaceType( resolvedType); + return super.visitGraphQLList(node, context); + } + + @Override + public TraversalControl visitGraphQLNonNull(GraphQLNonNull node, TraverserContext context) { + node.replaceType( resolvedType); + return super.visitGraphQLNonNull(node, context); + } + } + + + public static class LeafVisitor extends TypeVisitorStub { + + @Override + public TraversalControl visitGraphQLScalarType(GraphQLScalarType node, TraverserContext context) { + context.setResult(true); + return QUIT; + } + + @Override + public TraversalControl visitGraphQLEnumType(GraphQLEnumType node, TraverserContext context) { + context.setResult(true); + return QUIT; + } + + @Override + protected TraversalControl visitGraphQLType(GraphQLType node, TraverserContext context) { + context.setResult(false); + return QUIT; + } + + @Override + public TraversalControl visitGraphQLList(GraphQLList node, TraverserContext context) { + return node.getWrappedType().accept(context,this); + } + + @Override + public TraversalControl visitGraphQLNonNull(GraphQLNonNull node, TraverserContext context) { + return node.getWrappedType().accept(context,this); + } + + } + + + class CollectingVisitor extends TypeVisitorStub { + + private final Map result = new HashMap<>(); + + @Override + public TraversalControl visitGraphQLEnumType(GraphQLEnumType node, TraverserContext context) { + assertTypeUniqueness(node,result); + save(node.getName(),node); + return super.visitGraphQLEnumType(node, context); + } + + @Override + public TraversalControl visitGraphQLScalarType(GraphQLScalarType node, TraverserContext context) { + assertTypeUniqueness(node,result); + save(node.getName(),node); + return super.visitGraphQLScalarType(node, context); + } + + @Override + public TraversalControl visitGraphQLObjectType(GraphQLObjectType node, TraverserContext context) { + if (isTypeReference(node.getName())) { + assertTypeUniqueness(node, result); + } else { + save(node.getName(), node); + } + return super.visitGraphQLObjectType(node,context); + } + + @Override + public TraversalControl visitGraphQLInputObjectType(GraphQLInputObjectType node, TraverserContext context) { + if (isTypeReference(node.getName())) { + assertTypeUniqueness(node, result); + } else { + save(node.getName(), node); + } + return super.visitGraphQLInputObjectType(node, context); + } + + @Override + public TraversalControl visitGraphQLInterfaceType(GraphQLInterfaceType node, TraverserContext context) { + if (isTypeReference(node.getName())) { + assertTypeUniqueness(node, result); + } else { + save(node.getName(), node); + } + + return super.visitGraphQLInterfaceType(node, context); + } + + @Override + public TraversalControl visitGraphQLUnionType(GraphQLUnionType node, TraverserContext context) { + assertTypeUniqueness(node,result); + save(node.getName(),node); + return super.visitGraphQLUnionType(node, context); + } + + @Override + public TraversalControl visitGraphQLFieldDefinition(GraphQLFieldDefinition node, TraverserContext context) { + + return super.visitGraphQLFieldDefinition(node, context); + } + + // TODO: eh? Isn't it similar to assertTypeUniqueness? + private boolean isTypeReference(String name) { + return result.containsKey(name) && !(result.get(name) instanceof GraphQLTypeReference); + } + + private void save(String name, GraphQLType type) { + result.put(name,type); + } + + public Map getResult() { + return result; + } + } + + + + private static final TypeTraverser SHALLOW_TRAVERSER = new TypeTraverser((node) -> Collections.emptyList()); + + private static final TypeTraverser TRAVERSER = new TypeTraverser(); + + + } diff --git a/src/main/java/graphql/schema/TypeTraverser.java b/src/main/java/graphql/schema/TypeTraverser.java new file mode 100644 index 0000000000..9c8cfe9727 --- /dev/null +++ b/src/main/java/graphql/schema/TypeTraverser.java @@ -0,0 +1,62 @@ +package graphql.schema; + + +import graphql.util.TraversalControl; +import graphql.util.Traverser; +import graphql.util.TraverserContext; +import graphql.util.TraverserResult; +import graphql.util.TraverserVisitor; + + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +public class TypeTraverser { + + + private final Function> getChildren; + + public TypeTraverser(Function> getChildren) { + this.getChildren = getChildren; + } + + public TypeTraverser() { + this(GraphQLType::getChildren); + } + + public TraverserResult depthFirst(TypeVisitor typeVisitor, GraphQLType root) { + return depthFirst(typeVisitor, Collections.singletonList(root)); + } + + public TraverserResult depthFirst(final TypeVisitor typeVisitor, Collection roots) { + return Traverser.depthFirst(getChildren).traverse(roots, new TraverserDelegateVisitor(typeVisitor)); + } + + public TraverserResult depthFirst(final TypeVisitor typeVisitor, + Collection roots, + Map types) { + return Traverser.depthFirst(getChildren).rootVar(TypeTraverser.class, types).traverse(roots, new TraverserDelegateVisitor(typeVisitor)); + } + + class TraverserDelegateVisitor implements TraverserVisitor { + private final TypeVisitor delegate; + + public TraverserDelegateVisitor(TypeVisitor delegate) { + this.delegate = delegate; + } + + @Override + public TraversalControl enter(TraverserContext context) { + return context.thisNode().accept(context, delegate); + } + + @Override + public TraversalControl leave(TraverserContext context) { + return context.thisNode().accept(context, delegate); + } + } + +} diff --git a/src/main/java/graphql/schema/TypeVisitor.java b/src/main/java/graphql/schema/TypeVisitor.java new file mode 100644 index 0000000000..083539302d --- /dev/null +++ b/src/main/java/graphql/schema/TypeVisitor.java @@ -0,0 +1,59 @@ +package graphql.schema; + +import graphql.util.TraversalControl; +import graphql.util.TraverserContext; + +public interface TypeVisitor { + TraversalControl visitGraphQLArgument(GraphQLArgument node, TraverserContext context); + TraversalControl visitGraphQLInterfaceType(GraphQLInterfaceType node, TraverserContext context); + TraversalControl visitGraphQLEnumType(GraphQLEnumType node, TraverserContext context); + TraversalControl visitGraphQLEnumValueDefinition(GraphQLEnumValueDefinition node, TraverserContext context); + TraversalControl visitGraphQLFieldDefinition(GraphQLFieldDefinition node, TraverserContext context); + TraversalControl visitGraphQLInputObjectField(GraphQLInputObjectField node, TraverserContext context); + TraversalControl visitGraphQLInputObjectType(GraphQLInputObjectType node, TraverserContext context); + TraversalControl visitGraphQLList(GraphQLList node, TraverserContext context); + TraversalControl visitGraphQLNonNull(GraphQLNonNull node, TraverserContext context); + TraversalControl visitGraphQLObjectType(GraphQLObjectType node, TraverserContext context); + TraversalControl visitGraphQLScalarType(GraphQLScalarType node, TraverserContext context); + TraversalControl visitGraphQLTypeReference(GraphQLTypeReference node, TraverserContext context); + TraversalControl visitGraphQLUnionType(GraphQLUnionType node, TraverserContext context); + + // Marker interfaces + default TraversalControl visitGraphQLModifiedType(GraphQLModifiedType node, TraverserContext context) { + throw new UnsupportedOperationException(); + } + + default TraversalControl visitGraphQLCompositeType(GraphQLCompositeType node, TraverserContext context) { + throw new UnsupportedOperationException(); + } + + default TraversalControl visitGraphQLDirectiveContainer(GraphQLDirectiveContainer node, TraverserContext context) { + throw new UnsupportedOperationException(); + } + + default TraversalControl visitGraphQLFieldsContainer(GraphQLFieldsContainer node, TraverserContext context) { + throw new UnsupportedOperationException(); + } + + default TraversalControl visitGraphQLInputFieldsContainer(GraphQLInputFieldsContainer node, TraverserContext context) { + throw new UnsupportedOperationException(); + } + + default TraversalControl visitGraphQLInputType(GraphQLInputType node, TraverserContext context) { + throw new UnsupportedOperationException(); + } + + default TraversalControl visitGraphQLNullableType(GraphQLNullableType node, TraverserContext context) { + throw new UnsupportedOperationException(); + } + + default TraversalControl visitGraphQLOutputType(GraphQLOutputType node, TraverserContext context) { + throw new UnsupportedOperationException(); + } + + default TraversalControl visitGraphQLUnmodifiedType(GraphQLUnmodifiedType node, TraverserContext context) { + throw new UnsupportedOperationException(); + } + + +} diff --git a/src/main/java/graphql/schema/TypeVisitorStub.java b/src/main/java/graphql/schema/TypeVisitorStub.java new file mode 100644 index 0000000000..0cdea34b55 --- /dev/null +++ b/src/main/java/graphql/schema/TypeVisitorStub.java @@ -0,0 +1,76 @@ +package graphql.schema; + +import graphql.util.TraversalControl; +import graphql.util.TraverserContext; +import static graphql.util.TraversalControl.CONTINUE; + +public class TypeVisitorStub implements TypeVisitor { + @Override + public TraversalControl visitGraphQLArgument(GraphQLArgument node, TraverserContext context) { + return visitGraphQLType(node,context); + } + + @Override + public TraversalControl visitGraphQLInterfaceType(GraphQLInterfaceType node, TraverserContext context) { + return visitGraphQLType(node,context); + } + + @Override + public TraversalControl visitGraphQLEnumType(GraphQLEnumType node, TraverserContext context) { + return visitGraphQLType(node,context); + } + + @Override + public TraversalControl visitGraphQLEnumValueDefinition(GraphQLEnumValueDefinition node, TraverserContext context) { + return visitGraphQLType(node,context); + } + + @Override + public TraversalControl visitGraphQLFieldDefinition(GraphQLFieldDefinition node, TraverserContext context) { + return visitGraphQLType(node,context); + } + + @Override + public TraversalControl visitGraphQLInputObjectField(GraphQLInputObjectField node, TraverserContext context) { + return visitGraphQLType(node,context); + } + + @Override + public TraversalControl visitGraphQLInputObjectType(GraphQLInputObjectType node, TraverserContext context) { + return visitGraphQLType(node,context); + } + + @Override + public TraversalControl visitGraphQLList(GraphQLList node, TraverserContext context) { + return visitGraphQLType(node,context); + } + + @Override + public TraversalControl visitGraphQLNonNull(GraphQLNonNull node, TraverserContext context) { + return visitGraphQLType(node,context); + } + + @Override + public TraversalControl visitGraphQLObjectType(GraphQLObjectType node, TraverserContext context) { + return visitGraphQLType(node,context); + } + + @Override + public TraversalControl visitGraphQLScalarType(GraphQLScalarType node, TraverserContext context) { + return visitGraphQLType(node,context); + } + + @Override + public TraversalControl visitGraphQLTypeReference(GraphQLTypeReference node, TraverserContext context) { + return visitGraphQLType(node,context); + } + + @Override + public TraversalControl visitGraphQLUnionType(GraphQLUnionType node, TraverserContext context) { + return visitGraphQLType(node,context); + } + + protected TraversalControl visitGraphQLType(GraphQLType node, TraverserContext context) { + return CONTINUE; + } +} diff --git a/src/test/groovy/graphql/StarWarsIntrospectionTests.groovy b/src/test/groovy/graphql/StarWarsIntrospectionTests.groovy index 3550665626..b34e3aa5dd 100644 --- a/src/test/groovy/graphql/StarWarsIntrospectionTests.groovy +++ b/src/test/groovy/graphql/StarWarsIntrospectionTests.groovy @@ -19,21 +19,22 @@ class StarWarsIntrospectionTests extends Specification { """ def expected = [ __schema: [types: - [[name: 'QueryType'], + [[name: 'Human'], + [name: '__TypeKind'], + [name: '__Field'], [name: 'Character'], - [name: 'String'], - [name: 'Episode'], - [name: 'Human'], - [name: 'Droid'], [name: '__Schema'], [name: '__Type'], - [name: '__TypeKind'], - [name: '__Field'], + [name: '__EnumValue'], + [name: '__DirectiveLocation'], + [name: 'String'], + [name: 'Droid'], + [name: 'Episode'], [name: '__InputValue'], [name: 'Boolean'], - [name: '__EnumValue'], - [name: '__Directive'], - [name: '__DirectiveLocation']] + [name: 'QueryType'], + [name: '__Directive'] + ] ] ] diff --git a/src/test/groovy/graphql/UnionTest.groovy b/src/test/groovy/graphql/UnionTest.groovy index bf6b757047..63745e2f41 100644 --- a/src/test/groovy/graphql/UnionTest.groovy +++ b/src/test/groovy/graphql/UnionTest.groovy @@ -37,8 +37,8 @@ class UnionTest extends Specification { ], interfaces : null, possibleTypes: [ - [name: 'Person'], [name: 'Cat'], + [name: 'Person'], [name: 'Dog'] ], enumValues : null, From 9c96a2c1123ead1bcf451a0950161815079e1097 Mon Sep 17 00:00:00 2001 From: amatiushkin Date: Sun, 17 Jun 2018 15:04:19 -0700 Subject: [PATCH 02/13] Add javadoc --- src/main/java/graphql/schema/GraphQLType.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/main/java/graphql/schema/GraphQLType.java b/src/main/java/graphql/schema/GraphQLType.java index bcc76f9aaa..74c19246a3 100644 --- a/src/main/java/graphql/schema/GraphQLType.java +++ b/src/main/java/graphql/schema/GraphQLType.java @@ -23,5 +23,18 @@ public interface GraphQLType { */ default List getChildren() { return Collections.emptyList(); } + /** + * Double-dispatch entry point. + * + * It allows to travers a given non-trivial graphQL type and move from root to nested or enclosed types. + * + * This implements similar pattern as {@link graphql.language.Node}, see accept(...) for more details about the pattern. + * + * @param context TraverserContext bound to this graphQL type object + * @param visitor Visitor instance that performs actual processing on the types(s) + * + * @return Result of Visitor's operation. + * Note! Visitor's operation might return special results to control traversal process. + */ TraversalControl accept(TraverserContext context, TypeVisitor visitor); } From 7cfc8a7e90cec2016b4ba9d07a45079b41b250ca Mon Sep 17 00:00:00 2001 From: amatiushkin Date: Mon, 18 Jun 2018 14:59:15 -0700 Subject: [PATCH 03/13] Code review comments --- .../java/graphql/schema/GraphQLArgument.java | 2 +- .../java/graphql/schema/GraphQLEnumType.java | 2 +- .../schema/GraphQLEnumValueDefinition.java | 2 +- .../schema/GraphQLFieldDefinition.java | 2 +- .../schema/GraphQLInputObjectField.java | 2 +- .../schema/GraphQLInputObjectType.java | 2 +- .../graphql/schema/GraphQLInterfaceType.java | 2 +- src/main/java/graphql/schema/GraphQLList.java | 2 +- .../java/graphql/schema/GraphQLNonNull.java | 2 +- .../graphql/schema/GraphQLObjectType.java | 3 +- .../graphql/schema/GraphQLScalarType.java | 2 +- src/main/java/graphql/schema/GraphQLType.java | 2 +- .../graphql/schema/GraphQLTypeReference.java | 2 +- .../java/graphql/schema/GraphQLUnionType.java | 2 +- ...peVisitor.java => GraphqlTypeVisitor.java} | 4 +- ...rStub.java => GraphqlTypeVisitorStub.java} | 8 +- .../graphql/schema/GraphqlTypeVisitors.java | 237 ++++++++++++++++++ src/main/java/graphql/schema/SchemaUtil.java | 220 +--------------- .../java/graphql/schema/TypeTraverser.java | 16 +- 19 files changed, 279 insertions(+), 235 deletions(-) rename src/main/java/graphql/schema/{TypeVisitor.java => GraphqlTypeVisitor.java} (97%) rename src/main/java/graphql/schema/{TypeVisitorStub.java => GraphqlTypeVisitorStub.java} (89%) create mode 100644 src/main/java/graphql/schema/GraphqlTypeVisitors.java diff --git a/src/main/java/graphql/schema/GraphQLArgument.java b/src/main/java/graphql/schema/GraphQLArgument.java index 2238f3782b..befe435dbd 100644 --- a/src/main/java/graphql/schema/GraphQLArgument.java +++ b/src/main/java/graphql/schema/GraphQLArgument.java @@ -148,7 +148,7 @@ public static Builder newArgument(GraphQLArgument existing) { } @Override - public TraversalControl accept(TraverserContext context, TypeVisitor visitor) { + public TraversalControl accept(TraverserContext context, GraphqlTypeVisitor visitor) { return visitor.visitGraphQLArgument(this, context); } diff --git a/src/main/java/graphql/schema/GraphQLEnumType.java b/src/main/java/graphql/schema/GraphQLEnumType.java index 7320c25064..b861d8c618 100644 --- a/src/main/java/graphql/schema/GraphQLEnumType.java +++ b/src/main/java/graphql/schema/GraphQLEnumType.java @@ -178,7 +178,7 @@ public GraphQLEnumType transform(Consumer builderConsumer) { } @Override - public TraversalControl accept(TraverserContext context, TypeVisitor visitor) { + public TraversalControl accept(TraverserContext context, GraphqlTypeVisitor visitor) { return visitor.visitGraphQLEnumType(this, context); } diff --git a/src/main/java/graphql/schema/GraphQLEnumValueDefinition.java b/src/main/java/graphql/schema/GraphQLEnumValueDefinition.java index 41facc24b9..2f14840580 100644 --- a/src/main/java/graphql/schema/GraphQLEnumValueDefinition.java +++ b/src/main/java/graphql/schema/GraphQLEnumValueDefinition.java @@ -108,7 +108,7 @@ public GraphQLEnumValueDefinition transform(Consumer builderConsumer) { } @Override - public TraversalControl accept(TraverserContext context, TypeVisitor visitor) { + public TraversalControl accept(TraverserContext context, GraphqlTypeVisitor visitor) { return visitor.visitGraphQLEnumValueDefinition(this, context); } diff --git a/src/main/java/graphql/schema/GraphQLFieldDefinition.java b/src/main/java/graphql/schema/GraphQLFieldDefinition.java index 17a115bed1..870bedcd76 100644 --- a/src/main/java/graphql/schema/GraphQLFieldDefinition.java +++ b/src/main/java/graphql/schema/GraphQLFieldDefinition.java @@ -152,7 +152,7 @@ public GraphQLFieldDefinition transform(Consumer builderConsumer) { } @Override - public TraversalControl accept(TraverserContext context, TypeVisitor visitor) { + public TraversalControl accept(TraverserContext context, GraphqlTypeVisitor visitor) { return visitor.visitGraphQLFieldDefinition(this, context); } diff --git a/src/main/java/graphql/schema/GraphQLInputObjectField.java b/src/main/java/graphql/schema/GraphQLInputObjectField.java index c1e42d38f8..bf6387fd7b 100644 --- a/src/main/java/graphql/schema/GraphQLInputObjectField.java +++ b/src/main/java/graphql/schema/GraphQLInputObjectField.java @@ -111,7 +111,7 @@ public GraphQLInputObjectField transform(Consumer builderConsumer) { } @Override - public TraversalControl accept(TraverserContext context, TypeVisitor visitor) { + public TraversalControl accept(TraverserContext context, GraphqlTypeVisitor visitor) { return visitor.visitGraphQLInputObjectField(this, context); } diff --git a/src/main/java/graphql/schema/GraphQLInputObjectType.java b/src/main/java/graphql/schema/GraphQLInputObjectType.java index 0257af0fab..4d953ea4f2 100644 --- a/src/main/java/graphql/schema/GraphQLInputObjectType.java +++ b/src/main/java/graphql/schema/GraphQLInputObjectType.java @@ -113,7 +113,7 @@ public GraphQLInputObjectType transform(Consumer builderConsumer) { } @Override - public TraversalControl accept(TraverserContext context, TypeVisitor visitor) { + public TraversalControl accept(TraverserContext context, GraphqlTypeVisitor visitor) { return visitor.visitGraphQLInputObjectType(this, context); } diff --git a/src/main/java/graphql/schema/GraphQLInterfaceType.java b/src/main/java/graphql/schema/GraphQLInterfaceType.java index b509033b22..e7fa556e22 100644 --- a/src/main/java/graphql/schema/GraphQLInterfaceType.java +++ b/src/main/java/graphql/schema/GraphQLInterfaceType.java @@ -128,7 +128,7 @@ public GraphQLInterfaceType transform(Consumer builderConsumer) { } @Override - public TraversalControl accept(TraverserContext context, TypeVisitor visitor) { + public TraversalControl accept(TraverserContext context, GraphqlTypeVisitor visitor) { return visitor.visitGraphQLInterfaceType(this, context); } diff --git a/src/main/java/graphql/schema/GraphQLList.java b/src/main/java/graphql/schema/GraphQLList.java index de340ca7d7..0c3ec838ce 100644 --- a/src/main/java/graphql/schema/GraphQLList.java +++ b/src/main/java/graphql/schema/GraphQLList.java @@ -76,7 +76,7 @@ public String getName() { } @Override - public TraversalControl accept(TraverserContext context, TypeVisitor visitor) { + public TraversalControl accept(TraverserContext context, GraphqlTypeVisitor visitor) { return visitor.visitGraphQLList(this, context); } diff --git a/src/main/java/graphql/schema/GraphQLNonNull.java b/src/main/java/graphql/schema/GraphQLNonNull.java index 5a7e7dfad9..81e7852a99 100644 --- a/src/main/java/graphql/schema/GraphQLNonNull.java +++ b/src/main/java/graphql/schema/GraphQLNonNull.java @@ -83,7 +83,7 @@ public String getName() { } @Override - public TraversalControl accept(TraverserContext context, TypeVisitor visitor) { + public TraversalControl accept(TraverserContext context, GraphqlTypeVisitor visitor) { return visitor.visitGraphQLNonNull(this, context); } diff --git a/src/main/java/graphql/schema/GraphQLObjectType.java b/src/main/java/graphql/schema/GraphQLObjectType.java index 9f3188db9f..3a5f2fdafa 100644 --- a/src/main/java/graphql/schema/GraphQLObjectType.java +++ b/src/main/java/graphql/schema/GraphQLObjectType.java @@ -11,7 +11,6 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.UnaryOperator; import java.util.stream.Collectors; @@ -147,7 +146,7 @@ public GraphQLObjectType transform(Consumer builderConsumer) { } @Override - public TraversalControl accept(TraverserContext context, TypeVisitor visitor) { + public TraversalControl accept(TraverserContext context, GraphqlTypeVisitor visitor) { return visitor.visitGraphQLObjectType(this, context); } diff --git a/src/main/java/graphql/schema/GraphQLScalarType.java b/src/main/java/graphql/schema/GraphQLScalarType.java index 13b9bafb68..1306a2b1b5 100644 --- a/src/main/java/graphql/schema/GraphQLScalarType.java +++ b/src/main/java/graphql/schema/GraphQLScalarType.java @@ -108,7 +108,7 @@ public GraphQLScalarType transform(Consumer builderConsumer) { } @Override - public TraversalControl accept(TraverserContext context, TypeVisitor visitor) { + public TraversalControl accept(TraverserContext context, GraphqlTypeVisitor visitor) { return visitor.visitGraphQLScalarType(this, context); } diff --git a/src/main/java/graphql/schema/GraphQLType.java b/src/main/java/graphql/schema/GraphQLType.java index 74c19246a3..14b3d61dc9 100644 --- a/src/main/java/graphql/schema/GraphQLType.java +++ b/src/main/java/graphql/schema/GraphQLType.java @@ -36,5 +36,5 @@ public interface GraphQLType { * @return Result of Visitor's operation. * Note! Visitor's operation might return special results to control traversal process. */ - TraversalControl accept(TraverserContext context, TypeVisitor visitor); + TraversalControl accept(TraverserContext context, GraphqlTypeVisitor visitor); } diff --git a/src/main/java/graphql/schema/GraphQLTypeReference.java b/src/main/java/graphql/schema/GraphQLTypeReference.java index 79006ef997..6d7cabd055 100644 --- a/src/main/java/graphql/schema/GraphQLTypeReference.java +++ b/src/main/java/graphql/schema/GraphQLTypeReference.java @@ -41,7 +41,7 @@ public String getName() { } @Override - public TraversalControl accept(TraverserContext context, TypeVisitor visitor) { + public TraversalControl accept(TraverserContext context, GraphqlTypeVisitor visitor) { return visitor.visitGraphQLTypeReference(this, context); } } diff --git a/src/main/java/graphql/schema/GraphQLUnionType.java b/src/main/java/graphql/schema/GraphQLUnionType.java index f035752ef9..229d0810a0 100644 --- a/src/main/java/graphql/schema/GraphQLUnionType.java +++ b/src/main/java/graphql/schema/GraphQLUnionType.java @@ -120,7 +120,7 @@ public GraphQLUnionType transform(Consumer builderConsumer) { } @Override - public TraversalControl accept(TraverserContext context, TypeVisitor visitor) { + public TraversalControl accept(TraverserContext context, GraphqlTypeVisitor visitor) { return visitor.visitGraphQLUnionType(this, context); } diff --git a/src/main/java/graphql/schema/TypeVisitor.java b/src/main/java/graphql/schema/GraphqlTypeVisitor.java similarity index 97% rename from src/main/java/graphql/schema/TypeVisitor.java rename to src/main/java/graphql/schema/GraphqlTypeVisitor.java index 083539302d..5fc8a37a5a 100644 --- a/src/main/java/graphql/schema/TypeVisitor.java +++ b/src/main/java/graphql/schema/GraphqlTypeVisitor.java @@ -1,9 +1,11 @@ package graphql.schema; +import graphql.Internal; import graphql.util.TraversalControl; import graphql.util.TraverserContext; -public interface TypeVisitor { +@Internal +public interface GraphqlTypeVisitor { TraversalControl visitGraphQLArgument(GraphQLArgument node, TraverserContext context); TraversalControl visitGraphQLInterfaceType(GraphQLInterfaceType node, TraverserContext context); TraversalControl visitGraphQLEnumType(GraphQLEnumType node, TraverserContext context); diff --git a/src/main/java/graphql/schema/TypeVisitorStub.java b/src/main/java/graphql/schema/GraphqlTypeVisitorStub.java similarity index 89% rename from src/main/java/graphql/schema/TypeVisitorStub.java rename to src/main/java/graphql/schema/GraphqlTypeVisitorStub.java index 0cdea34b55..1486d774c8 100644 --- a/src/main/java/graphql/schema/TypeVisitorStub.java +++ b/src/main/java/graphql/schema/GraphqlTypeVisitorStub.java @@ -1,10 +1,16 @@ package graphql.schema; +import graphql.PublicApi; import graphql.util.TraversalControl; import graphql.util.TraverserContext; import static graphql.util.TraversalControl.CONTINUE; -public class TypeVisitorStub implements TypeVisitor { +/** + * Base implementation of {@link GraphqlTypeVisitor} for convenience. + * Overwrite only required methods and/or {@link #visitGraphQLType(GraphQLType, TraverserContext)} as default fallback. + */ +@PublicApi +public class GraphqlTypeVisitorStub implements GraphqlTypeVisitor { @Override public TraversalControl visitGraphQLArgument(GraphQLArgument node, TraverserContext context) { return visitGraphQLType(node,context); diff --git a/src/main/java/graphql/schema/GraphqlTypeVisitors.java b/src/main/java/graphql/schema/GraphqlTypeVisitors.java new file mode 100644 index 0000000000..e5ac24ff70 --- /dev/null +++ b/src/main/java/graphql/schema/GraphqlTypeVisitors.java @@ -0,0 +1,237 @@ +package graphql.schema; + +import graphql.Assert; +import graphql.AssertException; +import graphql.util.TraversalControl; +import graphql.util.TraverserContext; + +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Collectors; + +import static graphql.util.TraversalControl.QUIT; +import static java.lang.String.format; + +/** + * GraphQL Type visitors library + */ +class GraphqlTypeVisitors { + + private GraphqlTypeVisitors() {} + + + static class LeafVisitor extends GraphqlTypeVisitorStub { + + @Override + public TraversalControl visitGraphQLScalarType(GraphQLScalarType node, TraverserContext context) { + context.setResult(true); + return QUIT; + } + + @Override + public TraversalControl visitGraphQLEnumType(GraphQLEnumType node, TraverserContext context) { + context.setResult(true); + return QUIT; + } + + @Override + protected TraversalControl visitGraphQLType(GraphQLType node, TraverserContext context) { + context.setResult(false); + return QUIT; + } + + @Override + public TraversalControl visitGraphQLList(GraphQLList node, TraverserContext context) { + return node.getWrappedType().accept(context,this); + } + + @Override + public TraversalControl visitGraphQLNonNull(GraphQLNonNull node, TraverserContext context) { + return node.getWrappedType().accept(context,this); + } + + } + + static class CollectingVisitor extends GraphqlTypeVisitorStub { + + private final Map result = new HashMap<>(); + + public CollectingVisitor() { + } + + @Override + public TraversalControl visitGraphQLEnumType(GraphQLEnumType node, TraverserContext context) { + assertTypeUniqueness(node,result); + save(node.getName(),node); + return super.visitGraphQLEnumType(node, context); + } + + @Override + public TraversalControl visitGraphQLScalarType(GraphQLScalarType node, TraverserContext context) { + assertTypeUniqueness(node,result); + save(node.getName(),node); + return super.visitGraphQLScalarType(node, context); + } + + @Override + public TraversalControl visitGraphQLObjectType(GraphQLObjectType node, TraverserContext context) { + if (isTypeReference(node.getName())) { + assertTypeUniqueness(node, result); + } else { + save(node.getName(), node); + } + return super.visitGraphQLObjectType(node,context); + } + + @Override + public TraversalControl visitGraphQLInputObjectType(GraphQLInputObjectType node, TraverserContext context) { + if (isTypeReference(node.getName())) { + assertTypeUniqueness(node, result); + } else { + save(node.getName(), node); + } + return super.visitGraphQLInputObjectType(node, context); + } + + @Override + public TraversalControl visitGraphQLInterfaceType(GraphQLInterfaceType node, TraverserContext context) { + if (isTypeReference(node.getName())) { + assertTypeUniqueness(node, result); + } else { + save(node.getName(), node); + } + + return super.visitGraphQLInterfaceType(node, context); + } + + @Override + public TraversalControl visitGraphQLUnionType(GraphQLUnionType node, TraverserContext context) { + assertTypeUniqueness(node,result); + save(node.getName(),node); + return super.visitGraphQLUnionType(node, context); + } + + @Override + public TraversalControl visitGraphQLFieldDefinition(GraphQLFieldDefinition node, TraverserContext context) { + + return super.visitGraphQLFieldDefinition(node, context); + } + + // TODO: eh? Isn't it similar to assertTypeUniqueness? + private boolean isTypeReference(String name) { + return result.containsKey(name) && !(result.get(name) instanceof GraphQLTypeReference); + } + + private void save(String name, GraphQLType type) { + result.put(name,type); + } + + + /* + From http://facebook.github.io/graphql/#sec-Type-System + + All types within a GraphQL schema must have unique names. No two provided types may have the same name. + No provided type may have a name which conflicts with any built in types (including Scalar and Introspection types). + + Enforcing this helps avoid problems later down the track fo example https://github.com/graphql-java/graphql-java/issues/373 + */ + private void assertTypeUniqueness(GraphQLType type, Map result) { + GraphQLType existingType = result.get(type.getName()); + // do we have an existing definition + if (existingType != null) { + // type references are ok + if (!(existingType instanceof GraphQLTypeReference || type instanceof GraphQLTypeReference)) + // object comparison here is deliberate + if (existingType != type) { + throw new AssertException(format("All types within a GraphQL schema must have unique names. No two provided types may have the same name.\n" + + "No provided type may have a name which conflicts with any built in types (including Scalar and Introspection types).\n" + + "You have redefined the type '%s' from being a '%s' to a '%s'", + type.getName(), existingType.getClass().getSimpleName(), type.getClass().getSimpleName())); + } + } + } + + public Map getResult() { + return result; + } + + + } + + static class RefResolvingVisitor extends GraphqlTypeVisitorStub { + + final private GraphQLType resolvedType; + public RefResolvingVisitor(GraphQLType resolvedType) { + this.resolvedType = resolvedType; + } + + + + @Override + public TraversalControl visitGraphQLFieldDefinition(GraphQLFieldDefinition node, TraverserContext context) { + node.replaceType((GraphQLOutputType) resolvedType); + return super.visitGraphQLFieldDefinition(node, context); + } + + @Override + public TraversalControl visitGraphQLArgument(GraphQLArgument node, TraverserContext context) { + node.replaceType((GraphQLInputType) resolvedType); + return super.visitGraphQLArgument(node, context); + } + + @Override + public TraversalControl visitGraphQLInputObjectField(GraphQLInputObjectField node, TraverserContext context) { + node.replaceType((GraphQLInputType) resolvedType); + return super.visitGraphQLInputObjectField(node, context); + } + + @Override + public TraversalControl visitGraphQLList(GraphQLList node, TraverserContext context) { + node.replaceType( resolvedType); + return super.visitGraphQLList(node, context); + } + + @Override + public TraversalControl visitGraphQLNonNull(GraphQLNonNull node, TraverserContext context) { + node.replaceType( resolvedType); + return super.visitGraphQLNonNull(node, context); + } + + } + + static class TypeResolvingVisitor extends GraphqlTypeVisitorStub { + + private final Map typeMap; + + public TypeResolvingVisitor( Map typeMap) { + this.typeMap = typeMap; + } + + @Override + public TraversalControl visitGraphQLObjectType(GraphQLObjectType node, TraverserContext context) { + + node.replaceInterfaces(node.getInterfaces().stream() + .map(type -> (GraphQLOutputType)typeMap.get(type.getName())) + .collect(Collectors.toList())); + return super.visitGraphQLObjectType(node, context); + } + + @Override + public TraversalControl visitGraphQLUnionType(GraphQLUnionType node, TraverserContext context) { + + node.replaceTypes(node.getTypes().stream() + .map(type -> (GraphQLOutputType)typeMap.get(type.getName())) + .collect(Collectors.toList())); + return super.visitGraphQLUnionType(node, context); + } + + @Override + public TraversalControl visitGraphQLTypeReference(GraphQLTypeReference node, TraverserContext context) { + + final GraphQLType resolvedType = typeMap.get(node.getName()); + Assert.assertTrue(resolvedType != null, "type %s not found in schema", node.getName()); + context.getParentContext().thisNode().accept(context, new RefResolvingVisitor(resolvedType) ); + return super.visitGraphQLTypeReference(node, context); + } + } +} diff --git a/src/main/java/graphql/schema/SchemaUtil.java b/src/main/java/graphql/schema/SchemaUtil.java index a10844aae5..eed3154a23 100644 --- a/src/main/java/graphql/schema/SchemaUtil.java +++ b/src/main/java/graphql/schema/SchemaUtil.java @@ -2,11 +2,13 @@ import graphql.Assert; -import graphql.AssertException; import graphql.Internal; import graphql.introspection.Introspection; import graphql.util.TraversalControl; import static graphql.util.TraversalControl.QUIT; +import static graphql.schema.GraphqlTypeVisitors.LeafVisitor; +import static graphql.schema.GraphqlTypeVisitors.CollectingVisitor; +import static graphql.schema.GraphqlTypeVisitors.TypeResolvingVisitor; import graphql.util.TraverserContext; import java.util.ArrayList; @@ -15,7 +17,6 @@ import java.util.List; import java.util.Map; import java.util.Set; -import java.util.stream.Collectors; import static graphql.schema.GraphQLTypeUtil.isList; import static graphql.schema.GraphQLTypeUtil.isNonNull; @@ -25,11 +26,17 @@ @Internal public class SchemaUtil { + private static final TypeTraverser SHALLOW_TRAVERSER = new TypeTraverser((node) -> Collections.emptyList()); + + private static final TypeTraverser TRAVERSER = new TypeTraverser(); + + public Boolean isLeafType(GraphQLType graphQLType) { return (Boolean) SHALLOW_TRAVERSER.depthFirst(new LeafVisitor(), graphQLType).getResult(); } public boolean isInputType(GraphQLType graphQLType) { + return (Boolean) SHALLOW_TRAVERSER.depthFirst(new LeafVisitor() { @Override public TraversalControl visitGraphQLInputObjectType(GraphQLInputObjectType node, TraverserContext context) { @@ -52,29 +59,7 @@ public GraphQLUnmodifiedType getUnmodifiedType(GraphQLType graphQLType) { } - /* - From http://facebook.github.io/graphql/#sec-Type-System - - All types within a GraphQL schema must have unique names. No two provided types may have the same name. - No provided type may have a name which conflicts with any built in types (including Scalar and Introspection types). - Enforcing this helps avoid problems later down the track fo example https://github.com/graphql-java/graphql-java/issues/373 - */ - private void assertTypeUniqueness(GraphQLType type, Map result) { - GraphQLType existingType = result.get(type.getName()); - // do we have an existing definition - if (existingType != null) { - // type references are ok - if (!(existingType instanceof GraphQLTypeReference || type instanceof GraphQLTypeReference)) - // object comparison here is deliberate - if (existingType != type) { - throw new AssertException(format("All types within a GraphQL schema must have unique names. No two provided types may have the same name.\n" + - "No provided type may have a name which conflicts with any built in types (including Scalar and Introspection types).\n" + - "You have redefined the type '%s' from being a '%s' to a '%s'", - type.getName(), existingType.getClass().getSimpleName(), type.getClass().getSimpleName())); - } - } - } Map allTypes(final GraphQLSchema schema,final Set additionalTypes) { List roots = new ArrayList() {{ @@ -158,39 +143,8 @@ public List findImplementations(GraphQLSchema schema, GraphQL } void replaceTypeReferences(GraphQLSchema schema) { - final Map typeMap = schema.getTypeMap(); - - TRAVERSER.depthFirst(new TypeVisitorStub() { - - @Override - public TraversalControl visitGraphQLObjectType(GraphQLObjectType node, TraverserContext context) { - - node.replaceInterfaces(node.getInterfaces().stream() - .map(type -> (GraphQLOutputType)typeMap.get(type.getName())) - .collect(Collectors.toList())); - return super.visitGraphQLObjectType(node, context); - } - - @Override - public TraversalControl visitGraphQLUnionType(GraphQLUnionType node, TraverserContext context) { - - node.replaceTypes(node.getTypes().stream() - .map(type -> (GraphQLOutputType)typeMap.get(type.getName())) - .collect(Collectors.toList())); - return super.visitGraphQLUnionType(node, context); - } - - @Override - public TraversalControl visitGraphQLTypeReference(GraphQLTypeReference node, TraverserContext context) { - - final GraphQLType resolvedType = typeMap.get(node.getName()); - Assert.assertTrue(resolvedType != null, "type %s not found in schema", node.getName()); - context.getParentContext().thisNode().accept(context, new RefResolvingVisitor(resolvedType) ); - return super.visitGraphQLTypeReference(node, context); - } - },typeMap.values()); - + TRAVERSER.depthFirst(new TypeResolvingVisitor(typeMap),typeMap.values()); } @Deprecated @@ -204,160 +158,6 @@ GraphQLType resolveTypeReference(GraphQLType type, Map type } - class RefResolvingVisitor extends TypeVisitorStub { - - final private GraphQLType resolvedType; - public RefResolvingVisitor(GraphQLType resolvedType) { - this.resolvedType = resolvedType; - } - - @Override - public TraversalControl visitGraphQLFieldDefinition(GraphQLFieldDefinition node, TraverserContext context) { - node.replaceType((GraphQLOutputType) resolvedType); - return super.visitGraphQLFieldDefinition(node, context); - } - - @Override - public TraversalControl visitGraphQLArgument(GraphQLArgument node, TraverserContext context) { - node.replaceType((GraphQLInputType) resolvedType); - return super.visitGraphQLArgument(node, context); - } - - @Override - public TraversalControl visitGraphQLInputObjectField(GraphQLInputObjectField node, TraverserContext context) { - node.replaceType((GraphQLInputType) resolvedType); - return super.visitGraphQLInputObjectField(node, context); - } - - @Override - public TraversalControl visitGraphQLList(GraphQLList node, TraverserContext context) { - node.replaceType( resolvedType); - return super.visitGraphQLList(node, context); - } - - @Override - public TraversalControl visitGraphQLNonNull(GraphQLNonNull node, TraverserContext context) { - node.replaceType( resolvedType); - return super.visitGraphQLNonNull(node, context); - } - - } - - - public static class LeafVisitor extends TypeVisitorStub { - - @Override - public TraversalControl visitGraphQLScalarType(GraphQLScalarType node, TraverserContext context) { - context.setResult(true); - return QUIT; - } - - @Override - public TraversalControl visitGraphQLEnumType(GraphQLEnumType node, TraverserContext context) { - context.setResult(true); - return QUIT; - } - - @Override - protected TraversalControl visitGraphQLType(GraphQLType node, TraverserContext context) { - context.setResult(false); - return QUIT; - } - - @Override - public TraversalControl visitGraphQLList(GraphQLList node, TraverserContext context) { - return node.getWrappedType().accept(context,this); - } - - @Override - public TraversalControl visitGraphQLNonNull(GraphQLNonNull node, TraverserContext context) { - return node.getWrappedType().accept(context,this); - } - - } - - - class CollectingVisitor extends TypeVisitorStub { - - private final Map result = new HashMap<>(); - - @Override - public TraversalControl visitGraphQLEnumType(GraphQLEnumType node, TraverserContext context) { - assertTypeUniqueness(node,result); - save(node.getName(),node); - return super.visitGraphQLEnumType(node, context); - } - - @Override - public TraversalControl visitGraphQLScalarType(GraphQLScalarType node, TraverserContext context) { - assertTypeUniqueness(node,result); - save(node.getName(),node); - return super.visitGraphQLScalarType(node, context); - } - - @Override - public TraversalControl visitGraphQLObjectType(GraphQLObjectType node, TraverserContext context) { - if (isTypeReference(node.getName())) { - assertTypeUniqueness(node, result); - } else { - save(node.getName(), node); - } - return super.visitGraphQLObjectType(node,context); - } - - @Override - public TraversalControl visitGraphQLInputObjectType(GraphQLInputObjectType node, TraverserContext context) { - if (isTypeReference(node.getName())) { - assertTypeUniqueness(node, result); - } else { - save(node.getName(), node); - } - return super.visitGraphQLInputObjectType(node, context); - } - - @Override - public TraversalControl visitGraphQLInterfaceType(GraphQLInterfaceType node, TraverserContext context) { - if (isTypeReference(node.getName())) { - assertTypeUniqueness(node, result); - } else { - save(node.getName(), node); - } - - return super.visitGraphQLInterfaceType(node, context); - } - - @Override - public TraversalControl visitGraphQLUnionType(GraphQLUnionType node, TraverserContext context) { - assertTypeUniqueness(node,result); - save(node.getName(),node); - return super.visitGraphQLUnionType(node, context); - } - - @Override - public TraversalControl visitGraphQLFieldDefinition(GraphQLFieldDefinition node, TraverserContext context) { - - return super.visitGraphQLFieldDefinition(node, context); - } - - // TODO: eh? Isn't it similar to assertTypeUniqueness? - private boolean isTypeReference(String name) { - return result.containsKey(name) && !(result.get(name) instanceof GraphQLTypeReference); - } - - private void save(String name, GraphQLType type) { - result.put(name,type); - } - - public Map getResult() { - return result; - } - } - - - - private static final TypeTraverser SHALLOW_TRAVERSER = new TypeTraverser((node) -> Collections.emptyList()); - - private static final TypeTraverser TRAVERSER = new TypeTraverser(); diff --git a/src/main/java/graphql/schema/TypeTraverser.java b/src/main/java/graphql/schema/TypeTraverser.java index 9c8cfe9727..45b9ab4080 100644 --- a/src/main/java/graphql/schema/TypeTraverser.java +++ b/src/main/java/graphql/schema/TypeTraverser.java @@ -27,24 +27,24 @@ public TypeTraverser() { this(GraphQLType::getChildren); } - public TraverserResult depthFirst(TypeVisitor typeVisitor, GraphQLType root) { - return depthFirst(typeVisitor, Collections.singletonList(root)); + public TraverserResult depthFirst(GraphqlTypeVisitor graphqlTypeVisitor, GraphQLType root) { + return depthFirst(graphqlTypeVisitor, Collections.singletonList(root)); } - public TraverserResult depthFirst(final TypeVisitor typeVisitor, Collection roots) { - return Traverser.depthFirst(getChildren).traverse(roots, new TraverserDelegateVisitor(typeVisitor)); + public TraverserResult depthFirst(final GraphqlTypeVisitor graphqlTypeVisitor, Collection roots) { + return Traverser.depthFirst(getChildren).traverse(roots, new TraverserDelegateVisitor(graphqlTypeVisitor)); } - public TraverserResult depthFirst(final TypeVisitor typeVisitor, + public TraverserResult depthFirst(final GraphqlTypeVisitor graphqlTypeVisitor, Collection roots, Map types) { - return Traverser.depthFirst(getChildren).rootVar(TypeTraverser.class, types).traverse(roots, new TraverserDelegateVisitor(typeVisitor)); + return Traverser.depthFirst(getChildren).rootVar(TypeTraverser.class, types).traverse(roots, new TraverserDelegateVisitor(graphqlTypeVisitor)); } class TraverserDelegateVisitor implements TraverserVisitor { - private final TypeVisitor delegate; + private final GraphqlTypeVisitor delegate; - public TraverserDelegateVisitor(TypeVisitor delegate) { + public TraverserDelegateVisitor(GraphqlTypeVisitor delegate) { this.delegate = delegate; } From 847ab4b89c0a06112f6a9e988835d890102043bb Mon Sep 17 00:00:00 2001 From: amatiushkin Date: Tue, 19 Jun 2018 17:55:39 -0700 Subject: [PATCH 04/13] fix few bugs and add tests --- .../java/graphql/schema/GraphQLEnumType.java | 5 + .../java/graphql/schema/TypeTraverser.java | 37 ++- .../graphql/schema/TypeTraverserTest.groovy | 282 ++++++++++++++++++ 3 files changed, 317 insertions(+), 7 deletions(-) create mode 100644 src/test/groovy/graphql/schema/TypeTraverserTest.groovy diff --git a/src/main/java/graphql/schema/GraphQLEnumType.java b/src/main/java/graphql/schema/GraphQLEnumType.java index b861d8c618..4a87d339cc 100644 --- a/src/main/java/graphql/schema/GraphQLEnumType.java +++ b/src/main/java/graphql/schema/GraphQLEnumType.java @@ -182,6 +182,11 @@ public TraversalControl accept(TraverserContext context, GraphqlTyp return visitor.visitGraphQLEnumType(this, context); } + @Override + public List getChildren() { + return new ArrayList<>(valueDefinitionMap.values()); + } + public static Builder newEnum() { return new Builder(); } diff --git a/src/main/java/graphql/schema/TypeTraverser.java b/src/main/java/graphql/schema/TypeTraverser.java index 45b9ab4080..fa9f827f62 100644 --- a/src/main/java/graphql/schema/TypeTraverser.java +++ b/src/main/java/graphql/schema/TypeTraverser.java @@ -18,6 +18,7 @@ public class TypeTraverser { private final Function> getChildren; + private static final GraphqlTypeVisitor NO_OP = new GraphqlTypeVisitorStub(); public TypeTraverser(Function> getChildren) { this.getChildren = getChildren; @@ -32,30 +33,52 @@ public TraverserResult depthFirst(GraphqlTypeVisitor graphqlTypeVisitor, GraphQL } public TraverserResult depthFirst(final GraphqlTypeVisitor graphqlTypeVisitor, Collection roots) { - return Traverser.depthFirst(getChildren).traverse(roots, new TraverserDelegateVisitor(graphqlTypeVisitor)); + return depthFirst(initTraverser(), new TraverserDelegateVisitor(graphqlTypeVisitor), roots); } public TraverserResult depthFirst(final GraphqlTypeVisitor graphqlTypeVisitor, Collection roots, Map types) { - return Traverser.depthFirst(getChildren).rootVar(TypeTraverser.class, types).traverse(roots, new TraverserDelegateVisitor(graphqlTypeVisitor)); + return depthFirst(initTraverser().rootVar(TypeTraverser.class, types), new TraverserDelegateVisitor(graphqlTypeVisitor), roots); + } + + public TraverserResult depthFirst(final Traverser traverser, + final TraverserDelegateVisitor traverserDelegateVisitor, + Collection roots) { + return doTraverse(traverser, roots, traverserDelegateVisitor); + } + + protected Traverser initTraverser() { + return Traverser.depthFirst(getChildren); + } + + protected TraverserResult doTraverse(Traverser traverser, Collection roots, TraverserDelegateVisitor traverserDelegateVisitor) { + return traverser.traverse(roots,traverserDelegateVisitor); } class TraverserDelegateVisitor implements TraverserVisitor { - private final GraphqlTypeVisitor delegate; + private final GraphqlTypeVisitor before; + private final GraphqlTypeVisitor after; + - public TraverserDelegateVisitor(GraphqlTypeVisitor delegate) { - this.delegate = delegate; + TraverserDelegateVisitor(GraphqlTypeVisitor delegate) { + this(delegate,NO_OP); } + TraverserDelegateVisitor(GraphqlTypeVisitor delegateBefore, GraphqlTypeVisitor delegateAfter) { + this.before = delegateBefore; + this.after = delegateAfter; + } + + @Override public TraversalControl enter(TraverserContext context) { - return context.thisNode().accept(context, delegate); + return context.thisNode().accept(context, before); } @Override public TraversalControl leave(TraverserContext context) { - return context.thisNode().accept(context, delegate); + return context.thisNode().accept(context, after); } } diff --git a/src/test/groovy/graphql/schema/TypeTraverserTest.groovy b/src/test/groovy/graphql/schema/TypeTraverserTest.groovy new file mode 100644 index 0000000000..816212df72 --- /dev/null +++ b/src/test/groovy/graphql/schema/TypeTraverserTest.groovy @@ -0,0 +1,282 @@ +package graphql.schema + +import graphql.Scalars +import graphql.TypeResolutionEnvironment +import graphql.util.TraversalControl +import graphql.util.TraverserContext +import spock.lang.Specification + +class TypeTraverserTest extends Specification { + + + def "reachable scalar type"() { + + when: + + def visitor = new GraphqlTestingVisitor() + new TypeTraverser().depthFirst(visitor, Scalars.GraphQLString) + + then: + + visitor.getStack() == ["scalar: String", "fallback: String"] + + + } + + def "reachable string argument type"() { + when: def visitor = new GraphqlTestingVisitor() + + new TypeTraverser().depthFirst(visitor, GraphQLArgument.newArgument() + .name("Test") + .type(Scalars.GraphQLString) + .build()) + then: + visitor.getStack() == [ "argument: Test", "fallback: Test", "scalar: String", "fallback: String" ] + } + + def "reachable number argument type"() { + when: def visitor = new GraphqlTestingVisitor() + new TypeTraverser().depthFirst(visitor, GraphQLArgument.newArgument() + .name("Test") + .type(Scalars.GraphQLInt) + .build()) + then: + visitor.getStack() == ["argument: Test", "fallback: Test", "scalar: Int", "fallback: Int"] + + } + + def "reachable enum type"() { + when: def visitor = new GraphqlTestingVisitor() + new TypeTraverser().depthFirst(visitor, GraphQLEnumType + .newEnum() + .name("foo") + .value("bar") + .value(GraphQLEnumValueDefinition.newEnumValueDefinition().name("abc").value(123).build()) + .build()) + then: + visitor.getStack() == ["enum: foo", "fallback: foo", + "enum value: bar", "fallback: bar", + "enum value: abc", "fallback: abc"] + + } + + def "reachable field definition type"() { + when: def visitor = new GraphqlTestingVisitor() + new TypeTraverser().depthFirst(visitor,GraphQLFieldDefinition.newFieldDefinition() + .name("foo") + .type(Scalars.GraphQLString) + .build()) + then: + visitor.getStack() == ["field: foo","fallback: foo","scalar: String", "fallback: String"] + + } + + def "reachable input object field type"() { + when: def visitor = new GraphqlTestingVisitor() + new TypeTraverser().depthFirst(visitor,GraphQLInputObjectField.newInputObjectField() + .name("bar") + .type(Scalars.GraphQLString) + .build()) + then: + visitor.getStack() == ["input object field: bar","fallback: bar","scalar: String", "fallback: String"] + } + + def "reachable input object type"() { + when: def visitor = new GraphqlTestingVisitor() + new TypeTraverser().depthFirst(visitor,GraphQLInputObjectType.newInputObject() + .name("foo") + .field(GraphQLInputObjectField.newInputObjectField() + .name("bar") + .type(Scalars.GraphQLString) + .build()) + .build()) + then: + visitor.getStack() == ["input object: foo","fallback: foo", + "input object field: bar","fallback: bar", + "scalar: String", "fallback: String"] + } + + + def "reachable interface type"() { + when: def visitor = new GraphqlTestingVisitor() + new TypeTraverser().depthFirst(visitor,GraphQLInterfaceType.newInterface() + .name("foo") + .field(GraphQLFieldDefinition.newFieldDefinition() + .name("bar") + .type(Scalars.GraphQLString) + .build()) + .typeResolver(NOOP_RESOLVER) + .build()) + then: + visitor.getStack() == ["interface: foo","fallback: foo", + "field: bar","fallback: bar", + "scalar: String", "fallback: String"] + } + + def "reachable list type"() { + when: def visitor = new GraphqlTestingVisitor() + new TypeTraverser().depthFirst(visitor,GraphQLList.list(Scalars.GraphQLString)) + then: + visitor.getStack() == ["list: String","fallback: null", + "scalar: String", "fallback: String"] + } + + + def "reachable nonNull type"() { + when: def visitor = new GraphqlTestingVisitor() + new TypeTraverser().depthFirst(visitor,GraphQLNonNull.nonNull(Scalars.GraphQLString)) + then: + visitor.getStack() == ["nonNull: String","fallback: null", + "scalar: String", "fallback: String"] + } + + def "reachable object type"() { + when: def visitor = new GraphqlTestingVisitor() + new TypeTraverser().depthFirst(visitor,GraphQLObjectType.newObject() + .name("myObject") + .field(GraphQLFieldDefinition.newFieldDefinition() + .name("foo") + .type(Scalars.GraphQLString) + .build()) + .withInterface(GraphQLInterfaceType.newInterface() + .name("bar") + .typeResolver(NOOP_RESOLVER) + .build()) + .build()) + then: + visitor.getStack() == ["object: myObject", "fallback: myObject", + "field: foo","fallback: foo", + "scalar: String", "fallback: String", + "interface: bar","fallback: bar"] + } + + + + def "reachable reference type"() { + when: def visitor = new GraphqlTestingVisitor() + new TypeTraverser().depthFirst(visitor,GraphQLTypeReference.typeRef("something")) + then: + visitor.getStack() == ["reference: something","fallback: something"] + } + + def "reachable union type"() { + when: def visitor = new GraphqlTestingVisitor() + new TypeTraverser().depthFirst(visitor,GraphQLUnionType.newUnionType() + .name("foo") + .possibleType(GraphQLObjectType.newObject().name("dummy").build()) + .possibleType(GraphQLTypeReference.typeRef("dummyRef")) + .typeResolver(NOOP_RESOLVER) + .build()) + then: + visitor.getStack() == ["union: foo","fallback: foo", + "object: dummy", "fallback: dummy", + "reference: dummyRef", "fallback: dummyRef"] + } + + + + + def NOOP_RESOLVER = new TypeResolver() { + @Override + GraphQLObjectType getType(TypeResolutionEnvironment env) { + return null + } + } + + + class GraphqlTestingVisitor extends GraphqlTypeVisitorStub { + + def stack = [] + + @Override + TraversalControl visitGraphQLArgument(GraphQLArgument node, TraverserContext context) { + stack.add("argument: ${node.getName()}") + return super.visitGraphQLArgument(node, context) + } + + @Override + TraversalControl visitGraphQLScalarType(GraphQLScalarType node, TraverserContext context) { + stack.add("scalar: ${node.getName()}") + return super.visitGraphQLScalarType(node, context) + } + + @Override + protected TraversalControl visitGraphQLType(GraphQLType node, TraverserContext context) { + stack.add("fallback: ${node.getName()}") + return super.visitGraphQLType(node, context) + } + + @Override + TraversalControl visitGraphQLEnumType(GraphQLEnumType node, TraverserContext context) { + stack.add("enum: ${node.getName()}") + return super.visitGraphQLEnumType(node, context) + } + + @Override + TraversalControl visitGraphQLEnumValueDefinition(GraphQLEnumValueDefinition node, TraverserContext context) { + stack.add("enum value: ${node.getName()}") + return super.visitGraphQLEnumValueDefinition(node, context) + } + + @Override + TraversalControl visitGraphQLFieldDefinition(GraphQLFieldDefinition node, TraverserContext context) { + stack.add("field: ${node.getName()}") + return super.visitGraphQLFieldDefinition(node, context) + } + + @Override + TraversalControl visitGraphQLInputObjectField(GraphQLInputObjectField node, TraverserContext context) { + stack.add("input object field: ${node.getName()}") + return super.visitGraphQLInputObjectField(node, context) + } + + @Override + TraversalControl visitGraphQLInputObjectType(GraphQLInputObjectType node, TraverserContext context) { + stack.add("input object: ${node.getName()}") + return super.visitGraphQLInputObjectType(node, context) + } + + @Override + TraversalControl visitGraphQLInterfaceType(GraphQLInterfaceType node, TraverserContext context) { + stack.add("interface: ${node.getName()}") + return super.visitGraphQLInterfaceType(node, context) + } + + @Override + TraversalControl visitGraphQLList(GraphQLList node, TraverserContext context) { + stack.add("list: ${node.getWrappedType().getName()}") + return super.visitGraphQLList(node, context) + } + + @Override + TraversalControl visitGraphQLNonNull(GraphQLNonNull node, TraverserContext context) { + stack.add("nonNull: ${node.getWrappedType().getName()}") + return super.visitGraphQLNonNull(node, context) + } + + @Override + TraversalControl visitGraphQLObjectType(GraphQLObjectType node, TraverserContext context) { + stack.add("object: ${node.getName()}") + return super.visitGraphQLObjectType(node, context) + } + + @Override + TraversalControl visitGraphQLTypeReference(GraphQLTypeReference node, TraverserContext context) { + stack.add("reference: ${node.getName()}") + return super.visitGraphQLTypeReference(node, context) + } + + @Override + TraversalControl visitGraphQLUnionType(GraphQLUnionType node, TraverserContext context) { + stack.add("union: ${node.getName()}") + return super.visitGraphQLUnionType(node, context) + } + + def getStack() { + return stack + } + } + + + +} From b864afb3e7f8b803a9735881863c5b3b4ab4b4b5 Mon Sep 17 00:00:00 2001 From: amatiushkin Date: Mon, 25 Jun 2018 13:07:03 -0700 Subject: [PATCH 05/13] Review comments --- .../java/graphql/schema/GraphQLArgument.java | 5 ++- .../java/graphql/schema/GraphQLEnumType.java | 2 +- .../schema/GraphQLEnumValueDefinition.java | 2 +- .../schema/GraphQLFieldDefinition.java | 2 +- .../schema/GraphQLInputObjectField.java | 2 +- .../schema/GraphQLInputObjectType.java | 2 +- .../graphql/schema/GraphQLInterfaceType.java | 2 +- src/main/java/graphql/schema/GraphQLList.java | 2 +- .../java/graphql/schema/GraphQLNonNull.java | 2 +- .../graphql/schema/GraphQLObjectType.java | 2 +- .../graphql/schema/GraphQLScalarType.java | 2 +- src/main/java/graphql/schema/GraphQLType.java | 2 +- .../graphql/schema/GraphQLTypeReference.java | 2 +- ...peVisitor.java => GraphQLTypeVisitor.java} | 2 +- ...rStub.java => GraphQLTypeVisitorStub.java} | 4 +- .../java/graphql/schema/GraphQLUnionType.java | 2 +- .../graphql/schema/GraphqlTypeVisitors.java | 8 ++-- .../java/graphql/schema/TypeTraverser.java | 39 +++++++++---------- .../graphql/schema/TypeTraverserTest.groovy | 28 ++++++------- 19 files changed, 55 insertions(+), 57 deletions(-) rename src/main/java/graphql/schema/{GraphqlTypeVisitor.java => GraphQLTypeVisitor.java} (98%) rename src/main/java/graphql/schema/{GraphqlTypeVisitorStub.java => GraphQLTypeVisitorStub.java} (95%) diff --git a/src/main/java/graphql/schema/GraphQLArgument.java b/src/main/java/graphql/schema/GraphQLArgument.java index befe435dbd..67795b9920 100644 --- a/src/main/java/graphql/schema/GraphQLArgument.java +++ b/src/main/java/graphql/schema/GraphQLArgument.java @@ -78,11 +78,12 @@ void replaceTypeReferences(Map typeMap) { type = (GraphQLInputType) new SchemaUtil().resolveTypeReference(type, typeMap); } - @Override + void replaceType(GraphQLInputType type) { this.type = type; } + @Override public String getName() { return name; } @@ -148,7 +149,7 @@ public static Builder newArgument(GraphQLArgument existing) { } @Override - public TraversalControl accept(TraverserContext context, GraphqlTypeVisitor visitor) { + public TraversalControl accept(TraverserContext context, GraphQLTypeVisitor visitor) { return visitor.visitGraphQLArgument(this, context); } diff --git a/src/main/java/graphql/schema/GraphQLEnumType.java b/src/main/java/graphql/schema/GraphQLEnumType.java index 4a87d339cc..587d73b019 100644 --- a/src/main/java/graphql/schema/GraphQLEnumType.java +++ b/src/main/java/graphql/schema/GraphQLEnumType.java @@ -178,7 +178,7 @@ public GraphQLEnumType transform(Consumer builderConsumer) { } @Override - public TraversalControl accept(TraverserContext context, GraphqlTypeVisitor visitor) { + public TraversalControl accept(TraverserContext context, GraphQLTypeVisitor visitor) { return visitor.visitGraphQLEnumType(this, context); } diff --git a/src/main/java/graphql/schema/GraphQLEnumValueDefinition.java b/src/main/java/graphql/schema/GraphQLEnumValueDefinition.java index 2f14840580..fd561f0633 100644 --- a/src/main/java/graphql/schema/GraphQLEnumValueDefinition.java +++ b/src/main/java/graphql/schema/GraphQLEnumValueDefinition.java @@ -108,7 +108,7 @@ public GraphQLEnumValueDefinition transform(Consumer builderConsumer) { } @Override - public TraversalControl accept(TraverserContext context, GraphqlTypeVisitor visitor) { + public TraversalControl accept(TraverserContext context, GraphQLTypeVisitor visitor) { return visitor.visitGraphQLEnumValueDefinition(this, context); } diff --git a/src/main/java/graphql/schema/GraphQLFieldDefinition.java b/src/main/java/graphql/schema/GraphQLFieldDefinition.java index 870bedcd76..3a1d9d01e9 100644 --- a/src/main/java/graphql/schema/GraphQLFieldDefinition.java +++ b/src/main/java/graphql/schema/GraphQLFieldDefinition.java @@ -152,7 +152,7 @@ public GraphQLFieldDefinition transform(Consumer builderConsumer) { } @Override - public TraversalControl accept(TraverserContext context, GraphqlTypeVisitor visitor) { + public TraversalControl accept(TraverserContext context, GraphQLTypeVisitor visitor) { return visitor.visitGraphQLFieldDefinition(this, context); } diff --git a/src/main/java/graphql/schema/GraphQLInputObjectField.java b/src/main/java/graphql/schema/GraphQLInputObjectField.java index bf6387fd7b..0b1d0ca26c 100644 --- a/src/main/java/graphql/schema/GraphQLInputObjectField.java +++ b/src/main/java/graphql/schema/GraphQLInputObjectField.java @@ -111,7 +111,7 @@ public GraphQLInputObjectField transform(Consumer builderConsumer) { } @Override - public TraversalControl accept(TraverserContext context, GraphqlTypeVisitor visitor) { + public TraversalControl accept(TraverserContext context, GraphQLTypeVisitor visitor) { return visitor.visitGraphQLInputObjectField(this, context); } diff --git a/src/main/java/graphql/schema/GraphQLInputObjectType.java b/src/main/java/graphql/schema/GraphQLInputObjectType.java index 4d953ea4f2..344fcf86d3 100644 --- a/src/main/java/graphql/schema/GraphQLInputObjectType.java +++ b/src/main/java/graphql/schema/GraphQLInputObjectType.java @@ -113,7 +113,7 @@ public GraphQLInputObjectType transform(Consumer builderConsumer) { } @Override - public TraversalControl accept(TraverserContext context, GraphqlTypeVisitor visitor) { + public TraversalControl accept(TraverserContext context, GraphQLTypeVisitor visitor) { return visitor.visitGraphQLInputObjectType(this, context); } diff --git a/src/main/java/graphql/schema/GraphQLInterfaceType.java b/src/main/java/graphql/schema/GraphQLInterfaceType.java index e7fa556e22..c30f70ccfc 100644 --- a/src/main/java/graphql/schema/GraphQLInterfaceType.java +++ b/src/main/java/graphql/schema/GraphQLInterfaceType.java @@ -128,7 +128,7 @@ public GraphQLInterfaceType transform(Consumer builderConsumer) { } @Override - public TraversalControl accept(TraverserContext context, GraphqlTypeVisitor visitor) { + public TraversalControl accept(TraverserContext context, GraphQLTypeVisitor visitor) { return visitor.visitGraphQLInterfaceType(this, context); } diff --git a/src/main/java/graphql/schema/GraphQLList.java b/src/main/java/graphql/schema/GraphQLList.java index 0c3ec838ce..957e7be1b8 100644 --- a/src/main/java/graphql/schema/GraphQLList.java +++ b/src/main/java/graphql/schema/GraphQLList.java @@ -76,7 +76,7 @@ public String getName() { } @Override - public TraversalControl accept(TraverserContext context, GraphqlTypeVisitor visitor) { + public TraversalControl accept(TraverserContext context, GraphQLTypeVisitor visitor) { return visitor.visitGraphQLList(this, context); } diff --git a/src/main/java/graphql/schema/GraphQLNonNull.java b/src/main/java/graphql/schema/GraphQLNonNull.java index 81e7852a99..9080ee535a 100644 --- a/src/main/java/graphql/schema/GraphQLNonNull.java +++ b/src/main/java/graphql/schema/GraphQLNonNull.java @@ -83,7 +83,7 @@ public String getName() { } @Override - public TraversalControl accept(TraverserContext context, GraphqlTypeVisitor visitor) { + public TraversalControl accept(TraverserContext context, GraphQLTypeVisitor visitor) { return visitor.visitGraphQLNonNull(this, context); } diff --git a/src/main/java/graphql/schema/GraphQLObjectType.java b/src/main/java/graphql/schema/GraphQLObjectType.java index 3a5f2fdafa..b92aca73e4 100644 --- a/src/main/java/graphql/schema/GraphQLObjectType.java +++ b/src/main/java/graphql/schema/GraphQLObjectType.java @@ -146,7 +146,7 @@ public GraphQLObjectType transform(Consumer builderConsumer) { } @Override - public TraversalControl accept(TraverserContext context, GraphqlTypeVisitor visitor) { + public TraversalControl accept(TraverserContext context, GraphQLTypeVisitor visitor) { return visitor.visitGraphQLObjectType(this, context); } diff --git a/src/main/java/graphql/schema/GraphQLScalarType.java b/src/main/java/graphql/schema/GraphQLScalarType.java index 1306a2b1b5..d9ec6cf911 100644 --- a/src/main/java/graphql/schema/GraphQLScalarType.java +++ b/src/main/java/graphql/schema/GraphQLScalarType.java @@ -108,7 +108,7 @@ public GraphQLScalarType transform(Consumer builderConsumer) { } @Override - public TraversalControl accept(TraverserContext context, GraphqlTypeVisitor visitor) { + public TraversalControl accept(TraverserContext context, GraphQLTypeVisitor visitor) { return visitor.visitGraphQLScalarType(this, context); } diff --git a/src/main/java/graphql/schema/GraphQLType.java b/src/main/java/graphql/schema/GraphQLType.java index 14b3d61dc9..b1e5af81fb 100644 --- a/src/main/java/graphql/schema/GraphQLType.java +++ b/src/main/java/graphql/schema/GraphQLType.java @@ -36,5 +36,5 @@ public interface GraphQLType { * @return Result of Visitor's operation. * Note! Visitor's operation might return special results to control traversal process. */ - TraversalControl accept(TraverserContext context, GraphqlTypeVisitor visitor); + TraversalControl accept(TraverserContext context, GraphQLTypeVisitor visitor); } diff --git a/src/main/java/graphql/schema/GraphQLTypeReference.java b/src/main/java/graphql/schema/GraphQLTypeReference.java index 6d7cabd055..e1540be99a 100644 --- a/src/main/java/graphql/schema/GraphQLTypeReference.java +++ b/src/main/java/graphql/schema/GraphQLTypeReference.java @@ -41,7 +41,7 @@ public String getName() { } @Override - public TraversalControl accept(TraverserContext context, GraphqlTypeVisitor visitor) { + public TraversalControl accept(TraverserContext context, GraphQLTypeVisitor visitor) { return visitor.visitGraphQLTypeReference(this, context); } } diff --git a/src/main/java/graphql/schema/GraphqlTypeVisitor.java b/src/main/java/graphql/schema/GraphQLTypeVisitor.java similarity index 98% rename from src/main/java/graphql/schema/GraphqlTypeVisitor.java rename to src/main/java/graphql/schema/GraphQLTypeVisitor.java index 5fc8a37a5a..6868cd9529 100644 --- a/src/main/java/graphql/schema/GraphqlTypeVisitor.java +++ b/src/main/java/graphql/schema/GraphQLTypeVisitor.java @@ -5,7 +5,7 @@ import graphql.util.TraverserContext; @Internal -public interface GraphqlTypeVisitor { +public interface GraphQLTypeVisitor { TraversalControl visitGraphQLArgument(GraphQLArgument node, TraverserContext context); TraversalControl visitGraphQLInterfaceType(GraphQLInterfaceType node, TraverserContext context); TraversalControl visitGraphQLEnumType(GraphQLEnumType node, TraverserContext context); diff --git a/src/main/java/graphql/schema/GraphqlTypeVisitorStub.java b/src/main/java/graphql/schema/GraphQLTypeVisitorStub.java similarity index 95% rename from src/main/java/graphql/schema/GraphqlTypeVisitorStub.java rename to src/main/java/graphql/schema/GraphQLTypeVisitorStub.java index 1486d774c8..d16b62309f 100644 --- a/src/main/java/graphql/schema/GraphqlTypeVisitorStub.java +++ b/src/main/java/graphql/schema/GraphQLTypeVisitorStub.java @@ -6,11 +6,11 @@ import static graphql.util.TraversalControl.CONTINUE; /** - * Base implementation of {@link GraphqlTypeVisitor} for convenience. + * Base implementation of {@link GraphQLTypeVisitor} for convenience. * Overwrite only required methods and/or {@link #visitGraphQLType(GraphQLType, TraverserContext)} as default fallback. */ @PublicApi -public class GraphqlTypeVisitorStub implements GraphqlTypeVisitor { +public class GraphQLTypeVisitorStub implements GraphQLTypeVisitor { @Override public TraversalControl visitGraphQLArgument(GraphQLArgument node, TraverserContext context) { return visitGraphQLType(node,context); diff --git a/src/main/java/graphql/schema/GraphQLUnionType.java b/src/main/java/graphql/schema/GraphQLUnionType.java index 229d0810a0..5c7509e6ff 100644 --- a/src/main/java/graphql/schema/GraphQLUnionType.java +++ b/src/main/java/graphql/schema/GraphQLUnionType.java @@ -120,7 +120,7 @@ public GraphQLUnionType transform(Consumer builderConsumer) { } @Override - public TraversalControl accept(TraverserContext context, GraphqlTypeVisitor visitor) { + public TraversalControl accept(TraverserContext context, GraphQLTypeVisitor visitor) { return visitor.visitGraphQLUnionType(this, context); } diff --git a/src/main/java/graphql/schema/GraphqlTypeVisitors.java b/src/main/java/graphql/schema/GraphqlTypeVisitors.java index e5ac24ff70..1e692e1744 100644 --- a/src/main/java/graphql/schema/GraphqlTypeVisitors.java +++ b/src/main/java/graphql/schema/GraphqlTypeVisitors.java @@ -20,7 +20,7 @@ class GraphqlTypeVisitors { private GraphqlTypeVisitors() {} - static class LeafVisitor extends GraphqlTypeVisitorStub { + static class LeafVisitor extends GraphQLTypeVisitorStub { @Override public TraversalControl visitGraphQLScalarType(GraphQLScalarType node, TraverserContext context) { @@ -52,7 +52,7 @@ public TraversalControl visitGraphQLNonNull(GraphQLNonNull node, TraverserContex } - static class CollectingVisitor extends GraphqlTypeVisitorStub { + static class CollectingVisitor extends GraphQLTypeVisitorStub { private final Map result = new HashMap<>(); @@ -158,7 +158,7 @@ public Map getResult() { } - static class RefResolvingVisitor extends GraphqlTypeVisitorStub { + static class RefResolvingVisitor extends GraphQLTypeVisitorStub { final private GraphQLType resolvedType; public RefResolvingVisitor(GraphQLType resolvedType) { @@ -199,7 +199,7 @@ public TraversalControl visitGraphQLNonNull(GraphQLNonNull node, TraverserContex } - static class TypeResolvingVisitor extends GraphqlTypeVisitorStub { + static class TypeResolvingVisitor extends GraphQLTypeVisitorStub { private final Map typeMap; diff --git a/src/main/java/graphql/schema/TypeTraverser.java b/src/main/java/graphql/schema/TypeTraverser.java index fa9f827f62..6a8b52484c 100644 --- a/src/main/java/graphql/schema/TypeTraverser.java +++ b/src/main/java/graphql/schema/TypeTraverser.java @@ -1,6 +1,7 @@ package graphql.schema; +import graphql.Internal; import graphql.util.TraversalControl; import graphql.util.Traverser; import graphql.util.TraverserContext; @@ -14,11 +15,14 @@ import java.util.Map; import java.util.function.Function; +import static graphql.util.TraversalControl.CONTINUE; + +@Internal public class TypeTraverser { private final Function> getChildren; - private static final GraphqlTypeVisitor NO_OP = new GraphqlTypeVisitorStub(); + private static final GraphQLTypeVisitor NO_OP = new GraphQLTypeVisitorStub(); public TypeTraverser(Function> getChildren) { this.getChildren = getChildren; @@ -28,18 +32,18 @@ public TypeTraverser() { this(GraphQLType::getChildren); } - public TraverserResult depthFirst(GraphqlTypeVisitor graphqlTypeVisitor, GraphQLType root) { - return depthFirst(graphqlTypeVisitor, Collections.singletonList(root)); + public TraverserResult depthFirst(GraphQLTypeVisitor graphQLTypeVisitor, GraphQLType root) { + return depthFirst(graphQLTypeVisitor, Collections.singletonList(root)); } - public TraverserResult depthFirst(final GraphqlTypeVisitor graphqlTypeVisitor, Collection roots) { - return depthFirst(initTraverser(), new TraverserDelegateVisitor(graphqlTypeVisitor), roots); + public TraverserResult depthFirst(final GraphQLTypeVisitor graphQLTypeVisitor, Collection roots) { + return depthFirst(initTraverser(), new TraverserDelegateVisitor(graphQLTypeVisitor), roots); } - public TraverserResult depthFirst(final GraphqlTypeVisitor graphqlTypeVisitor, + public TraverserResult depthFirst(final GraphQLTypeVisitor graphQLTypeVisitor, Collection roots, Map types) { - return depthFirst(initTraverser().rootVar(TypeTraverser.class, types), new TraverserDelegateVisitor(graphqlTypeVisitor), roots); + return depthFirst(initTraverser().rootVar(TypeTraverser.class, types), new TraverserDelegateVisitor(graphQLTypeVisitor), roots); } public TraverserResult depthFirst(final Traverser traverser, @@ -48,29 +52,22 @@ public TraverserResult depthFirst(final Traverser traverser, return doTraverse(traverser, roots, traverserDelegateVisitor); } - protected Traverser initTraverser() { + private Traverser initTraverser() { return Traverser.depthFirst(getChildren); } - protected TraverserResult doTraverse(Traverser traverser, Collection roots, TraverserDelegateVisitor traverserDelegateVisitor) { + private TraverserResult doTraverse(Traverser traverser, Collection roots, TraverserDelegateVisitor traverserDelegateVisitor) { return traverser.traverse(roots,traverserDelegateVisitor); } - class TraverserDelegateVisitor implements TraverserVisitor { - private final GraphqlTypeVisitor before; - private final GraphqlTypeVisitor after; - + private static class TraverserDelegateVisitor implements TraverserVisitor { + private final GraphQLTypeVisitor before; - TraverserDelegateVisitor(GraphqlTypeVisitor delegate) { - this(delegate,NO_OP); - } + TraverserDelegateVisitor(GraphQLTypeVisitor delegate) { + this.before = delegate; - TraverserDelegateVisitor(GraphqlTypeVisitor delegateBefore, GraphqlTypeVisitor delegateAfter) { - this.before = delegateBefore; - this.after = delegateAfter; } - @Override public TraversalControl enter(TraverserContext context) { return context.thisNode().accept(context, before); @@ -78,7 +75,7 @@ public TraversalControl enter(TraverserContext context) { @Override public TraversalControl leave(TraverserContext context) { - return context.thisNode().accept(context, after); + return CONTINUE; } } diff --git a/src/test/groovy/graphql/schema/TypeTraverserTest.groovy b/src/test/groovy/graphql/schema/TypeTraverserTest.groovy index 816212df72..d04e945f6d 100644 --- a/src/test/groovy/graphql/schema/TypeTraverserTest.groovy +++ b/src/test/groovy/graphql/schema/TypeTraverserTest.groovy @@ -13,7 +13,7 @@ class TypeTraverserTest extends Specification { when: - def visitor = new GraphqlTestingVisitor() + def visitor = new GraphQLTestingVisitor() new TypeTraverser().depthFirst(visitor, Scalars.GraphQLString) then: @@ -24,7 +24,7 @@ class TypeTraverserTest extends Specification { } def "reachable string argument type"() { - when: def visitor = new GraphqlTestingVisitor() + when: def visitor = new GraphQLTestingVisitor() new TypeTraverser().depthFirst(visitor, GraphQLArgument.newArgument() .name("Test") @@ -35,7 +35,7 @@ class TypeTraverserTest extends Specification { } def "reachable number argument type"() { - when: def visitor = new GraphqlTestingVisitor() + when: def visitor = new GraphQLTestingVisitor() new TypeTraverser().depthFirst(visitor, GraphQLArgument.newArgument() .name("Test") .type(Scalars.GraphQLInt) @@ -46,7 +46,7 @@ class TypeTraverserTest extends Specification { } def "reachable enum type"() { - when: def visitor = new GraphqlTestingVisitor() + when: def visitor = new GraphQLTestingVisitor() new TypeTraverser().depthFirst(visitor, GraphQLEnumType .newEnum() .name("foo") @@ -61,7 +61,7 @@ class TypeTraverserTest extends Specification { } def "reachable field definition type"() { - when: def visitor = new GraphqlTestingVisitor() + when: def visitor = new GraphQLTestingVisitor() new TypeTraverser().depthFirst(visitor,GraphQLFieldDefinition.newFieldDefinition() .name("foo") .type(Scalars.GraphQLString) @@ -72,7 +72,7 @@ class TypeTraverserTest extends Specification { } def "reachable input object field type"() { - when: def visitor = new GraphqlTestingVisitor() + when: def visitor = new GraphQLTestingVisitor() new TypeTraverser().depthFirst(visitor,GraphQLInputObjectField.newInputObjectField() .name("bar") .type(Scalars.GraphQLString) @@ -82,7 +82,7 @@ class TypeTraverserTest extends Specification { } def "reachable input object type"() { - when: def visitor = new GraphqlTestingVisitor() + when: def visitor = new GraphQLTestingVisitor() new TypeTraverser().depthFirst(visitor,GraphQLInputObjectType.newInputObject() .name("foo") .field(GraphQLInputObjectField.newInputObjectField() @@ -98,7 +98,7 @@ class TypeTraverserTest extends Specification { def "reachable interface type"() { - when: def visitor = new GraphqlTestingVisitor() + when: def visitor = new GraphQLTestingVisitor() new TypeTraverser().depthFirst(visitor,GraphQLInterfaceType.newInterface() .name("foo") .field(GraphQLFieldDefinition.newFieldDefinition() @@ -114,7 +114,7 @@ class TypeTraverserTest extends Specification { } def "reachable list type"() { - when: def visitor = new GraphqlTestingVisitor() + when: def visitor = new GraphQLTestingVisitor() new TypeTraverser().depthFirst(visitor,GraphQLList.list(Scalars.GraphQLString)) then: visitor.getStack() == ["list: String","fallback: null", @@ -123,7 +123,7 @@ class TypeTraverserTest extends Specification { def "reachable nonNull type"() { - when: def visitor = new GraphqlTestingVisitor() + when: def visitor = new GraphQLTestingVisitor() new TypeTraverser().depthFirst(visitor,GraphQLNonNull.nonNull(Scalars.GraphQLString)) then: visitor.getStack() == ["nonNull: String","fallback: null", @@ -131,7 +131,7 @@ class TypeTraverserTest extends Specification { } def "reachable object type"() { - when: def visitor = new GraphqlTestingVisitor() + when: def visitor = new GraphQLTestingVisitor() new TypeTraverser().depthFirst(visitor,GraphQLObjectType.newObject() .name("myObject") .field(GraphQLFieldDefinition.newFieldDefinition() @@ -153,14 +153,14 @@ class TypeTraverserTest extends Specification { def "reachable reference type"() { - when: def visitor = new GraphqlTestingVisitor() + when: def visitor = new GraphQLTestingVisitor() new TypeTraverser().depthFirst(visitor,GraphQLTypeReference.typeRef("something")) then: visitor.getStack() == ["reference: something","fallback: something"] } def "reachable union type"() { - when: def visitor = new GraphqlTestingVisitor() + when: def visitor = new GraphQLTestingVisitor() new TypeTraverser().depthFirst(visitor,GraphQLUnionType.newUnionType() .name("foo") .possibleType(GraphQLObjectType.newObject().name("dummy").build()) @@ -184,7 +184,7 @@ class TypeTraverserTest extends Specification { } - class GraphqlTestingVisitor extends GraphqlTypeVisitorStub { + class GraphQLTestingVisitor extends GraphQLTypeVisitorStub { def stack = [] From 0afdea279926ff626b67810dd6478d6a53789edf Mon Sep 17 00:00:00 2001 From: amatiushkin Date: Mon, 25 Jun 2018 13:23:53 -0700 Subject: [PATCH 06/13] Clear deprecated methods --- .../java/graphql/schema/GraphQLArgument.java | 6 -- .../schema/GraphQLFieldDefinition.java | 6 -- .../schema/GraphQLInputObjectField.java | 4 -- src/main/java/graphql/schema/GraphQLList.java | 5 -- .../java/graphql/schema/GraphQLNonNull.java | 4 -- .../graphql/schema/GraphQLObjectType.java | 7 --- .../java/graphql/schema/GraphQLUnionType.java | 7 --- src/main/java/graphql/schema/SchemaUtil.java | 58 ------------------- 8 files changed, 97 deletions(-) diff --git a/src/main/java/graphql/schema/GraphQLArgument.java b/src/main/java/graphql/schema/GraphQLArgument.java index 67795b9920..87c017d20d 100644 --- a/src/main/java/graphql/schema/GraphQLArgument.java +++ b/src/main/java/graphql/schema/GraphQLArgument.java @@ -73,12 +73,6 @@ private GraphQLArgument(String name, String description, GraphQLInputType type, } - @Deprecated - void replaceTypeReferences(Map typeMap) { - type = (GraphQLInputType) new SchemaUtil().resolveTypeReference(type, typeMap); - } - - void replaceType(GraphQLInputType type) { this.type = type; } diff --git a/src/main/java/graphql/schema/GraphQLFieldDefinition.java b/src/main/java/graphql/schema/GraphQLFieldDefinition.java index 3a1d9d01e9..bd025ba5ab 100644 --- a/src/main/java/graphql/schema/GraphQLFieldDefinition.java +++ b/src/main/java/graphql/schema/GraphQLFieldDefinition.java @@ -66,12 +66,6 @@ public GraphQLFieldDefinition(String name, String description, GraphQLOutputType this.definition = definition; } - - void replaceTypeReferences(Map typeMap) { - this.type = (GraphQLOutputType) new SchemaUtil().resolveTypeReference(this.type, typeMap); - } - - void replaceType(GraphQLOutputType type) { this.type = type; } diff --git a/src/main/java/graphql/schema/GraphQLInputObjectField.java b/src/main/java/graphql/schema/GraphQLInputObjectField.java index 0b1d0ca26c..ad1dec7843 100644 --- a/src/main/java/graphql/schema/GraphQLInputObjectField.java +++ b/src/main/java/graphql/schema/GraphQLInputObjectField.java @@ -62,10 +62,6 @@ public GraphQLInputObjectField(String name, String description, GraphQLInputType this.definition = definition; } - void replaceTypeReferences(Map typeMap) { - type = (GraphQLInputType) new SchemaUtil().resolveTypeReference(type, typeMap); - } - void replaceType(GraphQLInputType type) { this.type = type; } diff --git a/src/main/java/graphql/schema/GraphQLList.java b/src/main/java/graphql/schema/GraphQLList.java index 957e7be1b8..f2615f0e3b 100644 --- a/src/main/java/graphql/schema/GraphQLList.java +++ b/src/main/java/graphql/schema/GraphQLList.java @@ -45,11 +45,6 @@ public GraphQLType getWrappedType() { return wrappedType; } - @Deprecated - void replaceTypeReferences(Map typeMap) { - wrappedType = new SchemaUtil().resolveTypeReference(wrappedType, typeMap); - } - void replaceType(GraphQLType type) { wrappedType = type; } diff --git a/src/main/java/graphql/schema/GraphQLNonNull.java b/src/main/java/graphql/schema/GraphQLNonNull.java index 9080ee535a..4a0e2cab1a 100644 --- a/src/main/java/graphql/schema/GraphQLNonNull.java +++ b/src/main/java/graphql/schema/GraphQLNonNull.java @@ -45,10 +45,6 @@ public GraphQLType getWrappedType() { return wrappedType; } - @Deprecated - void replaceTypeReferences(Map typeMap) { - wrappedType = new SchemaUtil().resolveTypeReference(wrappedType, typeMap); - } void replaceType(GraphQLType type) { wrappedType = type; diff --git a/src/main/java/graphql/schema/GraphQLObjectType.java b/src/main/java/graphql/schema/GraphQLObjectType.java index b92aca73e4..cfee27cbb9 100644 --- a/src/main/java/graphql/schema/GraphQLObjectType.java +++ b/src/main/java/graphql/schema/GraphQLObjectType.java @@ -62,13 +62,6 @@ public GraphQLObjectType(String name, String description, List typeMap) { - this.interfaces = this.interfaces.stream() - .map(type -> (GraphQLOutputType) new SchemaUtil().resolveTypeReference(type, typeMap)) - .collect(Collectors.toList()); - } - void replaceInterfaces(List interfaces) { this.interfaces = interfaces; } diff --git a/src/main/java/graphql/schema/GraphQLUnionType.java b/src/main/java/graphql/schema/GraphQLUnionType.java index 5c7509e6ff..2d2629fc39 100644 --- a/src/main/java/graphql/schema/GraphQLUnionType.java +++ b/src/main/java/graphql/schema/GraphQLUnionType.java @@ -63,13 +63,6 @@ public GraphQLUnionType(String name, String description, List this.directives = directives; } - @Deprecated - void replaceTypeReferences(Map typeMap) { - this.types = this.types.stream() - .map(type -> (GraphQLOutputType) new SchemaUtil().resolveTypeReference(type, typeMap)) - .collect(Collectors.toList()); - } - void replaceTypes(List types) { this.types = types; } diff --git a/src/main/java/graphql/schema/SchemaUtil.java b/src/main/java/graphql/schema/SchemaUtil.java index eed3154a23..89f6f59992 100644 --- a/src/main/java/graphql/schema/SchemaUtil.java +++ b/src/main/java/graphql/schema/SchemaUtil.java @@ -1,66 +1,23 @@ package graphql.schema; -import graphql.Assert; import graphql.Internal; import graphql.introspection.Introspection; -import graphql.util.TraversalControl; -import static graphql.util.TraversalControl.QUIT; -import static graphql.schema.GraphqlTypeVisitors.LeafVisitor; import static graphql.schema.GraphqlTypeVisitors.CollectingVisitor; import static graphql.schema.GraphqlTypeVisitors.TypeResolvingVisitor; -import graphql.util.TraverserContext; import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; -import static graphql.schema.GraphQLTypeUtil.isList; -import static graphql.schema.GraphQLTypeUtil.isNonNull; -import static graphql.schema.GraphQLTypeUtil.unwrapOne; -import static java.lang.String.format; - @Internal public class SchemaUtil { - private static final TypeTraverser SHALLOW_TRAVERSER = new TypeTraverser((node) -> Collections.emptyList()); - private static final TypeTraverser TRAVERSER = new TypeTraverser(); - public Boolean isLeafType(GraphQLType graphQLType) { - return (Boolean) SHALLOW_TRAVERSER.depthFirst(new LeafVisitor(), graphQLType).getResult(); - } - - public boolean isInputType(GraphQLType graphQLType) { - - return (Boolean) SHALLOW_TRAVERSER.depthFirst(new LeafVisitor() { - @Override - public TraversalControl visitGraphQLInputObjectType(GraphQLInputObjectType node, TraverserContext context) { - context.setResult(true); - return QUIT; - } - }, graphQLType).getResult(); - } - - - /** - * Use custom visitor - */ - @Deprecated - public GraphQLUnmodifiedType getUnmodifiedType(GraphQLType graphQLType) { - if (graphQLType instanceof GraphQLModifiedType) { - return getUnmodifiedType(((GraphQLModifiedType) graphQLType).getWrappedType()); - } - return (GraphQLUnmodifiedType) graphQLType; - - } - - - Map allTypes(final GraphQLSchema schema,final Set additionalTypes) { List roots = new ArrayList() {{ add(schema.getQueryType()); @@ -146,19 +103,4 @@ void replaceTypeReferences(GraphQLSchema schema) { final Map typeMap = schema.getTypeMap(); TRAVERSER.depthFirst(new TypeResolvingVisitor(typeMap),typeMap.values()); } - - @Deprecated - GraphQLType resolveTypeReference(GraphQLType type, Map typeMap) { - if (type instanceof GraphQLTypeReference || typeMap.containsKey(type.getName())) { - GraphQLType resolvedType = typeMap.get(type.getName()); - Assert.assertTrue(resolvedType != null, "type %s not found in schema", type.getName()); - return resolvedType; - } - return type; - } - - - - - } From 925e343fb602e0083de35e857df84844f64f6797 Mon Sep 17 00:00:00 2001 From: amatiushkin Date: Mon, 25 Jun 2018 13:25:07 -0700 Subject: [PATCH 07/13] Remove unsused statement --- src/main/java/graphql/schema/TypeTraverser.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/graphql/schema/TypeTraverser.java b/src/main/java/graphql/schema/TypeTraverser.java index 6a8b52484c..cb2fa04219 100644 --- a/src/main/java/graphql/schema/TypeTraverser.java +++ b/src/main/java/graphql/schema/TypeTraverser.java @@ -22,7 +22,6 @@ public class TypeTraverser { private final Function> getChildren; - private static final GraphQLTypeVisitor NO_OP = new GraphQLTypeVisitorStub(); public TypeTraverser(Function> getChildren) { this.getChildren = getChildren; From f989e9229a7830532f284ba536d846678aff6a0b Mon Sep 17 00:00:00 2001 From: amatiushkin Date: Mon, 25 Jun 2018 13:47:47 -0700 Subject: [PATCH 08/13] Extract visitors to stand-alone classes --- .../schema/GraphQLTypeCollectingVisitor.java | 119 +++++++++ .../GraphQLTypeRefResolvingVisitor.java | 44 ++++ .../schema/GraphQLTypeResolvingVisitor.java | 45 ++++ .../graphql/schema/GraphqlTypeVisitors.java | 237 ------------------ src/main/java/graphql/schema/SchemaUtil.java | 6 +- 5 files changed, 210 insertions(+), 241 deletions(-) create mode 100644 src/main/java/graphql/schema/GraphQLTypeCollectingVisitor.java create mode 100644 src/main/java/graphql/schema/GraphQLTypeRefResolvingVisitor.java create mode 100644 src/main/java/graphql/schema/GraphQLTypeResolvingVisitor.java delete mode 100644 src/main/java/graphql/schema/GraphqlTypeVisitors.java diff --git a/src/main/java/graphql/schema/GraphQLTypeCollectingVisitor.java b/src/main/java/graphql/schema/GraphQLTypeCollectingVisitor.java new file mode 100644 index 0000000000..f9d55c2b0b --- /dev/null +++ b/src/main/java/graphql/schema/GraphQLTypeCollectingVisitor.java @@ -0,0 +1,119 @@ +package graphql.schema; + +import graphql.AssertException; +import graphql.Internal; +import graphql.util.TraversalControl; +import graphql.util.TraverserContext; + +import java.util.HashMap; +import java.util.Map; + +import static java.lang.String.format; + +@Internal +public class GraphQLTypeCollectingVisitor extends GraphQLTypeVisitorStub { + + private final Map result = new HashMap<>(); + + public GraphQLTypeCollectingVisitor() { + } + + @Override + public TraversalControl visitGraphQLEnumType(GraphQLEnumType node, TraverserContext context) { + assertTypeUniqueness(node,result); + save(node.getName(),node); + return super.visitGraphQLEnumType(node, context); + } + + @Override + public TraversalControl visitGraphQLScalarType(GraphQLScalarType node, TraverserContext context) { + assertTypeUniqueness(node,result); + save(node.getName(),node); + return super.visitGraphQLScalarType(node, context); + } + + @Override + public TraversalControl visitGraphQLObjectType(GraphQLObjectType node, TraverserContext context) { + if (isTypeReference(node.getName())) { + assertTypeUniqueness(node, result); + } else { + save(node.getName(), node); + } + return super.visitGraphQLObjectType(node,context); + } + + @Override + public TraversalControl visitGraphQLInputObjectType(GraphQLInputObjectType node, TraverserContext context) { + if (isTypeReference(node.getName())) { + assertTypeUniqueness(node, result); + } else { + save(node.getName(), node); + } + return super.visitGraphQLInputObjectType(node, context); + } + + @Override + public TraversalControl visitGraphQLInterfaceType(GraphQLInterfaceType node, TraverserContext context) { + if (isTypeReference(node.getName())) { + assertTypeUniqueness(node, result); + } else { + save(node.getName(), node); + } + + return super.visitGraphQLInterfaceType(node, context); + } + + @Override + public TraversalControl visitGraphQLUnionType(GraphQLUnionType node, TraverserContext context) { + assertTypeUniqueness(node,result); + save(node.getName(),node); + return super.visitGraphQLUnionType(node, context); + } + + @Override + public TraversalControl visitGraphQLFieldDefinition(GraphQLFieldDefinition node, TraverserContext context) { + + return super.visitGraphQLFieldDefinition(node, context); + } + + // TODO: eh? Isn't it similar to assertTypeUniqueness? + private boolean isTypeReference(String name) { + return result.containsKey(name) && !(result.get(name) instanceof GraphQLTypeReference); + } + + private void save(String name, GraphQLType type) { + result.put(name,type); + } + + + /* +From http://facebook.github.io/graphql/#sec-Type-System + + All types within a GraphQL schema must have unique names. No two provided types may have the same name. + No provided type may have a name which conflicts with any built in types (including Scalar and Introspection types). + +Enforcing this helps avoid problems later down the track fo example https://github.com/graphql-java/graphql-java/issues/373 +*/ + private void assertTypeUniqueness(GraphQLType type, Map result) { + GraphQLType existingType = result.get(type.getName()); + // do we have an existing definition + if (existingType != null) { + // type references are ok + if (!(existingType instanceof GraphQLTypeReference || type instanceof GraphQLTypeReference)) + // object comparison here is deliberate + if (existingType != type) { + throw new AssertException(format("All types within a GraphQL schema must have unique names. No two provided types may have the same name.\n" + + "No provided type may have a name which conflicts with any built in types (including Scalar and Introspection types).\n" + + "You have redefined the type '%s' from being a '%s' to a '%s'", + type.getName(), existingType.getClass().getSimpleName(), type.getClass().getSimpleName())); + } + } + } + + public Map getResult() { + return result; + } + + + +} diff --git a/src/main/java/graphql/schema/GraphQLTypeRefResolvingVisitor.java b/src/main/java/graphql/schema/GraphQLTypeRefResolvingVisitor.java new file mode 100644 index 0000000000..44c3f4c50c --- /dev/null +++ b/src/main/java/graphql/schema/GraphQLTypeRefResolvingVisitor.java @@ -0,0 +1,44 @@ +package graphql.schema; + +import graphql.Internal; +import graphql.util.TraversalControl; +import graphql.util.TraverserContext; + +@Internal +public class GraphQLTypeRefResolvingVisitor extends GraphQLTypeVisitorStub { + protected final GraphQLType resolvedType; + + public GraphQLTypeRefResolvingVisitor(GraphQLType resolvedType) { + this.resolvedType = resolvedType; + } + + @Override + public TraversalControl visitGraphQLFieldDefinition(GraphQLFieldDefinition node, TraverserContext context) { + node.replaceType((GraphQLOutputType) resolvedType); + return super.visitGraphQLFieldDefinition(node, context); + } + + @Override + public TraversalControl visitGraphQLArgument(GraphQLArgument node, TraverserContext context) { + node.replaceType((GraphQLInputType) resolvedType); + return super.visitGraphQLArgument(node, context); + } + + @Override + public TraversalControl visitGraphQLInputObjectField(GraphQLInputObjectField node, TraverserContext context) { + node.replaceType((GraphQLInputType) resolvedType); + return super.visitGraphQLInputObjectField(node, context); + } + + @Override + public TraversalControl visitGraphQLList(GraphQLList node, TraverserContext context) { + node.replaceType( resolvedType); + return super.visitGraphQLList(node, context); + } + + @Override + public TraversalControl visitGraphQLNonNull(GraphQLNonNull node, TraverserContext context) { + node.replaceType( resolvedType); + return super.visitGraphQLNonNull(node, context); + } +} diff --git a/src/main/java/graphql/schema/GraphQLTypeResolvingVisitor.java b/src/main/java/graphql/schema/GraphQLTypeResolvingVisitor.java new file mode 100644 index 0000000000..f244596a71 --- /dev/null +++ b/src/main/java/graphql/schema/GraphQLTypeResolvingVisitor.java @@ -0,0 +1,45 @@ +package graphql.schema; + +import graphql.Assert; +import graphql.Internal; +import graphql.util.TraversalControl; +import graphql.util.TraverserContext; + +import java.util.Map; +import java.util.stream.Collectors; + +@Internal +public class GraphQLTypeResolvingVisitor extends GraphQLTypeVisitorStub { + protected final Map typeMap; + + public GraphQLTypeResolvingVisitor(Map typeMap) { + this.typeMap = typeMap; + } + + @Override + public TraversalControl visitGraphQLObjectType(GraphQLObjectType node, TraverserContext context) { + + node.replaceInterfaces(node.getInterfaces().stream() + .map(type -> (GraphQLOutputType)typeMap.get(type.getName())) + .collect(Collectors.toList())); + return super.visitGraphQLObjectType(node, context); + } + + @Override + public TraversalControl visitGraphQLUnionType(GraphQLUnionType node, TraverserContext context) { + + node.replaceTypes(node.getTypes().stream() + .map(type -> (GraphQLOutputType)typeMap.get(type.getName())) + .collect(Collectors.toList())); + return super.visitGraphQLUnionType(node, context); + } + + @Override + public TraversalControl visitGraphQLTypeReference(GraphQLTypeReference node, TraverserContext context) { + + final GraphQLType resolvedType = typeMap.get(node.getName()); + Assert.assertTrue(resolvedType != null, "type %s not found in schema", node.getName()); + context.getParentContext().thisNode().accept(context, new GraphQLTypeRefResolvingVisitor(resolvedType) ); + return super.visitGraphQLTypeReference(node, context); + } +} diff --git a/src/main/java/graphql/schema/GraphqlTypeVisitors.java b/src/main/java/graphql/schema/GraphqlTypeVisitors.java deleted file mode 100644 index 1e692e1744..0000000000 --- a/src/main/java/graphql/schema/GraphqlTypeVisitors.java +++ /dev/null @@ -1,237 +0,0 @@ -package graphql.schema; - -import graphql.Assert; -import graphql.AssertException; -import graphql.util.TraversalControl; -import graphql.util.TraverserContext; - -import java.util.HashMap; -import java.util.Map; -import java.util.stream.Collectors; - -import static graphql.util.TraversalControl.QUIT; -import static java.lang.String.format; - -/** - * GraphQL Type visitors library - */ -class GraphqlTypeVisitors { - - private GraphqlTypeVisitors() {} - - - static class LeafVisitor extends GraphQLTypeVisitorStub { - - @Override - public TraversalControl visitGraphQLScalarType(GraphQLScalarType node, TraverserContext context) { - context.setResult(true); - return QUIT; - } - - @Override - public TraversalControl visitGraphQLEnumType(GraphQLEnumType node, TraverserContext context) { - context.setResult(true); - return QUIT; - } - - @Override - protected TraversalControl visitGraphQLType(GraphQLType node, TraverserContext context) { - context.setResult(false); - return QUIT; - } - - @Override - public TraversalControl visitGraphQLList(GraphQLList node, TraverserContext context) { - return node.getWrappedType().accept(context,this); - } - - @Override - public TraversalControl visitGraphQLNonNull(GraphQLNonNull node, TraverserContext context) { - return node.getWrappedType().accept(context,this); - } - - } - - static class CollectingVisitor extends GraphQLTypeVisitorStub { - - private final Map result = new HashMap<>(); - - public CollectingVisitor() { - } - - @Override - public TraversalControl visitGraphQLEnumType(GraphQLEnumType node, TraverserContext context) { - assertTypeUniqueness(node,result); - save(node.getName(),node); - return super.visitGraphQLEnumType(node, context); - } - - @Override - public TraversalControl visitGraphQLScalarType(GraphQLScalarType node, TraverserContext context) { - assertTypeUniqueness(node,result); - save(node.getName(),node); - return super.visitGraphQLScalarType(node, context); - } - - @Override - public TraversalControl visitGraphQLObjectType(GraphQLObjectType node, TraverserContext context) { - if (isTypeReference(node.getName())) { - assertTypeUniqueness(node, result); - } else { - save(node.getName(), node); - } - return super.visitGraphQLObjectType(node,context); - } - - @Override - public TraversalControl visitGraphQLInputObjectType(GraphQLInputObjectType node, TraverserContext context) { - if (isTypeReference(node.getName())) { - assertTypeUniqueness(node, result); - } else { - save(node.getName(), node); - } - return super.visitGraphQLInputObjectType(node, context); - } - - @Override - public TraversalControl visitGraphQLInterfaceType(GraphQLInterfaceType node, TraverserContext context) { - if (isTypeReference(node.getName())) { - assertTypeUniqueness(node, result); - } else { - save(node.getName(), node); - } - - return super.visitGraphQLInterfaceType(node, context); - } - - @Override - public TraversalControl visitGraphQLUnionType(GraphQLUnionType node, TraverserContext context) { - assertTypeUniqueness(node,result); - save(node.getName(),node); - return super.visitGraphQLUnionType(node, context); - } - - @Override - public TraversalControl visitGraphQLFieldDefinition(GraphQLFieldDefinition node, TraverserContext context) { - - return super.visitGraphQLFieldDefinition(node, context); - } - - // TODO: eh? Isn't it similar to assertTypeUniqueness? - private boolean isTypeReference(String name) { - return result.containsKey(name) && !(result.get(name) instanceof GraphQLTypeReference); - } - - private void save(String name, GraphQLType type) { - result.put(name,type); - } - - - /* - From http://facebook.github.io/graphql/#sec-Type-System - - All types within a GraphQL schema must have unique names. No two provided types may have the same name. - No provided type may have a name which conflicts with any built in types (including Scalar and Introspection types). - - Enforcing this helps avoid problems later down the track fo example https://github.com/graphql-java/graphql-java/issues/373 - */ - private void assertTypeUniqueness(GraphQLType type, Map result) { - GraphQLType existingType = result.get(type.getName()); - // do we have an existing definition - if (existingType != null) { - // type references are ok - if (!(existingType instanceof GraphQLTypeReference || type instanceof GraphQLTypeReference)) - // object comparison here is deliberate - if (existingType != type) { - throw new AssertException(format("All types within a GraphQL schema must have unique names. No two provided types may have the same name.\n" + - "No provided type may have a name which conflicts with any built in types (including Scalar and Introspection types).\n" + - "You have redefined the type '%s' from being a '%s' to a '%s'", - type.getName(), existingType.getClass().getSimpleName(), type.getClass().getSimpleName())); - } - } - } - - public Map getResult() { - return result; - } - - - } - - static class RefResolvingVisitor extends GraphQLTypeVisitorStub { - - final private GraphQLType resolvedType; - public RefResolvingVisitor(GraphQLType resolvedType) { - this.resolvedType = resolvedType; - } - - - - @Override - public TraversalControl visitGraphQLFieldDefinition(GraphQLFieldDefinition node, TraverserContext context) { - node.replaceType((GraphQLOutputType) resolvedType); - return super.visitGraphQLFieldDefinition(node, context); - } - - @Override - public TraversalControl visitGraphQLArgument(GraphQLArgument node, TraverserContext context) { - node.replaceType((GraphQLInputType) resolvedType); - return super.visitGraphQLArgument(node, context); - } - - @Override - public TraversalControl visitGraphQLInputObjectField(GraphQLInputObjectField node, TraverserContext context) { - node.replaceType((GraphQLInputType) resolvedType); - return super.visitGraphQLInputObjectField(node, context); - } - - @Override - public TraversalControl visitGraphQLList(GraphQLList node, TraverserContext context) { - node.replaceType( resolvedType); - return super.visitGraphQLList(node, context); - } - - @Override - public TraversalControl visitGraphQLNonNull(GraphQLNonNull node, TraverserContext context) { - node.replaceType( resolvedType); - return super.visitGraphQLNonNull(node, context); - } - - } - - static class TypeResolvingVisitor extends GraphQLTypeVisitorStub { - - private final Map typeMap; - - public TypeResolvingVisitor( Map typeMap) { - this.typeMap = typeMap; - } - - @Override - public TraversalControl visitGraphQLObjectType(GraphQLObjectType node, TraverserContext context) { - - node.replaceInterfaces(node.getInterfaces().stream() - .map(type -> (GraphQLOutputType)typeMap.get(type.getName())) - .collect(Collectors.toList())); - return super.visitGraphQLObjectType(node, context); - } - - @Override - public TraversalControl visitGraphQLUnionType(GraphQLUnionType node, TraverserContext context) { - - node.replaceTypes(node.getTypes().stream() - .map(type -> (GraphQLOutputType)typeMap.get(type.getName())) - .collect(Collectors.toList())); - return super.visitGraphQLUnionType(node, context); - } - - @Override - public TraversalControl visitGraphQLTypeReference(GraphQLTypeReference node, TraverserContext context) { - - final GraphQLType resolvedType = typeMap.get(node.getName()); - Assert.assertTrue(resolvedType != null, "type %s not found in schema", node.getName()); - context.getParentContext().thisNode().accept(context, new RefResolvingVisitor(resolvedType) ); - return super.visitGraphQLTypeReference(node, context); - } - } -} diff --git a/src/main/java/graphql/schema/SchemaUtil.java b/src/main/java/graphql/schema/SchemaUtil.java index 89f6f59992..e1a723e543 100644 --- a/src/main/java/graphql/schema/SchemaUtil.java +++ b/src/main/java/graphql/schema/SchemaUtil.java @@ -3,8 +3,6 @@ import graphql.Internal; import graphql.introspection.Introspection; -import static graphql.schema.GraphqlTypeVisitors.CollectingVisitor; -import static graphql.schema.GraphqlTypeVisitors.TypeResolvingVisitor; import java.util.ArrayList; import java.util.HashMap; @@ -37,7 +35,7 @@ Map allTypes(final GraphQLSchema schema,final Set findImplementations(GraphQLSchema schema, GraphQL void replaceTypeReferences(GraphQLSchema schema) { final Map typeMap = schema.getTypeMap(); - TRAVERSER.depthFirst(new TypeResolvingVisitor(typeMap),typeMap.values()); + TRAVERSER.depthFirst(new GraphQLTypeResolvingVisitor(typeMap),typeMap.values()); } } From 4f6488e7b2363332690231b8b43eb456c4a1e4aa Mon Sep 17 00:00:00 2001 From: amatiushkin Date: Mon, 25 Jun 2018 14:34:46 -0700 Subject: [PATCH 09/13] Use project codestyle --- .../schema/GraphQLTypeCollectingVisitor.java | 21 ++- .../GraphQLTypeRefResolvingVisitor.java | 4 +- .../schema/GraphQLTypeResolvingVisitor.java | 6 +- .../graphql/schema/GraphQLTypeVisitor.java | 12 ++ .../schema/GraphQLTypeVisitorStub.java | 27 ++-- src/main/java/graphql/schema/SchemaUtil.java | 13 +- .../graphql/schema/TypeTraverserTest.groovy | 128 ++++++++++-------- 7 files changed, 115 insertions(+), 96 deletions(-) diff --git a/src/main/java/graphql/schema/GraphQLTypeCollectingVisitor.java b/src/main/java/graphql/schema/GraphQLTypeCollectingVisitor.java index f9d55c2b0b..d436c0d588 100644 --- a/src/main/java/graphql/schema/GraphQLTypeCollectingVisitor.java +++ b/src/main/java/graphql/schema/GraphQLTypeCollectingVisitor.java @@ -11,24 +11,24 @@ import static java.lang.String.format; @Internal -public class GraphQLTypeCollectingVisitor extends GraphQLTypeVisitorStub { +public class GraphQLTypeCollectingVisitor extends GraphQLTypeVisitorStub { - private final Map result = new HashMap<>(); + private final Map result = new HashMap<>(); public GraphQLTypeCollectingVisitor() { } @Override public TraversalControl visitGraphQLEnumType(GraphQLEnumType node, TraverserContext context) { - assertTypeUniqueness(node,result); - save(node.getName(),node); + assertTypeUniqueness(node, result); + save(node.getName(), node); return super.visitGraphQLEnumType(node, context); } @Override public TraversalControl visitGraphQLScalarType(GraphQLScalarType node, TraverserContext context) { - assertTypeUniqueness(node,result); - save(node.getName(),node); + assertTypeUniqueness(node, result); + save(node.getName(), node); return super.visitGraphQLScalarType(node, context); } @@ -39,7 +39,7 @@ public TraversalControl visitGraphQLObjectType(GraphQLObjectType node, Traverser } else { save(node.getName(), node); } - return super.visitGraphQLObjectType(node,context); + return super.visitGraphQLObjectType(node, context); } @Override @@ -65,8 +65,8 @@ public TraversalControl visitGraphQLInterfaceType(GraphQLInterfaceType node, Tra @Override public TraversalControl visitGraphQLUnionType(GraphQLUnionType node, TraverserContext context) { - assertTypeUniqueness(node,result); - save(node.getName(),node); + assertTypeUniqueness(node, result); + save(node.getName(), node); return super.visitGraphQLUnionType(node, context); } @@ -82,7 +82,7 @@ private boolean isTypeReference(String name) { } private void save(String name, GraphQLType type) { - result.put(name,type); + result.put(name, type); } @@ -115,5 +115,4 @@ public Map getResult() { } - } diff --git a/src/main/java/graphql/schema/GraphQLTypeRefResolvingVisitor.java b/src/main/java/graphql/schema/GraphQLTypeRefResolvingVisitor.java index 44c3f4c50c..3428527b85 100644 --- a/src/main/java/graphql/schema/GraphQLTypeRefResolvingVisitor.java +++ b/src/main/java/graphql/schema/GraphQLTypeRefResolvingVisitor.java @@ -32,13 +32,13 @@ public TraversalControl visitGraphQLInputObjectField(GraphQLInputObjectField nod @Override public TraversalControl visitGraphQLList(GraphQLList node, TraverserContext context) { - node.replaceType( resolvedType); + node.replaceType(resolvedType); return super.visitGraphQLList(node, context); } @Override public TraversalControl visitGraphQLNonNull(GraphQLNonNull node, TraverserContext context) { - node.replaceType( resolvedType); + node.replaceType(resolvedType); return super.visitGraphQLNonNull(node, context); } } diff --git a/src/main/java/graphql/schema/GraphQLTypeResolvingVisitor.java b/src/main/java/graphql/schema/GraphQLTypeResolvingVisitor.java index f244596a71..cf8875eeb0 100644 --- a/src/main/java/graphql/schema/GraphQLTypeResolvingVisitor.java +++ b/src/main/java/graphql/schema/GraphQLTypeResolvingVisitor.java @@ -20,7 +20,7 @@ public GraphQLTypeResolvingVisitor(Map typeMap) { public TraversalControl visitGraphQLObjectType(GraphQLObjectType node, TraverserContext context) { node.replaceInterfaces(node.getInterfaces().stream() - .map(type -> (GraphQLOutputType)typeMap.get(type.getName())) + .map(type -> (GraphQLOutputType) typeMap.get(type.getName())) .collect(Collectors.toList())); return super.visitGraphQLObjectType(node, context); } @@ -29,7 +29,7 @@ public TraversalControl visitGraphQLObjectType(GraphQLObjectType node, Traverser public TraversalControl visitGraphQLUnionType(GraphQLUnionType node, TraverserContext context) { node.replaceTypes(node.getTypes().stream() - .map(type -> (GraphQLOutputType)typeMap.get(type.getName())) + .map(type -> (GraphQLOutputType) typeMap.get(type.getName())) .collect(Collectors.toList())); return super.visitGraphQLUnionType(node, context); } @@ -39,7 +39,7 @@ public TraversalControl visitGraphQLTypeReference(GraphQLTypeReference node, Tra final GraphQLType resolvedType = typeMap.get(node.getName()); Assert.assertTrue(resolvedType != null, "type %s not found in schema", node.getName()); - context.getParentContext().thisNode().accept(context, new GraphQLTypeRefResolvingVisitor(resolvedType) ); + context.getParentContext().thisNode().accept(context, new GraphQLTypeRefResolvingVisitor(resolvedType)); return super.visitGraphQLTypeReference(node, context); } } diff --git a/src/main/java/graphql/schema/GraphQLTypeVisitor.java b/src/main/java/graphql/schema/GraphQLTypeVisitor.java index 6868cd9529..308f2b2e37 100644 --- a/src/main/java/graphql/schema/GraphQLTypeVisitor.java +++ b/src/main/java/graphql/schema/GraphQLTypeVisitor.java @@ -7,17 +7,29 @@ @Internal public interface GraphQLTypeVisitor { TraversalControl visitGraphQLArgument(GraphQLArgument node, TraverserContext context); + TraversalControl visitGraphQLInterfaceType(GraphQLInterfaceType node, TraverserContext context); + TraversalControl visitGraphQLEnumType(GraphQLEnumType node, TraverserContext context); + TraversalControl visitGraphQLEnumValueDefinition(GraphQLEnumValueDefinition node, TraverserContext context); + TraversalControl visitGraphQLFieldDefinition(GraphQLFieldDefinition node, TraverserContext context); + TraversalControl visitGraphQLInputObjectField(GraphQLInputObjectField node, TraverserContext context); + TraversalControl visitGraphQLInputObjectType(GraphQLInputObjectType node, TraverserContext context); + TraversalControl visitGraphQLList(GraphQLList node, TraverserContext context); + TraversalControl visitGraphQLNonNull(GraphQLNonNull node, TraverserContext context); + TraversalControl visitGraphQLObjectType(GraphQLObjectType node, TraverserContext context); + TraversalControl visitGraphQLScalarType(GraphQLScalarType node, TraverserContext context); + TraversalControl visitGraphQLTypeReference(GraphQLTypeReference node, TraverserContext context); + TraversalControl visitGraphQLUnionType(GraphQLUnionType node, TraverserContext context); // Marker interfaces diff --git a/src/main/java/graphql/schema/GraphQLTypeVisitorStub.java b/src/main/java/graphql/schema/GraphQLTypeVisitorStub.java index d16b62309f..54b569727d 100644 --- a/src/main/java/graphql/schema/GraphQLTypeVisitorStub.java +++ b/src/main/java/graphql/schema/GraphQLTypeVisitorStub.java @@ -3,6 +3,7 @@ import graphql.PublicApi; import graphql.util.TraversalControl; import graphql.util.TraverserContext; + import static graphql.util.TraversalControl.CONTINUE; /** @@ -13,67 +14,67 @@ public class GraphQLTypeVisitorStub implements GraphQLTypeVisitor { @Override public TraversalControl visitGraphQLArgument(GraphQLArgument node, TraverserContext context) { - return visitGraphQLType(node,context); + return visitGraphQLType(node, context); } @Override public TraversalControl visitGraphQLInterfaceType(GraphQLInterfaceType node, TraverserContext context) { - return visitGraphQLType(node,context); + return visitGraphQLType(node, context); } @Override public TraversalControl visitGraphQLEnumType(GraphQLEnumType node, TraverserContext context) { - return visitGraphQLType(node,context); + return visitGraphQLType(node, context); } @Override public TraversalControl visitGraphQLEnumValueDefinition(GraphQLEnumValueDefinition node, TraverserContext context) { - return visitGraphQLType(node,context); + return visitGraphQLType(node, context); } @Override public TraversalControl visitGraphQLFieldDefinition(GraphQLFieldDefinition node, TraverserContext context) { - return visitGraphQLType(node,context); + return visitGraphQLType(node, context); } @Override public TraversalControl visitGraphQLInputObjectField(GraphQLInputObjectField node, TraverserContext context) { - return visitGraphQLType(node,context); + return visitGraphQLType(node, context); } @Override public TraversalControl visitGraphQLInputObjectType(GraphQLInputObjectType node, TraverserContext context) { - return visitGraphQLType(node,context); + return visitGraphQLType(node, context); } @Override public TraversalControl visitGraphQLList(GraphQLList node, TraverserContext context) { - return visitGraphQLType(node,context); + return visitGraphQLType(node, context); } @Override public TraversalControl visitGraphQLNonNull(GraphQLNonNull node, TraverserContext context) { - return visitGraphQLType(node,context); + return visitGraphQLType(node, context); } @Override public TraversalControl visitGraphQLObjectType(GraphQLObjectType node, TraverserContext context) { - return visitGraphQLType(node,context); + return visitGraphQLType(node, context); } @Override public TraversalControl visitGraphQLScalarType(GraphQLScalarType node, TraverserContext context) { - return visitGraphQLType(node,context); + return visitGraphQLType(node, context); } @Override public TraversalControl visitGraphQLTypeReference(GraphQLTypeReference node, TraverserContext context) { - return visitGraphQLType(node,context); + return visitGraphQLType(node, context); } @Override public TraversalControl visitGraphQLUnionType(GraphQLUnionType node, TraverserContext context) { - return visitGraphQLType(node,context); + return visitGraphQLType(node, context); } protected TraversalControl visitGraphQLType(GraphQLType node, TraverserContext context) { diff --git a/src/main/java/graphql/schema/SchemaUtil.java b/src/main/java/graphql/schema/SchemaUtil.java index e1a723e543..516d452e74 100644 --- a/src/main/java/graphql/schema/SchemaUtil.java +++ b/src/main/java/graphql/schema/SchemaUtil.java @@ -16,19 +16,19 @@ public class SchemaUtil { private static final TypeTraverser TRAVERSER = new TypeTraverser(); - Map allTypes(final GraphQLSchema schema,final Set additionalTypes) { + Map allTypes(final GraphQLSchema schema, final Set additionalTypes) { List roots = new ArrayList() {{ add(schema.getQueryType()); - if(schema.isSupportingMutations()) { + if (schema.isSupportingMutations()) { add(schema.getMutationType()); } - if(schema.isSupportingSubscriptions()) { + if (schema.isSupportingSubscriptions()) { add(schema.getSubscriptionType()); } - if(additionalTypes != null) { + if (additionalTypes != null) { addAll(additionalTypes); } @@ -41,14 +41,13 @@ Map allTypes(final GraphQLSchema schema,final Set> groupImplementations(GraphQLSchema schema) { Map> result = new HashMap<>(); @@ -99,6 +98,6 @@ public List findImplementations(GraphQLSchema schema, GraphQL void replaceTypeReferences(GraphQLSchema schema) { final Map typeMap = schema.getTypeMap(); - TRAVERSER.depthFirst(new GraphQLTypeResolvingVisitor(typeMap),typeMap.values()); + TRAVERSER.depthFirst(new GraphQLTypeResolvingVisitor(typeMap), typeMap.values()); } } diff --git a/src/test/groovy/graphql/schema/TypeTraverserTest.groovy b/src/test/groovy/graphql/schema/TypeTraverserTest.groovy index d04e945f6d..03d3a94bb0 100644 --- a/src/test/groovy/graphql/schema/TypeTraverserTest.groovy +++ b/src/test/groovy/graphql/schema/TypeTraverserTest.groovy @@ -6,47 +6,50 @@ import graphql.util.TraversalControl import graphql.util.TraverserContext import spock.lang.Specification -class TypeTraverserTest extends Specification { +class TypeTraverserTest extends Specification { def "reachable scalar type"() { when: - def visitor = new GraphQLTestingVisitor() - new TypeTraverser().depthFirst(visitor, Scalars.GraphQLString) + def visitor = new GraphQLTestingVisitor() + new TypeTraverser().depthFirst(visitor, Scalars.GraphQLString) then: - visitor.getStack() == ["scalar: String", "fallback: String"] + visitor.getStack() == ["scalar: String", "fallback: String"] } def "reachable string argument type"() { - when: def visitor = new GraphQLTestingVisitor() - - new TypeTraverser().depthFirst(visitor, GraphQLArgument.newArgument() - .name("Test") - .type(Scalars.GraphQLString) - .build()) - then: - visitor.getStack() == [ "argument: Test", "fallback: Test", "scalar: String", "fallback: String" ] + when: + def visitor = new GraphQLTestingVisitor() + + new TypeTraverser().depthFirst(visitor, GraphQLArgument.newArgument() + .name("Test") + .type(Scalars.GraphQLString) + .build()) + then: + visitor.getStack() == ["argument: Test", "fallback: Test", "scalar: String", "fallback: String"] } def "reachable number argument type"() { - when: def visitor = new GraphQLTestingVisitor() - new TypeTraverser().depthFirst(visitor, GraphQLArgument.newArgument() - .name("Test") - .type(Scalars.GraphQLInt) - .build()) + when: + def visitor = new GraphQLTestingVisitor() + new TypeTraverser().depthFirst(visitor, GraphQLArgument.newArgument() + .name("Test") + .type(Scalars.GraphQLInt) + .build()) then: - visitor.getStack() == ["argument: Test", "fallback: Test", "scalar: Int", "fallback: Int"] + visitor.getStack() == ["argument: Test", "fallback: Test", "scalar: Int", "fallback: Int"] } def "reachable enum type"() { - when: def visitor = new GraphQLTestingVisitor() + when: + def visitor = new GraphQLTestingVisitor() new TypeTraverser().depthFirst(visitor, GraphQLEnumType .newEnum() .name("foo") @@ -61,29 +64,32 @@ class TypeTraverserTest extends Specification { } def "reachable field definition type"() { - when: def visitor = new GraphQLTestingVisitor() - new TypeTraverser().depthFirst(visitor,GraphQLFieldDefinition.newFieldDefinition() + when: + def visitor = new GraphQLTestingVisitor() + new TypeTraverser().depthFirst(visitor, GraphQLFieldDefinition.newFieldDefinition() .name("foo") .type(Scalars.GraphQLString) .build()) then: - visitor.getStack() == ["field: foo","fallback: foo","scalar: String", "fallback: String"] + visitor.getStack() == ["field: foo", "fallback: foo", "scalar: String", "fallback: String"] } def "reachable input object field type"() { - when: def visitor = new GraphQLTestingVisitor() - new TypeTraverser().depthFirst(visitor,GraphQLInputObjectField.newInputObjectField() + when: + def visitor = new GraphQLTestingVisitor() + new TypeTraverser().depthFirst(visitor, GraphQLInputObjectField.newInputObjectField() .name("bar") .type(Scalars.GraphQLString) .build()) then: - visitor.getStack() == ["input object field: bar","fallback: bar","scalar: String", "fallback: String"] + visitor.getStack() == ["input object field: bar", "fallback: bar", "scalar: String", "fallback: String"] } def "reachable input object type"() { - when: def visitor = new GraphQLTestingVisitor() - new TypeTraverser().depthFirst(visitor,GraphQLInputObjectType.newInputObject() + when: + def visitor = new GraphQLTestingVisitor() + new TypeTraverser().depthFirst(visitor, GraphQLInputObjectType.newInputObject() .name("foo") .field(GraphQLInputObjectField.newInputObjectField() .name("bar") @@ -91,15 +97,16 @@ class TypeTraverserTest extends Specification { .build()) .build()) then: - visitor.getStack() == ["input object: foo","fallback: foo", - "input object field: bar","fallback: bar", + visitor.getStack() == ["input object: foo", "fallback: foo", + "input object field: bar", "fallback: bar", "scalar: String", "fallback: String"] } def "reachable interface type"() { - when: def visitor = new GraphQLTestingVisitor() - new TypeTraverser().depthFirst(visitor,GraphQLInterfaceType.newInterface() + when: + def visitor = new GraphQLTestingVisitor() + new TypeTraverser().depthFirst(visitor, GraphQLInterfaceType.newInterface() .name("foo") .field(GraphQLFieldDefinition.newFieldDefinition() .name("bar") @@ -108,74 +115,76 @@ class TypeTraverserTest extends Specification { .typeResolver(NOOP_RESOLVER) .build()) then: - visitor.getStack() == ["interface: foo","fallback: foo", - "field: bar","fallback: bar", + visitor.getStack() == ["interface: foo", "fallback: foo", + "field: bar", "fallback: bar", "scalar: String", "fallback: String"] } def "reachable list type"() { - when: def visitor = new GraphQLTestingVisitor() - new TypeTraverser().depthFirst(visitor,GraphQLList.list(Scalars.GraphQLString)) + when: + def visitor = new GraphQLTestingVisitor() + new TypeTraverser().depthFirst(visitor, GraphQLList.list(Scalars.GraphQLString)) then: - visitor.getStack() == ["list: String","fallback: null", + visitor.getStack() == ["list: String", "fallback: null", "scalar: String", "fallback: String"] } def "reachable nonNull type"() { - when: def visitor = new GraphQLTestingVisitor() - new TypeTraverser().depthFirst(visitor,GraphQLNonNull.nonNull(Scalars.GraphQLString)) + when: + def visitor = new GraphQLTestingVisitor() + new TypeTraverser().depthFirst(visitor, GraphQLNonNull.nonNull(Scalars.GraphQLString)) then: - visitor.getStack() == ["nonNull: String","fallback: null", + visitor.getStack() == ["nonNull: String", "fallback: null", "scalar: String", "fallback: String"] } def "reachable object type"() { - when: def visitor = new GraphQLTestingVisitor() - new TypeTraverser().depthFirst(visitor,GraphQLObjectType.newObject() + when: + def visitor = new GraphQLTestingVisitor() + new TypeTraverser().depthFirst(visitor, GraphQLObjectType.newObject() .name("myObject") .field(GraphQLFieldDefinition.newFieldDefinition() - .name("foo") - .type(Scalars.GraphQLString) - .build()) + .name("foo") + .type(Scalars.GraphQLString) + .build()) .withInterface(GraphQLInterfaceType.newInterface() - .name("bar") - .typeResolver(NOOP_RESOLVER) - .build()) + .name("bar") + .typeResolver(NOOP_RESOLVER) + .build()) .build()) then: visitor.getStack() == ["object: myObject", "fallback: myObject", - "field: foo","fallback: foo", + "field: foo", "fallback: foo", "scalar: String", "fallback: String", - "interface: bar","fallback: bar"] + "interface: bar", "fallback: bar"] } - def "reachable reference type"() { - when: def visitor = new GraphQLTestingVisitor() - new TypeTraverser().depthFirst(visitor,GraphQLTypeReference.typeRef("something")) + when: + def visitor = new GraphQLTestingVisitor() + new TypeTraverser().depthFirst(visitor, GraphQLTypeReference.typeRef("something")) then: - visitor.getStack() == ["reference: something","fallback: something"] + visitor.getStack() == ["reference: something", "fallback: something"] } def "reachable union type"() { - when: def visitor = new GraphQLTestingVisitor() - new TypeTraverser().depthFirst(visitor,GraphQLUnionType.newUnionType() + when: + def visitor = new GraphQLTestingVisitor() + new TypeTraverser().depthFirst(visitor, GraphQLUnionType.newUnionType() .name("foo") .possibleType(GraphQLObjectType.newObject().name("dummy").build()) .possibleType(GraphQLTypeReference.typeRef("dummyRef")) .typeResolver(NOOP_RESOLVER) .build()) then: - visitor.getStack() == ["union: foo","fallback: foo", + visitor.getStack() == ["union: foo", "fallback: foo", "object: dummy", "fallback: dummy", "reference: dummyRef", "fallback: dummyRef"] } - - def NOOP_RESOLVER = new TypeResolver() { @Override GraphQLObjectType getType(TypeResolutionEnvironment env) { @@ -186,7 +195,7 @@ class TypeTraverserTest extends Specification { class GraphQLTestingVisitor extends GraphQLTypeVisitorStub { - def stack = [] + def stack = [] @Override TraversalControl visitGraphQLArgument(GraphQLArgument node, TraverserContext context) { @@ -278,5 +287,4 @@ class TypeTraverserTest extends Specification { } - } From 126f3df8c33b3d5126505f853ba29fd24beeea29 Mon Sep 17 00:00:00 2001 From: amatiushkin Date: Mon, 25 Jun 2018 15:52:31 -0700 Subject: [PATCH 10/13] Make TypeTraverser public with respect to #1097 --- src/main/java/graphql/schema/TypeTraverser.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/graphql/schema/TypeTraverser.java b/src/main/java/graphql/schema/TypeTraverser.java index cb2fa04219..0bb151a41a 100644 --- a/src/main/java/graphql/schema/TypeTraverser.java +++ b/src/main/java/graphql/schema/TypeTraverser.java @@ -2,6 +2,7 @@ import graphql.Internal; +import graphql.PublicApi; import graphql.util.TraversalControl; import graphql.util.Traverser; import graphql.util.TraverserContext; @@ -17,7 +18,7 @@ import static graphql.util.TraversalControl.CONTINUE; -@Internal +@PublicApi public class TypeTraverser { From 58925daf67aadada2613f4e6245afd2bf169cc31 Mon Sep 17 00:00:00 2001 From: amatiushkin Date: Mon, 16 Jul 2018 13:45:39 -0700 Subject: [PATCH 11/13] Add a test for GraphQLTypeVisitorStub --- .../schema/GraphQLTypeVisitorStubTest.groovy | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 src/test/groovy/graphql/schema/GraphQLTypeVisitorStubTest.groovy diff --git a/src/test/groovy/graphql/schema/GraphQLTypeVisitorStubTest.groovy b/src/test/groovy/graphql/schema/GraphQLTypeVisitorStubTest.groovy new file mode 100644 index 0000000000..22ec38ba09 --- /dev/null +++ b/src/test/groovy/graphql/schema/GraphQLTypeVisitorStubTest.groovy @@ -0,0 +1,40 @@ +package graphql.schema + +import graphql.Scalars +import graphql.util.TraversalControl +import graphql.util.TraverserContext +import spock.lang.Specification +import spock.lang.Unroll + +class GraphQLTypeVisitorStubTest extends Specification { + + + @Unroll + def "#visitMethod scalar type"() { + given: + GraphQLTypeVisitorStub typeVisitorStub = Spy(GraphQLTypeVisitorStub, constructorArgs: []) + TraverserContext context = Mock(TraverserContext) + + when: + def control = typeVisitorStub."$visitMethod"(node, context) + then: + typeVisitorStub.visitGraphQLType(node, context) >> TraversalControl.CONTINUE + control == TraversalControl.CONTINUE + + where: + node | visitMethod + Mock(GraphQLScalarType) | 'visitGraphQLScalarType' + Mock(GraphQLArgument) | 'visitGraphQLArgument' + Mock(GraphQLInterfaceType) | 'visitGraphQLInterfaceType' + Mock(GraphQLEnumType) | 'visitGraphQLEnumType' + Mock(GraphQLEnumValueDefinition) | 'visitGraphQLEnumValueDefinition' + Mock(GraphQLFieldDefinition) | 'visitGraphQLFieldDefinition' + Mock(GraphQLInputObjectField) | 'visitGraphQLInputObjectField' + Mock(GraphQLInputObjectType) | 'visitGraphQLInputObjectType' + Mock(GraphQLList) | 'visitGraphQLList' + Mock(GraphQLNonNull) | 'visitGraphQLNonNull' + Mock(GraphQLObjectType) | 'visitGraphQLObjectType' + Mock(GraphQLTypeReference) | 'visitGraphQLTypeReference' + Mock(GraphQLUnionType) | 'visitGraphQLUnionType' + } +} From 12528517b5ebc995e4be6ab33fd306942844c09a Mon Sep 17 00:00:00 2001 From: amatiushkin Date: Tue, 4 Sep 2018 20:34:58 -0700 Subject: [PATCH 12/13] - reference resolving visitor is inner type of more general type resolver - type visitor promoted to public api - better code style for assertion --- .../GraphQLTypeRefResolvingVisitor.java | 44 ------------------ .../schema/GraphQLTypeResolvingVisitor.java | 45 +++++++++++++++++-- .../graphql/schema/GraphQLTypeVisitor.java | 4 +- 3 files changed, 44 insertions(+), 49 deletions(-) delete mode 100644 src/main/java/graphql/schema/GraphQLTypeRefResolvingVisitor.java diff --git a/src/main/java/graphql/schema/GraphQLTypeRefResolvingVisitor.java b/src/main/java/graphql/schema/GraphQLTypeRefResolvingVisitor.java deleted file mode 100644 index 3428527b85..0000000000 --- a/src/main/java/graphql/schema/GraphQLTypeRefResolvingVisitor.java +++ /dev/null @@ -1,44 +0,0 @@ -package graphql.schema; - -import graphql.Internal; -import graphql.util.TraversalControl; -import graphql.util.TraverserContext; - -@Internal -public class GraphQLTypeRefResolvingVisitor extends GraphQLTypeVisitorStub { - protected final GraphQLType resolvedType; - - public GraphQLTypeRefResolvingVisitor(GraphQLType resolvedType) { - this.resolvedType = resolvedType; - } - - @Override - public TraversalControl visitGraphQLFieldDefinition(GraphQLFieldDefinition node, TraverserContext context) { - node.replaceType((GraphQLOutputType) resolvedType); - return super.visitGraphQLFieldDefinition(node, context); - } - - @Override - public TraversalControl visitGraphQLArgument(GraphQLArgument node, TraverserContext context) { - node.replaceType((GraphQLInputType) resolvedType); - return super.visitGraphQLArgument(node, context); - } - - @Override - public TraversalControl visitGraphQLInputObjectField(GraphQLInputObjectField node, TraverserContext context) { - node.replaceType((GraphQLInputType) resolvedType); - return super.visitGraphQLInputObjectField(node, context); - } - - @Override - public TraversalControl visitGraphQLList(GraphQLList node, TraverserContext context) { - node.replaceType(resolvedType); - return super.visitGraphQLList(node, context); - } - - @Override - public TraversalControl visitGraphQLNonNull(GraphQLNonNull node, TraverserContext context) { - node.replaceType(resolvedType); - return super.visitGraphQLNonNull(node, context); - } -} diff --git a/src/main/java/graphql/schema/GraphQLTypeResolvingVisitor.java b/src/main/java/graphql/schema/GraphQLTypeResolvingVisitor.java index cf8875eeb0..b89c245edc 100644 --- a/src/main/java/graphql/schema/GraphQLTypeResolvingVisitor.java +++ b/src/main/java/graphql/schema/GraphQLTypeResolvingVisitor.java @@ -1,6 +1,6 @@ package graphql.schema; -import graphql.Assert; +import static graphql.Assert.assertNotNull; import graphql.Internal; import graphql.util.TraversalControl; import graphql.util.TraverserContext; @@ -38,8 +38,47 @@ public TraversalControl visitGraphQLUnionType(GraphQLUnionType node, TraverserCo public TraversalControl visitGraphQLTypeReference(GraphQLTypeReference node, TraverserContext context) { final GraphQLType resolvedType = typeMap.get(node.getName()); - Assert.assertTrue(resolvedType != null, "type %s not found in schema", node.getName()); - context.getParentContext().thisNode().accept(context, new GraphQLTypeRefResolvingVisitor(resolvedType)); + assertNotNull(resolvedType != null, "type %s not found in schema", node.getName()); + context.getParentContext().thisNode().accept(context, new TypeRefResolvingVisitor(resolvedType)); return super.visitGraphQLTypeReference(node, context); } + + + private class TypeRefResolvingVisitor extends GraphQLTypeVisitorStub { + protected final GraphQLType resolvedType; + + TypeRefResolvingVisitor(GraphQLType resolvedType) { + this.resolvedType = resolvedType; + } + + @Override + public TraversalControl visitGraphQLFieldDefinition(GraphQLFieldDefinition node, TraverserContext context) { + node.replaceType((GraphQLOutputType) resolvedType); + return super.visitGraphQLFieldDefinition(node, context); + } + + @Override + public TraversalControl visitGraphQLArgument(GraphQLArgument node, TraverserContext context) { + node.replaceType((GraphQLInputType) resolvedType); + return super.visitGraphQLArgument(node, context); + } + + @Override + public TraversalControl visitGraphQLInputObjectField(GraphQLInputObjectField node, TraverserContext context) { + node.replaceType((GraphQLInputType) resolvedType); + return super.visitGraphQLInputObjectField(node, context); + } + + @Override + public TraversalControl visitGraphQLList(GraphQLList node, TraverserContext context) { + node.replaceType(resolvedType); + return super.visitGraphQLList(node, context); + } + + @Override + public TraversalControl visitGraphQLNonNull(GraphQLNonNull node, TraverserContext context) { + node.replaceType(resolvedType); + return super.visitGraphQLNonNull(node, context); + } + } } diff --git a/src/main/java/graphql/schema/GraphQLTypeVisitor.java b/src/main/java/graphql/schema/GraphQLTypeVisitor.java index 308f2b2e37..49e5975711 100644 --- a/src/main/java/graphql/schema/GraphQLTypeVisitor.java +++ b/src/main/java/graphql/schema/GraphQLTypeVisitor.java @@ -1,10 +1,10 @@ package graphql.schema; -import graphql.Internal; +import graphql.PublicApi; import graphql.util.TraversalControl; import graphql.util.TraverserContext; -@Internal +@PublicApi public interface GraphQLTypeVisitor { TraversalControl visitGraphQLArgument(GraphQLArgument node, TraverserContext context); From a4850c0f4c2eee1e914311d8f1a7b019b4c81d0a Mon Sep 17 00:00:00 2001 From: andimarek Date: Sun, 9 Sep 2018 11:41:48 +1000 Subject: [PATCH 13/13] fix assertNotNull argument --- .../java/graphql/schema/GraphQLTypeResolvingVisitor.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/graphql/schema/GraphQLTypeResolvingVisitor.java b/src/main/java/graphql/schema/GraphQLTypeResolvingVisitor.java index b89c245edc..8e48961783 100644 --- a/src/main/java/graphql/schema/GraphQLTypeResolvingVisitor.java +++ b/src/main/java/graphql/schema/GraphQLTypeResolvingVisitor.java @@ -1,6 +1,5 @@ package graphql.schema; -import static graphql.Assert.assertNotNull; import graphql.Internal; import graphql.util.TraversalControl; import graphql.util.TraverserContext; @@ -8,6 +7,8 @@ import java.util.Map; import java.util.stream.Collectors; +import static graphql.Assert.assertNotNull; + @Internal public class GraphQLTypeResolvingVisitor extends GraphQLTypeVisitorStub { protected final Map typeMap; @@ -38,7 +39,7 @@ public TraversalControl visitGraphQLUnionType(GraphQLUnionType node, TraverserCo public TraversalControl visitGraphQLTypeReference(GraphQLTypeReference node, TraverserContext context) { final GraphQLType resolvedType = typeMap.get(node.getName()); - assertNotNull(resolvedType != null, "type %s not found in schema", node.getName()); + assertNotNull(resolvedType, "type %s not found in schema", node.getName()); context.getParentContext().thisNode().accept(context, new TypeRefResolvingVisitor(resolvedType)); return super.visitGraphQLTypeReference(node, context); }