From 3895c0fb3f227eb0e49c045d7a56610a8e96141c Mon Sep 17 00:00:00 2001 From: "Sachin D. Shinde" Date: Thu, 12 Mar 2020 11:18:44 -0700 Subject: [PATCH 01/15] Bump graphql-java to v14 in pom.xml --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 01cfc791..5c9be9dc 100644 --- a/pom.xml +++ b/pom.xml @@ -50,7 +50,7 @@ ${java.version} ${java.version} 2.7 - 13.0 + 14.0 5.10.0 1.8 17.0.0 From 7d277d000d9d5f83a3b96b7d695a7f28be49ca40 Mon Sep 17 00:00:00 2001 From: "Sachin D. Shinde" Date: Wed, 25 Mar 2020 16:00:21 -0700 Subject: [PATCH 02/15] Remove old FederationSdlPrinter --- .../graphqljava/FederationSdlPrinter.java | 898 ------------------ 1 file changed, 898 deletions(-) delete mode 100644 graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/FederationSdlPrinter.java diff --git a/graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/FederationSdlPrinter.java b/graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/FederationSdlPrinter.java deleted file mode 100644 index c65ec57a..00000000 --- a/graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/FederationSdlPrinter.java +++ /dev/null @@ -1,898 +0,0 @@ -package com.apollographql.federation.graphqljava; - -import graphql.Assert; -import graphql.language.AstPrinter; -import graphql.language.AstValueHelper; -import graphql.language.Comment; -import graphql.language.Description; -import graphql.language.Document; -import graphql.language.Node; -import graphql.schema.DefaultGraphqlTypeComparatorRegistry; -import graphql.schema.GraphQLArgument; -import graphql.schema.GraphQLDirective; -import graphql.schema.GraphQLEnumType; -import graphql.schema.GraphQLEnumValueDefinition; -import graphql.schema.GraphQLFieldDefinition; -import graphql.schema.GraphQLInputObjectField; -import graphql.schema.GraphQLInputObjectType; -import graphql.schema.GraphQLInputType; -import graphql.schema.GraphQLInterfaceType; -import graphql.schema.GraphQLObjectType; -import graphql.schema.GraphQLOutputType; -import graphql.schema.GraphQLScalarType; -import graphql.schema.GraphQLSchema; -import graphql.schema.GraphQLType; -import graphql.schema.GraphQLTypeUtil; -import graphql.schema.GraphQLUnionType; -import graphql.schema.GraphqlTypeComparatorEnvironment; -import graphql.schema.GraphqlTypeComparatorRegistry; -import graphql.schema.idl.ScalarInfo; -import graphql.schema.idl.SchemaParser; -import graphql.schema.idl.TypeDefinitionRegistry; -import graphql.schema.idl.UnExecutableSchemaGenerator; -import graphql.schema.visibility.GraphqlFieldVisibility; - -import java.io.PrintWriter; -import java.io.StringWriter; -import java.util.Arrays; -import java.util.Comparator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.function.Predicate; -import java.util.function.Supplier; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import static graphql.schema.visibility.DefaultGraphqlFieldVisibility.DEFAULT_FIELD_VISIBILITY; -import static java.util.stream.Collectors.joining; -import static java.util.stream.Collectors.toList; - -/** - * This can print an in memory GraphQL schema back to a logical schema definition - */ -public class FederationSdlPrinter { - - /** - * Options to use when printing a schema - */ - public static class Options { - - private final boolean includeIntrospectionTypes; - - private final boolean includeScalars; - - private final boolean includeExtendedScalars; - - private final boolean includeSchemaDefinition; - - private final boolean includeDirectives; - - private final Predicate includeDirectiveDefinition; - - private final Predicate includeTypeDefinition; - - private final GraphqlTypeComparatorRegistry comparatorRegistry; - - private Options(boolean includeIntrospectionTypes, - boolean includeScalars, - boolean includeExtendedScalars, - boolean includeSchemaDefinition, - boolean includeDirectives, - Predicate includeDirectiveDefinition, - Predicate includeTypeDefinition, - GraphqlTypeComparatorRegistry comparatorRegistry) { - this.includeIntrospectionTypes = includeIntrospectionTypes; - this.includeScalars = includeScalars; - this.includeExtendedScalars = includeExtendedScalars; - this.includeSchemaDefinition = includeSchemaDefinition; - this.includeDirectives = includeDirectives; - this.includeDirectiveDefinition = includeDirectiveDefinition; - this.includeTypeDefinition = includeTypeDefinition; - this.comparatorRegistry = comparatorRegistry; - } - - public boolean isIncludeIntrospectionTypes() { - return includeIntrospectionTypes; - } - - public boolean isIncludeScalars() { - return includeScalars; - } - - public boolean isIncludeExtendedScalars() { - return includeExtendedScalars; - } - - public boolean isIncludeSchemaDefinition() { - return includeSchemaDefinition; - } - - public boolean isIncludeDirectives() { - return includeDirectives; - } - - public static Options defaultOptions() { - return new Options(false, false, false, false, true, - directiveDefinition -> true, typeDefinition -> true, - DefaultGraphqlTypeComparatorRegistry.defaultComparators()); - } - - /** - * This will allow you to include introspection types that are contained in a schema - * - * @param flag whether to include them - * - * @return options - */ - public Options includeIntrospectionTypes(boolean flag) { - return new Options(flag, this.includeScalars, this.includeExtendedScalars, this.includeSchemaDefinition, this.includeDirectives, this.includeDirectiveDefinition, this.includeTypeDefinition, this.comparatorRegistry); - } - - /** - * This will allow you to include scalar types that are contained in a schema - * - * @param flag whether to include them - * - * @return options - */ - public Options includeScalarTypes(boolean flag) { - return new Options(this.includeIntrospectionTypes, flag, this.includeExtendedScalars, this.includeSchemaDefinition, this.includeDirectives, this.includeDirectiveDefinition, this.includeTypeDefinition, this.comparatorRegistry); - } - - /** - * This will allow you to include the graphql 'extended' scalar types that come with graphql-java such as - * GraphQLBigDecimal or GraphQLBigInteger - * - * @param flag whether to include them - * - * @return options - */ - public Options includeExtendedScalarTypes(boolean flag) { - return new Options(this.includeIntrospectionTypes, this.includeScalars, flag, this.includeSchemaDefinition, this.includeDirectives, this.includeDirectiveDefinition, this.includeTypeDefinition, this.comparatorRegistry); - } - - /** - * This will force the printing of the graphql schema definition even if the query, mutation, and/or subscription - * types use the default names. Some graphql parsers require this information even if the schema uses the - * default type names. The schema definition will always be printed if any of the query, mutation, or subscription - * types do not use the default names. - * - * @param flag whether to force include the schema definition - * - * @return options - */ - public Options includeSchemaDefintion(boolean flag) { - return new Options(this.includeIntrospectionTypes, this.includeScalars, this.includeExtendedScalars, flag, this.includeDirectives, this.includeDirectiveDefinition, this.includeTypeDefinition, this.comparatorRegistry); - } - - /** - * Allow to print directives. In some situations, auto-generated schemas contain a lot of directives that - * make the printout noisy and having this flag would allow cleaner printout. On by default. - * - * @param flag whether to print directives - * - * @return new instance of options - */ - public Options includeDirectives(boolean flag) { - return new Options(this.includeIntrospectionTypes, this.includeScalars, this.includeExtendedScalars, this.includeSchemaDefinition, flag, this.includeDirectiveDefinition, this.includeTypeDefinition, this.comparatorRegistry); - } - - /** - * Filter printing of directive definitions. In Apollo Federation, some directive - * definitions need to be hidden, and this predicate allows filtering out such definitions. - * Prints all definitions by default. Note that both this predicate and the flag in - * {@link #includeDirectives(boolean)} must be true for a definition to be printed. - * - * @param includeDirectiveDefinition returns true if the definition should be printed - * @return new instance of options - */ - public Options includeDirectiveDefinitions(Predicate includeDirectiveDefinition) { - return new Options(this.includeIntrospectionTypes, this.includeScalars, this.includeExtendedScalars, this.includeSchemaDefinition, this.includeDirectives, includeDirectiveDefinition, this.includeTypeDefinition, this.comparatorRegistry); - } - - /** - * Filter printing of type definitions. In Apollo Federation, some type definitions need to - * be hidden, and this predicate allows filtering out such definitions. Prints all - * definitions by default. - * - * @param includeTypeDefinition returns true if the definition should be printed - * @return new instance of options - */ - public Options includeTypeDefinitions(Predicate includeTypeDefinition) { - return new Options(this.includeIntrospectionTypes, this.includeScalars, this.includeExtendedScalars, this.includeSchemaDefinition, this.includeDirectives, this.includeDirectiveDefinition, includeTypeDefinition, this.comparatorRegistry); - } - - /** - * The comparator registry controls the printing order for registered {@code GraphQLType}s. - *

- * The default is to sort elements by name but you can put in your own code to decide on the field order - * - * @param comparatorRegistry The registry containing the {@code Comparator} and environment scoping rules. - * - * @return options - */ - public Options setComparators(GraphqlTypeComparatorRegistry comparatorRegistry) { - return new Options(this.includeIntrospectionTypes, this.includeScalars, this.includeExtendedScalars, this.includeSchemaDefinition, this.includeDirectives, this.includeDirectiveDefinition, this.includeTypeDefinition, - comparatorRegistry); - } - - public GraphqlTypeComparatorRegistry getComparatorRegistry() { - return comparatorRegistry; - } - } - - private final Map> printers = new LinkedHashMap<>(); - - private final Options options; - - public FederationSdlPrinter() { - this(Options.defaultOptions()); - } - - public FederationSdlPrinter(Options options) { - this.options = options; - printers.put(GraphQLSchema.class, schemaPrinter()); - printers.put(GraphQLObjectType.class, objectPrinter()); - printers.put(GraphQLEnumType.class, enumPrinter()); - printers.put(GraphQLScalarType.class, scalarPrinter()); - printers.put(GraphQLInterfaceType.class, interfacePrinter()); - printers.put(GraphQLUnionType.class, unionPrinter()); - printers.put(GraphQLInputObjectType.class, inputObjectPrinter()); - } - - /** - * This can print an in memory GraphQL IDL document back to a logical schema definition. - * If you want to turn a Introspection query result into a Document (and then into a printed - * schema) then use {@link graphql.introspection.IntrospectionResultToSchema#createSchemaDefinition(java.util.Map)} - * first to get the {@link graphql.language.Document} and then print that. - * - * @param schemaIDL the parsed schema IDL - * - * @return the logical schema definition - */ - public String print(Document schemaIDL) { - TypeDefinitionRegistry registry = new SchemaParser().buildRegistry(schemaIDL); - return print(UnExecutableSchemaGenerator.makeUnExecutableSchema(registry)); - } - - /** - * This can print an in memory GraphQL schema back to a logical schema definition - * - * @param schema the schema in play - * - * @return the logical schema definition - */ - public String print(GraphQLSchema schema) { - StringWriter sw = new StringWriter(); - PrintWriter out = new PrintWriter(sw); - - GraphqlFieldVisibility visibility = schema.getCodeRegistry().getFieldVisibility(); - - printer(schema.getClass()).print(out, schema, visibility); - - List typesAsList = schema.getAllTypesAsList() - .stream() - .sorted(Comparator.comparing(GraphQLType::getName)) - .filter(options.includeTypeDefinition) - .collect(toList()); - - printType(out, typesAsList, GraphQLInterfaceType.class, visibility); - printType(out, typesAsList, GraphQLUnionType.class, visibility); - printType(out, typesAsList, GraphQLObjectType.class, visibility); - printType(out, typesAsList, GraphQLEnumType.class, visibility); - printType(out, typesAsList, GraphQLScalarType.class, visibility); - printType(out, typesAsList, GraphQLInputObjectType.class, visibility); - - String result = sw.toString(); - if (result.endsWith("\n\n")) { - result = result.substring(0, result.length() - 1); - } - return result; - } - - private interface TypePrinter { - - void print(PrintWriter out, T type, GraphqlFieldVisibility visibility); - - } - - private boolean isIntrospectionType(GraphQLType type) { - return !options.isIncludeIntrospectionTypes() && type.getName().startsWith("__"); - } - - private TypePrinter scalarPrinter() { - return (out, type, visibility) -> { - if (!options.isIncludeScalars()) { - return; - } - boolean printScalar; - if (ScalarInfo.isStandardScalar(type)) { - printScalar = false; - //noinspection RedundantIfStatement - if (options.isIncludeExtendedScalars() && !ScalarInfo.isGraphqlSpecifiedScalar(type)) { - printScalar = true; - } - } else { - printScalar = true; - } - if (printScalar) { - printComments(out, type, ""); - out.format("scalar %s%s\n\n", type.getName(), directivesString(GraphQLScalarType.class, type.getDirectives())); - } - }; - } - - private TypePrinter enumPrinter() { - return (out, type, visibility) -> { - if (isIntrospectionType(type)) { - return; - } - - GraphqlTypeComparatorEnvironment environment = GraphqlTypeComparatorEnvironment.newEnvironment() - .parentType(GraphQLEnumType.class) - .elementType(GraphQLEnumValueDefinition.class) - .build(); - Comparator comparator = options.comparatorRegistry.getComparator(environment); - - printComments(out, type, ""); - out.format("enum %s%s", type.getName(), directivesString(GraphQLEnumType.class, type.getDirectives())); - List values = type.getValues() - .stream() - .sorted(comparator) - .collect(toList()); - if (values.size() > 0) { - out.format(" {\n"); - for (GraphQLEnumValueDefinition enumValueDefinition : values) { - printComments(out, enumValueDefinition, " "); - out.format(" %s%s\n", enumValueDefinition.getName(), directivesString(GraphQLEnumValueDefinition.class, enumValueDefinition.getDirectives())); - } - out.format("}"); - } - out.format("\n\n"); - }; - } - - private TypePrinter interfacePrinter() { - return (out, type, visibility) -> { - if (isIntrospectionType(type)) { - return; - } - - GraphqlTypeComparatorEnvironment environment = GraphqlTypeComparatorEnvironment.newEnvironment() - .parentType(GraphQLInterfaceType.class) - .elementType(GraphQLFieldDefinition.class) - .build(); - Comparator comparator = options.comparatorRegistry.getComparator(environment); - - printComments(out, type, ""); - out.format("interface %s%s", type.getName(), directivesString(GraphQLInterfaceType.class, type.getDirectives())); - List fieldDefinitions = visibility.getFieldDefinitions(type); - if (fieldDefinitions.size() > 0) { - out.format(" {\n"); - fieldDefinitions - .stream() - .sorted(comparator) - .forEach(fd -> { - printComments(out, fd, " "); - out.format(" %s%s: %s%s\n", - fd.getName(), argsString(GraphQLFieldDefinition.class, fd.getArguments()), typeString(fd.getType()), - directivesString(GraphQLFieldDefinition.class, fd.getDirectives())); - }); - out.format("}"); - } - out.format("\n\n"); - }; - } - - private TypePrinter unionPrinter() { - return (out, type, visibility) -> { - if (isIntrospectionType(type)) { - return; - } - - GraphqlTypeComparatorEnvironment environment = GraphqlTypeComparatorEnvironment.newEnvironment() - .parentType(GraphQLUnionType.class) - .elementType(GraphQLOutputType.class) - .build(); - Comparator comparator = options.comparatorRegistry.getComparator(environment); - - printComments(out, type, ""); - out.format("union %s%s = ", type.getName(), directivesString(GraphQLUnionType.class, type.getDirectives())); - List types = type.getTypes() - .stream() - .sorted(comparator) - .collect(toList()); - for (int i = 0; i < types.size(); i++) { - GraphQLOutputType objectType = types.get(i); - if (i > 0) { - out.format(" | "); - } - out.format("%s", objectType.getName()); - } - out.format("\n\n"); - }; - } - - private TypePrinter objectPrinter() { - return (out, type, visibility) -> { - if (isIntrospectionType(type)) { - return; - } - printComments(out, type, ""); - if (type.getInterfaces().isEmpty()) { - out.format("type %s%s", type.getName(), directivesString(GraphQLObjectType.class, type.getDirectives())); - } else { - - GraphqlTypeComparatorEnvironment environment = GraphqlTypeComparatorEnvironment.newEnvironment() - .parentType(GraphQLObjectType.class) - .elementType(GraphQLOutputType.class) - .build(); - Comparator implementsComparator = options.comparatorRegistry.getComparator(environment); - - Stream interfaceNames = type.getInterfaces() - .stream() - .sorted(implementsComparator) - .map(GraphQLType::getName); - out.format("type %s implements %s%s", - type.getName(), - interfaceNames.collect(joining(" & ")), - directivesString(GraphQLObjectType.class, type.getDirectives())); - } - - GraphqlTypeComparatorEnvironment environment = GraphqlTypeComparatorEnvironment.newEnvironment() - .parentType(GraphQLObjectType.class) - .elementType(GraphQLFieldDefinition.class) - .build(); - Comparator comparator = options.comparatorRegistry.getComparator(environment); - - List fieldDefinitions = visibility.getFieldDefinitions(type); - if (fieldDefinitions.size() > 0) { - out.format(" {\n"); - fieldDefinitions - .stream() - .sorted(comparator) - .forEach(fd -> { - printComments(out, fd, " "); - out.format(" %s%s: %s%s\n", - fd.getName(), argsString(GraphQLFieldDefinition.class, fd.getArguments()), typeString(fd.getType()), - directivesString(GraphQLFieldDefinition.class, fd.getDirectives())); - }); - out.format("}"); - } - out.format("\n\n"); - }; - } - - private TypePrinter inputObjectPrinter() { - return (out, type, visibility) -> { - if (isIntrospectionType(type)) { - return; - } - printComments(out, type, ""); - - GraphqlTypeComparatorEnvironment environment = GraphqlTypeComparatorEnvironment.newEnvironment() - .parentType(GraphQLInputObjectType.class) - .elementType(GraphQLInputObjectField.class) - .build(); - Comparator comparator = options.comparatorRegistry.getComparator(environment); - - out.format("input %s%s", type.getName(), directivesString(GraphQLInputObjectType.class, type.getDirectives())); - List inputObjectFields = visibility.getFieldDefinitions(type); - if (inputObjectFields.size() > 0) { - out.format(" {\n"); - inputObjectFields - .stream() - .sorted(comparator) - .forEach(fd -> { - printComments(out, fd, " "); - out.format(" %s: %s", - fd.getName(), typeString(fd.getType())); - Object defaultValue = fd.getDefaultValue(); - if (defaultValue != null) { - String astValue = printAst(defaultValue, fd.getType()); - out.format(" = %s", astValue); - } - out.format(directivesString(GraphQLInputObjectField.class, fd.getDirectives())); - out.format("\n"); - }); - out.format("}"); - } - out.format("\n\n"); - }; - } - - private static String printAst(Object value, GraphQLInputType type) { - return AstPrinter.printAst(AstValueHelper.astFromValue(value, type)); - } - - private TypePrinter schemaPrinter() { - return (out, schema, visibility) -> { - GraphQLObjectType queryType = schema.getQueryType(); - GraphQLObjectType mutationType = schema.getMutationType(); - GraphQLObjectType subscriptionType = schema.getSubscriptionType(); - - // when serializing a GraphQL schema using the type system language, a - // schema definition should be omitted if only uses the default root type names. - boolean needsSchemaPrinted = options.includeSchemaDefinition; - - if (!needsSchemaPrinted) { - if (queryType != null && !queryType.getName().equals("Query")) { - needsSchemaPrinted = true; - } - if (mutationType != null && !mutationType.getName().equals("Mutation")) { - needsSchemaPrinted = true; - } - if (subscriptionType != null && !subscriptionType.getName().equals("Subscription")) { - needsSchemaPrinted = true; - } - } - - if (needsSchemaPrinted) { - out.format("schema {\n"); - if (queryType != null) { - out.format(" query: %s\n", queryType.getName()); - } - if (mutationType != null) { - out.format(" mutation: %s\n", mutationType.getName()); - } - if (subscriptionType != null) { - out.format(" subscription: %s\n", subscriptionType.getName()); - } - out.format("}\n\n"); - } - - if (options.includeDirectives) { - out.format("%s", directiveDefinitions(getDirectives(schema))); - } - }; - } - - private List getDirectives(GraphQLSchema schema) { - - // we don't print the standard directives that always ship with graphql-java - List standardDirectives = Arrays.asList( - "skip", - "include", - "defer", - "deprecated"); - - Predicate standard = directive -> standardDirectives.contains(directive.getName()); - return schema.getDirectives().stream() - .filter(standard.negate()) - .filter(options.includeDirectiveDefinition) - .collect(Collectors.toList()); - } - - String typeString(GraphQLType rawType) { - return GraphQLTypeUtil.simplePrint(rawType); - } - - String argsString(List arguments) { - return argsString(null, arguments); - } - - String argsString(Class parent, List arguments) { - boolean hasDescriptions = arguments.stream().anyMatch(arg -> !isNullOrEmpty(arg.getDescription())); - String halfPrefix = hasDescriptions ? " " : ""; - String prefix = hasDescriptions ? " " : ""; - int count = 0; - StringBuilder sb = new StringBuilder(); - - GraphqlTypeComparatorEnvironment environment = GraphqlTypeComparatorEnvironment.newEnvironment() - .parentType(parent) - .elementType(GraphQLArgument.class) - .build(); - Comparator comparator = options.comparatorRegistry.getComparator(environment); - - arguments = arguments - .stream() - .sorted(comparator) - .collect(toList()); - for (GraphQLArgument argument : arguments) { - if (count == 0) { - sb.append("("); - } else { - sb.append(", "); - } - if (hasDescriptions) { - sb.append("\n"); - } - String description = argument.getDescription(); - if (!isNullOrEmpty(description)) { - String[] descriptionSplitByNewlines = description.split("\n"); - Stream stream = Arrays.stream(descriptionSplitByNewlines); - if (descriptionSplitByNewlines.length > 1) { - String multiLineComment = "\"\"\""; - stream = Stream.concat(Stream.of(multiLineComment), stream); - stream = Stream.concat(stream, Stream.of(multiLineComment)); - stream.map(s -> prefix + s + "\n").forEach(sb::append); - } else { - stream.map(s -> prefix + "#" + s + "\n").forEach(sb::append); - } - } - sb.append(prefix).append(argument.getName()).append(": ").append(typeString(argument.getType())); - Object defaultValue = argument.getDefaultValue(); - if (defaultValue != null) { - sb.append(" = "); - sb.append(printAst(defaultValue, argument.getType())); - } - - argument.getDirectives().stream() - .map(this::directiveString) - .filter(it -> !it.isEmpty()) - .forEach(directiveString -> sb.append(" ").append(directiveString)); - - count++; - } - if (count > 0) { - if (hasDescriptions) { - sb.append("\n"); - } - sb.append(halfPrefix).append(")"); - } - return sb.toString(); - } - - String directivesString(Class parent, List directives) { - if (!options.includeDirectives) { - return ""; - } - StringBuilder sb = new StringBuilder(); - if (!directives.isEmpty()) { - sb.append(" "); - } - - GraphqlTypeComparatorEnvironment environment = GraphqlTypeComparatorEnvironment.newEnvironment() - .parentType(parent) - .elementType(GraphQLDirective.class) - .build(); - Comparator comparator = options.comparatorRegistry.getComparator(environment); - - directives = directives - .stream() - .sorted(comparator) - .collect(toList()); - for (int i = 0; i < directives.size(); i++) { - GraphQLDirective directive = directives.get(i); - sb.append(directiveString(directive)); - if (i < directives.size() - 1) { - sb.append(" "); - } - } - return sb.toString(); - } - - private String directiveString(GraphQLDirective directive) { - if (!options.includeDirectives) { - return ""; - } - - StringBuilder sb = new StringBuilder(); - sb.append("@").append(directive.getName()); - - GraphqlTypeComparatorEnvironment environment = GraphqlTypeComparatorEnvironment.newEnvironment() - .parentType(GraphQLDirective.class) - .elementType(GraphQLArgument.class) - .build(); - Comparator comparator = options.comparatorRegistry.getComparator(environment); - - List args = directive.getArguments(); - args = args - .stream() - .sorted(comparator) - .collect(toList()); - if (!args.isEmpty()) { - sb.append("("); - for (int i = 0; i < args.size(); i++) { - GraphQLArgument arg = args.get(i); - sb.append(arg.getName()); - if (arg.getValue() != null) { - sb.append(" : "); - sb.append(printAst(arg.getValue(), arg.getType())); - } else if (arg.getDefaultValue() != null) { - sb.append(" : "); - sb.append(printAst(arg.getDefaultValue(), arg.getType())); - } - if (i < args.size() - 1) { - sb.append(", "); - } - } - sb.append(")"); - } - return sb.toString(); - } - - private String directiveDefinitions(List directives) { - StringBuilder sb = new StringBuilder(); - for (GraphQLDirective directive : directives) { - sb.append(directiveDefinition(directive)); - sb.append("\n\n"); - } - return sb.toString(); - } - - private String directiveDefinition(GraphQLDirective directive) { - StringBuilder sb = new StringBuilder(); - - StringWriter sw = new StringWriter(); - printComments(new PrintWriter(sw), directive, ""); - - sb.append(sw.toString()); - - sb.append("directive @").append(directive.getName()); - - GraphqlTypeComparatorEnvironment environment = GraphqlTypeComparatorEnvironment.newEnvironment() - .parentType(GraphQLDirective.class) - .elementType(GraphQLArgument.class) - .build(); - Comparator comparator = options.comparatorRegistry.getComparator(environment); - - List args = directive.getArguments(); - args = args - .stream() - .sorted(comparator) - .collect(toList()); - - sb.append(argsString(GraphQLDirective.class, args)); - - sb.append(" on "); - - String locations = directive.validLocations().stream().map(Enum::name).collect(Collectors.joining(" | ")); - sb.append(locations); - - return sb.toString(); - } - - - @SuppressWarnings("unchecked") - private TypePrinter printer(Class clazz) { - TypePrinter typePrinter = printers.computeIfAbsent(clazz, k -> { - Class superClazz = clazz.getSuperclass(); - TypePrinter result; - if (superClazz != Object.class) { - result = printer(superClazz); - } else { - result = (out, type, visibility) -> out.println("Type not implemented : " + type); - } - return result; - }); - return (TypePrinter) typePrinter; - } - - public String print(GraphQLType type) { - StringWriter sw = new StringWriter(); - PrintWriter out = new PrintWriter(sw); - - printType(out, type, DEFAULT_FIELD_VISIBILITY); - - return sw.toString(); - } - - @SuppressWarnings("unchecked") - private void printType(PrintWriter out, List typesAsList, Class typeClazz, GraphqlFieldVisibility visibility) { - typesAsList.stream() - .filter(type -> typeClazz.isAssignableFrom(type.getClass())) - .forEach(type -> printType(out, type, visibility)); - } - - private void printType(PrintWriter out, GraphQLType type, GraphqlFieldVisibility visibility) { - TypePrinter printer = printer(type.getClass()); - printer.print(out, type, visibility); - } - - private void printComments(PrintWriter out, Object graphQLType, String prefix) { - - AstDescriptionAndComments descriptionAndComments = getDescriptionAndComments(graphQLType); - if (descriptionAndComments == null) { - return; - } - - Description astDescription = descriptionAndComments.descriptionAst; - if (astDescription != null) { - String quoteStr = "\""; - if (astDescription.isMultiLine()) { - quoteStr = "\"\"\""; - } - out.write(prefix); - out.write(quoteStr); - out.write(astDescription.getContent()); - out.write(quoteStr); - out.write("\n"); - - return; - } - - if (descriptionAndComments.comments != null) { - descriptionAndComments.comments.forEach(cmt -> { - String commentText = cmt.getContent() == null ? "" : cmt.getContent(); - // it possible that in fact they manage to sneak in a multi line comment - // into what should be a single line comment. So cater for that. - List lines = Arrays.asList(commentText.split("\n")); - lines.forEach(t -> { - out.write(prefix); - out.write("#"); - out.write(commentText); - out.write("\n"); - }); - }); - } else { - String runtimeDescription = descriptionAndComments.runtimeDescription; - if (!isNullOrEmpty(runtimeDescription)) { - Stream stream = Arrays.stream(runtimeDescription.split("\n")); - stream.map(s -> prefix + "#" + s + "\n").forEach(out::write); - } - } - } - - static class AstDescriptionAndComments { - - String runtimeDescription; - - Description descriptionAst; - - List comments; - - public AstDescriptionAndComments(String runtimeDescription, Description descriptionAst, List comments) { - this.runtimeDescription = runtimeDescription; - this.descriptionAst = descriptionAst; - this.comments = comments; - } - } - - private AstDescriptionAndComments getDescriptionAndComments(Object descriptionHolder) { - if (descriptionHolder instanceof GraphQLObjectType) { - GraphQLObjectType type = (GraphQLObjectType) descriptionHolder; - return descriptionAndComments(type::getDescription, type::getDefinition, () -> type.getDefinition().getDescription()); - } else if (descriptionHolder instanceof GraphQLEnumType) { - GraphQLEnumType type = (GraphQLEnumType) descriptionHolder; - return descriptionAndComments(type::getDescription, type::getDefinition, () -> type.getDefinition().getDescription()); - } else if (descriptionHolder instanceof GraphQLFieldDefinition) { - GraphQLFieldDefinition type = (GraphQLFieldDefinition) descriptionHolder; - return descriptionAndComments(type::getDescription, type::getDefinition, () -> type.getDefinition().getDescription()); - } else if (descriptionHolder instanceof GraphQLEnumValueDefinition) { - GraphQLEnumValueDefinition type = (GraphQLEnumValueDefinition) descriptionHolder; - return descriptionAndComments(type::getDescription, () -> null, () -> null); - } else if (descriptionHolder instanceof GraphQLUnionType) { - GraphQLUnionType type = (GraphQLUnionType) descriptionHolder; - return descriptionAndComments(type::getDescription, type::getDefinition, () -> type.getDefinition().getDescription()); - } else if (descriptionHolder instanceof GraphQLInputObjectType) { - GraphQLInputObjectType type = (GraphQLInputObjectType) descriptionHolder; - return descriptionAndComments(type::getDescription, type::getDefinition, () -> type.getDefinition().getDescription()); - } else if (descriptionHolder instanceof GraphQLInputObjectField) { - GraphQLInputObjectField type = (GraphQLInputObjectField) descriptionHolder; - return descriptionAndComments(type::getDescription, type::getDefinition, () -> type.getDefinition().getDescription()); - } else if (descriptionHolder instanceof GraphQLInterfaceType) { - GraphQLInterfaceType type = (GraphQLInterfaceType) descriptionHolder; - return descriptionAndComments(type::getDescription, type::getDefinition, () -> type.getDefinition().getDescription()); - } else if (descriptionHolder instanceof GraphQLScalarType) { - GraphQLScalarType type = (GraphQLScalarType) descriptionHolder; - return descriptionAndComments(type::getDescription, type::getDefinition, () -> type.getDefinition().getDescription()); - } else if (descriptionHolder instanceof GraphQLArgument) { - GraphQLArgument type = (GraphQLArgument) descriptionHolder; - return descriptionAndComments(type::getDescription, type::getDefinition, () -> type.getDefinition().getDescription()); - } else if (descriptionHolder instanceof GraphQLDirective) { - GraphQLDirective type = (GraphQLDirective) descriptionHolder; - return descriptionAndComments(type::getDescription, () -> null, () -> null); - } else { - return Assert.assertShouldNeverHappen(); - } - } - - AstDescriptionAndComments descriptionAndComments(Supplier runtimeDescriptionSupplier, Supplier nodeSupplier, Supplier descriptionSupplier) { - String runtimeDesc = runtimeDescriptionSupplier.get(); - Node node = nodeSupplier.get(); - Description description = null; - List comments = null; - if (node != null) { - comments = node.getComments(); - description = descriptionSupplier.get(); - } - return new AstDescriptionAndComments(runtimeDesc, description, comments); - - } - - private static boolean isNullOrEmpty(String s) { - return s == null || s.isEmpty(); - } -} From 4ef650d6d8fa56c05c34092f1b8ef7c599608a67 Mon Sep 17 00:00:00 2001 From: "Sachin D. Shinde" Date: Wed, 25 Mar 2020 16:18:12 -0700 Subject: [PATCH 03/15] Copy SchemaPrinter v14 and change name to FederationSdlPrinter --- .../graphqljava/FederationSdlPrinter.java | 961 ++++++++++++++++++ 1 file changed, 961 insertions(+) create mode 100644 graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/FederationSdlPrinter.java diff --git a/graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/FederationSdlPrinter.java b/graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/FederationSdlPrinter.java new file mode 100644 index 00000000..9b350113 --- /dev/null +++ b/graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/FederationSdlPrinter.java @@ -0,0 +1,961 @@ +package com.apollographql.federation.graphqljava; + +import graphql.Assert; +import graphql.language.AstPrinter; +import graphql.language.AstValueHelper; +import graphql.language.Description; +import graphql.language.Document; +import graphql.language.EnumTypeDefinition; +import graphql.language.EnumValueDefinition; +import graphql.language.FieldDefinition; +import graphql.language.InputObjectTypeDefinition; +import graphql.language.InputValueDefinition; +import graphql.language.InterfaceTypeDefinition; +import graphql.language.ObjectTypeDefinition; +import graphql.language.ScalarTypeDefinition; +import graphql.language.TypeDefinition; +import graphql.language.UnionTypeDefinition; +import graphql.schema.DefaultGraphqlTypeComparatorRegistry; +import graphql.schema.GraphQLArgument; +import graphql.schema.GraphQLDirective; +import graphql.schema.GraphQLEnumType; +import graphql.schema.GraphQLEnumValueDefinition; +import graphql.schema.GraphQLFieldDefinition; +import graphql.schema.GraphQLInputObjectField; +import graphql.schema.GraphQLInputObjectType; +import graphql.schema.GraphQLInputType; +import graphql.schema.GraphQLInterfaceType; +import graphql.schema.GraphQLNamedOutputType; +import graphql.schema.GraphQLNamedType; +import graphql.schema.GraphQLObjectType; +import graphql.schema.GraphQLOutputType; +import graphql.schema.GraphQLScalarType; +import graphql.schema.GraphQLSchema; +import graphql.schema.GraphQLSchemaElement; +import graphql.schema.GraphQLType; +import graphql.schema.GraphQLTypeUtil; +import graphql.schema.GraphQLUnionType; +import graphql.schema.GraphqlTypeComparatorEnvironment; +import graphql.schema.GraphqlTypeComparatorRegistry; +import graphql.schema.idl.ScalarInfo; +import graphql.schema.idl.SchemaParser; +import graphql.schema.idl.TypeDefinitionRegistry; +import graphql.schema.idl.UnExecutableSchemaGenerator; +import graphql.schema.visibility.GraphqlFieldVisibility; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static graphql.Directives.DeprecatedDirective; +import static graphql.introspection.Introspection.DirectiveLocation.ENUM_VALUE; +import static graphql.introspection.Introspection.DirectiveLocation.FIELD_DEFINITION; +import static graphql.schema.visibility.DefaultGraphqlFieldVisibility.DEFAULT_FIELD_VISIBILITY; +import static java.util.Optional.ofNullable; +import static java.util.stream.Collectors.joining; +import static java.util.stream.Collectors.toList; + +/** + * This can print an in memory GraphQL schema back to a logical schema definition + */ +public class FederationSdlPrinter { + // + // we use this so that we get the simple "@deprecated" as text and not a full exploded + // text with arguments (but only when we auto add this) + // + private static final GraphQLDirective DeprecatedDirective4Printing = GraphQLDirective.newDirective() + .name("deprecated") + .validLocations(FIELD_DEFINITION, ENUM_VALUE) + .build(); + + /** + * Options to use when printing a schema + */ + public static class Options { + + private final boolean includeIntrospectionTypes; + + private final boolean includeScalars; + + private final boolean useAstDefinitions; + + private final boolean includeExtendedScalars; + + private final boolean includeSchemaDefinition; + + private final boolean descriptionsAsHashComments; + + private final Predicate includeDirective; + + private final GraphqlTypeComparatorRegistry comparatorRegistry; + + private Options(boolean includeIntrospectionTypes, + boolean includeScalars, + boolean includeExtendedScalars, + boolean includeSchemaDefinition, + boolean useAstDefinitions, + boolean descriptionsAsHashComments, + Predicate includeDirective, + GraphqlTypeComparatorRegistry comparatorRegistry) { + this.includeIntrospectionTypes = includeIntrospectionTypes; + this.includeScalars = includeScalars; + this.includeExtendedScalars = includeExtendedScalars; + this.includeSchemaDefinition = includeSchemaDefinition; + this.includeDirective = includeDirective; + this.useAstDefinitions = useAstDefinitions; + this.descriptionsAsHashComments = descriptionsAsHashComments; + this.comparatorRegistry = comparatorRegistry; + } + + public boolean isIncludeIntrospectionTypes() { + return includeIntrospectionTypes; + } + + public boolean isIncludeScalars() { + return includeScalars; + } + + public boolean isIncludeExtendedScalars() { + return includeExtendedScalars; + } + + public boolean isIncludeSchemaDefinition() { + return includeSchemaDefinition; + } + + public Predicate getIncludeDirective() { + return includeDirective; + } + + public boolean isDescriptionsAsHashComments() { + return descriptionsAsHashComments; + } + + public GraphqlTypeComparatorRegistry getComparatorRegistry() { + return comparatorRegistry; + } + + public boolean isUseAstDefinitions() { + return useAstDefinitions; + } + + public static Options defaultOptions() { + return new Options(false, false, false, + false, false, false, + directive -> true, DefaultGraphqlTypeComparatorRegistry.defaultComparators()); + } + + /** + * This will allow you to include introspection types that are contained in a schema + * + * @param flag whether to include them + * @return options + */ + public Options includeIntrospectionTypes(boolean flag) { + return new Options(flag, this.includeScalars, this.includeExtendedScalars, this.includeSchemaDefinition, this.useAstDefinitions, this.descriptionsAsHashComments, this.includeDirective, this.comparatorRegistry); + } + + /** + * This will allow you to include scalar types that are contained in a schema + * + * @param flag whether to include them + * @return options + */ + public Options includeScalarTypes(boolean flag) { + return new Options(this.includeIntrospectionTypes, flag, this.includeExtendedScalars, this.includeSchemaDefinition, this.useAstDefinitions, this.descriptionsAsHashComments, this.includeDirective, this.comparatorRegistry); + } + + /** + * This will allow you to include the graphql 'extended' scalar types that come with graphql-java such as + * GraphQLBigDecimal or GraphQLBigInteger + * + * @param flag whether to include them + * @return options + */ + public Options includeExtendedScalarTypes(boolean flag) { + return new Options(this.includeIntrospectionTypes, this.includeScalars, flag, this.includeSchemaDefinition, this.useAstDefinitions, this.descriptionsAsHashComments, this.includeDirective, this.comparatorRegistry); + } + + /** + * This will force the printing of the graphql schema definition even if the query, mutation, and/or subscription + * types use the default names. Some graphql parsers require this information even if the schema uses the + * default type names. The schema definition will always be printed if any of the query, mutation, or subscription + * types do not use the default names. + * + * @param flag whether to force include the schema definition + * @return options + */ + public Options includeSchemaDefinition(boolean flag) { + return new Options(this.includeIntrospectionTypes, this.includeScalars, this.includeExtendedScalars, flag, this.useAstDefinitions, this.descriptionsAsHashComments, this.includeDirective, this.comparatorRegistry); + } + + /** + * Allow to print directives. In some situations, auto-generated schemas contain a lot of directives that + * make the printout noisy and having this flag would allow cleaner printout. On by default. + * + * @param flag whether to print directives + * @return new instance of options + */ + public Options includeDirectives(boolean flag) { + return new Options(this.includeIntrospectionTypes, this.includeScalars, this.includeExtendedScalars, this.includeSchemaDefinition, this.useAstDefinitions, this.descriptionsAsHashComments, directive -> flag, this.comparatorRegistry); + } + + public Options includeDirectives(Predicate includeDirective) { + return new Options(this.includeIntrospectionTypes, this.includeScalars, this.includeExtendedScalars, this.includeSchemaDefinition, this.useAstDefinitions, this.descriptionsAsHashComments, includeDirective, this.comparatorRegistry); + } + + /** + * This flag controls whether schema printer will use the {@link graphql.schema.GraphQLType}'s original Ast {@link graphql.language.TypeDefinition}s when printing the type. This + * allows access to any `extend type` declarations that might have been originally made. + * + * @param flag whether to print via AST type definitions + * @return new instance of options + */ + public Options useAstDefinitions(boolean flag) { + return new Options(this.includeIntrospectionTypes, this.includeScalars, this.includeExtendedScalars, this.includeSchemaDefinition, flag, this.descriptionsAsHashComments, this.includeDirective, this.comparatorRegistry); + } + + /** + * Descriptions are defined as preceding string literals, however an older legacy + * versions of SDL supported preceding '#' comments as + * descriptions. Set this to true to enable this deprecated behavior. + * This option is provided to ease adoption and may be removed in future versions. + * + * @param flag whether to print description as # comments + * @return new instance of options + */ + public Options descriptionsAsHashComments(boolean flag) { + return new Options(this.includeIntrospectionTypes, this.includeScalars, this.includeExtendedScalars, this.includeSchemaDefinition, this.useAstDefinitions, flag, this.includeDirective, this.comparatorRegistry); + } + + /** + * The comparator registry controls the printing order for registered {@code GraphQLType}s. + *

+ * The default is to sort elements by name but you can put in your own code to decide on the field order + * + * @param comparatorRegistry The registry containing the {@code Comparator} and environment scoping rules. + * @return options + */ + public Options setComparators(GraphqlTypeComparatorRegistry comparatorRegistry) { + return new Options(this.includeIntrospectionTypes, this.includeScalars, this.includeExtendedScalars, this.includeSchemaDefinition, this.useAstDefinitions, this.descriptionsAsHashComments, this.includeDirective, comparatorRegistry); + } + } + + private final Map> printers = new LinkedHashMap<>(); + + private final Options options; + + public FederationSdlPrinter() { + this(Options.defaultOptions()); + } + + public FederationSdlPrinter(Options options) { + this.options = options; + printers.put(GraphQLSchema.class, schemaPrinter()); + printers.put(GraphQLObjectType.class, objectPrinter()); + printers.put(GraphQLEnumType.class, enumPrinter()); + printers.put(GraphQLScalarType.class, scalarPrinter()); + printers.put(GraphQLInterfaceType.class, interfacePrinter()); + printers.put(GraphQLUnionType.class, unionPrinter()); + printers.put(GraphQLInputObjectType.class, inputObjectPrinter()); + } + + /** + * This can print an in memory GraphQL IDL document back to a logical schema definition. + * If you want to turn a Introspection query result into a Document (and then into a printed + * schema) then use {@link graphql.introspection.IntrospectionResultToSchema#createSchemaDefinition(java.util.Map)} + * first to get the {@link graphql.language.Document} and then print that. + * + * @param schemaIDL the parsed schema IDL + * @return the logical schema definition + */ + public String print(Document schemaIDL) { + TypeDefinitionRegistry registry = new SchemaParser().buildRegistry(schemaIDL); + return print(UnExecutableSchemaGenerator.makeUnExecutableSchema(registry)); + } + + /** + * This can print an in memory GraphQL schema back to a logical schema definition + * + * @param schema the schema in play + * @return the logical schema definition + */ + public String print(GraphQLSchema schema) { + StringWriter sw = new StringWriter(); + PrintWriter out = new PrintWriter(sw); + + GraphqlFieldVisibility visibility = schema.getCodeRegistry().getFieldVisibility(); + + printer(schema.getClass()).print(out, schema, visibility); + + List typesAsList = schema.getAllTypesAsList() + .stream() + .sorted(Comparator.comparing(GraphQLNamedType::getName)) + .collect(toList()); + + printType(out, typesAsList, GraphQLInterfaceType.class, visibility); + printType(out, typesAsList, GraphQLUnionType.class, visibility); + printType(out, typesAsList, GraphQLObjectType.class, visibility); + printType(out, typesAsList, GraphQLEnumType.class, visibility); + printType(out, typesAsList, GraphQLScalarType.class, visibility); + printType(out, typesAsList, GraphQLInputObjectType.class, visibility); + + String result = sw.toString(); + if (result.endsWith("\n\n")) { + result = result.substring(0, result.length() - 1); + } + return result; + } + + private interface TypePrinter { + + void print(PrintWriter out, T type, GraphqlFieldVisibility visibility); + + } + + private boolean isIntrospectionType(GraphQLNamedType type) { + return !options.isIncludeIntrospectionTypes() && type.getName().startsWith("__"); + } + + private TypePrinter scalarPrinter() { + return (out, type, visibility) -> { + if (!options.isIncludeScalars()) { + return; + } + boolean printScalar; + if (ScalarInfo.isStandardScalar(type)) { + printScalar = false; + //noinspection RedundantIfStatement + if (options.isIncludeExtendedScalars() && !ScalarInfo.isGraphqlSpecifiedScalar(type)) { + printScalar = true; + } + } else { + printScalar = true; + } + if (printScalar) { + if (shouldPrintAsAst(type.getDefinition())) { + printAsAst(out, type.getDefinition(), type.getExtensionDefinitions()); + } else { + printComments(out, type, ""); + out.format("scalar %s%s\n\n", type.getName(), directivesString(GraphQLScalarType.class, type.getDirectives())); + } + } + }; + } + + + private TypePrinter enumPrinter() { + return (out, type, visibility) -> { + if (isIntrospectionType(type)) { + return; + } + + GraphqlTypeComparatorEnvironment environment = GraphqlTypeComparatorEnvironment.newEnvironment() + .parentType(GraphQLEnumType.class) + .elementType(GraphQLEnumValueDefinition.class) + .build(); + Comparator comparator = options.comparatorRegistry.getComparator(environment); + + if (shouldPrintAsAst(type.getDefinition())) { + printAsAst(out, type.getDefinition(), type.getExtensionDefinitions()); + } else { + printComments(out, type, ""); + out.format("enum %s%s {\n", type.getName(), directivesString(GraphQLEnumType.class, type.getDirectives())); + List values = type.getValues() + .stream() + .sorted(comparator) + .collect(toList()); + for (GraphQLEnumValueDefinition enumValueDefinition : values) { + printComments(out, enumValueDefinition, " "); + List enumValueDirectives = enumValueDefinition.getDirectives(); + if (enumValueDefinition.isDeprecated()) { + enumValueDirectives = addDeprecatedDirectiveIfNeeded(enumValueDirectives); + } + out.format(" %s%s\n", enumValueDefinition.getName(), directivesString(GraphQLEnumValueDefinition.class, enumValueDirectives)); + } + out.format("}\n\n"); + } + }; + } + + private void printFieldDefinitions(PrintWriter out, Comparator comparator, List fieldDefinitions) { + fieldDefinitions + .stream() + .sorted(comparator) + .forEach(fd -> { + printComments(out, fd, " "); + List fieldDirectives = fd.getDirectives(); + if (fd.isDeprecated()) { + fieldDirectives = addDeprecatedDirectiveIfNeeded(fieldDirectives); + } + + out.format(" %s%s: %s%s\n", + fd.getName(), argsString(GraphQLFieldDefinition.class, fd.getArguments()), typeString(fd.getType()), + directivesString(GraphQLFieldDefinition.class, fieldDirectives)); + }); + } + + private TypePrinter interfacePrinter() { + return (out, type, visibility) -> { + if (isIntrospectionType(type)) { + return; + } + + GraphqlTypeComparatorEnvironment environment = GraphqlTypeComparatorEnvironment.newEnvironment() + .parentType(GraphQLInterfaceType.class) + .elementType(GraphQLFieldDefinition.class) + .build(); + Comparator comparator = options.comparatorRegistry.getComparator(environment); + + if (shouldPrintAsAst(type.getDefinition())) { + printAsAst(out, type.getDefinition(), type.getExtensionDefinitions()); + } else { + printComments(out, type, ""); + out.format("interface %s%s {\n", type.getName(), directivesString(GraphQLInterfaceType.class, type.getDirectives())); + printFieldDefinitions(out, comparator, visibility.getFieldDefinitions(type)); + out.format("}\n\n"); + } + }; + } + + private TypePrinter unionPrinter() { + return (out, type, visibility) -> { + if (isIntrospectionType(type)) { + return; + } + + GraphqlTypeComparatorEnvironment environment = GraphqlTypeComparatorEnvironment.newEnvironment() + .parentType(GraphQLUnionType.class) + .elementType(GraphQLOutputType.class) + .build(); + Comparator comparator = options.comparatorRegistry.getComparator(environment); + + if (shouldPrintAsAst(type.getDefinition())) { + printAsAst(out, type.getDefinition(), type.getExtensionDefinitions()); + } else { + printComments(out, type, ""); + out.format("union %s%s = ", type.getName(), directivesString(GraphQLUnionType.class, type.getDirectives())); + List types = type.getTypes() + .stream() + .sorted(comparator) + .collect(toList()); + for (int i = 0; i < types.size(); i++) { + GraphQLNamedOutputType objectType = types.get(i); + if (i > 0) { + out.format(" | "); + } + out.format("%s", objectType.getName()); + } + out.format("\n\n"); + } + }; + } + + private TypePrinter objectPrinter() { + return (out, type, visibility) -> { + if (isIntrospectionType(type)) { + return; + } + if (shouldPrintAsAst(type.getDefinition())) { + printAsAst(out, type.getDefinition(), type.getExtensionDefinitions()); + } else { + printComments(out, type, ""); + if (type.getInterfaces().isEmpty()) { + out.format("type %s%s {\n", type.getName(), directivesString(GraphQLObjectType.class, type.getDirectives())); + } else { + + GraphqlTypeComparatorEnvironment environment = GraphqlTypeComparatorEnvironment.newEnvironment() + .parentType(GraphQLObjectType.class) + .elementType(GraphQLOutputType.class) + .build(); + Comparator implementsComparator = options.comparatorRegistry.getComparator(environment); + + Stream interfaceNames = type.getInterfaces() + .stream() + .sorted(implementsComparator) + .map(GraphQLNamedType::getName); + out.format("type %s implements %s%s {\n", + type.getName(), + interfaceNames.collect(joining(" & ")), + directivesString(GraphQLObjectType.class, type.getDirectives())); + } + + GraphqlTypeComparatorEnvironment environment = GraphqlTypeComparatorEnvironment.newEnvironment() + .parentType(GraphQLObjectType.class) + .elementType(GraphQLFieldDefinition.class) + .build(); + Comparator comparator = options.comparatorRegistry.getComparator(environment); + + printFieldDefinitions(out, comparator, visibility.getFieldDefinitions(type)); + out.format("}\n\n"); + } + }; + } + + private TypePrinter inputObjectPrinter() { + return (out, type, visibility) -> { + if (isIntrospectionType(type)) { + return; + } + if (shouldPrintAsAst(type.getDefinition())) { + printAsAst(out, type.getDefinition(), type.getExtensionDefinitions()); + } else { + printComments(out, type, ""); + GraphqlTypeComparatorEnvironment environment = GraphqlTypeComparatorEnvironment.newEnvironment() + .parentType(GraphQLInputObjectType.class) + .elementType(GraphQLInputObjectField.class) + .build(); + Comparator comparator = options.comparatorRegistry.getComparator(environment); + + out.format("input %s%s {\n", type.getName(), directivesString(GraphQLInputObjectType.class, type.getDirectives())); + visibility.getFieldDefinitions(type) + .stream() + .sorted(comparator) + .forEach(fd -> { + printComments(out, fd, " "); + out.format(" %s: %s", + fd.getName(), typeString(fd.getType())); + Object defaultValue = fd.getDefaultValue(); + if (defaultValue != null) { + String astValue = printAst(defaultValue, fd.getType()); + out.format(" = %s", astValue); + } + out.format(directivesString(GraphQLInputObjectField.class, fd.getDirectives())); + out.format("\n"); + }); + out.format("}\n\n"); + } + }; + } + + /** + * This will return true if the options say to use the AST and we have an AST element + * + * @param definition the AST type definition + * @return true if we should print using AST nodes + */ + private boolean shouldPrintAsAst(TypeDefinition definition) { + return options.isUseAstDefinitions() && definition != null; + } + + /** + * This will print out a runtime graphql schema element using its contained AST type definition. This + * must be guarded by a called to {@link #shouldPrintAsAst(TypeDefinition)} + * + * @param out the output writer + * @param definition the AST type definition + * @param extensions a list of type definition extensions + */ + private void printAsAst(PrintWriter out, TypeDefinition definition, List extensions) { + out.printf("%s\n", AstPrinter.printAst(definition)); + if (extensions != null) { + for (TypeDefinition extension : extensions) { + out.printf("\n%s\n", AstPrinter.printAst(extension)); + } + } + out.println(); + } + + private static String printAst(Object value, GraphQLInputType type) { + return AstPrinter.printAst(AstValueHelper.astFromValue(value, type)); + } + + private TypePrinter schemaPrinter() { + return (out, schema, visibility) -> { + GraphQLObjectType queryType = schema.getQueryType(); + GraphQLObjectType mutationType = schema.getMutationType(); + GraphQLObjectType subscriptionType = schema.getSubscriptionType(); + + // when serializing a GraphQL schema using the type system language, a + // schema definition should be omitted if only uses the default root type names. + boolean needsSchemaPrinted = options.isIncludeSchemaDefinition(); + + if (!needsSchemaPrinted) { + if (queryType != null && !queryType.getName().equals("Query")) { + needsSchemaPrinted = true; + } + if (mutationType != null && !mutationType.getName().equals("Mutation")) { + needsSchemaPrinted = true; + } + if (subscriptionType != null && !subscriptionType.getName().equals("Subscription")) { + needsSchemaPrinted = true; + } + } + + if (needsSchemaPrinted) { + out.format("schema {\n"); + if (queryType != null) { + out.format(" query: %s\n", queryType.getName()); + } + if (mutationType != null) { + out.format(" mutation: %s\n", mutationType.getName()); + } + if (subscriptionType != null) { + out.format(" subscription: %s\n", subscriptionType.getName()); + } + out.format("}\n\n"); + } + + List directives = getSchemaDirectives(schema); + if (!directives.isEmpty()) { + out.format("%s", directiveDefinitions(directives)); + } + }; + } + + private List getSchemaDirectives(GraphQLSchema schema) { + return schema.getDirectives().stream() + .filter(options.getIncludeDirective()) + .collect(toList()); + } + + String typeString(GraphQLType rawType) { + return GraphQLTypeUtil.simplePrint(rawType); + } + + String argsString(List arguments) { + return argsString(null, arguments); + } + + String argsString(Class parent, List arguments) { + boolean hasDescriptions = arguments.stream().anyMatch(this::hasDescription); + String halfPrefix = hasDescriptions ? " " : ""; + String prefix = hasDescriptions ? " " : ""; + int count = 0; + StringBuilder sb = new StringBuilder(); + + GraphqlTypeComparatorEnvironment environment = GraphqlTypeComparatorEnvironment.newEnvironment() + .parentType(parent) + .elementType(GraphQLArgument.class) + .build(); + Comparator comparator = options.comparatorRegistry.getComparator(environment); + + arguments = arguments + .stream() + .sorted(comparator) + .collect(toList()); + for (GraphQLArgument argument : arguments) { + if (count == 0) { + sb.append("("); + } else { + sb.append(", "); + } + if (hasDescriptions) { + sb.append("\n"); + } + sb.append(printComments(argument, prefix)); + + sb.append(prefix).append(argument.getName()).append(": ").append(typeString(argument.getType())); + Object defaultValue = argument.getDefaultValue(); + if (defaultValue != null) { + sb.append(" = "); + sb.append(printAst(defaultValue, argument.getType())); + } + + argument.getDirectives().stream() + .map(this::directiveString) + .filter(it -> !it.isEmpty()) + .forEach(directiveString -> sb.append(" ").append(directiveString)); + + count++; + } + if (count > 0) { + if (hasDescriptions) { + sb.append("\n"); + } + sb.append(halfPrefix).append(")"); + } + return sb.toString(); + } + + String directivesString(Class parent, List directives) { + directives = directives.stream() + // @deprecated is special - we always print it if something is deprecated + .filter(directive -> options.getIncludeDirective().test(directive) || isDeprecatedDirective(directive)) + .collect(toList()); + + if (directives.isEmpty()) { + return ""; + } + StringBuilder sb = new StringBuilder(); + if (!directives.isEmpty()) { + sb.append(" "); + } + + GraphqlTypeComparatorEnvironment environment = GraphqlTypeComparatorEnvironment.newEnvironment() + .parentType(parent) + .elementType(GraphQLDirective.class) + .build(); + Comparator comparator = options.comparatorRegistry.getComparator(environment); + + directives = directives + .stream() + .sorted(comparator) + .collect(toList()); + for (int i = 0; i < directives.size(); i++) { + GraphQLDirective directive = directives.get(i); + sb.append(directiveString(directive)); + if (i < directives.size() - 1) { + sb.append(" "); + } + } + return sb.toString(); + } + + private String directiveString(GraphQLDirective directive) { + if (!options.getIncludeDirective().test(directive)) { + // @deprecated is special - we always print it if something is deprecated + if (!isDeprecatedDirective(directive)) { + return ""; + } + } + + StringBuilder sb = new StringBuilder(); + sb.append("@").append(directive.getName()); + + GraphqlTypeComparatorEnvironment environment = GraphqlTypeComparatorEnvironment.newEnvironment() + .parentType(GraphQLDirective.class) + .elementType(GraphQLArgument.class) + .build(); + Comparator comparator = options.comparatorRegistry.getComparator(environment); + + List args = directive.getArguments(); + args = args + .stream() + .sorted(comparator) + .collect(toList()); + if (!args.isEmpty()) { + sb.append("("); + for (int i = 0; i < args.size(); i++) { + GraphQLArgument arg = args.get(i); + String argValue = null; + if (arg.getValue() != null) { + argValue = printAst(arg.getValue(), arg.getType()); + } else if (arg.getDefaultValue() != null) { + argValue = printAst(arg.getDefaultValue(), arg.getType()); + } + if (!isNullOrEmpty(argValue)) { + sb.append(arg.getName()); + sb.append(" : "); + sb.append(argValue); + if (i < args.size() - 1) { + sb.append(", "); + } + } + } + sb.append(")"); + } + return sb.toString(); + } + + private boolean isDeprecatedDirective(GraphQLDirective directive) { + return directive.getName().equals(DeprecatedDirective.getName()); + } + + private boolean hasDeprecatedDirective(List directives) { + return directives.stream() + .filter(this::isDeprecatedDirective) + .count() == 1; + } + + private List addDeprecatedDirectiveIfNeeded(List directives) { + if (!hasDeprecatedDirective(directives)) { + directives = new ArrayList<>(directives); + directives.add(DeprecatedDirective4Printing); + } + return directives; + } + + private String directiveDefinitions(List directives) { + StringBuilder sb = new StringBuilder(); + for (GraphQLDirective directive : directives) { + sb.append(directiveDefinition(directive)); + sb.append("\n\n"); + } + return sb.toString(); + } + + private String directiveDefinition(GraphQLDirective directive) { + StringBuilder sb = new StringBuilder(); + + StringWriter sw = new StringWriter(); + printComments(new PrintWriter(sw), directive, ""); + + sb.append(sw.toString()); + + sb.append("directive @").append(directive.getName()); + + GraphqlTypeComparatorEnvironment environment = GraphqlTypeComparatorEnvironment.newEnvironment() + .parentType(GraphQLDirective.class) + .elementType(GraphQLArgument.class) + .build(); + Comparator comparator = options.comparatorRegistry.getComparator(environment); + + List args = directive.getArguments(); + args = args + .stream() + .sorted(comparator) + .collect(toList()); + + sb.append(argsString(GraphQLDirective.class, args)); + + sb.append(" on "); + + String locations = directive.validLocations().stream().map(Enum::name).collect(Collectors.joining(" | ")); + sb.append(locations); + + return sb.toString(); + } + + + @SuppressWarnings("unchecked") + private TypePrinter printer(Class clazz) { + TypePrinter typePrinter = printers.get(clazz); + if (typePrinter == null) { + Class superClazz = clazz.getSuperclass(); + if (superClazz != Object.class) { + typePrinter = printer(superClazz); + } else { + typePrinter = (out, type, visibility) -> out.println("Type not implemented : " + type); + } + printers.put(clazz, typePrinter); + } + return (TypePrinter) typePrinter; + } + + + public String print(GraphQLType type) { + StringWriter sw = new StringWriter(); + PrintWriter out = new PrintWriter(sw); + + printType(out, type, DEFAULT_FIELD_VISIBILITY); + + return sw.toString(); + } + + @SuppressWarnings("unchecked") + private void printType(PrintWriter out, List typesAsList, Class + typeClazz, GraphqlFieldVisibility visibility) { + typesAsList.stream() + .filter(type -> typeClazz.isAssignableFrom(type.getClass())) + .forEach(type -> printType(out, type, visibility)); + } + + private void printType(PrintWriter out, GraphQLType type, GraphqlFieldVisibility visibility) { + TypePrinter printer = printer(type.getClass()); + printer.print(out, type, visibility); + } + + private String printComments(Object graphQLType, String prefix) { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + printComments(pw, graphQLType, prefix); + return sw.toString(); + } + + private void printComments(PrintWriter out, Object graphQLType, String prefix) { + + String descriptionText = getDescription(graphQLType); + if (isNullOrEmpty(descriptionText)) { + return; + } + + if (!isNullOrEmpty(descriptionText)) { + List lines = Arrays.asList(descriptionText.split("\n")); + if (options.isDescriptionsAsHashComments()) { + printMultiLineHashDescription(out, prefix, lines); + } else { + if (lines.size() > 1) { + printMultiLineDescription(out, prefix, lines); + } else { + printSingleLineDescription(out, prefix, lines.get(0)); + } + } + } + } + + private void printMultiLineHashDescription(PrintWriter out, String prefix, List lines) { + lines.forEach(l -> out.printf("%s#%s\n", prefix, l)); + } + + private void printMultiLineDescription(PrintWriter out, String prefix, List lines) { + out.printf("%s\"\"\"\n", prefix); + lines.forEach(l -> out.printf("%s%s\n", prefix, l)); + out.printf("%s\"\"\"\n", prefix); + } + + private void printSingleLineDescription(PrintWriter out, String prefix, String s) { + out.printf("%s\"%s\"\n", prefix, s); + } + + private boolean hasDescription(Object descriptionHolder) { + String description = getDescription(descriptionHolder); + return !isNullOrEmpty(description); + } + + private String getDescription(Object descriptionHolder) { + if (descriptionHolder instanceof GraphQLObjectType) { + GraphQLObjectType type = (GraphQLObjectType) descriptionHolder; + return description(type.getDescription(), ofNullable(type.getDefinition()).map(ObjectTypeDefinition::getDescription).orElse(null)); + } else if (descriptionHolder instanceof GraphQLEnumType) { + GraphQLEnumType type = (GraphQLEnumType) descriptionHolder; + return description(type.getDescription(), ofNullable(type.getDefinition()).map(EnumTypeDefinition::getDescription).orElse(null)); + } else if (descriptionHolder instanceof GraphQLFieldDefinition) { + GraphQLFieldDefinition type = (GraphQLFieldDefinition) descriptionHolder; + return description(type.getDescription(), ofNullable(type.getDefinition()).map(FieldDefinition::getDescription).orElse(null)); + } else if (descriptionHolder instanceof GraphQLEnumValueDefinition) { + GraphQLEnumValueDefinition type = (GraphQLEnumValueDefinition) descriptionHolder; + return description(type.getDescription(), ofNullable(type.getDefinition()).map(EnumValueDefinition::getDescription).orElse(null)); + } else if (descriptionHolder instanceof GraphQLUnionType) { + GraphQLUnionType type = (GraphQLUnionType) descriptionHolder; + return description(type.getDescription(), ofNullable(type.getDefinition()).map(UnionTypeDefinition::getDescription).orElse(null)); + } else if (descriptionHolder instanceof GraphQLInputObjectType) { + GraphQLInputObjectType type = (GraphQLInputObjectType) descriptionHolder; + return description(type.getDescription(), ofNullable(type.getDefinition()).map(InputObjectTypeDefinition::getDescription).orElse(null)); + } else if (descriptionHolder instanceof GraphQLInputObjectField) { + GraphQLInputObjectField type = (GraphQLInputObjectField) descriptionHolder; + return description(type.getDescription(), ofNullable(type.getDefinition()).map(InputValueDefinition::getDescription).orElse(null)); + } else if (descriptionHolder instanceof GraphQLInterfaceType) { + GraphQLInterfaceType type = (GraphQLInterfaceType) descriptionHolder; + return description(type.getDescription(), ofNullable(type.getDefinition()).map(InterfaceTypeDefinition::getDescription).orElse(null)); + } else if (descriptionHolder instanceof GraphQLScalarType) { + GraphQLScalarType type = (GraphQLScalarType) descriptionHolder; + return description(type.getDescription(), ofNullable(type.getDefinition()).map(ScalarTypeDefinition::getDescription).orElse(null)); + } else if (descriptionHolder instanceof GraphQLArgument) { + GraphQLArgument type = (GraphQLArgument) descriptionHolder; + return description(type.getDescription(), ofNullable(type.getDefinition()).map(InputValueDefinition::getDescription).orElse(null)); + } else if (descriptionHolder instanceof GraphQLDirective) { + GraphQLDirective type = (GraphQLDirective) descriptionHolder; + return description(type.getDescription(), null); + } else { + return Assert.assertShouldNeverHappen(); + } + } + + String description(String runtimeDescription, Description descriptionAst) { + // + // 95% of the time if the schema was built from SchemaGenerator then the runtime description is the only description + // So the other code here is a really defensive way to get the description + // + String descriptionText = runtimeDescription; + if (isNullOrEmpty(descriptionText)) { + if (descriptionAst != null) { + descriptionText = descriptionAst.getContent(); + } + } + return descriptionText; + } + + private static boolean isNullOrEmpty(String s) { + return s == null || s.isEmpty(); + } +} From fc665a03f6d9d5466395ac1adda48ec7b6eeb151 Mon Sep 17 00:00:00 2001 From: "Sachin D. Shinde" Date: Wed, 18 Mar 2020 12:42:14 -0700 Subject: [PATCH 04/15] Fix FederationSdlPrinter.enumPrinter() --- .../graphqljava/FederationSdlPrinter.java | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/FederationSdlPrinter.java b/graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/FederationSdlPrinter.java index 9b350113..ea938ebf 100644 --- a/graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/FederationSdlPrinter.java +++ b/graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/FederationSdlPrinter.java @@ -368,20 +368,24 @@ private TypePrinter enumPrinter() { printAsAst(out, type.getDefinition(), type.getExtensionDefinitions()); } else { printComments(out, type, ""); - out.format("enum %s%s {\n", type.getName(), directivesString(GraphQLEnumType.class, type.getDirectives())); + out.format("enum %s%s", type.getName(), directivesString(GraphQLEnumType.class, type.getDirectives())); List values = type.getValues() .stream() .sorted(comparator) .collect(toList()); - for (GraphQLEnumValueDefinition enumValueDefinition : values) { - printComments(out, enumValueDefinition, " "); - List enumValueDirectives = enumValueDefinition.getDirectives(); - if (enumValueDefinition.isDeprecated()) { - enumValueDirectives = addDeprecatedDirectiveIfNeeded(enumValueDirectives); + if (values.size() > 0) { + out.format(" {\n"); + for (GraphQLEnumValueDefinition enumValueDefinition : values) { + printComments(out, enumValueDefinition, " "); + List enumValueDirectives = enumValueDefinition.getDirectives(); + if (enumValueDefinition.isDeprecated()) { + enumValueDirectives = addDeprecatedDirectiveIfNeeded(enumValueDirectives); + } + out.format(" %s%s\n", enumValueDefinition.getName(), directivesString(GraphQLEnumValueDefinition.class, enumValueDirectives)); } - out.format(" %s%s\n", enumValueDefinition.getName(), directivesString(GraphQLEnumValueDefinition.class, enumValueDirectives)); + out.format("}"); } - out.format("}\n\n"); + out.format("\n\n"); } }; } From 95622d462c18a603a0a712fe6ea880197ddf4149 Mon Sep 17 00:00:00 2001 From: "Sachin D. Shinde" Date: Wed, 18 Mar 2020 12:49:59 -0700 Subject: [PATCH 05/15] Fix FederationSdlPrinter.printFieldDefinitions() --- .../federation/graphqljava/FederationSdlPrinter.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/FederationSdlPrinter.java b/graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/FederationSdlPrinter.java index ea938ebf..429699ee 100644 --- a/graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/FederationSdlPrinter.java +++ b/graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/FederationSdlPrinter.java @@ -391,6 +391,11 @@ private TypePrinter enumPrinter() { } private void printFieldDefinitions(PrintWriter out, Comparator comparator, List fieldDefinitions) { + if (fieldDefinitions.size() == 0) { + return; + } + + out.format(" {\n"); fieldDefinitions .stream() .sorted(comparator) @@ -405,6 +410,7 @@ private void printFieldDefinitions(PrintWriter out, Comparator interfacePrinter() { From ee089860b0c57f2c2ed51cb9a9b23b54f35df0fa Mon Sep 17 00:00:00 2001 From: "Sachin D. Shinde" Date: Wed, 18 Mar 2020 12:51:22 -0700 Subject: [PATCH 06/15] Fix FederationSdlPrinter.interfacePrinter() --- .../federation/graphqljava/FederationSdlPrinter.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/FederationSdlPrinter.java b/graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/FederationSdlPrinter.java index 429699ee..cd54d3eb 100644 --- a/graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/FederationSdlPrinter.java +++ b/graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/FederationSdlPrinter.java @@ -429,9 +429,9 @@ private TypePrinter interfacePrinter() { printAsAst(out, type.getDefinition(), type.getExtensionDefinitions()); } else { printComments(out, type, ""); - out.format("interface %s%s {\n", type.getName(), directivesString(GraphQLInterfaceType.class, type.getDirectives())); + out.format("interface %s%s", type.getName(), directivesString(GraphQLInterfaceType.class, type.getDirectives())); printFieldDefinitions(out, comparator, visibility.getFieldDefinitions(type)); - out.format("}\n\n"); + out.format("\n\n"); } }; } From 038205e2cec112ac298943d6d8735e37fa1e21ca Mon Sep 17 00:00:00 2001 From: "Sachin D. Shinde" Date: Wed, 18 Mar 2020 12:52:45 -0700 Subject: [PATCH 07/15] Fix FederationSdlPrinter.objectPrinter() --- .../federation/graphqljava/FederationSdlPrinter.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/FederationSdlPrinter.java b/graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/FederationSdlPrinter.java index cd54d3eb..2b0c6fc6 100644 --- a/graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/FederationSdlPrinter.java +++ b/graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/FederationSdlPrinter.java @@ -479,7 +479,7 @@ private TypePrinter objectPrinter() { } else { printComments(out, type, ""); if (type.getInterfaces().isEmpty()) { - out.format("type %s%s {\n", type.getName(), directivesString(GraphQLObjectType.class, type.getDirectives())); + out.format("type %s%s", type.getName(), directivesString(GraphQLObjectType.class, type.getDirectives())); } else { GraphqlTypeComparatorEnvironment environment = GraphqlTypeComparatorEnvironment.newEnvironment() @@ -492,7 +492,7 @@ private TypePrinter objectPrinter() { .stream() .sorted(implementsComparator) .map(GraphQLNamedType::getName); - out.format("type %s implements %s%s {\n", + out.format("type %s implements %s%s", type.getName(), interfaceNames.collect(joining(" & ")), directivesString(GraphQLObjectType.class, type.getDirectives())); @@ -505,7 +505,7 @@ private TypePrinter objectPrinter() { Comparator comparator = options.comparatorRegistry.getComparator(environment); printFieldDefinitions(out, comparator, visibility.getFieldDefinitions(type)); - out.format("}\n\n"); + out.format("\n\n"); } }; } From efc2dd5299ff774ef274c0b118f71d50aa7cc8c8 Mon Sep 17 00:00:00 2001 From: "Sachin D. Shinde" Date: Wed, 18 Mar 2020 12:55:22 -0700 Subject: [PATCH 08/15] Fix FederationSdlPrinter.inputObjectPrinter() --- .../graphqljava/FederationSdlPrinter.java | 39 +++++++++++-------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/FederationSdlPrinter.java b/graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/FederationSdlPrinter.java index 2b0c6fc6..f0018859 100644 --- a/graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/FederationSdlPrinter.java +++ b/graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/FederationSdlPrinter.java @@ -525,23 +525,28 @@ private TypePrinter inputObjectPrinter() { .build(); Comparator comparator = options.comparatorRegistry.getComparator(environment); - out.format("input %s%s {\n", type.getName(), directivesString(GraphQLInputObjectType.class, type.getDirectives())); - visibility.getFieldDefinitions(type) - .stream() - .sorted(comparator) - .forEach(fd -> { - printComments(out, fd, " "); - out.format(" %s: %s", - fd.getName(), typeString(fd.getType())); - Object defaultValue = fd.getDefaultValue(); - if (defaultValue != null) { - String astValue = printAst(defaultValue, fd.getType()); - out.format(" = %s", astValue); - } - out.format(directivesString(GraphQLInputObjectField.class, fd.getDirectives())); - out.format("\n"); - }); - out.format("}\n\n"); + out.format("input %s%s", type.getName(), directivesString(GraphQLInputObjectType.class, type.getDirectives())); + List inputObjectFields = visibility.getFieldDefinitions(type); + if (inputObjectFields.size() > 0) { + out.format(" {\n"); + inputObjectFields + .stream() + .sorted(comparator) + .forEach(fd -> { + printComments(out, fd, " "); + out.format(" %s: %s", + fd.getName(), typeString(fd.getType())); + Object defaultValue = fd.getDefaultValue(); + if (defaultValue != null) { + String astValue = printAst(defaultValue, fd.getType()); + out.format(" = %s", astValue); + } + out.format(directivesString(GraphQLInputObjectField.class, fd.getDirectives())); + out.format("\n"); + }); + out.format("}"); + } + out.format("\n\n"); } }; } From df5f1b09005f7c187aba67ba54d8f4f3ee21e3d0 Mon Sep 17 00:00:00 2001 From: "Sachin D. Shinde" Date: Wed, 25 Mar 2020 18:06:31 -0700 Subject: [PATCH 09/15] Add directive definition and type definition filtering to FederationSdlPrinter --- .../graphqljava/FederationSdlPrinter.java | 64 ++++++++++++++++--- 1 file changed, 54 insertions(+), 10 deletions(-) diff --git a/graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/FederationSdlPrinter.java b/graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/FederationSdlPrinter.java index f0018859..69d300fe 100644 --- a/graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/FederationSdlPrinter.java +++ b/graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/FederationSdlPrinter.java @@ -95,6 +95,10 @@ public static class Options { private final Predicate includeDirective; + private final Predicate includeDirectiveDefinition; + + private final Predicate includeTypeDefinition; + private final GraphqlTypeComparatorRegistry comparatorRegistry; private Options(boolean includeIntrospectionTypes, @@ -104,12 +108,16 @@ private Options(boolean includeIntrospectionTypes, boolean useAstDefinitions, boolean descriptionsAsHashComments, Predicate includeDirective, + Predicate includeDirectiveDefinition, + Predicate includeTypeDefinition, GraphqlTypeComparatorRegistry comparatorRegistry) { this.includeIntrospectionTypes = includeIntrospectionTypes; this.includeScalars = includeScalars; this.includeExtendedScalars = includeExtendedScalars; this.includeSchemaDefinition = includeSchemaDefinition; this.includeDirective = includeDirective; + this.includeDirectiveDefinition = includeDirectiveDefinition; + this.includeTypeDefinition = includeTypeDefinition; this.useAstDefinitions = useAstDefinitions; this.descriptionsAsHashComments = descriptionsAsHashComments; this.comparatorRegistry = comparatorRegistry; @@ -135,6 +143,14 @@ public Predicate getIncludeDirective() { return includeDirective; } + public Predicate getIncludeDirectiveDefinition() { + return includeDirectiveDefinition; + } + + public Predicate getIncludeTypeDefinition() { + return includeTypeDefinition; + } + public boolean isDescriptionsAsHashComments() { return descriptionsAsHashComments; } @@ -150,7 +166,8 @@ public boolean isUseAstDefinitions() { public static Options defaultOptions() { return new Options(false, false, false, false, false, false, - directive -> true, DefaultGraphqlTypeComparatorRegistry.defaultComparators()); + directive -> true, directiveDefinition -> true, typeDefinition -> true, + DefaultGraphqlTypeComparatorRegistry.defaultComparators()); } /** @@ -160,7 +177,7 @@ public static Options defaultOptions() { * @return options */ public Options includeIntrospectionTypes(boolean flag) { - return new Options(flag, this.includeScalars, this.includeExtendedScalars, this.includeSchemaDefinition, this.useAstDefinitions, this.descriptionsAsHashComments, this.includeDirective, this.comparatorRegistry); + return new Options(flag, this.includeScalars, this.includeExtendedScalars, this.includeSchemaDefinition, this.useAstDefinitions, this.descriptionsAsHashComments, this.includeDirective, this.includeDirectiveDefinition, this.includeTypeDefinition, this.comparatorRegistry); } /** @@ -170,7 +187,7 @@ public Options includeIntrospectionTypes(boolean flag) { * @return options */ public Options includeScalarTypes(boolean flag) { - return new Options(this.includeIntrospectionTypes, flag, this.includeExtendedScalars, this.includeSchemaDefinition, this.useAstDefinitions, this.descriptionsAsHashComments, this.includeDirective, this.comparatorRegistry); + return new Options(this.includeIntrospectionTypes, flag, this.includeExtendedScalars, this.includeSchemaDefinition, this.useAstDefinitions, this.descriptionsAsHashComments, this.includeDirective, this.includeDirectiveDefinition, this.includeTypeDefinition, this.comparatorRegistry); } /** @@ -181,7 +198,7 @@ public Options includeScalarTypes(boolean flag) { * @return options */ public Options includeExtendedScalarTypes(boolean flag) { - return new Options(this.includeIntrospectionTypes, this.includeScalars, flag, this.includeSchemaDefinition, this.useAstDefinitions, this.descriptionsAsHashComments, this.includeDirective, this.comparatorRegistry); + return new Options(this.includeIntrospectionTypes, this.includeScalars, flag, this.includeSchemaDefinition, this.useAstDefinitions, this.descriptionsAsHashComments, this.includeDirective, this.includeDirectiveDefinition, this.includeTypeDefinition, this.comparatorRegistry); } /** @@ -194,7 +211,7 @@ public Options includeExtendedScalarTypes(boolean flag) { * @return options */ public Options includeSchemaDefinition(boolean flag) { - return new Options(this.includeIntrospectionTypes, this.includeScalars, this.includeExtendedScalars, flag, this.useAstDefinitions, this.descriptionsAsHashComments, this.includeDirective, this.comparatorRegistry); + return new Options(this.includeIntrospectionTypes, this.includeScalars, this.includeExtendedScalars, flag, this.useAstDefinitions, this.descriptionsAsHashComments, this.includeDirective, this.includeDirectiveDefinition, this.includeTypeDefinition, this.comparatorRegistry); } /** @@ -205,11 +222,36 @@ public Options includeSchemaDefinition(boolean flag) { * @return new instance of options */ public Options includeDirectives(boolean flag) { - return new Options(this.includeIntrospectionTypes, this.includeScalars, this.includeExtendedScalars, this.includeSchemaDefinition, this.useAstDefinitions, this.descriptionsAsHashComments, directive -> flag, this.comparatorRegistry); + return new Options(this.includeIntrospectionTypes, this.includeScalars, this.includeExtendedScalars, this.includeSchemaDefinition, this.useAstDefinitions, this.descriptionsAsHashComments, directive -> flag, this.includeDirectiveDefinition, this.includeTypeDefinition, this.comparatorRegistry); } public Options includeDirectives(Predicate includeDirective) { - return new Options(this.includeIntrospectionTypes, this.includeScalars, this.includeExtendedScalars, this.includeSchemaDefinition, this.useAstDefinitions, this.descriptionsAsHashComments, includeDirective, this.comparatorRegistry); + return new Options(this.includeIntrospectionTypes, this.includeScalars, this.includeExtendedScalars, this.includeSchemaDefinition, this.useAstDefinitions, this.descriptionsAsHashComments, includeDirective, this.includeDirectiveDefinition, this.includeTypeDefinition, this.comparatorRegistry); + } + + /** + * Filter printing of directive definitions. In Apollo Federation, some directive + * definitions need to be hidden, and this predicate allows filtering out such definitions. + * Prints all definitions by default. Note that both this predicate and the predicate in + * {@link #includeDirectives(Predicate)} must be true for a definition to be printed. + * + * @param includeDirectiveDefinition returns true if the definition should be printed + * @return new instance of options + */ + public Options includeDirectiveDefinitions(Predicate includeDirectiveDefinition) { + return new Options(this.includeIntrospectionTypes, this.includeScalars, this.includeExtendedScalars, this.includeSchemaDefinition, this.useAstDefinitions, this.descriptionsAsHashComments, this.includeDirective, includeDirectiveDefinition, this.includeTypeDefinition, this.comparatorRegistry); + } + + /** + * Filter printing of type definitions. In Apollo Federation, some type definitions need to + * be hidden, and this predicate allows filtering out such definitions. Prints all + * definitions by default. + * + * @param includeTypeDefinition returns true if the definition should be printed + * @return new instance of options + */ + public Options includeTypeDefinitions(Predicate includeTypeDefinition) { + return new Options(this.includeIntrospectionTypes, this.includeScalars, this.includeExtendedScalars, this.includeSchemaDefinition, this.useAstDefinitions, this.descriptionsAsHashComments, this.includeDirective, this.includeDirectiveDefinition, includeTypeDefinition, this.comparatorRegistry); } /** @@ -220,7 +262,7 @@ public Options includeDirectives(Predicate includeDirective) { * @return new instance of options */ public Options useAstDefinitions(boolean flag) { - return new Options(this.includeIntrospectionTypes, this.includeScalars, this.includeExtendedScalars, this.includeSchemaDefinition, flag, this.descriptionsAsHashComments, this.includeDirective, this.comparatorRegistry); + return new Options(this.includeIntrospectionTypes, this.includeScalars, this.includeExtendedScalars, this.includeSchemaDefinition, flag, this.descriptionsAsHashComments, this.includeDirective, this.includeDirectiveDefinition, this.includeTypeDefinition, this.comparatorRegistry); } /** @@ -233,7 +275,7 @@ public Options useAstDefinitions(boolean flag) { * @return new instance of options */ public Options descriptionsAsHashComments(boolean flag) { - return new Options(this.includeIntrospectionTypes, this.includeScalars, this.includeExtendedScalars, this.includeSchemaDefinition, this.useAstDefinitions, flag, this.includeDirective, this.comparatorRegistry); + return new Options(this.includeIntrospectionTypes, this.includeScalars, this.includeExtendedScalars, this.includeSchemaDefinition, this.useAstDefinitions, flag, this.includeDirective, this.includeDirectiveDefinition, this.includeTypeDefinition, this.comparatorRegistry); } /** @@ -245,7 +287,7 @@ public Options descriptionsAsHashComments(boolean flag) { * @return options */ public Options setComparators(GraphqlTypeComparatorRegistry comparatorRegistry) { - return new Options(this.includeIntrospectionTypes, this.includeScalars, this.includeExtendedScalars, this.includeSchemaDefinition, this.useAstDefinitions, this.descriptionsAsHashComments, this.includeDirective, comparatorRegistry); + return new Options(this.includeIntrospectionTypes, this.includeScalars, this.includeExtendedScalars, this.includeSchemaDefinition, this.useAstDefinitions, this.descriptionsAsHashComments, this.includeDirective, this.includeDirectiveDefinition, this.includeTypeDefinition, comparatorRegistry); } } @@ -299,6 +341,7 @@ public String print(GraphQLSchema schema) { List typesAsList = schema.getAllTypesAsList() .stream() .sorted(Comparator.comparing(GraphQLNamedType::getName)) + .filter(options.getIncludeTypeDefinition()) .collect(toList()); printType(out, typesAsList, GraphQLInterfaceType.class, visibility); @@ -630,6 +673,7 @@ private TypePrinter schemaPrinter() { private List getSchemaDirectives(GraphQLSchema schema) { return schema.getDirectives().stream() .filter(options.getIncludeDirective()) + .filter(options.getIncludeDirectiveDefinition()) .collect(toList()); } From 887b49c2ffae466764c2139fd829ffe2574e18a8 Mon Sep 17 00:00:00 2001 From: "Sachin D. Shinde" Date: Thu, 12 Mar 2020 11:20:01 -0700 Subject: [PATCH 10/15] Change GraphQLType::getName to GraphQLNamedType::getName --- .../federation/graphqljava/SchemaTransformer.java | 5 +++-- .../apollographql/federation/graphqljava/FederationTest.java | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/SchemaTransformer.java b/graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/SchemaTransformer.java index 6efd1e7f..95497992 100644 --- a/graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/SchemaTransformer.java +++ b/graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/SchemaTransformer.java @@ -7,6 +7,7 @@ import graphql.schema.FieldCoordinates; import graphql.schema.GraphQLCodeRegistry; import graphql.schema.GraphQLDirectiveContainer; +import graphql.schema.GraphQLNamedType; import graphql.schema.GraphQLObjectType; import graphql.schema.GraphQLSchema; import graphql.schema.GraphQLType; @@ -88,7 +89,7 @@ public final GraphQLSchema build() throws SchemaProblem { final Set entityTypeNames = originalSchema.getAllTypesAsList().stream() .filter(t -> t instanceof GraphQLDirectiveContainer && ((GraphQLDirectiveContainer) t).getDirective(FederationDirectives.keyName) != null) - .map(GraphQLType::getName) + .map(GraphQLNamedType::getName) .collect(Collectors.toSet()); final Set entityConcreteTypeNames = originalSchema.getAllTypesAsList() @@ -98,7 +99,7 @@ public final GraphQLSchema build() throws SchemaProblem { ((GraphQLObjectType) type).getInterfaces() .stream() .anyMatch(itf -> entityTypeNames.contains(itf.getName()))) - .map(GraphQLType::getName) + .map(GraphQLNamedType::getName) .collect(Collectors.toSet()); // If there are entity types install: Query._entities(representations: [_Any!]!): [_Entity]! diff --git a/graphql-java-support/src/test/java/com/apollographql/federation/graphqljava/FederationTest.java b/graphql-java-support/src/test/java/com/apollographql/federation/graphqljava/FederationTest.java index 79b9213c..07f259aa 100644 --- a/graphql-java-support/src/test/java/com/apollographql/federation/graphqljava/FederationTest.java +++ b/graphql-java-support/src/test/java/com/apollographql/federation/graphqljava/FederationTest.java @@ -3,6 +3,7 @@ import graphql.ExecutionResult; import graphql.Scalars; import graphql.schema.GraphQLFieldDefinition; +import graphql.schema.GraphQLNamedType; import graphql.schema.GraphQLScalarType; import graphql.schema.GraphQLSchema; import graphql.schema.GraphQLType; @@ -141,7 +142,7 @@ void testInterfacesAreCovered() { final Iterable unionTypes = entityType .getTypes() .stream() - .map(GraphQLType::getName) + .map(GraphQLNamedType::getName) .sorted() .collect(Collectors.toList()); From e2c12087ff88f8610d7c5624d34e39e71ac7805f Mon Sep 17 00:00:00 2001 From: "Sachin D. Shinde" Date: Thu, 12 Mar 2020 11:22:55 -0700 Subject: [PATCH 11/15] Change SchemaPrinter.Options.includeSchemaDefintion() to includeSchemaDefinition() --- .../apollographql/federation/graphqljava/SchemaTransformer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/SchemaTransformer.java b/graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/SchemaTransformer.java index 95497992..225c40d5 100644 --- a/graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/SchemaTransformer.java +++ b/graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/SchemaTransformer.java @@ -163,7 +163,7 @@ public static String sdl(GraphQLSchema schema) { final FederationSdlPrinter.Options options = FederationSdlPrinter.Options.defaultOptions() .includeScalarTypes(true) .includeExtendedScalarTypes(true) - .includeSchemaDefintion(true) + .includeSchemaDefinition(true) .includeDirectives(true) .includeDirectiveDefinitions(def -> !hiddenDirectiveDefinitions.contains(def.getName())) .includeTypeDefinitions(def -> !hiddenTypeDefinitions.contains(def.getName())); From ff085fc27ae6e593b6ae8a91d0ecdb19b4b07289 Mon Sep 17 00:00:00 2001 From: "Sachin D. Shinde" Date: Wed, 25 Mar 2020 18:20:04 -0700 Subject: [PATCH 12/15] Change RuntimeWiring.getSchemaTransformers() to RuntimeWiring.getSchemaGeneratorPostProcessings() --- .../com/apollographql/federation/graphqljava/Federation.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/Federation.java b/graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/Federation.java index c5e05845..a61bec2b 100644 --- a/graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/Federation.java +++ b/graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/Federation.java @@ -141,7 +141,7 @@ private static RuntimeWiring.Builder copyRuntimeWiring(RuntimeWiring runtimeWiri runtimeWiring.getRegisteredDirectiveWiring().forEach(builder::directive); runtimeWiring.getDirectiveWiring().forEach(builder::directiveWiring); builder.comparatorRegistry(runtimeWiring.getComparatorRegistry()); - runtimeWiring.getSchemaTransformers().forEach(builder::transformer); + runtimeWiring.getSchemaGeneratorPostProcessings().forEach(builder::transformer); return builder; } From dcf4c59c562ebbaf6236b33e22395a0bf635b3ab Mon Sep 17 00:00:00 2001 From: "Sachin D. Shinde" Date: Wed, 25 Mar 2020 17:51:28 -0700 Subject: [PATCH 13/15] Remove standard directive definitions in SchemaTransformer.sdl() --- .../federation/graphqljava/SchemaTransformer.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/SchemaTransformer.java b/graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/SchemaTransformer.java index 225c40d5..f034eb77 100644 --- a/graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/SchemaTransformer.java +++ b/graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/SchemaTransformer.java @@ -16,6 +16,7 @@ import org.jetbrains.annotations.NotNull; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -23,6 +24,9 @@ public final class SchemaTransformer { private static final Object DUMMY = new Object(); + // Apollo Gateway will fail composition if it sees standard directive definitions. + private static final Set STANDARD_DIRECTIVES = + new HashSet<>(Arrays.asList("deprecated", "include", "skip")); private final GraphQLSchema originalSchema; private TypeResolver entityTypeResolver = null; private DataFetcher entitiesDataFetcher = null; @@ -141,7 +145,9 @@ public final GraphQLSchema build() throws SchemaProblem { public static String sdl(GraphQLSchema schema) { // Gather directive definitions to hide. - final Set hiddenDirectiveDefinitions = new HashSet<>(FederationDirectives.allNames); + final Set hiddenDirectiveDefinitions = new HashSet<>(); + hiddenDirectiveDefinitions.addAll(STANDARD_DIRECTIVES); + hiddenDirectiveDefinitions.addAll(FederationDirectives.allNames); // Gather type definitions to hide. final Set hiddenTypeDefinitions = new HashSet<>(); From 1ebb028b91447b8aa1368022f3478c92db801758 Mon Sep 17 00:00:00 2001 From: "Sachin D. Shinde" Date: Mon, 16 Mar 2020 13:33:13 -0700 Subject: [PATCH 14/15] Change tests to ignore standard directive definitions --- .../graphqljava/FederationTest.java | 22 ++++++++++++++++--- .../federation/graphqljava/SchemaUtils.java | 6 ----- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/graphql-java-support/src/test/java/com/apollographql/federation/graphqljava/FederationTest.java b/graphql-java-support/src/test/java/com/apollographql/federation/graphqljava/FederationTest.java index 07f259aa..015ccaa6 100644 --- a/graphql-java-support/src/test/java/com/apollographql/federation/graphqljava/FederationTest.java +++ b/graphql-java-support/src/test/java/com/apollographql/federation/graphqljava/FederationTest.java @@ -18,8 +18,10 @@ import org.junit.jupiter.api.Test; import java.util.Arrays; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.stream.Collectors; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -35,6 +37,8 @@ class FederationTest { private final String printerEmptySDL = TestUtils.readResource("schemas/printerEmpty.graphql"); private final String printerFilterSDL = TestUtils.readResource("schemas/printerFilter.graphql"); private final String printerFilterExpectedSDL = TestUtils.readResource("schemas/printerFilterExpected.graphql"); + private final Set standardDirectives = + new HashSet<>(Arrays.asList("deprecated", "include", "skip")); @Test void testEmpty() { @@ -58,7 +62,12 @@ void testEmpty() { " sdl: String!\n" + "}\n" + "\n" + - "scalar _FieldSet\n", SchemaUtils.printSchema(federated)); + "scalar _FieldSet\n", + new FederationSdlPrinter(FederationSdlPrinter.Options.defaultOptions() + .includeScalarTypes(true) + .includeDirectiveDefinitions(def -> !standardDirectives.contains(def.getName())) + ).print(federated) + ); final GraphQLType _Service = federated.getType("_Service"); assertNotNull(_Service, "_Service type present"); @@ -164,7 +173,12 @@ void testPrinterEmpty() { typeDefinitionRegistry, runtimeWiring ); - Assertions.assertEquals(printerEmptySDL.trim(), new FederationSdlPrinter().print(graphQLSchema).trim()); + Assertions.assertEquals( + printerEmptySDL.trim(), + new FederationSdlPrinter(FederationSdlPrinter.Options.defaultOptions() + .includeDirectiveDefinitions(def -> !standardDirectives.contains(def.getName())) + ).print(graphQLSchema).trim() + ); } @Test @@ -196,7 +210,9 @@ void testPrinterFilter() { printerFilterExpectedSDL.trim(), new FederationSdlPrinter(FederationSdlPrinter.Options.defaultOptions() .includeScalarTypes(true) - .includeDirectiveDefinitions(def -> !def.getName().endsWith("1")) + .includeDirectiveDefinitions(def -> + !def.getName().endsWith("1") && !standardDirectives.contains(def.getName()) + ) .includeTypeDefinitions(def -> !def.getName().endsWith("1")) ).print(graphQLSchema).trim() ); diff --git a/graphql-java-support/src/test/java/com/apollographql/federation/graphqljava/SchemaUtils.java b/graphql-java-support/src/test/java/com/apollographql/federation/graphqljava/SchemaUtils.java index 285cef22..25160b02 100644 --- a/graphql-java-support/src/test/java/com/apollographql/federation/graphqljava/SchemaUtils.java +++ b/graphql-java-support/src/test/java/com/apollographql/federation/graphqljava/SchemaUtils.java @@ -15,12 +15,6 @@ final class SchemaUtils { private SchemaUtils() { } - static String printSchema(GraphQLSchema schema) { - return new FederationSdlPrinter(FederationSdlPrinter.Options.defaultOptions() - .includeScalarTypes(true) - ).print(schema); - } - static ExecutionResult execute(GraphQLSchema schema, String query) { return newGraphQL(schema).build().execute(newExecutionInput().query(query).build()); } From 3a0c3699794121faf24bcc069ba28258b58f2551 Mon Sep 17 00:00:00 2001 From: "Sachin D. Shinde" Date: Tue, 17 Mar 2020 09:11:28 -0700 Subject: [PATCH 15/15] Add @deprecated inclusion check to FederationTest --- .../federation/graphqljava/schemas/product.graphql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graphql-java-support/src/test/resources/com/apollographql/federation/graphqljava/schemas/product.graphql b/graphql-java-support/src/test/resources/com/apollographql/federation/graphqljava/schemas/product.graphql index 7f96ecfb..f5e2213e 100644 --- a/graphql-java-support/src/test/resources/com/apollographql/federation/graphqljava/schemas/product.graphql +++ b/graphql-java-support/src/test/resources/com/apollographql/federation/graphqljava/schemas/product.graphql @@ -4,7 +4,7 @@ schema { type Money { amount: Int! - currencyCode: String! + currencyCode: String! @deprecated(reason : "dummy") } type Product @key(fields : "upc") {