From 67f1607972ba568e24202f4949fafa9fd5dc28ec Mon Sep 17 00:00:00 2001 From: Kirill Shiryaev Date: Mon, 4 Dec 2023 19:03:45 -0300 Subject: [PATCH 01/19] add new plugin param for DataFetchResult generation --- .../codegen/gradle/GraphQLCodegenGradleTask.java | 14 ++++++++++++++ .../graphql/codegen/GraphQLCodegenMojo.java | 9 +++++++++ .../model/GraphQLCodegenConfiguration.java | 15 +++++++++++++++ .../graphql/codegen/model/MappingConfig.java | 11 +++++++++++ .../graphql/codegen/model/MappingContext.java | 5 +++++ 5 files changed, 54 insertions(+) diff --git a/plugins/gradle/graphql-java-codegen-gradle-plugin/src/main/java/io/github/kobylynskyi/graphql/codegen/gradle/GraphQLCodegenGradleTask.java b/plugins/gradle/graphql-java-codegen-gradle-plugin/src/main/java/io/github/kobylynskyi/graphql/codegen/gradle/GraphQLCodegenGradleTask.java index a3228c925..8d1c66422 100644 --- a/plugins/gradle/graphql-java-codegen-gradle-plugin/src/main/java/io/github/kobylynskyi/graphql/codegen/gradle/GraphQLCodegenGradleTask.java +++ b/plugins/gradle/graphql-java-codegen-gradle-plugin/src/main/java/io/github/kobylynskyi/graphql/codegen/gradle/GraphQLCodegenGradleTask.java @@ -101,6 +101,7 @@ public class GraphQLCodegenGradleTask extends DefaultTask implements GraphQLCode private Set typesAsInterfaces = new HashSet<>(); private Set resolverArgumentAnnotations = new HashSet<>(); private Set parametrizedResolverAnnotations = new HashSet<>(); + private Set fieldsWithDataFetcherResult = new HashSet<>(); private final RelayConfig relayConfig = new RelayConfig(); @@ -190,6 +191,8 @@ public void generate() throws Exception { fieldsWithoutResolvers != null ? fieldsWithoutResolvers : new HashSet<>()); mappingConfig.setFieldsToExcludeFromGeneration( fieldsToExcludeFromGeneration != null ? fieldsToExcludeFromGeneration : new HashSet<>()); + mappingConfig.setFieldsWithDataFetcherResult( + fieldsWithDataFetcherResult != null ? fieldsWithDataFetcherResult : new HashSet<>()); mappingConfig.setTypesAsInterfaces( typesAsInterfaces != null ? typesAsInterfaces : new HashSet<>()); mappingConfig.setResolverArgumentAnnotations( @@ -801,6 +804,17 @@ public void setFieldsToExcludeFromGeneration(Set fieldsToExcludeFromGene this.fieldsToExcludeFromGeneration = fieldsToExcludeFromGeneration; } + @Input + @Optional + @Override + public Set getFieldsWithDataFetcherResult() { + return fieldsWithDataFetcherResult; + } + + public void setFieldsWithDataFetcherResult(Set fieldsWithDataFetcherResult) { + this.fieldsWithDataFetcherResult = fieldsWithDataFetcherResult; + } + @Input @Optional @Override diff --git a/plugins/maven/graphql-java-codegen-maven-plugin/src/main/java/io/github/kobylynskyi/graphql/codegen/GraphQLCodegenMojo.java b/plugins/maven/graphql-java-codegen-maven-plugin/src/main/java/io/github/kobylynskyi/graphql/codegen/GraphQLCodegenMojo.java index a71c11a4e..5dfcaff34 100644 --- a/plugins/maven/graphql-java-codegen-maven-plugin/src/main/java/io/github/kobylynskyi/graphql/codegen/GraphQLCodegenMojo.java +++ b/plugins/maven/graphql-java-codegen-maven-plugin/src/main/java/io/github/kobylynskyi/graphql/codegen/GraphQLCodegenMojo.java @@ -183,6 +183,9 @@ public class GraphQLCodegenMojo extends AbstractMojo implements GraphQLCodegenCo @Parameter private String[] fieldsToExcludeFromGeneration; + @Parameter + private String[] fieldsWithDataFetcherResult; + @Parameter private RelayConfig relayConfig = new RelayConfig(); @@ -301,6 +304,7 @@ public void execute() throws MojoExecutionException { mappingConfig.setFieldsWithResolvers(mapToHashSet(fieldsWithResolvers)); mappingConfig.setFieldsWithoutResolvers(mapToHashSet(fieldsWithoutResolvers)); mappingConfig.setFieldsToExcludeFromGeneration(mapToHashSet(fieldsToExcludeFromGeneration)); + mappingConfig.setFieldsWithDataFetcherResult(mapToHashSet(fieldsWithDataFetcherResult)); mappingConfig.setRelayConfig(relayConfig); mappingConfig.setGenerateClient(generateClient); @@ -618,6 +622,11 @@ public Set getFieldsToExcludeFromGeneration() { return mapToHashSet(fieldsToExcludeFromGeneration); } + @Override + public Set getFieldsWithDataFetcherResult() { + return mapToHashSet(fieldsWithDataFetcherResult); + } + @Override public Boolean getGenerateAllMethodInProjection() { return generateAllMethodInProjection; diff --git a/src/main/java/com/kobylynskyi/graphql/codegen/model/GraphQLCodegenConfiguration.java b/src/main/java/com/kobylynskyi/graphql/codegen/model/GraphQLCodegenConfiguration.java index dfb7db970..840baf5c1 100644 --- a/src/main/java/com/kobylynskyi/graphql/codegen/model/GraphQLCodegenConfiguration.java +++ b/src/main/java/com/kobylynskyi/graphql/codegen/model/GraphQLCodegenConfiguration.java @@ -349,6 +349,21 @@ public interface GraphQLCodegenConfiguration { */ Set getFieldsToExcludeFromGeneration(); + /** + * Fields that require DataFetcherResult. + * + *

Values should be defined here in format: TypeName, TypeName.fieldName, @directive + * + * + *

E.g.: + *

    + *
  • {@code @dataFetcherResult}
  • + *
+ * + * @return Set of types and fields that should have DataFetcherResult. + */ + Set getFieldsWithDataFetcherResult(); + /** * Specifies whether return types of generated API interface should be wrapped into java.util.Optional * diff --git a/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingConfig.java b/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingConfig.java index dc29f4607..05762152a 100644 --- a/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingConfig.java +++ b/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingConfig.java @@ -64,6 +64,7 @@ public class MappingConfig implements GraphQLCodegenConfiguration, Combinable fieldsWithResolvers = new HashSet<>(); private Set fieldsWithoutResolvers = new HashSet<>(); private Set fieldsToExcludeFromGeneration = new HashSet<>(); + private Set fieldsWithDataFetcherResult = new HashSet<>(); // parent interfaces configs: private String queryResolverParentInterface; @@ -192,6 +193,7 @@ public void combine(MappingConfig source) { parametrizedInputSuffix = getValueOrDefaultToThis(source, GraphQLCodegenConfiguration::getParametrizedInputSuffix); fieldsWithResolvers = combineSet(fieldsWithResolvers, source.fieldsWithResolvers); + fieldsWithDataFetcherResult = combineSet(fieldsWithDataFetcherResult, source.fieldsWithDataFetcherResult); fieldsWithoutResolvers = combineSet(fieldsWithoutResolvers, source.fieldsWithoutResolvers); fieldsToExcludeFromGeneration = combineSet(fieldsToExcludeFromGeneration, source.fieldsToExcludeFromGeneration); customTypesMapping = combineMap(customTypesMapping, source.customTypesMapping); @@ -606,6 +608,15 @@ public Set getFieldsToExcludeFromGeneration() { return fieldsToExcludeFromGeneration; } + public void setFieldsWithDataFetcherResult(Set fieldsToExcludeFromGeneration) { + this.fieldsToExcludeFromGeneration = fieldsToExcludeFromGeneration; + } + + @Override + public Set getFieldsWithDataFetcherResult() { + return fieldsToExcludeFromGeneration; + } + public void setFieldsToExcludeFromGeneration(Set fieldsToExcludeFromGeneration) { this.fieldsToExcludeFromGeneration = fieldsToExcludeFromGeneration; } diff --git a/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingContext.java b/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingContext.java index f3531ca02..8f9a0e0f4 100644 --- a/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingContext.java +++ b/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingContext.java @@ -274,6 +274,11 @@ public Set getFieldsToExcludeFromGeneration() { return config.getFieldsToExcludeFromGeneration(); } + @Override + public Set getFieldsWithDataFetcherResult() { + return config.getFieldsWithDataFetcherResult(); + } + @Override public Boolean getGenerateClient() { return config.getGenerateClient(); From 3f76abe7f3f7a6404f2bb8241c70a13bc5b6b548 Mon Sep 17 00:00:00 2001 From: Kirill Shiryaev Date: Wed, 6 Dec 2023 19:44:56 -0300 Subject: [PATCH 02/19] add new plugin param for DataFetchResult generation --- docs/codegen-options.md | 141 ++++++++++++++++++++-------------------- 1 file changed, 71 insertions(+), 70 deletions(-) diff --git a/docs/codegen-options.md b/docs/codegen-options.md index 263b9d32b..98e0fd74a 100644 --- a/docs/codegen-options.md +++ b/docs/codegen-options.md @@ -1,75 +1,76 @@ # Codegen Options -| Option | Data Type | Default value | Description | -|:-----------------------------------------------------:|:----------------------------------------------------------------------:|:--------------------------------------------------------------:|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `graphqlSchemaPaths` | List(String) | (falls back to `graphqlSchemas`) | GraphQL schema locations. You can supply multiple paths to GraphQL schemas. To include many schemas from a folder hierarchy, use the `graphqlSchemas` block instead. | -| `graphqlSchemas` | *See
[graphqlSchemas](#option-graphqlschemas)* | All
`.graphqls`/`.graphql`
files in
resources | Block to define the input GraphQL schemas, when exact paths are too cumbersome. See table below for a list of options. *See [graphqlSchemas](#option-graphqlschemas)* | -| `graphqlQueryIntrospectionResu`
`ltPath` | String | None | Path to GraphQL Introspection Query result in json format (with root object `__schema` or `data.__schema`). Sample: [sample-introspection-query-result.json](../src/test/resources/introspection-result/sample-introspection-query-result.json) | -| `outputDir` | String | None | The output target directory into which code will be generated. | -| `configurationFiles` | List(String) | Empty | Paths to the files with mapping configurations. Supported formats. JSON, HOCON. Order of specified configuration files matters, so the default configuration should be placed at the end. | -| `packageName` | String | Empty | Java package for generated classes. | -| `apiPackageName` | String | Empty | Java package for generated api classes (Query, Mutation, Subscription). | -| `modelPackageName` | String | Empty | Java package for generated model classes (type, input, interface, enum, union). | -| `generateBuilder` | Boolean | True | Specifies whether generated model classes should have builder. | -| `generateApis` | Boolean | True | Specifies whether api classes should be generated as well as model classes. | -| `generateDataFetchingEnvironme`
`ntArgumentInApis` | Boolean | False | If true, then `graphql.schema.DataFetchingEnvironment env` will be added as a last argument to all methods of root type resolvers and field resolvers. | -| `generateEqualsAndHashCode` | Boolean | False | Specifies whether generated model classes should have equals and hashCode methods defined. | -| `generateParameterizedFieldsResolvers` | Boolean | True | Specifies whether separate `Resolver` interface for parametrized fields should be generated. If `false`, then add parametrized field to the type definition and ignore field parameters. If `true` then separate `Resolver` interface for parametrized fields will be generated. | -| `generateImmutableModels` | Boolean | False | Specifies whether generated model classes should be immutable. | -| `generateToString` | Boolean | False | Specifies whether generated model classes should have toString method defined. | -| `generateJacksonTypeIdResolver` | Boolean | False | Specifies whether generated union interfaces should be annotated with a custom Jackson type id resolver generated in model package. | -| `addGeneratedAnnotation` | Boolean | True | Specifies whether generated classes should have `@Generated` annotation. | -| `generatedAnnotation` | String | `jakarta.annotation.Generated`
`javax.annotation.Generated` | Qualified class name (with package) of the `@Generated` annotation that will be added on top of every generated class (if `addGeneratedAnnotation` is **true**) | -| `apiNamePrefix` | String | Empty | Sets the prefix for GraphQL api classes (query, mutation, subscription). | -| `apiNameSuffix` | String | `Resolver` | Sets the suffix for GraphQL api classes (query, mutation, subscription). | -| `apiInterfaceStrategy` | *See
[ApiInterfaceStrategy](#option-apiinterfacestrategy)* | `INTERFACE_PER_OPERATION` | *See [ApiInterfaceStrategy](#option-apiinterfacestrategy)* | -| `apiRootInterfaceStrategy` | *See
[ApiRootInterfaceStrategy](#option-apirootinterfacestrategy)* | `SINGLE_INTERFACE` | *See [ApiRootInterfaceStrategy](#option-apirootinterfacestrategy)* | -| `apiNamePrefixStrategy` | *See
[ApiNamePrefixStrategy](#option-apinameprefixstrategy)* | `CONSTANT` | *See [ApiNamePrefixStrategy](#option-apinameprefixstrategy)* | -| `modelNamePrefix` | String | Empty | Sets the prefix for GraphQL model classes (type, input, interface, enum, union). | -| `modelNameSuffix` | String | Empty | Sets the suffix for GraphQL model classes (type, input, interface, enum, union). | -| `modelValidationAnnotation` | String | `@javax.validation.`
`constraints.NotNull` | Annotation for mandatory (NonNull) fields. Can be null/empty. | -| `typeResolverPrefix` | String | Empty | Sets the prefix for GraphQL type resolver classes. | -| `typeResolverSuffix` | String | `Resolver` | Sets the suffix for GraphQL type resolver classes. | -| `customTypesMapping` | Map(String,String) | Empty | *See [CustomTypesMapping](#option-customtypesmapping)* | -| `customTemplatesRoot` | File | Project's dir | Use to supply the path the to custom FreeMarker templates root directory. | -| `customTemplates` | Map(String,String) | Empty | Use to supply paths to custom FreeMarker templates for code generation. | -| `customAnnotationsMapping` | Map(String,String[]) | Empty | *See [CustomAnnotationsMapping](#option-customannotationsmapping)* | -| `directiveAnnotationsMapping` | Map(String,String[]) | Empty | *See [DirectiveAnnotationsMapping](#option-directiveannotationsmapping)* | -| `fieldsWithResolvers` | Set(String) | Empty | Fields that require Resolvers should be defined here in format: `TypeName.fieldName` or `TypeName` or `@directive`. E.g.: `Person`, `Person.friends`, `@customResolver`. | -| `fieldsWithoutResolvers` | Set(String) | Empty | Fields that DO NOT require Resolvers should be defined here in format: `TypeName.fieldName` or `TypeName` or `@directive`. Can be used in conjunction with `generateExtensionFieldsResolvers` option. E.g.: `Person`, `Person.friends`, `@noResolver`. | -| `fieldsToExcludeFromGeneration` | Set(String) | Empty | Fields to exclude from generation should be defined here in format: `TypeName.fieldName`. | -| `resolverArgumentAnnotations` | Set(String) | Empty | Annotations that will be added to all resolver arguments. Can be used for [spring-graphql](https://github.com/spring-projects/spring-graphql) inegration by supplying: `org.springframework.graphql.data.method.annotation.Argument` | -| `parametrizedResolverAnnotations` | Set(String) | Empty | Annotations that will be added to all parametrized resolver methods. Can be used for [spring-graphql](https://github.com/spring-projects/spring-graphql) inegration by supplying: `org.springframework.graphql.data.method.annotation.SchemaMapping(typeName="{{TYPE_NAME}}")` | -| `generateParameterizedFieldsResolvers` | Boolean | True | If true, then generate separate `Resolver` interface for parametrized fields. If false, then add field to the type definition and ignore field parameters. | -| `generateExtensionFieldsResolvers` | Boolean | False | Specifies whether all fields in extensions (`extend type` and `extend interface`) should be present in Resolver interface instead of the type class itself. | -| `generateModelsForRootTypes` | Boolean | False | Specifies whether model classes should be generated for `type Query`, `type Subscription`, `type Mutation`. | -| `useOptionalForNullableReturnTypes` | Boolean | False | Specifies whether nullable return types of api methods should be wrapped into [`java.util.Optional<>`](https://docs.oracle.com/javase/8/docs/api/index.html?java/util/Optional.html). Lists will not be wrapped. | -| `generateApisWithThrowsException` | Boolean | True | Specifies whether api interface methods should have `throws Exception` in signature. | -| `generateApisWithSuspendFunctions` | Boolean | False | Specifies whether api interface methods should have `suspend` modifier in signature. Only supported in Kotlin. | -| `generateNoArgsConstructorOnly` | Boolean | False | Specifies whether model classes should only have a no-args constructor. All-args constructor will not be generated in case value is true | -| `generateModelsWithPublicFields` | Boolean | False | Specifies whether model classes should have public fields and NO getters/setters. By default, fields are private and there are getters/setters for each field. | -| `apiReturnType` | String | Empty | Return type for api methods (query/mutation). For example: `reactor.core.publisher.Mono`, etc. | -| `apiReturnListType` | String | Empty | Return type for api methods (query/mutation) having list type. For example: `reactor.core.publisher.Flux`, etc. By default is empty, so `apiReturnType` will be used. | -| `subscriptionReturnType` | String | Empty | Return type for subscription methods. For example: `org.reactivestreams.Publisher`, `io.reactivex.Observable`, etc. | -| `relayConfig` | *See
[RelayConfig](#option-relayconfig)* | `@connection(for: ...)` | *See [RelayConfig](#option-relayconfig)* | -| `generateClient` | Boolean | False | Specifies whether client-side classes should be generated for each query, mutation and subscription. This includes: `Request` classes (contain input data), `ResponseProjection` classes for each type (contain response fields) and `Response` classes (contain response data). | -| `requestSuffix` | String | Request | Sets the suffix for `Request` classes. | -| `responseSuffix` | String | Response | Sets the suffix for `Response` classes. | -| `responseProjectionSuffix` | String | ResponseProjection | Sets the suffix for `ResponseProjection` classes. | -| `parametrizedInputSuffix` | String | ParametrizedInput | Sets the suffix for `ParametrizedInput` classes. | -| `parentInterfaces` | *See
[parentInterfaces](#option-parentinterfaces)* | Empty | Block to define parent interfaces for generated interfaces (query / mutation / subscription / type resolver). *See [parentInterfaces](#option-parentinterfaces)* | -| `generateAllMethodInProjection` | Boolean | True | Enables whether the `all$()` method should be generated in the projection classes. Disabling enforces the client to select the fields manually. | -| `responseProjectionMaxDepth` | Integer | 3 | Sets max depth when use `all$()` which for facilitating the construction of projection automatically, the fields on all projections are provided when it be invoked. This is a global configuration, of course, you can use `all$(max)` to set for each method. For self recursive types, too big depth may result in a large number of returned data! | -| `generatedLanguage` | Enum | GeneratedLanguage.JAVA | Choose which language you want to generate, Java,Scala,Kotlin were supported. Note that due to language features, there are slight differences in default values between languages. | -| `generateModelOpenClasses` | Boolean | False | The class type of the generated model. If true, generate normal classes, else generate data classes. It only support in kotlin(```data class```) and scala(```case class```). Maybe we will consider to support Java ```record``` in the future. | -| `initializeNullableTypes` | Boolean | False | Adds a default null value to nullable arguments. Only supported in Kotlin. | -| `generateSealedInterfaces` | Boolean | False | This applies to generated interfaces on unions and interfaces. If true, generate sealed interfaces, else generate normal ones. It is only supported in Kotlin and Scala. | -| `typesAsInterfaces` | Set(String) | Empty | Types that must generated as interfaces should be defined here in format: `TypeName` or `@directive`. E.g.: `User`, `@asInterface`. | -| `useObjectMapperForRequestSerialization` | Set(String) | Empty | Fields that require serialization using `com.fasterxml.jackson.databind.ObjectMapper#writeValueAsString(Object)`. Values should be defined here in the following format: `GraphqlObjectName.fieldName` or `GraphqlTypeName`. If just type is specified, then all fields of this type will be serialized using ObjectMapper. E.g.: `["Person.createdDateTime", ZonedDateTime"]` | -| `supportUnknownFields` | Boolean | False | Specifies whether api classes should support unknown fields during serialization or deserialization. If `true`, classes will include a property of type [`java.util.Map`](https://docs.oracle.com/javase/8/docs/api/index.html?java/util/Map.html) that will store unknown fields. | -| `unknownFieldsPropertyName` | String | userDefinedFields | Specifies the name of the property to be included in api classes to support unknown fields during serialization or deserialization | -| `skip` | Boolean | False | If true, then code generation will not happen | -| `skipSchemaSizeLimit` | Boolean | True | When set to true, the GraphQL schema will be processed with token, character, line and rule depth limits. Set to false to process the schema regardless of its size. +| Option | Data Type | Default value | Description | +|:--------------------------------------------------------------:|:----------------------------------------------------------------------:|:--------------------------------------------------------------:|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `graphqlSchemaPaths` | List(String) | (falls back to `graphqlSchemas`) | GraphQL schema locations. You can supply multiple paths to GraphQL schemas. To include many schemas from a folder hierarchy, use the `graphqlSchemas` block instead. | +| `graphqlSchemas` | *See
[graphqlSchemas](#option-graphqlschemas)* | All
`.graphqls`/`.graphql`
files in
resources | Block to define the input GraphQL schemas, when exact paths are too cumbersome. See table below for a list of options. *See [graphqlSchemas](#option-graphqlschemas)* | +| `graphqlQueryIntrospectionResu`
`ltPath` | String | None | Path to GraphQL Introspection Query result in json format (with root object `__schema` or `data.__schema`). Sample: [sample-introspection-query-result.json](../src/test/resources/introspection-result/sample-introspection-query-result.json) | +| `outputDir` | String | None | The output target directory into which code will be generated. | +| `configurationFiles` | List(String) | Empty | Paths to the files with mapping configurations. Supported formats. JSON, HOCON. Order of specified configuration files matters, so the default configuration should be placed at the end. | +| `packageName` | String | Empty | Java package for generated classes. | +| `apiPackageName` | String | Empty | Java package for generated api classes (Query, Mutation, Subscription). | +| `modelPackageName` | String | Empty | Java package for generated model classes (type, input, interface, enum, union). | +| `generateBuilder` | Boolean | True | Specifies whether generated model classes should have builder. | +| `generateApis` | Boolean | True | Specifies whether api classes should be generated as well as model classes. | +| `generateDataFetchingEnvironme`
`ntArgumentInApis` | Boolean | False | If true, then `graphql.schema.DataFetchingEnvironment env` will be added as a last argument to all methods of root type resolvers and field resolvers. | +| `generateEqualsAndHashCode` | Boolean | False | Specifies whether generated model classes should have equals and hashCode methods defined. | +| `generateParameterizedFieldsResolvers` | Boolean | True | Specifies whether separate `Resolver` interface for parametrized fields should be generated. If `false`, then add parametrized field to the type definition and ignore field parameters. If `true` then separate `Resolver` interface for parametrized fields will be generated. | +| `generateImmutableModels` | Boolean | False | Specifies whether generated model classes should be immutable. | +| `generateToString` | Boolean | False | Specifies whether generated model classes should have toString method defined. | +| `generateJacksonTypeIdResolver` | Boolean | False | Specifies whether generated union interfaces should be annotated with a custom Jackson type id resolver generated in model package. | +| `addGeneratedAnnotation` | Boolean | True | Specifies whether generated classes should have `@Generated` annotation. | +| `generatedAnnotation` | String | `jakarta.annotation.Generated`
`javax.annotation.Generated` | Qualified class name (with package) of the `@Generated` annotation that will be added on top of every generated class (if `addGeneratedAnnotation` is **true**) | +| `apiNamePrefix` | String | Empty | Sets the prefix for GraphQL api classes (query, mutation, subscription). | +| `apiNameSuffix` | String | `Resolver` | Sets the suffix for GraphQL api classes (query, mutation, subscription). | +| `apiInterfaceStrategy` | *See
[ApiInterfaceStrategy](#option-apiinterfacestrategy)* | `INTERFACE_PER_OPERATION` | *See [ApiInterfaceStrategy](#option-apiinterfacestrategy)* | +| `apiRootInterfaceStrategy` | *See
[ApiRootInterfaceStrategy](#option-apirootinterfacestrategy)* | `SINGLE_INTERFACE` | *See [ApiRootInterfaceStrategy](#option-apirootinterfacestrategy)* | +| `apiNamePrefixStrategy` | *See
[ApiNamePrefixStrategy](#option-apinameprefixstrategy)* | `CONSTANT` | *See [ApiNamePrefixStrategy](#option-apinameprefixstrategy)* | +| `modelNamePrefix` | String | Empty | Sets the prefix for GraphQL model classes (type, input, interface, enum, union). | +| `modelNameSuffix` | String | Empty | Sets the suffix for GraphQL model classes (type, input, interface, enum, union). | +| `modelValidationAnnotation` | String | `@javax.validation.`
`constraints.NotNull` | Annotation for mandatory (NonNull) fields. Can be null/empty. | +| `typeResolverPrefix` | String | Empty | Sets the prefix for GraphQL type resolver classes. | +| `typeResolverSuffix` | String | `Resolver` | Sets the suffix for GraphQL type resolver classes. | +| `customTypesMapping` | Map(String,String) | Empty | *See [CustomTypesMapping](#option-customtypesmapping)* | +| `customTemplatesRoot` | File | Project's dir | Use to supply the path the to custom FreeMarker templates root directory. | +| `customTemplates` | Map(String,String) | Empty | Use to supply paths to custom FreeMarker templates for code generation. | +| `customAnnotationsMapping` | Map(String,String[]) | Empty | *See [CustomAnnotationsMapping](#option-customannotationsmapping)* | +| `directiveAnnotationsMapping` | Map(String,String[]) | Empty | *See [DirectiveAnnotationsMapping](#option-directiveannotationsmapping)* | +| `fieldsWithResolvers` | Set(String) | Empty | Fields that require Resolvers should be defined here in format: `TypeName.fieldName` or `TypeName` or `@directive`. E.g.: `Person`, `Person.friends`, `@customResolver`. | +| `fieldsWithoutResolvers` | Set(String) | Empty | Fields that DO NOT require Resolvers should be defined here in format: `TypeName.fieldName` or `TypeName` or `@directive`. Can be used in conjunction with `generateExtensionFieldsResolvers` option. E.g.: `Person`, `Person.friends`, `@noResolver`. | +| `fieldsToExcludeFromGeneration` | Set(String) | Empty | Fields to exclude from generation should be defined here in format: `TypeName.fieldName`. | +| `resolverArgumentAnnotations` | Set(String) | Empty | Annotations that will be added to all resolver arguments. Can be used for [spring-graphql](https://github.com/spring-projects/spring-graphql) inegration by supplying: `org.springframework.graphql.data.method.annotation.Argument` | +| `parametrizedResolverAnnotations` | Set(String) | Empty | Annotations that will be added to all parametrized resolver methods. Can be used for [spring-graphql](https://github.com/spring-projects/spring-graphql) inegration by supplying: `org.springframework.graphql.data.method.annotation.SchemaMapping(typeName="{{TYPE_NAME}}")` | +| `generateParameterizedFieldsResolvers` | Boolean | True | If true, then generate separate `Resolver` interface for parametrized fields. If false, then add field to the type definition and ignore field parameters. | +| `generateExtensionFieldsResolvers` | Boolean | False | Specifies whether all fields in extensions (`extend type` and `extend interface`) should be present in Resolver interface instead of the type class itself. | +| `generateModelsForRootTypes` | Boolean | False | Specifies whether model classes should be generated for `type Query`, `type Subscription`, `type Mutation`. | +| `useOptionalForNullableReturnTypes` | Boolean | False | Specifies whether nullable return types of api methods should be wrapped into [`java.util.Optional<>`](https://docs.oracle.com/javase/8/docs/api/index.html?java/util/Optional.html). Lists will not be wrapped. | +| `generateApisWithThrowsException` | Boolean | True | Specifies whether api interface methods should have `throws Exception` in signature. | +| `generateApisWithSuspendFunctions` | Boolean | False | Specifies whether api interface methods should have `suspend` modifier in signature. Only supported in Kotlin. | +| `generateNoArgsConstructorOnly` | Boolean | False | Specifies whether model classes should only have a no-args constructor. All-args constructor will not be generated in case value is true | +| `generateModelsWithPublicFields` | Boolean | False | Specifies whether model classes should have public fields and NO getters/setters. By default, fields are private and there are getters/setters for each field. | +| `apiReturnType` | String | Empty | Return type for api methods (query/mutation). For example: `reactor.core.publisher.Mono`, etc. | +| `apiReturnListType` | String | Empty | Return type for api methods (query/mutation) having list type. For example: `reactor.core.publisher.Flux`, etc. By default is empty, so `apiReturnType` will be used. | +| `subscriptionReturnType` | String | Empty | Return type for subscription methods. For example: `org.reactivestreams.Publisher`, `io.reactivex.Observable`, etc. | +| `relayConfig` | *See
[RelayConfig](#option-relayconfig)* | `@connection(for: ...)` | *See [RelayConfig](#option-relayconfig)* | +| `generateClient` | Boolean | False | Specifies whether client-side classes should be generated for each query, mutation and subscription. This includes: `Request` classes (contain input data), `ResponseProjection` classes for each type (contain response fields) and `Response` classes (contain response data). | +| `requestSuffix` | String | Request | Sets the suffix for `Request` classes. | +| `responseSuffix` | String | Response | Sets the suffix for `Response` classes. | +| `responseProjectionSuffix` | String | ResponseProjection | Sets the suffix for `ResponseProjection` classes. | +| `parametrizedInputSuffix` | String | ParametrizedInput | Sets the suffix for `ParametrizedInput` classes. | +| `parentInterfaces` | *See
[parentInterfaces](#option-parentinterfaces)* | Empty | Block to define parent interfaces for generated interfaces (query / mutation / subscription / type resolver). *See [parentInterfaces](#option-parentinterfaces)* | +| `generateAllMethodInProjection` | Boolean | True | Enables whether the `all$()` method should be generated in the projection classes. Disabling enforces the client to select the fields manually. | +| `responseProjectionMaxDepth` | Integer | 3 | Sets max depth when use `all$()` which for facilitating the construction of projection automatically, the fields on all projections are provided when it be invoked. This is a global configuration, of course, you can use `all$(max)` to set for each method. For self recursive types, too big depth may result in a large number of returned data! | +| `generatedLanguage` | Enum | GeneratedLanguage.JAVA | Choose which language you want to generate, Java,Scala,Kotlin were supported. Note that due to language features, there are slight differences in default values between languages. | +| `generateModelOpenClasses` | Boolean | False | The class type of the generated model. If true, generate normal classes, else generate data classes. It only support in kotlin(```data class```) and scala(```case class```). Maybe we will consider to support Java ```record``` in the future. | +| `initializeNullableTypes` | Boolean | False | Adds a default null value to nullable arguments. Only supported in Kotlin. | +| `generateSealedInterfaces` | Boolean | False | This applies to generated interfaces on unions and interfaces. If true, generate sealed interfaces, else generate normal ones. It is only supported in Kotlin and Scala. | +| `typesAsInterfaces` | Set(String) | Empty | Types that must generated as interfaces should be defined here in format: `TypeName` or `@directive`. E.g.: `User`, `@asInterface`. | +| `fieldsWithDataFetcherResult` | Set(String) | Empty | Types that must generated as interfaces should be defined here in format: `TypeName` or `@directive`. E.g.: `User`, `@dataFetcherResult`. | +| `useObjectMapperForRequestSerialization` | Set(String) | Empty | Fields that require serialization using `com.fasterxml.jackson.databind.ObjectMapper#writeValueAsString(Object)`. Values should be defined here in the following format: `GraphqlObjectName.fieldName` or `GraphqlTypeName`. If just type is specified, then all fields of this type will be serialized using ObjectMapper. E.g.: `["Person.createdDateTime", ZonedDateTime"]` | +| `supportUnknownFields` | Boolean | False | Specifies whether api classes should support unknown fields during serialization or deserialization. If `true`, classes will include a property of type [`java.util.Map`](https://docs.oracle.com/javase/8/docs/api/index.html?java/util/Map.html) that will store unknown fields. | +| `unknownFieldsPropertyName` | String | userDefinedFields | Specifies the name of the property to be included in api classes to support unknown fields during serialization or deserialization | +| `skip` | Boolean | False | If true, then code generation will not happen | +| `skipSchemaSizeLimit` | Boolean | True | When set to true, the GraphQL schema will be processed with token, character, line and rule depth limits. Set to false to process the schema regardless of its size. | From 73f964b7b4d806528df8c61e3b5778d8f28e4d85 Mon Sep 17 00:00:00 2001 From: Kirill Shiryaev Date: Wed, 6 Dec 2023 20:33:30 -0300 Subject: [PATCH 03/19] fix mapping context --- .../kobylynskyi/graphql/codegen/model/MappingConfig.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingConfig.java b/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingConfig.java index 05762152a..2bb72a786 100644 --- a/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingConfig.java +++ b/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingConfig.java @@ -608,13 +608,13 @@ public Set getFieldsToExcludeFromGeneration() { return fieldsToExcludeFromGeneration; } - public void setFieldsWithDataFetcherResult(Set fieldsToExcludeFromGeneration) { - this.fieldsToExcludeFromGeneration = fieldsToExcludeFromGeneration; + public void setFieldsWithDataFetcherResult(Set fieldsWithDataFetcherResult) { + this.fieldsWithDataFetcherResult = fieldsWithDataFetcherResult; } @Override public Set getFieldsWithDataFetcherResult() { - return fieldsToExcludeFromGeneration; + return fieldsWithDataFetcherResult; } public void setFieldsToExcludeFromGeneration(Set fieldsToExcludeFromGeneration) { From 6b101299583227a98fe4669562741043497af9bb Mon Sep 17 00:00:00 2001 From: Kirill Shiryaev Date: Wed, 6 Dec 2023 21:19:05 -0300 Subject: [PATCH 04/19] add test schema --- .../fields-with-data-fetcher-result.graphqls | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 src/test/resources/schemas/fields-with-data-fetcher-result.graphqls diff --git a/src/test/resources/schemas/fields-with-data-fetcher-result.graphqls b/src/test/resources/schemas/fields-with-data-fetcher-result.graphqls new file mode 100644 index 000000000..3a51590bd --- /dev/null +++ b/src/test/resources/schemas/fields-with-data-fetcher-result.graphqls @@ -0,0 +1,22 @@ +# A GraphQL schema provides a root type for each kind of operation. +schema { + # The query root. + query: Query +} + +type Query { + userCurrent: User +} + +type User { + username: String! + email: String! + orders: [Order!]! @dataFetcherResult +} + +type Order { + number: String! + price: String! +} + +directive @dataFetcherResult on FIELD_DEFINITION From 7472db701a6da9ed240bbccd199e1782021765b2 Mon Sep 17 00:00:00 2001 From: Kirill Shiryaev Date: Tue, 12 Dec 2023 10:46:16 -0300 Subject: [PATCH 05/19] update field mapper --- .../graphql/codegen/java/JavaGraphQLTypeMapper.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/java/com/kobylynskyi/graphql/codegen/java/JavaGraphQLTypeMapper.java b/src/main/java/com/kobylynskyi/graphql/codegen/java/JavaGraphQLTypeMapper.java index 223aa953a..fbdce8d70 100644 --- a/src/main/java/com/kobylynskyi/graphql/codegen/java/JavaGraphQLTypeMapper.java +++ b/src/main/java/com/kobylynskyi/graphql/codegen/java/JavaGraphQLTypeMapper.java @@ -116,6 +116,12 @@ public NamedDefinition getLanguageType(MappingContext mappingContext, String gra } else { langTypeName = DataModelMapper.getModelClassNameWithPrefixAndSuffix(mappingContext, graphQLType); } + + var fieldsWithWithDataFetcherResult = mappingContext.getFieldsWithDataFetcherResult(); + if (fieldsWithWithDataFetcherResult.contains(name)) { + langTypeName = wrapWithDataFetcherResult(langTypeName); + } + if (serializeFieldsUsingObjectMapper.contains(graphQLType) || (name != null && parentTypeName != null && serializeFieldsUsingObjectMapper.contains(parentTypeName + "." + name))) { @@ -126,4 +132,7 @@ public NamedDefinition getLanguageType(MappingContext mappingContext, String gra mandatory, primitiveCanBeUsed, serializeUsingObjectMapper); } + private String wrapWithDataFetcherResult(String typeName) { + return "graphql.execution.DataFetcherResult<" + typeName + ">"; + } } \ No newline at end of file From 6e21534305b9558aefd5788f52b6ba613134b280 Mon Sep 17 00:00:00 2001 From: Kirill Shiryaev Date: Tue, 12 Dec 2023 10:46:27 -0300 Subject: [PATCH 06/19] add tests --- .../schemas/fields-with-data-fetcher-result.graphqls | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/test/resources/schemas/fields-with-data-fetcher-result.graphqls b/src/test/resources/schemas/fields-with-data-fetcher-result.graphqls index 3a51590bd..4964dd74d 100644 --- a/src/test/resources/schemas/fields-with-data-fetcher-result.graphqls +++ b/src/test/resources/schemas/fields-with-data-fetcher-result.graphqls @@ -12,6 +12,7 @@ type User { username: String! email: String! orders: [Order!]! @dataFetcherResult + cart: Cart! @dataFetcherResult } type Order { @@ -19,4 +20,8 @@ type Order { price: String! } +type Cart { + id: Long! +} + directive @dataFetcherResult on FIELD_DEFINITION From 142db6f8ffdd789dc67f0bb83b8876e2a7199bee Mon Sep 17 00:00:00 2001 From: Kirill Shiryaev Date: Tue, 12 Dec 2023 10:46:40 -0300 Subject: [PATCH 07/19] add tests --- ...odegenFieldsWithDataFetcherResultTest.java | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenFieldsWithDataFetcherResultTest.java diff --git a/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenFieldsWithDataFetcherResultTest.java b/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenFieldsWithDataFetcherResultTest.java new file mode 100644 index 000000000..f506183f6 --- /dev/null +++ b/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenFieldsWithDataFetcherResultTest.java @@ -0,0 +1,61 @@ +package com.kobylynskyi.graphql.codegen; + +import com.kobylynskyi.graphql.codegen.java.JavaGraphQLCodegen; +import com.kobylynskyi.graphql.codegen.model.MappingConfig; +import com.kobylynskyi.graphql.codegen.utils.Utils; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; + +import static java.util.Arrays.asList; +import static java.util.Collections.singleton; +import static java.util.Collections.singletonList; +import static java.util.stream.Collectors.toList; +import static org.junit.jupiter.api.Assertions.assertEquals; + +class GraphQLCodegenFieldsWithDataFetcherResultTest { + + private final File outputBuildDir = new File("build/generated"); + private final File outputJavaClassesDir = new File("build/generated/com/github/graphql"); + private final MappingConfig mappingConfig = new MappingConfig(); + + @BeforeEach + void init() { + mappingConfig.setPackageName("com.github.graphql"); + mappingConfig.setFieldsWithDataFetcherResult(new HashSet<>(singleton("@dataFetcherResult"))); + } + + @AfterEach + void cleanup() { + Utils.deleteDir(outputBuildDir); + } + + @Test + void generate_fieldsWithDataFetcherResult() throws Exception { + mappingConfig.getFieldsWithDataFetcherResult().add("orders"); + mappingConfig.getFieldsWithDataFetcherResult().add("cart"); + + generate("src/test/resources/schemas/fields-with-data-fetcher-result.graphqls"); + + File[] files = Objects.requireNonNull(outputJavaClassesDir.listFiles()); + Assertions.assertNotNull(files); + + List generatedFileNames = Arrays.stream(files).map(File::getName).sorted().collect(toList()); + assertEquals(asList("Cart.java", "Order.java", "QueryResolver.java", "User.java", "UserCurrentQueryResolver.java"), generatedFileNames); + } + + private void generate(String o) throws IOException { + new JavaGraphQLCodegen(singletonList(o), outputBuildDir, mappingConfig, + TestUtils.getStaticGeneratedInfo(mappingConfig)) + .generate(); + } + +} From 3576f357af82a4329f58c5447e5246cfe68042cb Mon Sep 17 00:00:00 2001 From: Kirill Shiryaev Date: Tue, 12 Dec 2023 11:09:00 -0300 Subject: [PATCH 08/19] add fields assertion for generated test files --- .../GraphQLCodegenFieldsWithDataFetcherResultTest.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenFieldsWithDataFetcherResultTest.java b/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenFieldsWithDataFetcherResultTest.java index f506183f6..a55dc0f3c 100644 --- a/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenFieldsWithDataFetcherResultTest.java +++ b/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenFieldsWithDataFetcherResultTest.java @@ -15,11 +15,13 @@ import java.util.List; import java.util.Objects; +import static com.kobylynskyi.graphql.codegen.TestUtils.getFileByName; import static java.util.Arrays.asList; import static java.util.Collections.singleton; import static java.util.Collections.singletonList; import static java.util.stream.Collectors.toList; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; class GraphQLCodegenFieldsWithDataFetcherResultTest { @@ -50,6 +52,12 @@ void generate_fieldsWithDataFetcherResult() throws Exception { List generatedFileNames = Arrays.stream(files).map(File::getName).sorted().collect(toList()); assertEquals(asList("Cart.java", "Order.java", "QueryResolver.java", "User.java", "UserCurrentQueryResolver.java"), generatedFileNames); + + File user = getFileByName(files, "User.java"); + String userContext = Utils.getFileContent(user.getPath()).trim(); + + assertTrue(userContext.contains("java.util.List>")); + assertTrue(userContext.contains("graphql.execution.DataFetcherResult")); } private void generate(String o) throws IOException { @@ -57,5 +65,4 @@ private void generate(String o) throws IOException { TestUtils.getStaticGeneratedInfo(mappingConfig)) .generate(); } - } From 79b4fdc41349cca94dcb9aa7b2f00a040a5b8b3f Mon Sep 17 00:00:00 2001 From: Kirill Shiryaev Date: Tue, 12 Dec 2023 11:46:57 -0300 Subject: [PATCH 09/19] Fix logic --- .../codegen/java/JavaGraphQLTypeMapper.java | 12 +++-- .../FieldDefinitionToParameterMapper.java | 2 +- .../codegen/mapper/GraphQLTypeMapper.java | 45 ++++++++++++++++--- ...phQLCodegenFieldsWithDataFetcherTest.java} | 2 +- 4 files changed, 51 insertions(+), 10 deletions(-) rename src/test/java/com/kobylynskyi/graphql/codegen/{GraphQLCodegenFieldsWithDataFetcherResultTest.java => GraphQLCodegenFieldsWithDataFetcherTest.java} (98%) diff --git a/src/main/java/com/kobylynskyi/graphql/codegen/java/JavaGraphQLTypeMapper.java b/src/main/java/com/kobylynskyi/graphql/codegen/java/JavaGraphQLTypeMapper.java index fbdce8d70..d4fb622b5 100644 --- a/src/main/java/com/kobylynskyi/graphql/codegen/java/JavaGraphQLTypeMapper.java +++ b/src/main/java/com/kobylynskyi/graphql/codegen/java/JavaGraphQLTypeMapper.java @@ -7,12 +7,15 @@ import com.kobylynskyi.graphql.codegen.model.NamedDefinition; import com.kobylynskyi.graphql.codegen.model.graphql.GraphQLOperation; import com.kobylynskyi.graphql.codegen.utils.Utils; +import graphql.language.Directive; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Collectors; import static java.util.Arrays.asList; @@ -102,7 +105,7 @@ public boolean isPrimitive(String possiblyPrimitiveType) { @Override public NamedDefinition getLanguageType(MappingContext mappingContext, String graphQLType, String name, - String parentTypeName, boolean mandatory, boolean collection) { + String parentTypeName, boolean mandatory, boolean collection, List directives) { Map customTypesMapping = mappingContext.getCustomTypesMapping(); Set serializeFieldsUsingObjectMapper = mappingContext.getUseObjectMapperForRequestSerialization(); String langTypeName; @@ -117,8 +120,11 @@ public NamedDefinition getLanguageType(MappingContext mappingContext, String gra langTypeName = DataModelMapper.getModelClassNameWithPrefixAndSuffix(mappingContext, graphQLType); } - var fieldsWithWithDataFetcherResult = mappingContext.getFieldsWithDataFetcherResult(); - if (fieldsWithWithDataFetcherResult.contains(name)) { + Set fieldsWithDataFetcherResult = mappingContext.getFieldsWithDataFetcherResult(); + Set directivesNames = directives.stream() + .map(directive -> "@" + directive.getName()) + .collect(Collectors.toSet()); + if (directivesNames.stream().anyMatch(fieldsWithDataFetcherResult::contains)) { langTypeName = wrapWithDataFetcherResult(langTypeName); } diff --git a/src/main/java/com/kobylynskyi/graphql/codegen/mapper/FieldDefinitionToParameterMapper.java b/src/main/java/com/kobylynskyi/graphql/codegen/mapper/FieldDefinitionToParameterMapper.java index 14d83d5f6..386bed10b 100644 --- a/src/main/java/com/kobylynskyi/graphql/codegen/mapper/FieldDefinitionToParameterMapper.java +++ b/src/main/java/com/kobylynskyi/graphql/codegen/mapper/FieldDefinitionToParameterMapper.java @@ -146,7 +146,7 @@ private ParameterDefinition mapField(MappingContext mappingContext, ExtendedFieldDefinition fieldDef, ExtendedDefinition parentDefinition) { NamedDefinition namedDefinition = graphQLTypeMapper - .getLanguageType(mappingContext, fieldDef.getType(), fieldDef.getName(), parentDefinition.getName()); + .getLanguageType(mappingContext, fieldDef.getType(), fieldDef.getName(), parentDefinition.getName(), fieldDef.getDirectives()); ParameterDefinition parameter = new ParameterDefinition(); parameter.setName(dataModelMapper.capitalizeIfRestricted(mappingContext, fieldDef.getName())); diff --git a/src/main/java/com/kobylynskyi/graphql/codegen/mapper/GraphQLTypeMapper.java b/src/main/java/com/kobylynskyi/graphql/codegen/mapper/GraphQLTypeMapper.java index 0b1e372e6..0d30ba134 100644 --- a/src/main/java/com/kobylynskyi/graphql/codegen/mapper/GraphQLTypeMapper.java +++ b/src/main/java/com/kobylynskyi/graphql/codegen/mapper/GraphQLTypeMapper.java @@ -4,6 +4,7 @@ import com.kobylynskyi.graphql.codegen.model.NamedDefinition; import com.kobylynskyi.graphql.codegen.model.RelayConfig; import com.kobylynskyi.graphql.codegen.model.definitions.ExtendedFieldDefinition; +import graphql.com.google.common.collect.ImmutableList; import graphql.language.Argument; import graphql.language.Directive; import graphql.language.DirectivesContainer; @@ -161,6 +162,21 @@ public NamedDefinition getLanguageType(MappingContext mappingContext, Type gr return getLanguageType(mappingContext, graphqlType, name, parentTypeName, false, false); } + /** + * Convert GraphQL type to a corresponding language-specific type (java/scala/kotlin/etc) + * + * @param mappingContext Global mapping context + * @param graphqlType GraphQL type + * @param name GraphQL type name + * @param parentTypeName Name of the parent type + * @param directives GraphQL field directives + * @return Corresponding language-specific type (java/scala/kotlin/etc) + */ + public NamedDefinition getLanguageType(MappingContext mappingContext, Type graphqlType, String name, + String parentTypeName, List directives) { + return getLanguageType(mappingContext, graphqlType, name, parentTypeName, false, false, directives); + } + /** * Convert GraphQL type to a corresponding language-specific type (java/scala/kotlin/etc) * @@ -175,12 +191,30 @@ public NamedDefinition getLanguageType(MappingContext mappingContext, Type gr public NamedDefinition getLanguageType(MappingContext mappingContext, Type graphqlType, String name, String parentTypeName, boolean mandatory, boolean collection) { + return getLanguageType(mappingContext, graphqlType, name, parentTypeName, mandatory, collection, Collections.emptyList()); + } + + /** + * Convert GraphQL type to a corresponding language-specific type (java/scala/kotlin/etc) + * + * @param mappingContext Global mapping context + * @param graphqlType GraphQL type + * @param name GraphQL type name + * @param parentTypeName Name of the parent type + * @param mandatory GraphQL type is non-null + * @param collection GraphQL type is collection + * @param directives GraphQL field directives + * @return Corresponding language-specific type (java/scala/kotlin/etc) + */ + public NamedDefinition getLanguageType(MappingContext mappingContext, Type graphqlType, + String name, String parentTypeName, + boolean mandatory, boolean collection, List directives) { if (graphqlType instanceof TypeName) { return getLanguageType(mappingContext, ((TypeName) graphqlType).getName(), name, parentTypeName, mandatory, - collection); + collection, directives); } else if (graphqlType instanceof ListType) { NamedDefinition mappedCollectionType = getLanguageType(mappingContext, ((ListType) graphqlType).getType(), - name, parentTypeName, false, true); + name, parentTypeName, false, true, directives); if (mappedCollectionType.isInterfaceOrUnion() && isInterfaceOrUnion(mappingContext, parentTypeName)) { mappedCollectionType.setJavaName( @@ -192,7 +226,7 @@ public NamedDefinition getLanguageType(MappingContext mappingContext, Type gr return mappedCollectionType; } else if (graphqlType instanceof NonNullType) { return getLanguageType(mappingContext, ((NonNullType) graphqlType).getType(), name, parentTypeName, true, - collection); + collection, directives); } throw new IllegalArgumentException("Unknown type: " + graphqlType); } @@ -206,10 +240,12 @@ public NamedDefinition getLanguageType(MappingContext mappingContext, Type gr * @param parentTypeName Name of the parent type * @param mandatory GraphQL type is non-null * @param collection GraphQL type is collection + * @param directives GraphQL field directives * @return Corresponding language-specific type (java/scala/kotlin/etc) */ public NamedDefinition getLanguageType(MappingContext mappingContext, String graphQLType, String name, - String parentTypeName, boolean mandatory, boolean collection) { + String parentTypeName, boolean mandatory, boolean collection, + List directives) { Map customTypesMapping = mappingContext.getCustomTypesMapping(); Set serializeFieldsUsingObjectMapper = mappingContext.getUseObjectMapperForRequestSerialization(); String langTypeName; @@ -273,5 +309,4 @@ protected boolean isInterfaceOrUnion(MappingContext mappingContext, String graph return mappingContext.getInterfacesName().contains(graphQLType) || mappingContext.getUnionsNames().contains(graphQLType); } - } diff --git a/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenFieldsWithDataFetcherResultTest.java b/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenFieldsWithDataFetcherTest.java similarity index 98% rename from src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenFieldsWithDataFetcherResultTest.java rename to src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenFieldsWithDataFetcherTest.java index a55dc0f3c..0ddc41a9f 100644 --- a/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenFieldsWithDataFetcherResultTest.java +++ b/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenFieldsWithDataFetcherTest.java @@ -23,7 +23,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; -class GraphQLCodegenFieldsWithDataFetcherResultTest { +class GraphQLCodegenFieldsWithDataFetcherTest { private final File outputBuildDir = new File("build/generated"); private final File outputJavaClassesDir = new File("build/generated/com/github/graphql"); From 2f9342f1811dae1ffbbe530e4040cfe6d7a5cb74 Mon Sep 17 00:00:00 2001 From: Kirill Shiryaev Date: Fri, 15 Dec 2023 14:39:35 -0300 Subject: [PATCH 10/19] Fix code style --- .../codegen/GraphQLCodegenFieldsWithDataFetcherTest.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenFieldsWithDataFetcherTest.java b/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenFieldsWithDataFetcherTest.java index 0ddc41a9f..137b14bc9 100644 --- a/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenFieldsWithDataFetcherTest.java +++ b/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenFieldsWithDataFetcherTest.java @@ -51,7 +51,10 @@ void generate_fieldsWithDataFetcherResult() throws Exception { Assertions.assertNotNull(files); List generatedFileNames = Arrays.stream(files).map(File::getName).sorted().collect(toList()); - assertEquals(asList("Cart.java", "Order.java", "QueryResolver.java", "User.java", "UserCurrentQueryResolver.java"), generatedFileNames); + assertEquals( + asList("Cart.java", "Order.java", "QueryResolver.java", "User.java", "UserCurrentQueryResolver.java"), + generatedFileNames + ); File user = getFileByName(files, "User.java"); String userContext = Utils.getFileContent(user.getPath()).trim(); From b873e45de50d62ccf3556105ccbd8cee02e7bba6 Mon Sep 17 00:00:00 2001 From: Kirill Shiryaev Date: Fri, 15 Dec 2023 15:06:54 -0300 Subject: [PATCH 11/19] Fix code style --- .../graphql/codegen/java/JavaGraphQLTypeMapper.java | 3 ++- .../kobylynskyi/graphql/codegen/mapper/GraphQLTypeMapper.java | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/kobylynskyi/graphql/codegen/java/JavaGraphQLTypeMapper.java b/src/main/java/com/kobylynskyi/graphql/codegen/java/JavaGraphQLTypeMapper.java index d4fb622b5..abdf455a9 100644 --- a/src/main/java/com/kobylynskyi/graphql/codegen/java/JavaGraphQLTypeMapper.java +++ b/src/main/java/com/kobylynskyi/graphql/codegen/java/JavaGraphQLTypeMapper.java @@ -105,7 +105,8 @@ public boolean isPrimitive(String possiblyPrimitiveType) { @Override public NamedDefinition getLanguageType(MappingContext mappingContext, String graphQLType, String name, - String parentTypeName, boolean mandatory, boolean collection, List directives) { + String parentTypeName, boolean mandatory, boolean collection, + List directives) { Map customTypesMapping = mappingContext.getCustomTypesMapping(); Set serializeFieldsUsingObjectMapper = mappingContext.getUseObjectMapperForRequestSerialization(); String langTypeName; diff --git a/src/main/java/com/kobylynskyi/graphql/codegen/mapper/GraphQLTypeMapper.java b/src/main/java/com/kobylynskyi/graphql/codegen/mapper/GraphQLTypeMapper.java index 0d30ba134..927510727 100644 --- a/src/main/java/com/kobylynskyi/graphql/codegen/mapper/GraphQLTypeMapper.java +++ b/src/main/java/com/kobylynskyi/graphql/codegen/mapper/GraphQLTypeMapper.java @@ -4,7 +4,6 @@ import com.kobylynskyi.graphql.codegen.model.NamedDefinition; import com.kobylynskyi.graphql.codegen.model.RelayConfig; import com.kobylynskyi.graphql.codegen.model.definitions.ExtendedFieldDefinition; -import graphql.com.google.common.collect.ImmutableList; import graphql.language.Argument; import graphql.language.Directive; import graphql.language.DirectivesContainer; From 2c6c564a664c69b5fedae720b44095b2e226a755 Mon Sep 17 00:00:00 2001 From: Kirill Shiryaev Date: Fri, 15 Dec 2023 15:09:31 -0300 Subject: [PATCH 12/19] Fix code style --- .../graphql/codegen/mapper/GraphQLTypeMapper.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/kobylynskyi/graphql/codegen/mapper/GraphQLTypeMapper.java b/src/main/java/com/kobylynskyi/graphql/codegen/mapper/GraphQLTypeMapper.java index 927510727..df21251e0 100644 --- a/src/main/java/com/kobylynskyi/graphql/codegen/mapper/GraphQLTypeMapper.java +++ b/src/main/java/com/kobylynskyi/graphql/codegen/mapper/GraphQLTypeMapper.java @@ -173,7 +173,9 @@ public NamedDefinition getLanguageType(MappingContext mappingContext, Type gr */ public NamedDefinition getLanguageType(MappingContext mappingContext, Type graphqlType, String name, String parentTypeName, List directives) { - return getLanguageType(mappingContext, graphqlType, name, parentTypeName, false, false, directives); + return getLanguageType(mappingContext, graphqlType, name, parentTypeName, false, false, + directives + ); } /** @@ -190,7 +192,9 @@ public NamedDefinition getLanguageType(MappingContext mappingContext, Type gr public NamedDefinition getLanguageType(MappingContext mappingContext, Type graphqlType, String name, String parentTypeName, boolean mandatory, boolean collection) { - return getLanguageType(mappingContext, graphqlType, name, parentTypeName, mandatory, collection, Collections.emptyList()); + return getLanguageType(mappingContext, graphqlType, name, parentTypeName, mandatory, collection, + Collections.emptyList() + ); } /** @@ -224,8 +228,8 @@ public NamedDefinition getLanguageType(MappingContext mappingContext, Type gr } return mappedCollectionType; } else if (graphqlType instanceof NonNullType) { - return getLanguageType(mappingContext, ((NonNullType) graphqlType).getType(), name, parentTypeName, true, - collection, directives); + return getLanguageType(mappingContext, ((NonNullType) graphqlType).getType(), name, parentTypeName, + true, collection, directives); } throw new IllegalArgumentException("Unknown type: " + graphqlType); } From 83d7c21011ced4ec033910c9a7d99f3e135456fd Mon Sep 17 00:00:00 2001 From: Kirill Shiryaev Date: Fri, 15 Dec 2023 15:11:33 -0300 Subject: [PATCH 13/19] Fix code style --- .../codegen/mapper/FieldDefinitionToParameterMapper.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/kobylynskyi/graphql/codegen/mapper/FieldDefinitionToParameterMapper.java b/src/main/java/com/kobylynskyi/graphql/codegen/mapper/FieldDefinitionToParameterMapper.java index 386bed10b..9165b08f9 100644 --- a/src/main/java/com/kobylynskyi/graphql/codegen/mapper/FieldDefinitionToParameterMapper.java +++ b/src/main/java/com/kobylynskyi/graphql/codegen/mapper/FieldDefinitionToParameterMapper.java @@ -146,7 +146,9 @@ private ParameterDefinition mapField(MappingContext mappingContext, ExtendedFieldDefinition fieldDef, ExtendedDefinition parentDefinition) { NamedDefinition namedDefinition = graphQLTypeMapper - .getLanguageType(mappingContext, fieldDef.getType(), fieldDef.getName(), parentDefinition.getName(), fieldDef.getDirectives()); + .getLanguageType(mappingContext, fieldDef.getType(), fieldDef.getName(), parentDefinition.getName(), + fieldDef.getDirectives() + ); ParameterDefinition parameter = new ParameterDefinition(); parameter.setName(dataModelMapper.capitalizeIfRestricted(mappingContext, fieldDef.getName())); From 983c10721e6d3a37f32b7a7b689beddfa5906c47 Mon Sep 17 00:00:00 2001 From: Kirill Shiryaev Date: Fri, 15 Dec 2023 15:24:59 -0300 Subject: [PATCH 14/19] Fix description --- docs/codegen-options.md | 140 ++++++++++++++++++++-------------------- 1 file changed, 70 insertions(+), 70 deletions(-) diff --git a/docs/codegen-options.md b/docs/codegen-options.md index 98e0fd74a..d4720ad89 100644 --- a/docs/codegen-options.md +++ b/docs/codegen-options.md @@ -1,76 +1,76 @@ # Codegen Options -| Option | Data Type | Default value | Description | -|:--------------------------------------------------------------:|:----------------------------------------------------------------------:|:--------------------------------------------------------------:|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `graphqlSchemaPaths` | List(String) | (falls back to `graphqlSchemas`) | GraphQL schema locations. You can supply multiple paths to GraphQL schemas. To include many schemas from a folder hierarchy, use the `graphqlSchemas` block instead. | -| `graphqlSchemas` | *See
[graphqlSchemas](#option-graphqlschemas)* | All
`.graphqls`/`.graphql`
files in
resources | Block to define the input GraphQL schemas, when exact paths are too cumbersome. See table below for a list of options. *See [graphqlSchemas](#option-graphqlschemas)* | -| `graphqlQueryIntrospectionResu`
`ltPath` | String | None | Path to GraphQL Introspection Query result in json format (with root object `__schema` or `data.__schema`). Sample: [sample-introspection-query-result.json](../src/test/resources/introspection-result/sample-introspection-query-result.json) | -| `outputDir` | String | None | The output target directory into which code will be generated. | -| `configurationFiles` | List(String) | Empty | Paths to the files with mapping configurations. Supported formats. JSON, HOCON. Order of specified configuration files matters, so the default configuration should be placed at the end. | -| `packageName` | String | Empty | Java package for generated classes. | -| `apiPackageName` | String | Empty | Java package for generated api classes (Query, Mutation, Subscription). | -| `modelPackageName` | String | Empty | Java package for generated model classes (type, input, interface, enum, union). | -| `generateBuilder` | Boolean | True | Specifies whether generated model classes should have builder. | -| `generateApis` | Boolean | True | Specifies whether api classes should be generated as well as model classes. | -| `generateDataFetchingEnvironme`
`ntArgumentInApis` | Boolean | False | If true, then `graphql.schema.DataFetchingEnvironment env` will be added as a last argument to all methods of root type resolvers and field resolvers. | -| `generateEqualsAndHashCode` | Boolean | False | Specifies whether generated model classes should have equals and hashCode methods defined. | -| `generateParameterizedFieldsResolvers` | Boolean | True | Specifies whether separate `Resolver` interface for parametrized fields should be generated. If `false`, then add parametrized field to the type definition and ignore field parameters. If `true` then separate `Resolver` interface for parametrized fields will be generated. | -| `generateImmutableModels` | Boolean | False | Specifies whether generated model classes should be immutable. | -| `generateToString` | Boolean | False | Specifies whether generated model classes should have toString method defined. | -| `generateJacksonTypeIdResolver` | Boolean | False | Specifies whether generated union interfaces should be annotated with a custom Jackson type id resolver generated in model package. | -| `addGeneratedAnnotation` | Boolean | True | Specifies whether generated classes should have `@Generated` annotation. | -| `generatedAnnotation` | String | `jakarta.annotation.Generated`
`javax.annotation.Generated` | Qualified class name (with package) of the `@Generated` annotation that will be added on top of every generated class (if `addGeneratedAnnotation` is **true**) | -| `apiNamePrefix` | String | Empty | Sets the prefix for GraphQL api classes (query, mutation, subscription). | -| `apiNameSuffix` | String | `Resolver` | Sets the suffix for GraphQL api classes (query, mutation, subscription). | -| `apiInterfaceStrategy` | *See
[ApiInterfaceStrategy](#option-apiinterfacestrategy)* | `INTERFACE_PER_OPERATION` | *See [ApiInterfaceStrategy](#option-apiinterfacestrategy)* | -| `apiRootInterfaceStrategy` | *See
[ApiRootInterfaceStrategy](#option-apirootinterfacestrategy)* | `SINGLE_INTERFACE` | *See [ApiRootInterfaceStrategy](#option-apirootinterfacestrategy)* | -| `apiNamePrefixStrategy` | *See
[ApiNamePrefixStrategy](#option-apinameprefixstrategy)* | `CONSTANT` | *See [ApiNamePrefixStrategy](#option-apinameprefixstrategy)* | -| `modelNamePrefix` | String | Empty | Sets the prefix for GraphQL model classes (type, input, interface, enum, union). | -| `modelNameSuffix` | String | Empty | Sets the suffix for GraphQL model classes (type, input, interface, enum, union). | -| `modelValidationAnnotation` | String | `@javax.validation.`
`constraints.NotNull` | Annotation for mandatory (NonNull) fields. Can be null/empty. | -| `typeResolverPrefix` | String | Empty | Sets the prefix for GraphQL type resolver classes. | -| `typeResolverSuffix` | String | `Resolver` | Sets the suffix for GraphQL type resolver classes. | -| `customTypesMapping` | Map(String,String) | Empty | *See [CustomTypesMapping](#option-customtypesmapping)* | -| `customTemplatesRoot` | File | Project's dir | Use to supply the path the to custom FreeMarker templates root directory. | -| `customTemplates` | Map(String,String) | Empty | Use to supply paths to custom FreeMarker templates for code generation. | -| `customAnnotationsMapping` | Map(String,String[]) | Empty | *See [CustomAnnotationsMapping](#option-customannotationsmapping)* | -| `directiveAnnotationsMapping` | Map(String,String[]) | Empty | *See [DirectiveAnnotationsMapping](#option-directiveannotationsmapping)* | -| `fieldsWithResolvers` | Set(String) | Empty | Fields that require Resolvers should be defined here in format: `TypeName.fieldName` or `TypeName` or `@directive`. E.g.: `Person`, `Person.friends`, `@customResolver`. | -| `fieldsWithoutResolvers` | Set(String) | Empty | Fields that DO NOT require Resolvers should be defined here in format: `TypeName.fieldName` or `TypeName` or `@directive`. Can be used in conjunction with `generateExtensionFieldsResolvers` option. E.g.: `Person`, `Person.friends`, `@noResolver`. | -| `fieldsToExcludeFromGeneration` | Set(String) | Empty | Fields to exclude from generation should be defined here in format: `TypeName.fieldName`. | -| `resolverArgumentAnnotations` | Set(String) | Empty | Annotations that will be added to all resolver arguments. Can be used for [spring-graphql](https://github.com/spring-projects/spring-graphql) inegration by supplying: `org.springframework.graphql.data.method.annotation.Argument` | -| `parametrizedResolverAnnotations` | Set(String) | Empty | Annotations that will be added to all parametrized resolver methods. Can be used for [spring-graphql](https://github.com/spring-projects/spring-graphql) inegration by supplying: `org.springframework.graphql.data.method.annotation.SchemaMapping(typeName="{{TYPE_NAME}}")` | -| `generateParameterizedFieldsResolvers` | Boolean | True | If true, then generate separate `Resolver` interface for parametrized fields. If false, then add field to the type definition and ignore field parameters. | -| `generateExtensionFieldsResolvers` | Boolean | False | Specifies whether all fields in extensions (`extend type` and `extend interface`) should be present in Resolver interface instead of the type class itself. | -| `generateModelsForRootTypes` | Boolean | False | Specifies whether model classes should be generated for `type Query`, `type Subscription`, `type Mutation`. | -| `useOptionalForNullableReturnTypes` | Boolean | False | Specifies whether nullable return types of api methods should be wrapped into [`java.util.Optional<>`](https://docs.oracle.com/javase/8/docs/api/index.html?java/util/Optional.html). Lists will not be wrapped. | -| `generateApisWithThrowsException` | Boolean | True | Specifies whether api interface methods should have `throws Exception` in signature. | -| `generateApisWithSuspendFunctions` | Boolean | False | Specifies whether api interface methods should have `suspend` modifier in signature. Only supported in Kotlin. | -| `generateNoArgsConstructorOnly` | Boolean | False | Specifies whether model classes should only have a no-args constructor. All-args constructor will not be generated in case value is true | -| `generateModelsWithPublicFields` | Boolean | False | Specifies whether model classes should have public fields and NO getters/setters. By default, fields are private and there are getters/setters for each field. | -| `apiReturnType` | String | Empty | Return type for api methods (query/mutation). For example: `reactor.core.publisher.Mono`, etc. | -| `apiReturnListType` | String | Empty | Return type for api methods (query/mutation) having list type. For example: `reactor.core.publisher.Flux`, etc. By default is empty, so `apiReturnType` will be used. | -| `subscriptionReturnType` | String | Empty | Return type for subscription methods. For example: `org.reactivestreams.Publisher`, `io.reactivex.Observable`, etc. | -| `relayConfig` | *See
[RelayConfig](#option-relayconfig)* | `@connection(for: ...)` | *See [RelayConfig](#option-relayconfig)* | -| `generateClient` | Boolean | False | Specifies whether client-side classes should be generated for each query, mutation and subscription. This includes: `Request` classes (contain input data), `ResponseProjection` classes for each type (contain response fields) and `Response` classes (contain response data). | -| `requestSuffix` | String | Request | Sets the suffix for `Request` classes. | -| `responseSuffix` | String | Response | Sets the suffix for `Response` classes. | -| `responseProjectionSuffix` | String | ResponseProjection | Sets the suffix for `ResponseProjection` classes. | -| `parametrizedInputSuffix` | String | ParametrizedInput | Sets the suffix for `ParametrizedInput` classes. | -| `parentInterfaces` | *See
[parentInterfaces](#option-parentinterfaces)* | Empty | Block to define parent interfaces for generated interfaces (query / mutation / subscription / type resolver). *See [parentInterfaces](#option-parentinterfaces)* | -| `generateAllMethodInProjection` | Boolean | True | Enables whether the `all$()` method should be generated in the projection classes. Disabling enforces the client to select the fields manually. | -| `responseProjectionMaxDepth` | Integer | 3 | Sets max depth when use `all$()` which for facilitating the construction of projection automatically, the fields on all projections are provided when it be invoked. This is a global configuration, of course, you can use `all$(max)` to set for each method. For self recursive types, too big depth may result in a large number of returned data! | -| `generatedLanguage` | Enum | GeneratedLanguage.JAVA | Choose which language you want to generate, Java,Scala,Kotlin were supported. Note that due to language features, there are slight differences in default values between languages. | -| `generateModelOpenClasses` | Boolean | False | The class type of the generated model. If true, generate normal classes, else generate data classes. It only support in kotlin(```data class```) and scala(```case class```). Maybe we will consider to support Java ```record``` in the future. | -| `initializeNullableTypes` | Boolean | False | Adds a default null value to nullable arguments. Only supported in Kotlin. | -| `generateSealedInterfaces` | Boolean | False | This applies to generated interfaces on unions and interfaces. If true, generate sealed interfaces, else generate normal ones. It is only supported in Kotlin and Scala. | -| `typesAsInterfaces` | Set(String) | Empty | Types that must generated as interfaces should be defined here in format: `TypeName` or `@directive`. E.g.: `User`, `@asInterface`. | -| `fieldsWithDataFetcherResult` | Set(String) | Empty | Types that must generated as interfaces should be defined here in format: `TypeName` or `@directive`. E.g.: `User`, `@dataFetcherResult`. | +| Option | Data Type | Default value | Description | +|:--------------------------------------------------------------:|:----------------------------------------------------------------------:|:--------------------------------------------------------------:|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `graphqlSchemaPaths` | List(String) | (falls back to `graphqlSchemas`) | GraphQL schema locations. You can supply multiple paths to GraphQL schemas. To include many schemas from a folder hierarchy, use the `graphqlSchemas` block instead. | +| `graphqlSchemas` | *See
[graphqlSchemas](#option-graphqlschemas)* | All
`.graphqls`/`.graphql`
files in
resources | Block to define the input GraphQL schemas, when exact paths are too cumbersome. See table below for a list of options. *See [graphqlSchemas](#option-graphqlschemas)* | +| `graphqlQueryIntrospectionResu`
`ltPath` | String | None | Path to GraphQL Introspection Query result in json format (with root object `__schema` or `data.__schema`). Sample: [sample-introspection-query-result.json](../src/test/resources/introspection-result/sample-introspection-query-result.json) | +| `outputDir` | String | None | The output target directory into which code will be generated. | +| `configurationFiles` | List(String) | Empty | Paths to the files with mapping configurations. Supported formats. JSON, HOCON. Order of specified configuration files matters, so the default configuration should be placed at the end. | +| `packageName` | String | Empty | Java package for generated classes. | +| `apiPackageName` | String | Empty | Java package for generated api classes (Query, Mutation, Subscription). | +| `modelPackageName` | String | Empty | Java package for generated model classes (type, input, interface, enum, union). | +| `generateBuilder` | Boolean | True | Specifies whether generated model classes should have builder. | +| `generateApis` | Boolean | True | Specifies whether api classes should be generated as well as model classes. | +| `generateDataFetchingEnvironme`
`ntArgumentInApis` | Boolean | False | If true, then `graphql.schema.DataFetchingEnvironment env` will be added as a last argument to all methods of root type resolvers and field resolvers. | +| `generateEqualsAndHashCode` | Boolean | False | Specifies whether generated model classes should have equals and hashCode methods defined. | +| `generateParameterizedFieldsResolvers` | Boolean | True | Specifies whether separate `Resolver` interface for parametrized fields should be generated. If `false`, then add parametrized field to the type definition and ignore field parameters. If `true` then separate `Resolver` interface for parametrized fields will be generated. | +| `generateImmutableModels` | Boolean | False | Specifies whether generated model classes should be immutable. | +| `generateToString` | Boolean | False | Specifies whether generated model classes should have toString method defined. | +| `generateJacksonTypeIdResolver` | Boolean | False | Specifies whether generated union interfaces should be annotated with a custom Jackson type id resolver generated in model package. | +| `addGeneratedAnnotation` | Boolean | True | Specifies whether generated classes should have `@Generated` annotation. | +| `generatedAnnotation` | String | `jakarta.annotation.Generated`
`javax.annotation.Generated` | Qualified class name (with package) of the `@Generated` annotation that will be added on top of every generated class (if `addGeneratedAnnotation` is **true**) | +| `apiNamePrefix` | String | Empty | Sets the prefix for GraphQL api classes (query, mutation, subscription). | +| `apiNameSuffix` | String | `Resolver` | Sets the suffix for GraphQL api classes (query, mutation, subscription). | +| `apiInterfaceStrategy` | *See
[ApiInterfaceStrategy](#option-apiinterfacestrategy)* | `INTERFACE_PER_OPERATION` | *See [ApiInterfaceStrategy](#option-apiinterfacestrategy)* | +| `apiRootInterfaceStrategy` | *See
[ApiRootInterfaceStrategy](#option-apirootinterfacestrategy)* | `SINGLE_INTERFACE` | *See [ApiRootInterfaceStrategy](#option-apirootinterfacestrategy)* | +| `apiNamePrefixStrategy` | *See
[ApiNamePrefixStrategy](#option-apinameprefixstrategy)* | `CONSTANT` | *See [ApiNamePrefixStrategy](#option-apinameprefixstrategy)* | +| `modelNamePrefix` | String | Empty | Sets the prefix for GraphQL model classes (type, input, interface, enum, union). | +| `modelNameSuffix` | String | Empty | Sets the suffix for GraphQL model classes (type, input, interface, enum, union). | +| `modelValidationAnnotation` | String | `@javax.validation.`
`constraints.NotNull` | Annotation for mandatory (NonNull) fields. Can be null/empty. | +| `typeResolverPrefix` | String | Empty | Sets the prefix for GraphQL type resolver classes. | +| `typeResolverSuffix` | String | `Resolver` | Sets the suffix for GraphQL type resolver classes. | +| `customTypesMapping` | Map(String,String) | Empty | *See [CustomTypesMapping](#option-customtypesmapping)* | +| `customTemplatesRoot` | File | Project's dir | Use to supply the path the to custom FreeMarker templates root directory. | +| `customTemplates` | Map(String,String) | Empty | Use to supply paths to custom FreeMarker templates for code generation. | +| `customAnnotationsMapping` | Map(String,String[]) | Empty | *See [CustomAnnotationsMapping](#option-customannotationsmapping)* | +| `directiveAnnotationsMapping` | Map(String,String[]) | Empty | *See [DirectiveAnnotationsMapping](#option-directiveannotationsmapping)* | +| `fieldsWithResolvers` | Set(String) | Empty | Fields that require Resolvers should be defined here in format: `TypeName.fieldName` or `TypeName` or `@directive`. E.g.: `Person`, `Person.friends`, `@customResolver`. | +| `fieldsWithoutResolvers` | Set(String) | Empty | Fields that DO NOT require Resolvers should be defined here in format: `TypeName.fieldName` or `TypeName` or `@directive`. Can be used in conjunction with `generateExtensionFieldsResolvers` option. E.g.: `Person`, `Person.friends`, `@noResolver`. | +| `fieldsToExcludeFromGeneration` | Set(String) | Empty | Fields to exclude from generation should be defined here in format: `TypeName.fieldName`. | +| `resolverArgumentAnnotations` | Set(String) | Empty | Annotations that will be added to all resolver arguments. Can be used for [spring-graphql](https://github.com/spring-projects/spring-graphql) inegration by supplying: `org.springframework.graphql.data.method.annotation.Argument` | +| `parametrizedResolverAnnotations` | Set(String) | Empty | Annotations that will be added to all parametrized resolver methods. Can be used for [spring-graphql](https://github.com/spring-projects/spring-graphql) inegration by supplying: `org.springframework.graphql.data.method.annotation.SchemaMapping(typeName="{{TYPE_NAME}}")` | +| `generateParameterizedFieldsResolvers` | Boolean | True | If true, then generate separate `Resolver` interface for parametrized fields. If false, then add field to the type definition and ignore field parameters. | +| `generateExtensionFieldsResolvers` | Boolean | False | Specifies whether all fields in extensions (`extend type` and `extend interface`) should be present in Resolver interface instead of the type class itself. | +| `generateModelsForRootTypes` | Boolean | False | Specifies whether model classes should be generated for `type Query`, `type Subscription`, `type Mutation`. | +| `useOptionalForNullableReturnTypes` | Boolean | False | Specifies whether nullable return types of api methods should be wrapped into [`java.util.Optional<>`](https://docs.oracle.com/javase/8/docs/api/index.html?java/util/Optional.html). Lists will not be wrapped. | +| `generateApisWithThrowsException` | Boolean | True | Specifies whether api interface methods should have `throws Exception` in signature. | +| `generateApisWithSuspendFunctions` | Boolean | False | Specifies whether api interface methods should have `suspend` modifier in signature. Only supported in Kotlin. | +| `generateNoArgsConstructorOnly` | Boolean | False | Specifies whether model classes should only have a no-args constructor. All-args constructor will not be generated in case value is true | +| `generateModelsWithPublicFields` | Boolean | False | Specifies whether model classes should have public fields and NO getters/setters. By default, fields are private and there are getters/setters for each field. | +| `apiReturnType` | String | Empty | Return type for api methods (query/mutation). For example: `reactor.core.publisher.Mono`, etc. | +| `apiReturnListType` | String | Empty | Return type for api methods (query/mutation) having list type. For example: `reactor.core.publisher.Flux`, etc. By default is empty, so `apiReturnType` will be used. | +| `subscriptionReturnType` | String | Empty | Return type for subscription methods. For example: `org.reactivestreams.Publisher`, `io.reactivex.Observable`, etc. | +| `relayConfig` | *See
[RelayConfig](#option-relayconfig)* | `@connection(for: ...)` | *See [RelayConfig](#option-relayconfig)* | +| `generateClient` | Boolean | False | Specifies whether client-side classes should be generated for each query, mutation and subscription. This includes: `Request` classes (contain input data), `ResponseProjection` classes for each type (contain response fields) and `Response` classes (contain response data). | +| `requestSuffix` | String | Request | Sets the suffix for `Request` classes. | +| `responseSuffix` | String | Response | Sets the suffix for `Response` classes. | +| `responseProjectionSuffix` | String | ResponseProjection | Sets the suffix for `ResponseProjection` classes. | +| `parametrizedInputSuffix` | String | ParametrizedInput | Sets the suffix for `ParametrizedInput` classes. | +| `parentInterfaces` | *See
[parentInterfaces](#option-parentinterfaces)* | Empty | Block to define parent interfaces for generated interfaces (query / mutation / subscription / type resolver). *See [parentInterfaces](#option-parentinterfaces)* | +| `generateAllMethodInProjection` | Boolean | True | Enables whether the `all$()` method should be generated in the projection classes. Disabling enforces the client to select the fields manually. | +| `responseProjectionMaxDepth` | Integer | 3 | Sets max depth when use `all$()` which for facilitating the construction of projection automatically, the fields on all projections are provided when it be invoked. This is a global configuration, of course, you can use `all$(max)` to set for each method. For self recursive types, too big depth may result in a large number of returned data! | +| `generatedLanguage` | Enum | GeneratedLanguage.JAVA | Choose which language you want to generate, Java,Scala,Kotlin were supported. Note that due to language features, there are slight differences in default values between languages. | +| `generateModelOpenClasses` | Boolean | False | The class type of the generated model. If true, generate normal classes, else generate data classes. It only support in kotlin(```data class```) and scala(```case class```). Maybe we will consider to support Java ```record``` in the future. | +| `initializeNullableTypes` | Boolean | False | Adds a default null value to nullable arguments. Only supported in Kotlin. | +| `generateSealedInterfaces` | Boolean | False | This applies to generated interfaces on unions and interfaces. If true, generate sealed interfaces, else generate normal ones. It is only supported in Kotlin and Scala. | +| `typesAsInterfaces` | Set(String) | Empty | Types that must generated as interfaces should be defined here in format: `TypeName` or `@directive`. E.g.: `User`, `@asInterface`. | +| `fieldsWithDataFetcherResult` | Set(String) | Empty | Types that must have DataFetchResult should be defined here in format: `@directive`. E.g.: `@dataFetcherResult`. | | `useObjectMapperForRequestSerialization` | Set(String) | Empty | Fields that require serialization using `com.fasterxml.jackson.databind.ObjectMapper#writeValueAsString(Object)`. Values should be defined here in the following format: `GraphqlObjectName.fieldName` or `GraphqlTypeName`. If just type is specified, then all fields of this type will be serialized using ObjectMapper. E.g.: `["Person.createdDateTime", ZonedDateTime"]` | -| `supportUnknownFields` | Boolean | False | Specifies whether api classes should support unknown fields during serialization or deserialization. If `true`, classes will include a property of type [`java.util.Map`](https://docs.oracle.com/javase/8/docs/api/index.html?java/util/Map.html) that will store unknown fields. | -| `unknownFieldsPropertyName` | String | userDefinedFields | Specifies the name of the property to be included in api classes to support unknown fields during serialization or deserialization | -| `skip` | Boolean | False | If true, then code generation will not happen | -| `skipSchemaSizeLimit` | Boolean | True | When set to true, the GraphQL schema will be processed with token, character, line and rule depth limits. Set to false to process the schema regardless of its size. +| `supportUnknownFields` | Boolean | False | Specifies whether api classes should support unknown fields during serialization or deserialization. If `true`, classes will include a property of type [`java.util.Map`](https://docs.oracle.com/javase/8/docs/api/index.html?java/util/Map.html) that will store unknown fields. | +| `unknownFieldsPropertyName` | String | userDefinedFields | Specifies the name of the property to be included in api classes to support unknown fields during serialization or deserialization | +| `skip` | Boolean | False | If true, then code generation will not happen | +| `skipSchemaSizeLimit` | Boolean | True | When set to true, the GraphQL schema will be processed with token, character, line and rule depth limits. Set to false to process the schema regardless of its size. | From 592957ff992a744adcc6e8c1485387c836874026 Mon Sep 17 00:00:00 2001 From: Kirill Shiryaev Date: Wed, 10 Jan 2024 13:14:59 -0300 Subject: [PATCH 15/19] Add code generation based on Type name or field name --- docs/codegen-options.md | 140 +++++++++--------- .../codegen/java/JavaGraphQLTypeMapper.java | 33 +++-- 2 files changed, 93 insertions(+), 80 deletions(-) diff --git a/docs/codegen-options.md b/docs/codegen-options.md index d4720ad89..d34df1e41 100644 --- a/docs/codegen-options.md +++ b/docs/codegen-options.md @@ -1,76 +1,76 @@ # Codegen Options -| Option | Data Type | Default value | Description | -|:--------------------------------------------------------------:|:----------------------------------------------------------------------:|:--------------------------------------------------------------:|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `graphqlSchemaPaths` | List(String) | (falls back to `graphqlSchemas`) | GraphQL schema locations. You can supply multiple paths to GraphQL schemas. To include many schemas from a folder hierarchy, use the `graphqlSchemas` block instead. | -| `graphqlSchemas` | *See
[graphqlSchemas](#option-graphqlschemas)* | All
`.graphqls`/`.graphql`
files in
resources | Block to define the input GraphQL schemas, when exact paths are too cumbersome. See table below for a list of options. *See [graphqlSchemas](#option-graphqlschemas)* | -| `graphqlQueryIntrospectionResu`
`ltPath` | String | None | Path to GraphQL Introspection Query result in json format (with root object `__schema` or `data.__schema`). Sample: [sample-introspection-query-result.json](../src/test/resources/introspection-result/sample-introspection-query-result.json) | -| `outputDir` | String | None | The output target directory into which code will be generated. | -| `configurationFiles` | List(String) | Empty | Paths to the files with mapping configurations. Supported formats. JSON, HOCON. Order of specified configuration files matters, so the default configuration should be placed at the end. | -| `packageName` | String | Empty | Java package for generated classes. | -| `apiPackageName` | String | Empty | Java package for generated api classes (Query, Mutation, Subscription). | -| `modelPackageName` | String | Empty | Java package for generated model classes (type, input, interface, enum, union). | -| `generateBuilder` | Boolean | True | Specifies whether generated model classes should have builder. | -| `generateApis` | Boolean | True | Specifies whether api classes should be generated as well as model classes. | -| `generateDataFetchingEnvironme`
`ntArgumentInApis` | Boolean | False | If true, then `graphql.schema.DataFetchingEnvironment env` will be added as a last argument to all methods of root type resolvers and field resolvers. | -| `generateEqualsAndHashCode` | Boolean | False | Specifies whether generated model classes should have equals and hashCode methods defined. | -| `generateParameterizedFieldsResolvers` | Boolean | True | Specifies whether separate `Resolver` interface for parametrized fields should be generated. If `false`, then add parametrized field to the type definition and ignore field parameters. If `true` then separate `Resolver` interface for parametrized fields will be generated. | -| `generateImmutableModels` | Boolean | False | Specifies whether generated model classes should be immutable. | -| `generateToString` | Boolean | False | Specifies whether generated model classes should have toString method defined. | -| `generateJacksonTypeIdResolver` | Boolean | False | Specifies whether generated union interfaces should be annotated with a custom Jackson type id resolver generated in model package. | -| `addGeneratedAnnotation` | Boolean | True | Specifies whether generated classes should have `@Generated` annotation. | -| `generatedAnnotation` | String | `jakarta.annotation.Generated`
`javax.annotation.Generated` | Qualified class name (with package) of the `@Generated` annotation that will be added on top of every generated class (if `addGeneratedAnnotation` is **true**) | -| `apiNamePrefix` | String | Empty | Sets the prefix for GraphQL api classes (query, mutation, subscription). | -| `apiNameSuffix` | String | `Resolver` | Sets the suffix for GraphQL api classes (query, mutation, subscription). | -| `apiInterfaceStrategy` | *See
[ApiInterfaceStrategy](#option-apiinterfacestrategy)* | `INTERFACE_PER_OPERATION` | *See [ApiInterfaceStrategy](#option-apiinterfacestrategy)* | -| `apiRootInterfaceStrategy` | *See
[ApiRootInterfaceStrategy](#option-apirootinterfacestrategy)* | `SINGLE_INTERFACE` | *See [ApiRootInterfaceStrategy](#option-apirootinterfacestrategy)* | -| `apiNamePrefixStrategy` | *See
[ApiNamePrefixStrategy](#option-apinameprefixstrategy)* | `CONSTANT` | *See [ApiNamePrefixStrategy](#option-apinameprefixstrategy)* | -| `modelNamePrefix` | String | Empty | Sets the prefix for GraphQL model classes (type, input, interface, enum, union). | -| `modelNameSuffix` | String | Empty | Sets the suffix for GraphQL model classes (type, input, interface, enum, union). | -| `modelValidationAnnotation` | String | `@javax.validation.`
`constraints.NotNull` | Annotation for mandatory (NonNull) fields. Can be null/empty. | -| `typeResolverPrefix` | String | Empty | Sets the prefix for GraphQL type resolver classes. | -| `typeResolverSuffix` | String | `Resolver` | Sets the suffix for GraphQL type resolver classes. | -| `customTypesMapping` | Map(String,String) | Empty | *See [CustomTypesMapping](#option-customtypesmapping)* | -| `customTemplatesRoot` | File | Project's dir | Use to supply the path the to custom FreeMarker templates root directory. | -| `customTemplates` | Map(String,String) | Empty | Use to supply paths to custom FreeMarker templates for code generation. | -| `customAnnotationsMapping` | Map(String,String[]) | Empty | *See [CustomAnnotationsMapping](#option-customannotationsmapping)* | -| `directiveAnnotationsMapping` | Map(String,String[]) | Empty | *See [DirectiveAnnotationsMapping](#option-directiveannotationsmapping)* | -| `fieldsWithResolvers` | Set(String) | Empty | Fields that require Resolvers should be defined here in format: `TypeName.fieldName` or `TypeName` or `@directive`. E.g.: `Person`, `Person.friends`, `@customResolver`. | -| `fieldsWithoutResolvers` | Set(String) | Empty | Fields that DO NOT require Resolvers should be defined here in format: `TypeName.fieldName` or `TypeName` or `@directive`. Can be used in conjunction with `generateExtensionFieldsResolvers` option. E.g.: `Person`, `Person.friends`, `@noResolver`. | -| `fieldsToExcludeFromGeneration` | Set(String) | Empty | Fields to exclude from generation should be defined here in format: `TypeName.fieldName`. | -| `resolverArgumentAnnotations` | Set(String) | Empty | Annotations that will be added to all resolver arguments. Can be used for [spring-graphql](https://github.com/spring-projects/spring-graphql) inegration by supplying: `org.springframework.graphql.data.method.annotation.Argument` | -| `parametrizedResolverAnnotations` | Set(String) | Empty | Annotations that will be added to all parametrized resolver methods. Can be used for [spring-graphql](https://github.com/spring-projects/spring-graphql) inegration by supplying: `org.springframework.graphql.data.method.annotation.SchemaMapping(typeName="{{TYPE_NAME}}")` | -| `generateParameterizedFieldsResolvers` | Boolean | True | If true, then generate separate `Resolver` interface for parametrized fields. If false, then add field to the type definition and ignore field parameters. | -| `generateExtensionFieldsResolvers` | Boolean | False | Specifies whether all fields in extensions (`extend type` and `extend interface`) should be present in Resolver interface instead of the type class itself. | -| `generateModelsForRootTypes` | Boolean | False | Specifies whether model classes should be generated for `type Query`, `type Subscription`, `type Mutation`. | -| `useOptionalForNullableReturnTypes` | Boolean | False | Specifies whether nullable return types of api methods should be wrapped into [`java.util.Optional<>`](https://docs.oracle.com/javase/8/docs/api/index.html?java/util/Optional.html). Lists will not be wrapped. | -| `generateApisWithThrowsException` | Boolean | True | Specifies whether api interface methods should have `throws Exception` in signature. | -| `generateApisWithSuspendFunctions` | Boolean | False | Specifies whether api interface methods should have `suspend` modifier in signature. Only supported in Kotlin. | -| `generateNoArgsConstructorOnly` | Boolean | False | Specifies whether model classes should only have a no-args constructor. All-args constructor will not be generated in case value is true | -| `generateModelsWithPublicFields` | Boolean | False | Specifies whether model classes should have public fields and NO getters/setters. By default, fields are private and there are getters/setters for each field. | -| `apiReturnType` | String | Empty | Return type for api methods (query/mutation). For example: `reactor.core.publisher.Mono`, etc. | -| `apiReturnListType` | String | Empty | Return type for api methods (query/mutation) having list type. For example: `reactor.core.publisher.Flux`, etc. By default is empty, so `apiReturnType` will be used. | -| `subscriptionReturnType` | String | Empty | Return type for subscription methods. For example: `org.reactivestreams.Publisher`, `io.reactivex.Observable`, etc. | -| `relayConfig` | *See
[RelayConfig](#option-relayconfig)* | `@connection(for: ...)` | *See [RelayConfig](#option-relayconfig)* | -| `generateClient` | Boolean | False | Specifies whether client-side classes should be generated for each query, mutation and subscription. This includes: `Request` classes (contain input data), `ResponseProjection` classes for each type (contain response fields) and `Response` classes (contain response data). | -| `requestSuffix` | String | Request | Sets the suffix for `Request` classes. | -| `responseSuffix` | String | Response | Sets the suffix for `Response` classes. | -| `responseProjectionSuffix` | String | ResponseProjection | Sets the suffix for `ResponseProjection` classes. | -| `parametrizedInputSuffix` | String | ParametrizedInput | Sets the suffix for `ParametrizedInput` classes. | -| `parentInterfaces` | *See
[parentInterfaces](#option-parentinterfaces)* | Empty | Block to define parent interfaces for generated interfaces (query / mutation / subscription / type resolver). *See [parentInterfaces](#option-parentinterfaces)* | -| `generateAllMethodInProjection` | Boolean | True | Enables whether the `all$()` method should be generated in the projection classes. Disabling enforces the client to select the fields manually. | -| `responseProjectionMaxDepth` | Integer | 3 | Sets max depth when use `all$()` which for facilitating the construction of projection automatically, the fields on all projections are provided when it be invoked. This is a global configuration, of course, you can use `all$(max)` to set for each method. For self recursive types, too big depth may result in a large number of returned data! | -| `generatedLanguage` | Enum | GeneratedLanguage.JAVA | Choose which language you want to generate, Java,Scala,Kotlin were supported. Note that due to language features, there are slight differences in default values between languages. | -| `generateModelOpenClasses` | Boolean | False | The class type of the generated model. If true, generate normal classes, else generate data classes. It only support in kotlin(```data class```) and scala(```case class```). Maybe we will consider to support Java ```record``` in the future. | -| `initializeNullableTypes` | Boolean | False | Adds a default null value to nullable arguments. Only supported in Kotlin. | -| `generateSealedInterfaces` | Boolean | False | This applies to generated interfaces on unions and interfaces. If true, generate sealed interfaces, else generate normal ones. It is only supported in Kotlin and Scala. | -| `typesAsInterfaces` | Set(String) | Empty | Types that must generated as interfaces should be defined here in format: `TypeName` or `@directive`. E.g.: `User`, `@asInterface`. | -| `fieldsWithDataFetcherResult` | Set(String) | Empty | Types that must have DataFetchResult should be defined here in format: `@directive`. E.g.: `@dataFetcherResult`. | +| Option | Data Type | Default value | Description | +|:--------------------------------------------------------------:|:----------------------------------------------------------------------:|:--------------------------------------------------------------:|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `graphqlSchemaPaths` | List(String) | (falls back to `graphqlSchemas`) | GraphQL schema locations. You can supply multiple paths to GraphQL schemas. To include many schemas from a folder hierarchy, use the `graphqlSchemas` block instead. | +| `graphqlSchemas` | *See
[graphqlSchemas](#option-graphqlschemas)* | All
`.graphqls`/`.graphql`
files in
resources | Block to define the input GraphQL schemas, when exact paths are too cumbersome. See table below for a list of options. *See [graphqlSchemas](#option-graphqlschemas)* | +| `graphqlQueryIntrospectionResu`
`ltPath` | String | None | Path to GraphQL Introspection Query result in json format (with root object `__schema` or `data.__schema`). Sample: [sample-introspection-query-result.json](../src/test/resources/introspection-result/sample-introspection-query-result.json) | +| `outputDir` | String | None | The output target directory into which code will be generated. | +| `configurationFiles` | List(String) | Empty | Paths to the files with mapping configurations. Supported formats. JSON, HOCON. Order of specified configuration files matters, so the default configuration should be placed at the end. | +| `packageName` | String | Empty | Java package for generated classes. | +| `apiPackageName` | String | Empty | Java package for generated api classes (Query, Mutation, Subscription). | +| `modelPackageName` | String | Empty | Java package for generated model classes (type, input, interface, enum, union). | +| `generateBuilder` | Boolean | True | Specifies whether generated model classes should have builder. | +| `generateApis` | Boolean | True | Specifies whether api classes should be generated as well as model classes. | +| `generateDataFetchingEnvironme`
`ntArgumentInApis` | Boolean | False | If true, then `graphql.schema.DataFetchingEnvironment env` will be added as a last argument to all methods of root type resolvers and field resolvers. | +| `generateEqualsAndHashCode` | Boolean | False | Specifies whether generated model classes should have equals and hashCode methods defined. | +| `generateParameterizedFieldsResolvers` | Boolean | True | Specifies whether separate `Resolver` interface for parametrized fields should be generated. If `false`, then add parametrized field to the type definition and ignore field parameters. If `true` then separate `Resolver` interface for parametrized fields will be generated. | +| `generateImmutableModels` | Boolean | False | Specifies whether generated model classes should be immutable. | +| `generateToString` | Boolean | False | Specifies whether generated model classes should have toString method defined. | +| `generateJacksonTypeIdResolver` | Boolean | False | Specifies whether generated union interfaces should be annotated with a custom Jackson type id resolver generated in model package. | +| `addGeneratedAnnotation` | Boolean | True | Specifies whether generated classes should have `@Generated` annotation. | +| `generatedAnnotation` | String | `jakarta.annotation.Generated`
`javax.annotation.Generated` | Qualified class name (with package) of the `@Generated` annotation that will be added on top of every generated class (if `addGeneratedAnnotation` is **true**) | +| `apiNamePrefix` | String | Empty | Sets the prefix for GraphQL api classes (query, mutation, subscription). | +| `apiNameSuffix` | String | `Resolver` | Sets the suffix for GraphQL api classes (query, mutation, subscription). | +| `apiInterfaceStrategy` | *See
[ApiInterfaceStrategy](#option-apiinterfacestrategy)* | `INTERFACE_PER_OPERATION` | *See [ApiInterfaceStrategy](#option-apiinterfacestrategy)* | +| `apiRootInterfaceStrategy` | *See
[ApiRootInterfaceStrategy](#option-apirootinterfacestrategy)* | `SINGLE_INTERFACE` | *See [ApiRootInterfaceStrategy](#option-apirootinterfacestrategy)* | +| `apiNamePrefixStrategy` | *See
[ApiNamePrefixStrategy](#option-apinameprefixstrategy)* | `CONSTANT` | *See [ApiNamePrefixStrategy](#option-apinameprefixstrategy)* | +| `modelNamePrefix` | String | Empty | Sets the prefix for GraphQL model classes (type, input, interface, enum, union). | +| `modelNameSuffix` | String | Empty | Sets the suffix for GraphQL model classes (type, input, interface, enum, union). | +| `modelValidationAnnotation` | String | `@javax.validation.`
`constraints.NotNull` | Annotation for mandatory (NonNull) fields. Can be null/empty. | +| `typeResolverPrefix` | String | Empty | Sets the prefix for GraphQL type resolver classes. | +| `typeResolverSuffix` | String | `Resolver` | Sets the suffix for GraphQL type resolver classes. | +| `customTypesMapping` | Map(String,String) | Empty | *See [CustomTypesMapping](#option-customtypesmapping)* | +| `customTemplatesRoot` | File | Project's dir | Use to supply the path the to custom FreeMarker templates root directory. | +| `customTemplates` | Map(String,String) | Empty | Use to supply paths to custom FreeMarker templates for code generation. | +| `customAnnotationsMapping` | Map(String,String[]) | Empty | *See [CustomAnnotationsMapping](#option-customannotationsmapping)* | +| `directiveAnnotationsMapping` | Map(String,String[]) | Empty | *See [DirectiveAnnotationsMapping](#option-directiveannotationsmapping)* | +| `fieldsWithResolvers` | Set(String) | Empty | Fields that require Resolvers should be defined here in format: `TypeName.fieldName` or `TypeName` or `@directive`. E.g.: `Person`, `Person.friends`, `@customResolver`. | +| `fieldsWithoutResolvers` | Set(String) | Empty | Fields that DO NOT require Resolvers should be defined here in format: `TypeName.fieldName` or `TypeName` or `@directive`. Can be used in conjunction with `generateExtensionFieldsResolvers` option. E.g.: `Person`, `Person.friends`, `@noResolver`. | +| `fieldsToExcludeFromGeneration` | Set(String) | Empty | Fields to exclude from generation should be defined here in format: `TypeName.fieldName`. | +| `resolverArgumentAnnotations` | Set(String) | Empty | Annotations that will be added to all resolver arguments. Can be used for [spring-graphql](https://github.com/spring-projects/spring-graphql) inegration by supplying: `org.springframework.graphql.data.method.annotation.Argument` | +| `parametrizedResolverAnnotations` | Set(String) | Empty | Annotations that will be added to all parametrized resolver methods. Can be used for [spring-graphql](https://github.com/spring-projects/spring-graphql) inegration by supplying: `org.springframework.graphql.data.method.annotation.SchemaMapping(typeName="{{TYPE_NAME}}")` | +| `generateParameterizedFieldsResolvers` | Boolean | True | If true, then generate separate `Resolver` interface for parametrized fields. If false, then add field to the type definition and ignore field parameters. | +| `generateExtensionFieldsResolvers` | Boolean | False | Specifies whether all fields in extensions (`extend type` and `extend interface`) should be present in Resolver interface instead of the type class itself. | +| `generateModelsForRootTypes` | Boolean | False | Specifies whether model classes should be generated for `type Query`, `type Subscription`, `type Mutation`. | +| `useOptionalForNullableReturnTypes` | Boolean | False | Specifies whether nullable return types of api methods should be wrapped into [`java.util.Optional<>`](https://docs.oracle.com/javase/8/docs/api/index.html?java/util/Optional.html). Lists will not be wrapped. | +| `generateApisWithThrowsException` | Boolean | True | Specifies whether api interface methods should have `throws Exception` in signature. | +| `generateApisWithSuspendFunctions` | Boolean | False | Specifies whether api interface methods should have `suspend` modifier in signature. Only supported in Kotlin. | +| `generateNoArgsConstructorOnly` | Boolean | False | Specifies whether model classes should only have a no-args constructor. All-args constructor will not be generated in case value is true | +| `generateModelsWithPublicFields` | Boolean | False | Specifies whether model classes should have public fields and NO getters/setters. By default, fields are private and there are getters/setters for each field. | +| `apiReturnType` | String | Empty | Return type for api methods (query/mutation). For example: `reactor.core.publisher.Mono`, etc. | +| `apiReturnListType` | String | Empty | Return type for api methods (query/mutation) having list type. For example: `reactor.core.publisher.Flux`, etc. By default is empty, so `apiReturnType` will be used. | +| `subscriptionReturnType` | String | Empty | Return type for subscription methods. For example: `org.reactivestreams.Publisher`, `io.reactivex.Observable`, etc. | +| `relayConfig` | *See
[RelayConfig](#option-relayconfig)* | `@connection(for: ...)` | *See [RelayConfig](#option-relayconfig)* | +| `generateClient` | Boolean | False | Specifies whether client-side classes should be generated for each query, mutation and subscription. This includes: `Request` classes (contain input data), `ResponseProjection` classes for each type (contain response fields) and `Response` classes (contain response data). | +| `requestSuffix` | String | Request | Sets the suffix for `Request` classes. | +| `responseSuffix` | String | Response | Sets the suffix for `Response` classes. | +| `responseProjectionSuffix` | String | ResponseProjection | Sets the suffix for `ResponseProjection` classes. | +| `parametrizedInputSuffix` | String | ParametrizedInput | Sets the suffix for `ParametrizedInput` classes. | +| `parentInterfaces` | *See
[parentInterfaces](#option-parentinterfaces)* | Empty | Block to define parent interfaces for generated interfaces (query / mutation / subscription / type resolver). *See [parentInterfaces](#option-parentinterfaces)* | +| `generateAllMethodInProjection` | Boolean | True | Enables whether the `all$()` method should be generated in the projection classes. Disabling enforces the client to select the fields manually. | +| `responseProjectionMaxDepth` | Integer | 3 | Sets max depth when use `all$()` which for facilitating the construction of projection automatically, the fields on all projections are provided when it be invoked. This is a global configuration, of course, you can use `all$(max)` to set for each method. For self recursive types, too big depth may result in a large number of returned data! | +| `generatedLanguage` | Enum | GeneratedLanguage.JAVA | Choose which language you want to generate, Java,Scala,Kotlin were supported. Note that due to language features, there are slight differences in default values between languages. | +| `generateModelOpenClasses` | Boolean | False | The class type of the generated model. If true, generate normal classes, else generate data classes. It only support in kotlin(```data class```) and scala(```case class```). Maybe we will consider to support Java ```record``` in the future. | +| `initializeNullableTypes` | Boolean | False | Adds a default null value to nullable arguments. Only supported in Kotlin. | +| `generateSealedInterfaces` | Boolean | False | This applies to generated interfaces on unions and interfaces. If true, generate sealed interfaces, else generate normal ones. It is only supported in Kotlin and Scala. | +| `typesAsInterfaces` | Set(String) | Empty | Types that must generated as interfaces should be defined here in format: `TypeName` or `@directive`. E.g.: `User`, `@asInterface`. | +| `fieldsWithDataFetcherResult` | Set(String) | Empty | Types that must have DataFetchResult should be defined here in format: `TypeName`, or `TypeName.fieldName` or `@directive`. E.g.: `Item`, `Item.items` or `@dataFetcherResult`. | | `useObjectMapperForRequestSerialization` | Set(String) | Empty | Fields that require serialization using `com.fasterxml.jackson.databind.ObjectMapper#writeValueAsString(Object)`. Values should be defined here in the following format: `GraphqlObjectName.fieldName` or `GraphqlTypeName`. If just type is specified, then all fields of this type will be serialized using ObjectMapper. E.g.: `["Person.createdDateTime", ZonedDateTime"]` | -| `supportUnknownFields` | Boolean | False | Specifies whether api classes should support unknown fields during serialization or deserialization. If `true`, classes will include a property of type [`java.util.Map`](https://docs.oracle.com/javase/8/docs/api/index.html?java/util/Map.html) that will store unknown fields. | -| `unknownFieldsPropertyName` | String | userDefinedFields | Specifies the name of the property to be included in api classes to support unknown fields during serialization or deserialization | -| `skip` | Boolean | False | If true, then code generation will not happen | -| `skipSchemaSizeLimit` | Boolean | True | When set to true, the GraphQL schema will be processed with token, character, line and rule depth limits. Set to false to process the schema regardless of its size. +| `supportUnknownFields` | Boolean | False | Specifies whether api classes should support unknown fields during serialization or deserialization. If `true`, classes will include a property of type [`java.util.Map`](https://docs.oracle.com/javase/8/docs/api/index.html?java/util/Map.html) that will store unknown fields. | +| `unknownFieldsPropertyName` | String | userDefinedFields | Specifies the name of the property to be included in api classes to support unknown fields during serialization or deserialization | +| `skip` | Boolean | False | If true, then code generation will not happen | +| `skipSchemaSizeLimit` | Boolean | True | When set to true, the GraphQL schema will be processed with token, character, line and rule depth limits. Set to false to process the schema regardless of its size. | diff --git a/src/main/java/com/kobylynskyi/graphql/codegen/java/JavaGraphQLTypeMapper.java b/src/main/java/com/kobylynskyi/graphql/codegen/java/JavaGraphQLTypeMapper.java index abdf455a9..87c6c646f 100644 --- a/src/main/java/com/kobylynskyi/graphql/codegen/java/JavaGraphQLTypeMapper.java +++ b/src/main/java/com/kobylynskyi/graphql/codegen/java/JavaGraphQLTypeMapper.java @@ -121,13 +121,7 @@ public NamedDefinition getLanguageType(MappingContext mappingContext, String gra langTypeName = DataModelMapper.getModelClassNameWithPrefixAndSuffix(mappingContext, graphQLType); } - Set fieldsWithDataFetcherResult = mappingContext.getFieldsWithDataFetcherResult(); - Set directivesNames = directives.stream() - .map(directive -> "@" + directive.getName()) - .collect(Collectors.toSet()); - if (directivesNames.stream().anyMatch(fieldsWithDataFetcherResult::contains)) { - langTypeName = wrapWithDataFetcherResult(langTypeName); - } + langTypeName = wrapWithDataFetcherResultIfRequired(mappingContext, directives, langTypeName, name); if (serializeFieldsUsingObjectMapper.contains(graphQLType) || (name != null && parentTypeName != null && @@ -139,7 +133,26 @@ public NamedDefinition getLanguageType(MappingContext mappingContext, String gra mandatory, primitiveCanBeUsed, serializeUsingObjectMapper); } - private String wrapWithDataFetcherResult(String typeName) { - return "graphql.execution.DataFetcherResult<" + typeName + ">"; + private String wrapWithDataFetcherResultIfRequired(MappingContext mappingContext, + List directives, + String langTypeName, + String name) { + Set fieldsWithDataFetcherResult = mappingContext.getFieldsWithDataFetcherResult(); + Set directivesNames = directives.stream() + .map(directive -> "@" + directive.getName()) + .collect(Collectors.toSet()); + + // Create the representation of 'name' + String nameRepresentation = langTypeName + "." + name; + + boolean shouldWrap = directivesNames.stream().anyMatch(fieldsWithDataFetcherResult::contains) + || fieldsWithDataFetcherResult.contains(langTypeName) + || fieldsWithDataFetcherResult.contains(nameRepresentation); + + if (shouldWrap) { + langTypeName = "graphql.execution.DataFetcherResult<" + langTypeName + ">"; + } + + return langTypeName; } -} \ No newline at end of file +} From cdb847c1875ca2866e2260d4bd731c7f1c102b75 Mon Sep 17 00:00:00 2001 From: Kirill Shiryaev Date: Wed, 10 Jan 2024 13:19:26 -0300 Subject: [PATCH 16/19] Add tests --- ...aphQLCodegenFieldsWithDataFetcherTest.java | 51 +++++++++++++++++-- .../fields-with-data-fetcher-result.graphqls | 5 ++ 2 files changed, 51 insertions(+), 5 deletions(-) diff --git a/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenFieldsWithDataFetcherTest.java b/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenFieldsWithDataFetcherTest.java index 137b14bc9..bf817734b 100644 --- a/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenFieldsWithDataFetcherTest.java +++ b/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenFieldsWithDataFetcherTest.java @@ -41,10 +41,7 @@ void cleanup() { } @Test - void generate_fieldsWithDataFetcherResult() throws Exception { - mappingConfig.getFieldsWithDataFetcherResult().add("orders"); - mappingConfig.getFieldsWithDataFetcherResult().add("cart"); - + void generate_fieldsWithDataFetcherResult_with_directives() throws Exception { generate("src/test/resources/schemas/fields-with-data-fetcher-result.graphqls"); File[] files = Objects.requireNonNull(outputJavaClassesDir.listFiles()); @@ -52,7 +49,7 @@ void generate_fieldsWithDataFetcherResult() throws Exception { List generatedFileNames = Arrays.stream(files).map(File::getName).sorted().collect(toList()); assertEquals( - asList("Cart.java", "Order.java", "QueryResolver.java", "User.java", "UserCurrentQueryResolver.java"), + asList("Cart.java", "Item.java", "Order.java", "QueryResolver.java", "User.java", "UserCurrentQueryResolver.java"), generatedFileNames ); @@ -63,6 +60,50 @@ void generate_fieldsWithDataFetcherResult() throws Exception { assertTrue(userContext.contains("graphql.execution.DataFetcherResult")); } + @Test + void generate_fieldsWithDataFetcherResult_with_typename() throws Exception { + mappingConfig.getFieldsWithDataFetcherResult().add("Item"); + + generate("src/test/resources/schemas/fields-with-data-fetcher-result.graphqls"); + + File[] files = Objects.requireNonNull(outputJavaClassesDir.listFiles()); + Assertions.assertNotNull(files); + + List generatedFileNames = Arrays.stream(files).map(File::getName).sorted().collect(toList()); + assertEquals( + asList("Cart.java", "Item.java", "Order.java", "QueryResolver.java", "User.java", + "UserCurrentQueryResolver.java"), + generatedFileNames + ); + + File cart = getFileByName(files, "Cart.java"); + String userContext = Utils.getFileContent(cart.getPath()).trim(); + + assertTrue(userContext.contains("java.util.List>")); + } + + @Test + void generate_fieldsWithDataFetcherResult_with_name() throws Exception { + mappingConfig.getFieldsWithDataFetcherResult().add("Item.items"); + + generate("src/test/resources/schemas/fields-with-data-fetcher-result.graphqls"); + + File[] files = Objects.requireNonNull(outputJavaClassesDir.listFiles()); + Assertions.assertNotNull(files); + + List generatedFileNames = Arrays.stream(files).map(File::getName).sorted().collect(toList()); + assertEquals( + asList("Cart.java", "Item.java", "Order.java", "QueryResolver.java", "User.java", + "UserCurrentQueryResolver.java"), + generatedFileNames + ); + + File cart = getFileByName(files, "Cart.java"); + String userContext = Utils.getFileContent(cart.getPath()).trim(); + + assertTrue(userContext.contains("java.util.List>")); + } + private void generate(String o) throws IOException { new JavaGraphQLCodegen(singletonList(o), outputBuildDir, mappingConfig, TestUtils.getStaticGeneratedInfo(mappingConfig)) diff --git a/src/test/resources/schemas/fields-with-data-fetcher-result.graphqls b/src/test/resources/schemas/fields-with-data-fetcher-result.graphqls index 4964dd74d..56b3a2c18 100644 --- a/src/test/resources/schemas/fields-with-data-fetcher-result.graphqls +++ b/src/test/resources/schemas/fields-with-data-fetcher-result.graphqls @@ -22,6 +22,11 @@ type Order { type Cart { id: Long! + items: [Item!]! +} + +type Item { + id: String } directive @dataFetcherResult on FIELD_DEFINITION From 6f40cc564cce52cf173abea3eea8c00b3c488123 Mon Sep 17 00:00:00 2001 From: Kirill Shiryaev Date: Wed, 10 Jan 2024 13:35:21 -0300 Subject: [PATCH 17/19] Fix code style --- .../codegen/GraphQLCodegenFieldsWithDataFetcherTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenFieldsWithDataFetcherTest.java b/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenFieldsWithDataFetcherTest.java index bf817734b..9998173f8 100644 --- a/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenFieldsWithDataFetcherTest.java +++ b/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenFieldsWithDataFetcherTest.java @@ -49,7 +49,8 @@ void generate_fieldsWithDataFetcherResult_with_directives() throws Exception { List generatedFileNames = Arrays.stream(files).map(File::getName).sorted().collect(toList()); assertEquals( - asList("Cart.java", "Item.java", "Order.java", "QueryResolver.java", "User.java", "UserCurrentQueryResolver.java"), + asList("Cart.java", "Item.java", "Order.java", "QueryResolver.java", "User.java", + "UserCurrentQueryResolver.java"), generatedFileNames ); From 5ed5834ccfb5c91bd9c0356ec223442367d8c12f Mon Sep 17 00:00:00 2001 From: Kirill Shiryaev Date: Fri, 2 Feb 2024 11:18:13 -0300 Subject: [PATCH 18/19] Fix code style --- .../kobylynskyi/graphql/codegen/model/MappingConfig.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingConfig.java b/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingConfig.java index 2bb72a786..cdb140ceb 100644 --- a/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingConfig.java +++ b/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingConfig.java @@ -608,8 +608,8 @@ public Set getFieldsToExcludeFromGeneration() { return fieldsToExcludeFromGeneration; } - public void setFieldsWithDataFetcherResult(Set fieldsWithDataFetcherResult) { - this.fieldsWithDataFetcherResult = fieldsWithDataFetcherResult; + public void setFieldsToExcludeFromGeneration(Set fieldsToExcludeFromGeneration) { + this.fieldsToExcludeFromGeneration = fieldsToExcludeFromGeneration; } @Override @@ -617,8 +617,8 @@ public Set getFieldsWithDataFetcherResult() { return fieldsWithDataFetcherResult; } - public void setFieldsToExcludeFromGeneration(Set fieldsToExcludeFromGeneration) { - this.fieldsToExcludeFromGeneration = fieldsToExcludeFromGeneration; + public void setFieldsWithDataFetcherResult(Set fieldsWithDataFetcherResult) { + this.fieldsWithDataFetcherResult = fieldsWithDataFetcherResult; } @Override From 32ea7a41eef051cac29132a9706e8460ceda4b9d Mon Sep 17 00:00:00 2001 From: Bogdan Kobylynskyi <92bogdan@gmail.com> Date: Sat, 24 Feb 2024 11:05:51 -0500 Subject: [PATCH 19/19] Fix codegen-options.md formatting --- docs/codegen-options.md | 159 ++++++++++++++++++++-------------------- 1 file changed, 80 insertions(+), 79 deletions(-) diff --git a/docs/codegen-options.md b/docs/codegen-options.md index 3f6c5826f..c64ad322c 100644 --- a/docs/codegen-options.md +++ b/docs/codegen-options.md @@ -1,91 +1,90 @@ # Codegen Options -| Option | Data Type | Default value | Description | -|:--------------------------------------------------------------:|:----------------------------------------------------------------------:|:--------------------------------------------------------------:|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `graphqlSchemaPaths` | List(String) | (falls back to `graphqlSchemas`) | GraphQL schema locations. You can supply multiple paths to GraphQL schemas. To include many schemas from a folder hierarchy, use the `graphqlSchemas` block instead. | -| `graphqlSchemas` | *See
[graphqlSchemas](#option-graphqlschemas)* | All
`.graphqls`/`.graphql`
files in
resources | Block to define the input GraphQL schemas, when exact paths are too cumbersome. See table below for a list of options. *See [graphqlSchemas](#option-graphqlschemas)* | -| `graphqlQueryIntrospectionResu`
`ltPath` | String | None | Path to GraphQL Introspection Query result in json format (with root object `__schema` or `data.__schema`). Sample: [sample-introspection-query-result.json](../src/test/resources/introspection-result/sample-introspection-query-result.json) | -| `outputDir` | String | None | The output target directory into which code will be generated. | -| `configurationFiles` | List(String) | Empty | Paths to the files with mapping configurations. Supported formats. JSON, HOCON. Order of specified configuration files matters, so the default configuration should be placed at the end. | -| `packageName` | String | Empty | Java package for generated classes. | -| `apiPackageName` | String | Empty | Java package for generated api classes (Query, Mutation, Subscription). | -| `modelPackageName` | String | Empty | Java package for generated model classes (type, input, interface, enum, union). | -| `generateBuilder` | Boolean | True | Specifies whether generated model classes should have builder. | -| `generateApis` | Boolean | True | Specifies whether api classes should be generated as well as model classes. | -| `generateDataFetchingEnvironme`
`ntArgumentInApis` | Boolean | False | If true, then `graphql.schema.DataFetchingEnvironment env` will be added as a last argument to all methods of root type resolvers and field resolvers. | -| `generateEqualsAndHashCode` | Boolean | False | Specifies whether generated model classes should have equals and hashCode methods defined. | -| `generateParameterizedFieldsResolvers` | Boolean | True | Specifies whether separate `Resolver` interface for parametrized fields should be generated. If `false`, then add parametrized field to the type definition and ignore field parameters. If `true` then separate `Resolver` interface for parametrized fields will be generated. | -| `generateImmutableModels` | Boolean | False | Specifies whether generated model classes should be immutable. | -| `generateToString` | Boolean | False | Specifies whether generated model classes should have toString method defined. | -| `generateJacksonTypeIdResolver` | Boolean | False | Specifies whether generated union interfaces should be annotated with a custom Jackson type id resolver generated in model package. | -| `addGeneratedAnnotation` | Boolean | True | Specifies whether generated classes should have `@Generated` annotation. | -| `generatedAnnotation` | String | `jakarta.annotation.Generated`
`javax.annotation.Generated` | Qualified class name (with package) of the `@Generated` annotation that will be added on top of every generated class (if `addGeneratedAnnotation` is **true**) | -| `apiNamePrefix` | String | Empty | Sets the prefix for GraphQL api classes (query, mutation, subscription). | -| `apiNameSuffix` | String | `Resolver` | Sets the suffix for GraphQL api classes (query, mutation, subscription). | -| `apiInterfaceStrategy` | *See
[ApiInterfaceStrategy](#option-apiinterfacestrategy)* | `INTERFACE_PER_OPERATION` | *See [ApiInterfaceStrategy](#option-apiinterfacestrategy)* | -| `apiRootInterfaceStrategy` | *See
[ApiRootInterfaceStrategy](#option-apirootinterfacestrategy)* | `SINGLE_INTERFACE` | *See [ApiRootInterfaceStrategy](#option-apirootinterfacestrategy)* | -| `apiNamePrefixStrategy` | *See
[ApiNamePrefixStrategy](#option-apinameprefixstrategy)* | `CONSTANT` | *See [ApiNamePrefixStrategy](#option-apinameprefixstrategy)* | -| `modelNamePrefix` | String | Empty | Sets the prefix for GraphQL model classes (type, input, interface, enum, union). | -| `modelNameSuffix` | String | Empty | Sets the suffix for GraphQL model classes (type, input, interface, enum, union). | -| `modelValidationAnnotation` | String | `@javax.validation.`
`constraints.NotNull` | Annotation for mandatory (NonNull) fields. Can be null/empty. | -| `typeResolverPrefix` | String | Empty | Sets the prefix for GraphQL type resolver classes. | -| `typeResolverSuffix` | String | `Resolver` | Sets the suffix for GraphQL type resolver classes. | -| `customTypesMapping` | Map(String,String) | Empty | *See [CustomTypesMapping](#option-customtypesmapping)* | -| `customTemplatesRoot` | File | Project's dir | Use to supply the path the to custom FreeMarker templates root directory. | -| `customTemplates` | Map(String,String) | Empty | Use to supply paths to custom FreeMarker templates for code generation. | -| `customAnnotationsMapping` | Map(String,String[]) | Empty | *See [CustomAnnotationsMapping](#option-customannotationsmapping)* | -| `directiveAnnotationsMapping` | Map(String,String[]) | Empty | *See [DirectiveAnnotationsMapping](#option-directiveannotationsmapping)* | -| `fieldsWithResolvers` | Set(String) | Empty | Fields that require Resolvers should be defined here in format: `TypeName.fieldName` or `TypeName` or `@directive`. E.g.: `Person`, `Person.friends`, `@customResolver`. | -| `fieldsWithoutResolvers` | Set(String) | Empty | Fields that DO NOT require Resolvers should be defined here in format: `TypeName.fieldName` or `TypeName` or `@directive`. Can be used in conjunction with `generateExtensionFieldsResolvers` option. E.g.: `Person`, `Person.friends`, `@noResolver`. | -| `fieldsToExcludeFromGeneration` | Set(String) | Empty | Fields to exclude from generation should be defined here in format: `TypeName.fieldName`. | -| `resolverArgumentAnnotations` | Set(String) | Empty | Annotations that will be added to all resolver arguments. Can be used for [spring-graphql](https://github.com/spring-projects/spring-graphql) inegration by supplying: `org.springframework.graphql.data.method.annotation.Argument` | -| `parametrizedResolverAnnotations` | Set(String) | Empty | Annotations that will be added to all parametrized resolver methods. Can be used for [spring-graphql](https://github.com/spring-projects/spring-graphql) inegration by supplying: `org.springframework.graphql.data.method.annotation.SchemaMapping(typeName="{{TYPE_NAME}}")` | -| `generateParameterizedFieldsResolvers` | Boolean | True | If true, then generate separate `Resolver` interface for parametrized fields. If false, then add field to the type definition and ignore field parameters. | -| `generateExtensionFieldsResolvers` | Boolean | False | Specifies whether all fields in extensions (`extend type` and `extend interface`) should be present in Resolver interface instead of the type class itself. | -| `generateModelsForRootTypes` | Boolean | False | Specifies whether model classes should be generated for `type Query`, `type Subscription`, `type Mutation`. | -| `useOptionalForNullableReturnTypes` | Boolean | False | Specifies whether nullable return types of api methods should be wrapped into [`java.util.Optional<>`](https://docs.oracle.com/javase/8/docs/api/index.html?java/util/Optional.html). Lists will not be wrapped. | -| `useWrapperForNullableInputTypes` | Boolean | False | Specifies whether nullable parameters on input types should be wrapped into [`ArgumentValue<>`](https://docs.spring.io/spring-graphql/docs/current/api/org/springframework/graphql/data/ArgumentValue.html). This requires org.springframework.graphql.data version 1.1.0+. Lists will not be wrapped. | -| `generateApisWithThrowsException` | Boolean | True | Specifies whether api interface methods should have `throws Exception` in signature. | -| `generateApisWithSuspendFunctions` | Boolean | False | Specifies whether api interface methods should have `suspend` modifier in signature. Only supported in Kotlin. | -| `generateNoArgsConstructorOnly` | Boolean | False | Specifies whether model classes should only have a no-args constructor. All-args constructor will not be generated in case value is true | -| `generateModelsWithPublicFields` | Boolean | False | Specifies whether model classes should have public fields and NO getters/setters. By default, fields are private and there are getters/setters for each field. | -| `apiReturnType` | String | Empty | Return type for api methods (query/mutation). For example: `reactor.core.publisher.Mono`, etc. | -| `apiReturnListType` | String | Empty | Return type for api methods (query/mutation) having list type. For example: `reactor.core.publisher.Flux`, etc. By default is empty, so `apiReturnType` will be used. | -| `subscriptionReturnType` | String | Empty | Return type for subscription methods. For example: `org.reactivestreams.Publisher`, `io.reactivex.Observable`, etc. | -| `relayConfig` | *See
[RelayConfig](#option-relayconfig)* | `@connection(for: ...)` | *See [RelayConfig](#option-relayconfig)* | -| `generateClient` | Boolean | False | Specifies whether client-side classes should be generated for each query, mutation and subscription. This includes: `Request` classes (contain input data), `ResponseProjection` classes for each type (contain response fields) and `Response` classes (contain response data). | -| `requestSuffix` | String | Request | Sets the suffix for `Request` classes. | -| `responseSuffix` | String | Response | Sets the suffix for `Response` classes. | -| `responseProjectionSuffix` | String | ResponseProjection | Sets the suffix for `ResponseProjection` classes. | -| `parametrizedInputSuffix` | String | ParametrizedInput | Sets the suffix for `ParametrizedInput` classes. | -| `parentInterfaces` | *See
[parentInterfaces](#option-parentinterfaces)* | Empty | Block to define parent interfaces for generated interfaces (query / mutation / subscription / type resolver). *See [parentInterfaces](#option-parentinterfaces)* | -| `generateAllMethodInProjection` | Boolean | True | Enables whether the `all$()` method should be generated in the projection classes. Disabling enforces the client to select the fields manually. | -| `responseProjectionMaxDepth` | Integer | 3 | Sets max depth when use `all$()` which for facilitating the construction of projection automatically, the fields on all projections are provided when it be invoked. This is a global configuration, of course, you can use `all$(max)` to set for each method. For self recursive types, too big depth may result in a large number of returned data! | -| `generatedLanguage` | Enum | GeneratedLanguage.JAVA | Choose which language you want to generate, Java,Scala,Kotlin were supported. Note that due to language features, there are slight differences in default values between languages. | -| `generateModelOpenClasses` | Boolean | False | The class type of the generated model. If true, generate normal classes, else generate data classes. It only support in kotlin(```data class```) and scala(```case class```). Maybe we will consider to support Java ```record``` in the future. | -| `initializeNullableTypes` | Boolean | False | Adds a default null value to nullable arguments. Only supported in Kotlin. | -| `generateSealedInterfaces` | Boolean | False | This applies to generated interfaces on unions and interfaces. If true, generate sealed interfaces, else generate normal ones. It is only supported in Kotlin and Scala. | -| `typesAsInterfaces` | Set(String) | Empty | Types that must generated as interfaces should be defined here in format: `TypeName` or `@directive`. E.g.: `User`, `@asInterface`. | -| `fieldsWithDataFetcherResult` | Set(String) | Empty | Types that must have DataFetchResult should be defined here in format: `TypeName`, or `TypeName.fieldName` or `@directive`. E.g.: `Item`, `Item.items` or `@dataFetcherResult`. | -| `useObjectMapperForRequestSerialization` | Set(String) | Empty | Fields that require serialization using `com.fasterxml.jackson.databind.ObjectMapper#writeValueAsString(Object)`. Values should be defined here in the following format: `GraphqlObjectName.fieldName` or `GraphqlTypeName`. If just type is specified, then all fields of this type will be serialized using ObjectMapper. E.g.: `["Person.createdDateTime", ZonedDateTime"]` | -| `supportUnknownFields` | Boolean | False | Specifies whether api classes should support unknown fields during serialization or deserialization. If `true`, classes will include a property of type [`java.util.Map`](https://docs.oracle.com/javase/8/docs/api/index.html?java/util/Map.html) that will store unknown fields. | -| `unknownFieldsPropertyName` | String | userDefinedFields | Specifies the name of the property to be included in api classes to support unknown fields during serialization or deserialization | -| `skip` | Boolean | False | If true, then code generation will not happen | -| `skipSchemaSizeLimit` | Boolean | True | When set to true, the GraphQL schema will be processed with token, character, line and rule depth limits. Set to false to process the schema regardless of its size. +| Option | Data Type | Default value | Description | +|:-----------------------------------------------------:|:---------------------------------------------------------------------:|:--------------------------------------------------------------:|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `graphqlSchemaPaths` | List(String) | (falls back to `graphqlSchemas`) | GraphQL schema locations. You can supply multiple paths to GraphQL schemas. To include many schemas from a folder hierarchy, use the `graphqlSchemas` block instead. | +| `graphqlSchemas` | *See
[graphqlSchemas](#option-graphqlschemas)* | All
`.graphqls`/`.graphql`
files in
resources | Block to define the input GraphQL schemas, when exact paths are too cumbersome. See table below for a list of options. *See [graphqlSchemas](#option-graphqlschemas)* | +| `graphqlQueryIntrospectionResu`
`ltPath` | String | None | Path to GraphQL Introspection Query result in json format (with root object `__schema` or `data.__schema`). Sample: [sample-introspection-query-result.json](../src/test/resources/introspection-result/sample-introspection-query-result.json) | +| `outputDir` | String | None | The output target directory into which code will be generated. | +| `configurationFiles` | List(String) | Empty | Paths to the files with mapping configurations. Supported formats. JSON, HOCON. Order of specified configuration files matters, so the default configuration should be placed at the end. | +| `packageName` | String | Empty | Java package for generated classes. | +| `apiPackageName` | String | Empty | Java package for generated api classes (Query, Mutation, Subscription). | +| `modelPackageName` | String | Empty | Java package for generated model classes (type, input, interface, enum, union). | +| `generateBuilder` | Boolean | True | Specifies whether generated model classes should have builder. | +| `generateApis` | Boolean | True | Specifies whether api classes should be generated as well as model classes. | +| `generateDataFetchingEnvironme`
`ntArgumentInApis` | Boolean | False | If true, then `graphql.schema.DataFetchingEnvironment env` will be added as a last argument to all methods of root type resolvers and field resolvers. | +| `generateEqualsAndHashCode` | Boolean | False | Specifies whether generated model classes should have equals and hashCode methods defined. | +| `generateParameterizedFieldsResolvers` | Boolean | True | Specifies whether separate `Resolver` interface for parametrized fields should be generated. If `false`, then add parametrized field to the type definition and ignore field parameters. If `true` then separate `Resolver` interface for parametrized fields will be generated. | +| `generateImmutableModels` | Boolean | False | Specifies whether generated model classes should be immutable. | +| `generateToString` | Boolean | False | Specifies whether generated model classes should have toString method defined. | +| `generateJacksonTypeIdResolver` | Boolean | False | Specifies whether generated union interfaces should be annotated with a custom Jackson type id resolver generated in model package. | +| `addGeneratedAnnotation` | Boolean | True | Specifies whether generated classes should have `@Generated` annotation. | +| `generatedAnnotation` | String | `jakarta.annotation.Generated`
`javax.annotation.Generated` | Qualified class name (with package) of the `@Generated` annotation that will be added on top of every generated class (if `addGeneratedAnnotation` is **true**) | +| `apiNamePrefix` | String | Empty | Sets the prefix for GraphQL api classes (query, mutation, subscription). | +| `apiNameSuffix` | String | `Resolver` | Sets the suffix for GraphQL api classes (query, mutation, subscription). | +| `apiInterfaceStrategy` | *See
[ApiInterfaceStrategy](#option-apiinterfacestrategy)* | `INTERFACE_PER_OPERATION` | *See [ApiInterfaceStrategy](#option-apiinterfacestrategy)* | +| `apiRootInterfaceStrategy` | *See
[ApiRootInterfaceStrategy](#option-apirootinterfacestrategy)* | `SINGLE_INTERFACE` | *See [ApiRootInterfaceStrategy](#option-apirootinterfacestrategy)* | +| `apiNamePrefixStrategy` | *See
[ApiNamePrefixStrategy](#option-apinameprefixstrategy)* | `CONSTANT` | *See [ApiNamePrefixStrategy](#option-apinameprefixstrategy)* | +| `modelNamePrefix` | String | Empty | Sets the prefix for GraphQL model classes (type, input, interface, enum, union). | +| `modelNameSuffix` | String | Empty | Sets the suffix for GraphQL model classes (type, input, interface, enum, union). | +| `modelValidationAnnotation` | String | `@javax.validation.`
`constraints.NotNull` | Annotation for mandatory (NonNull) fields. Can be null/empty. | +| `typeResolverPrefix` | String | Empty | Sets the prefix for GraphQL type resolver classes. | +| `typeResolverSuffix` | String | `Resolver` | Sets the suffix for GraphQL type resolver classes. | +| `customTypesMapping` | Map(String,String) | Empty | *See [CustomTypesMapping](#option-customtypesmapping)* | +| `customTemplatesRoot` | File | Project's dir | Use to supply the path the to custom FreeMarker templates root directory. | +| `customTemplates` | Map(String,String) | Empty | Use to supply paths to custom FreeMarker templates for code generation. | +| `customAnnotationsMapping` | Map(String,String[]) | Empty | *See [CustomAnnotationsMapping](#option-customannotationsmapping)* | +| `directiveAnnotationsMapping` | Map(String,String[]) | Empty | *See [DirectiveAnnotationsMapping](#option-directiveannotationsmapping)* | +| `fieldsWithResolvers` | Set(String) | Empty | Fields that require Resolvers should be defined here in format: `TypeName.fieldName` or `TypeName` or `@directive`. E.g.: `Person`, `Person.friends`, `@customResolver`. | +| `fieldsWithoutResolvers` | Set(String) | Empty | Fields that DO NOT require Resolvers should be defined here in format: `TypeName.fieldName` or `TypeName` or `@directive`. Can be used in conjunction with `generateExtensionFieldsResolvers` option. E.g.: `Person`, `Person.friends`, `@noResolver`. | +| `fieldsToExcludeFromGeneration` | Set(String) | Empty | Fields to exclude from generation should be defined here in format: `TypeName.fieldName`. | +| `resolverArgumentAnnotations` | Set(String) | Empty | Annotations that will be added to all resolver arguments. Can be used for [spring-graphql](https://github.com/spring-projects/spring-graphql) inegration by supplying: `org.springframework.graphql.data.method.annotation.Argument` | +| `parametrizedResolverAnnotations` | Set(String) | Empty | Annotations that will be added to all parametrized resolver methods. Can be used for [spring-graphql](https://github.com/spring-projects/spring-graphql) inegration by supplying: `org.springframework.graphql.data.method.annotation.SchemaMapping(typeName="{{TYPE_NAME}}")` | +| `generateParameterizedFieldsResolvers` | Boolean | True | If true, then generate separate `Resolver` interface for parametrized fields. If false, then add field to the type definition and ignore field parameters. | +| `generateExtensionFieldsResolvers` | Boolean | False | Specifies whether all fields in extensions (`extend type` and `extend interface`) should be present in Resolver interface instead of the type class itself. | +| `generateModelsForRootTypes` | Boolean | False | Specifies whether model classes should be generated for `type Query`, `type Subscription`, `type Mutation`. | +| `useOptionalForNullableReturnTypes` | Boolean | False | Specifies whether nullable return types of api methods should be wrapped into [`java.util.Optional<>`](https://docs.oracle.com/javase/8/docs/api/index.html?java/util/Optional.html). Lists will not be wrapped. | +| `useWrapperForNullableInputTypes` | Boolean | False | Specifies whether nullable parameters on input types should be wrapped into [`ArgumentValue<>`](https://docs.spring.io/spring-graphql/docs/current/api/org/springframework/graphql/data/ArgumentValue.html). This requires org.springframework.graphql.data version 1.1.0+. Lists will not be wrapped. | +| `generateApisWithThrowsException` | Boolean | True | Specifies whether api interface methods should have `throws Exception` in signature. | +| `generateApisWithSuspendFunctions` | Boolean | False | Specifies whether api interface methods should have `suspend` modifier in signature. Only supported in Kotlin. | +| `generateNoArgsConstructorOnly` | Boolean | False | Specifies whether model classes should only have a no-args constructor. All-args constructor will not be generated in case value is true | +| `generateModelsWithPublicFields` | Boolean | False | Specifies whether model classes should have public fields and NO getters/setters. By default, fields are private and there are getters/setters for each field. | +| `apiReturnType` | String | Empty | Return type for api methods (query/mutation). For example: `reactor.core.publisher.Mono`, etc. | +| `apiReturnListType` | String | Empty | Return type for api methods (query/mutation) having list type. For example: `reactor.core.publisher.Flux`, etc. By default is empty, so `apiReturnType` will be used. | +| `subscriptionReturnType` | String | Empty | Return type for subscription methods. For example: `org.reactivestreams.Publisher`, `io.reactivex.Observable`, etc. | +| `relayConfig` | *See
[RelayConfig](#option-relayconfig)* | `@connection(for: ...)` | *See [RelayConfig](#option-relayconfig)* | +| `generateClient` | Boolean | False | Specifies whether client-side classes should be generated for each query, mutation and subscription. This includes: `Request` classes (contain input data), `ResponseProjection` classes for each type (contain response fields) and `Response` classes (contain response data). | +| `requestSuffix` | String | Request | Sets the suffix for `Request` classes. | +| `responseSuffix` | String | Response | Sets the suffix for `Response` classes. | +| `responseProjectionSuffix` | String | ResponseProjection | Sets the suffix for `ResponseProjection` classes. | +| `parametrizedInputSuffix` | String | ParametrizedInput | Sets the suffix for `ParametrizedInput` classes. | +| `parentInterfaces` | *See
[parentInterfaces](#option-parentinterfaces)* | Empty | Block to define parent interfaces for generated interfaces (query / mutation / subscription / type resolver). *See [parentInterfaces](#option-parentinterfaces)* | +| `generateAllMethodInProjection` | Boolean | True | Enables whether the `all$()` method should be generated in the projection classes. Disabling enforces the client to select the fields manually. | +| `responseProjectionMaxDepth` | Integer | 3 | Sets max depth when use `all$()` which for facilitating the construction of projection automatically, the fields on all projections are provided when it be invoked. This is a global configuration, of course, you can use `all$(max)` to set for each method. For self recursive types, too big depth may result in a large number of returned data! | +| `generatedLanguage` | Enum | GeneratedLanguage.JAVA | Choose which language you want to generate, Java,Scala,Kotlin were supported. Note that due to language features, there are slight differences in default values between languages. | +| `generateModelOpenClasses` | Boolean | False | The class type of the generated model. If true, generate normal classes, else generate data classes. It only support in kotlin(```data class```) and scala(```case class```). Maybe we will consider to support Java ```record``` in the future. | +| `initializeNullableTypes` | Boolean | False | Adds a default null value to nullable arguments. Only supported in Kotlin. | +| `generateSealedInterfaces` | Boolean | False | This applies to generated interfaces on unions and interfaces. If true, generate sealed interfaces, else generate normal ones. It is only supported in Kotlin and Scala. | +| `typesAsInterfaces` | Set(String) | Empty | Types that must generated as interfaces should be defined here in format: `TypeName` or `@directive`. E.g.: `User`, `@asInterface`. | +| `fieldsWithDataFetcherResult` | Set(String) | Empty | Types that must have DataFetchResult should be defined here in format: `TypeName`, or `TypeName.fieldName` or `@directive`. E.g.: `Item`, `Item.items` or `@dataFetcherResult`. | +| `useObjectMapperForRequestSerialization` | Set(String) | Empty | Fields that require serialization using `com.fasterxml.jackson.databind.ObjectMapper#writeValueAsString(Object)`. Values should be defined here in the following format: `GraphqlObjectName.fieldName` or `GraphqlTypeName`. If just type is specified, then all fields of this type will be serialized using ObjectMapper. E.g.: `["Person.createdDateTime", ZonedDateTime"]` | +| `supportUnknownFields` | Boolean | False | Specifies whether api classes should support unknown fields during serialization or deserialization. If `true`, classes will include a property of type [`java.util.Map`](https://docs.oracle.com/javase/8/docs/api/index.html?java/util/Map.html) that will store unknown fields. | +| `unknownFieldsPropertyName` | String | userDefinedFields | Specifies the name of the property to be included in api classes to support unknown fields during serialization or deserialization | +| `skip` | Boolean | False | If true, then code generation will not happen | +| `skipSchemaSizeLimit` | Boolean | True | When set to true, the GraphQL schema will be processed with token, character, line and rule depth limits. Set to false to process the schema regardless of its size. | - ### Option `graphqlSchemas` When exact paths to GraphQL schemas are too cumbersome to provide in the `graphqlSchemaPaths`, use the `graphqlSchemas` block. The parameters inside that block are the following: -| Key inside `graphqlSchemas` | Data Type | Default value | Description | -|:---------------------------:|:------------:|:------------------:|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `rootDir` | String | Main resources dir | The root directory from which to start searching for schema files. | -| `recursive` | Boolean | `true` | Whether to recursively look into sub directories. | -| `includePattern` | String | `.*\.graphqls?` | A Java regex that file names must match to be included. It should be a regex as defined by the [Pattern](https://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html) JDK class. It will be used to match only the file name without path. | -| `excludedFiles` | Set | (empty set) | A set of files to exclude, even if they match the include pattern. These paths should be either absolute or relative to the provided `rootDir`. | +| Key inside `graphqlSchemas` | Data Type | Default value | Description | +|:---------------------------:|:-----------:|:------------------:|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `rootDir` | String | Main resources dir | The root directory from which to start searching for schema files. | +| `recursive` | Boolean | `true` | Whether to recursively look into sub directories. | +| `includePattern` | String | `.*\.graphqls?` | A Java regex that file names must match to be included. It should be a regex as defined by the [Pattern](https://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html) JDK class. It will be used to match only the file name without path. | +| `excludedFiles` | Set | (empty set) | A set of files to exclude, even if they match the include pattern. These paths should be either absolute or relative to the provided `rootDir`. | ### Option `ApiInterfaceStrategy` @@ -206,6 +205,7 @@ Provide a path to external file via property `configurationFiles` Sample content of the file: JSON: + ```json { "generateApis": true, @@ -217,6 +217,7 @@ JSON: ``` [HOCON](https://en.wikipedia.org/wiki/HOCON): + ``` generateClient=true generateApis=true