From 9867d9cad8ee3cab42a36e90f336e9a176193b0f Mon Sep 17 00:00:00 2001
From: Bogdan Kobylynskyi <92bogdan@gmail.com>
Date: Sun, 31 Jul 2022 16:21:07 -0400
Subject: [PATCH 1/2] Ability to supply resolverArgumentAnnotations and
parametrizedResolverAnnotations #983
---
docs/codegen-options.md | 184 +++++++++---------
.../gradle/GraphQLCodegenGradleTask.java | 28 +++
.../graphql/codegen/GraphQLCodegenMojo.java | 18 ++
.../graphql/codegen/GraphQLCodegen.java | 10 +
.../impl/FieldResolversGenerator.java | 5 +-
.../codegen/mapper/AnnotationsMapper.java | 13 ++
.../model/GraphQLCodegenConfiguration.java | 24 +++
.../graphql/codegen/model/MappingConfig.java | 33 +++-
.../codegen/model/MappingConfigConstants.java | 1 +
.../graphql/codegen/model/MappingContext.java | 40 +++-
.../model/definitions/ExtendedDocument.java | 18 ++
.../GraphQLCodegenAnnotationsTest.java | 43 +++-
.../codegen/model/MappingConfigTest.java | 13 ++
...ationResolver_ArgumentAnnotations.java.txt | 19 ++
...r_ParametrizedResolverAnnotations.java.txt | 50 +++++
...QueryResolver_ArgumentAnnotations.java.txt | 34 ++++
16 files changed, 429 insertions(+), 104 deletions(-)
create mode 100644 src/test/resources/expected-classes/annotation/CreateEventMutationResolver_ArgumentAnnotations.java.txt
create mode 100644 src/test/resources/expected-classes/annotation/EventPropertyResolver_ParametrizedResolverAnnotations.java.txt
create mode 100644 src/test/resources/expected-classes/annotation/QueryResolver_ArgumentAnnotations.java.txt
diff --git a/docs/codegen-options.md b/docs/codegen-options.md
index bc43da2a2..54abc7da8 100644
--- a/docs/codegen-options.md
+++ b/docs/codegen-options.md
@@ -1,67 +1,66 @@
# 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. |
-| `addGeneratedAnnotation` | Boolean | True | Specifies whether generated classes should have `@Generated` annotation. |
-| `generateJacksonTypeIdResolver` | Boolean | False | Specifies whether generated union interfaces should be annotated with a custom Jackson type id resolver generated in model package. |
-| `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)* |
-| `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`. |
-| `generateParameterizedFieldsR`
`esolvers` | 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. |
-| `generateExtensionFieldsResol`
`vers` | 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`. |
-| `useOptionalForNullableReturn`
`Types` | 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. |
-| `generateApisWithThrowsExcept`
`ion` | Boolean | True | Specifies whether api interface methods should have `throws Exception` in signature. |
-| `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. |
-| `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|
+| 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. |
+| `addGeneratedAnnotation` | Boolean | True | Specifies whether generated classes should have `@Generated` annotation. |
+| `generateJacksonTypeIdResolver` | Boolean | False | Specifies whether generated union interfaces should be annotated with a custom Jackson type id resolver generated in model package. |
+| `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)* |
+| `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`. |
+| `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}}")` |
+| `generateParameterizedFieldsR`
`esolvers` | 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. |
+| `generateExtensionFieldsResol`
`vers` | 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`. |
+| `useOptionalForNullableReturn`
`Types` | 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. |
+| `generateApisWithThrowsExcept`
`ion` | Boolean | True | Specifies whether api interface methods should have `throws Exception` in signature. |
+| `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. |
+| `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 |
### Option `graphqlSchemas`
@@ -69,12 +68,12 @@ See [DirectiveAnnotationsMapping](#option-directiveannotationsmapping)* |
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`
@@ -83,32 +82,31 @@ to skip generation of separate interface class for each operation in favor of ha
see *[ApiRootInterfaceStrategy](#option-apirootinterfacestrategy)*
and *[ApiNamePrefixStrategy](#option-apinameprefixstrategy)*)
-| Value | Description |
-| --------------------------------------- | ----------- |
-| `INTERFACE_PER_OPERATION` **(default)** | Generate separate interface classes for each GraphQL operation. |
-| `DO_NOT_GENERATE` | Do not generate separate interfaces classes for GraphQL operation. |
+| Value | Description |
+|:---------------------------------------:|--------------------------------------------------------------------|
+| `INTERFACE_PER_OPERATION` **(default)** | Generate separate interface classes for each GraphQL operation. |
+| `DO_NOT_GENERATE` | Do not generate separate interfaces classes for GraphQL operation. |
### Option `ApiRootInterfaceStrategy`
Defines how root interface (`QueryResolver` / `MutationResolver` / `SubscriptionResolver` will be generated (in addition
to separate interfaces for each query/mutation/subscription)
-| Value | Description |
-| -------------------------------- | ----------- |
-| `INTERFACE_PER_SCHEMA` | Generate multiple super-interfaces for each graphql file.
Takes into account `apiNamePrefixStrategy`.
E.g.: `OrderServiceQueryResolver.java`, `ProductServiceQueryResolver.java`, etc. |
-| `SINGLE_INTERFACE` **(
-default)** | Generate a single `QueryResolver.java`, `MutationResolver.java`, `SubscriptionResolver.java` for all graphql schema files. |
-| `DO_NOT_GENERATE` | Do not generate super interface for GraphQL operations. |
+| Value | Description |
+|:--------------------------------:|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| `INTERFACE_PER_SCHEMA` | Generate multiple super-interfaces for each graphql file.
Takes into account `apiNamePrefixStrategy`.
E.g.: `OrderServiceQueryResolver.java`, `ProductServiceQueryResolver.java`, etc. |
+| `SINGLE_INTERFACE` **(default)** | Generate a single `QueryResolver.java`, `MutationResolver.java`, `SubscriptionResolver.java` for all graphql schema files. |
+| `DO_NOT_GENERATE` | Do not generate super interface for GraphQL operations. |
### Option `ApiNamePrefixStrategy`
Defines which prefix to use for API interfaces.
-| Value | Description |
-| ------------------------ | ----------- |
-| `FILE_NAME_AS_PREFIX` | Will take GraphQL file name as a prefix for all generated API interfaces + value of `apiNamePrefix` config option.
E.g.:
* following schemas: *resources/schemas/order-service.graphql*, *resources/schemas/product-service.graphql*
* will result in: `OrderServiceQueryResolver.java`, `ProductServiceQueryResolver.java`, etc |
+| Value | Description |
+|:------------------------:|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| `FILE_NAME_AS_PREFIX` | Will take GraphQL file name as a prefix for all generated API interfaces + value of `apiNamePrefix` config option.
E.g.:
* following schemas: *resources/schemas/order-service.graphql*, *resources/schemas/product-service.graphql*
* will result in: `OrderServiceQueryResolver.java`, `ProductServiceQueryResolver.java`, etc |
| `FOLDER_NAME_AS_PREFIX` | Will take parent folder name as a prefix for all generated API interfaces + value of `apiNamePrefix` config option. E.g.:
* following schemas: *resources/order-service/schema1.graphql*, *resources/order-service/schema2.graphql*
* will result in: `OrderServiceQueryResolver.java`, `OrderServiceGetOrderByIdQueryResolver.java`, etc |
-| `CONSTANT` **(default)** | Will take only the value of `apiNamePrefix` config option. |
+| `CONSTANT` **(default)** | Will take only the value of `apiNamePrefix` config option. |
resources/schemas/order-service.graphql*, *
resources/schemas/product-service.graphql*
* will result in: `OrderServiceQueryResolver.java`
@@ -128,12 +126,12 @@ to extend only interfaces generated by this plugin.
**Note:** if you want to include a GraphQL type name into the interface name, then use `{{TYPE}}` placeholder.
E.g.: `graphql.kickstart.tools.GraphQLResolver<{{TYPE}}>`
-| Key inside `parentInterfaces` | Data Type | Default value | Description |
-| ----------------------------- | --------- | ------------- | ----------- |
-| `queryResolver` | String | Empty | Interface that will be added as "extend" to all generated api Query interfaces. |
-| `mutationResolver` | String | Empty | Interface that will be added as "extend" to all generated api Mutation interfaces. |
-| `subscriptionResolver` | String | Empty | Interface that will be added as "extend" to all generated api Subscription interfaces. |
-| `resolver` | String | Empty | Interface that will be added as "extend" to all generated TypeResolver interfaces. |
+| Key inside `parentInterfaces` | Data Type | Default value | Description |
+|:-----------------------------:|:---------:|:-------------:|----------------------------------------------------------------------------------------|
+| `queryResolver` | String | Empty | Interface that will be added as "extend" to all generated api Query interfaces. |
+| `mutationResolver` | String | Empty | Interface that will be added as "extend" to all generated api Mutation interfaces. |
+| `subscriptionResolver` | String | Empty | Interface that will be added as "extend" to all generated api Subscription interfaces. |
+| `resolver` | String | Empty | Interface that will be added as "extend" to all generated TypeResolver interfaces. |
### Option `customTypesMapping`
@@ -172,11 +170,11 @@ can also use one of the formatters for directive argument value: `{{val?toString
Can be used to supply a custom configuration for Relay support. For reference
see: https://www.graphql-java-kickstart.com/tools/relay/
-| Key inside `relayConfig` | Data Type | Default value | Description |
-| ------------------------ | --------- | -------------------------- | ----------- |
-| `directiveName` | String | `connection` | Directive name used for marking a field. |
-| `directiveArgumentName` | String | `for` | Directive argument name that contains a GraphQL type name. |
-| `connectionType` | String | `graphql.relay.Connection` | Generic Connection type. |
+| Key inside `relayConfig` | Data Type | Default value | Description |
+|:------------------------:|:---------:|:--------------------------:|------------------------------------------------------------|
+| `directiveName` | String | `connection` | Directive name used for marking a field. |
+| `directiveArgumentName` | String | `for` | Directive argument name that contains a GraphQL type name. |
+| `connectionType` | String | `graphql.relay.Connection` | Generic Connection type. |
For example, the following schema:
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 4b032aec0..c15ef29f1 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
@@ -87,6 +87,8 @@ public class GraphQLCodegenGradleTask extends DefaultTask implements GraphQLCode
private Set fieldsWithResolvers = new HashSet<>();
private Set fieldsWithoutResolvers = new HashSet<>();
private Set typesAsInterfaces = new HashSet<>();
+ private Set resolverArgumentAnnotations = new HashSet<>();
+ private Set parametrizedResolverAnnotations = new HashSet<>();
private final RelayConfig relayConfig = new RelayConfig();
@@ -164,6 +166,10 @@ public void generate() throws Exception {
fieldsWithoutResolvers != null ? fieldsWithoutResolvers : new HashSet<>());
mappingConfig.setTypesAsInterfaces(
typesAsInterfaces != null ? typesAsInterfaces : new HashSet<>());
+ mappingConfig.setResolverArgumentAnnotations(
+ resolverArgumentAnnotations != null ? resolverArgumentAnnotations : new HashSet<>());
+ mappingConfig.setParametrizedResolverAnnotations(
+ parametrizedResolverAnnotations != null ? parametrizedResolverAnnotations : new HashSet<>());
mappingConfig.setRelayConfig(relayConfig);
mappingConfig.setGenerateClient(generateClient);
@@ -689,6 +695,28 @@ public void setTypesAsInterfaces(Set typesAsInterfaces) {
this.typesAsInterfaces = typesAsInterfaces;
}
+ @Input
+ @Optional
+ @Override
+ public Set getResolverArgumentAnnotations() {
+ return resolverArgumentAnnotations;
+ }
+
+ public void setResolverArgumentAnnotations(Set resolverArgumentAnnotations) {
+ this.resolverArgumentAnnotations = resolverArgumentAnnotations;
+ }
+
+ @Input
+ @Optional
+ @Override
+ public Set getParametrizedResolverAnnotations() {
+ return parametrizedResolverAnnotations;
+ }
+
+ public void setParametrizedResolverAnnotations(Set parametrizedResolverAnnotations) {
+ this.parametrizedResolverAnnotations = parametrizedResolverAnnotations;
+ }
+
@Nested
@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 e2982fc29..96cae7575 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
@@ -185,6 +185,12 @@ public class GraphQLCodegenMojo extends AbstractMojo implements GraphQLCodegenCo
@Parameter
private String[] typesAsInterfaces;
+ @Parameter
+ private String[] resolverArgumentAnnotations;
+
+ @Parameter
+ private String[] parametrizedResolverAnnotations;
+
@Parameter(defaultValue = MappingConfigConstants.DEFAULT_RESPONSE_PROJECTION_MAX_DEPTH_STRING)
private int responseProjectionMaxDepth;
@@ -271,6 +277,8 @@ public void execute() throws MojoExecutionException {
mappingConfig.setResponseProjectionMaxDepth(responseProjectionMaxDepth);
mappingConfig.setUseObjectMapperForRequestSerialization(mapToHashSet(useObjectMapperForRequestSerialization));
mappingConfig.setTypesAsInterfaces(mapToHashSet(typesAsInterfaces));
+ mappingConfig.setResolverArgumentAnnotations(mapToHashSet(resolverArgumentAnnotations));
+ mappingConfig.setParametrizedResolverAnnotations(mapToHashSet(parametrizedResolverAnnotations));
mappingConfig.setResolverParentInterface(getResolverParentInterface());
mappingConfig.setQueryResolverParentInterface(getQueryResolverParentInterface());
@@ -590,6 +598,16 @@ public Set getTypesAsInterfaces() {
return mapToHashSet(typesAsInterfaces);
}
+ @Override
+ public Set getResolverArgumentAnnotations() {
+ return mapToHashSet(resolverArgumentAnnotations);
+ }
+
+ @Override
+ public Set getParametrizedResolverAnnotations() {
+ return mapToHashSet(parametrizedResolverAnnotations);
+ }
+
@Override
public String getQueryResolverParentInterface() {
return parentInterfaces.getQueryResolver();
diff --git a/src/main/java/com/kobylynskyi/graphql/codegen/GraphQLCodegen.java b/src/main/java/com/kobylynskyi/graphql/codegen/GraphQLCodegen.java
index 638a1871d..2a59423e3 100644
--- a/src/main/java/com/kobylynskyi/graphql/codegen/GraphQLCodegen.java
+++ b/src/main/java/com/kobylynskyi/graphql/codegen/GraphQLCodegen.java
@@ -22,6 +22,7 @@
import java.util.Collection;
import java.util.List;
import java.util.Map;
+import java.util.stream.Collectors;
import static java.util.stream.Collectors.toList;
@@ -96,6 +97,15 @@ private static void sanitizeValues(MappingConfig mappingConfig) {
mappingConfig.setModelValidationAnnotation(
Utils.replaceLeadingAtSign(mappingConfig.getModelValidationAnnotation()));
+ if (mappingConfig.getResolverArgumentAnnotations() != null) {
+ mappingConfig.setResolverArgumentAnnotations(mappingConfig.getResolverArgumentAnnotations().stream()
+ .map(Utils::replaceLeadingAtSign).collect(Collectors.toSet()));
+ }
+ if (mappingConfig.getParametrizedResolverAnnotations() != null) {
+ mappingConfig.setParametrizedResolverAnnotations(mappingConfig.getParametrizedResolverAnnotations().stream()
+ .map(Utils::replaceLeadingAtSign).collect(Collectors.toSet()));
+ }
+
Map> customAnnotationsMapping = mappingConfig.getCustomAnnotationsMapping();
if (customAnnotationsMapping != null) {
for (Map.Entry> entry : customAnnotationsMapping.entrySet()) {
diff --git a/src/main/java/com/kobylynskyi/graphql/codegen/generators/impl/FieldResolversGenerator.java b/src/main/java/com/kobylynskyi/graphql/codegen/generators/impl/FieldResolversGenerator.java
index e668ad7bf..e96eb8d9e 100644
--- a/src/main/java/com/kobylynskyi/graphql/codegen/generators/impl/FieldResolversGenerator.java
+++ b/src/main/java/com/kobylynskyi/graphql/codegen/generators/impl/FieldResolversGenerator.java
@@ -17,6 +17,7 @@
import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import static java.util.stream.Collectors.toList;
@@ -51,9 +52,9 @@ private List generate(List fieldDefinitions,
if (!Boolean.TRUE.equals(mappingContext.getGenerateApis())) {
return Collections.emptyList();
}
+ Set fieldNamesWithResolvers = mappingContext.getFieldNamesWithResolvers();
List fieldDefsWithResolvers = fieldDefinitions.stream()
- .filter(fieldDef -> FieldDefinitionToParameterMapper.generateResolversForField(
- mappingContext, fieldDef, parentDefinition))
+ .filter(fieldDef -> fieldNamesWithResolvers.contains(parentDefinition.getName() + "." + fieldDef.getName()))
.collect(toList());
List generatedFiles = new ArrayList<>();
diff --git a/src/main/java/com/kobylynskyi/graphql/codegen/mapper/AnnotationsMapper.java b/src/main/java/com/kobylynskyi/graphql/codegen/mapper/AnnotationsMapper.java
index 5a23d5ce6..ecc6a103e 100644
--- a/src/main/java/com/kobylynskyi/graphql/codegen/mapper/AnnotationsMapper.java
+++ b/src/main/java/com/kobylynskyi/graphql/codegen/mapper/AnnotationsMapper.java
@@ -1,5 +1,6 @@
package com.kobylynskyi.graphql.codegen.mapper;
+import com.kobylynskyi.graphql.codegen.model.MappingConfigConstants;
import com.kobylynskyi.graphql.codegen.model.MappingContext;
import com.kobylynskyi.graphql.codegen.model.definitions.ExtendedDefinition;
import com.kobylynskyi.graphql.codegen.model.definitions.ExtendedFieldDefinition;
@@ -120,6 +121,18 @@ public List getAnnotations(MappingContext mappingContext, String graphQL
annotations.addAll(getAnnotationsForDirective(mappingContext, directiveAnnotations, directive));
}
}
+ // 6. Add annotations for resolver arguments
+ if (!Utils.isEmpty(mappingContext.getResolverArgumentAnnotations())
+ && mappingContext.getOperationsName().contains(parentTypeName)) {
+ annotations.addAll(mappingContext.getResolverArgumentAnnotations());
+ }
+ // 7. Add annotations for parametrized resolvers
+ if (!Utils.isEmpty(mappingContext.getParametrizedResolverAnnotations())
+ && mappingContext.getFieldNamesWithResolvers().contains(parentTypeName + "." + name)) {
+ for (String annotation : mappingContext.getParametrizedResolverAnnotations()) {
+ annotations.add(annotation.replace(MappingConfigConstants.TYPE_NAME_PLACEHOLDER, parentTypeName));
+ }
+ }
return annotations;
}
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 efc0c4a5f..fd6d74cdf 100644
--- a/src/main/java/com/kobylynskyi/graphql/codegen/model/GraphQLCodegenConfiguration.java
+++ b/src/main/java/com/kobylynskyi/graphql/codegen/model/GraphQLCodegenConfiguration.java
@@ -432,6 +432,30 @@ public interface GraphQLCodegenConfiguration {
*/
Set getTypesAsInterfaces();
+ /**
+ * Annotations that will be added to all resolver arguments.
+ *
+ * E.g.:
+ *
+ * - {@code @org.springframework.graphql.data.method.annotation.Argument}
+ *
+ *
+ * @return Set of annotations that every resolver argument will have.
+ */
+ Set getResolverArgumentAnnotations();
+
+ /**
+ * Annotations that will be added to all parametrized resolver methods.
+ *
+ * E.g.:
+ *
+ * - {@code @org.springframework.graphql.data.method.annotation.Argument}
+ *
+ *
+ * @return Set of annotations that every parametrized resolver method will have.
+ */
+ Set getParametrizedResolverAnnotations();
+
/**
* Generate code with lang
*
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 128901e52..50397b9a1 100644
--- a/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingConfig.java
+++ b/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingConfig.java
@@ -1,5 +1,6 @@
package com.kobylynskyi.graphql.codegen.model;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -15,10 +16,6 @@
*/
public class MappingConfig implements GraphQLCodegenConfiguration, Combinable {
- private Map customTypesMapping = new HashMap<>();
- private Map> customAnnotationsMapping = new HashMap<>();
- private Map> directiveAnnotationsMapping = new HashMap<>();
-
// package name configs:
private String packageName;
private String apiPackageName;
@@ -77,6 +74,14 @@ public class MappingConfig implements GraphQLCodegenConfiguration, Combinable useObjectMapperForRequestSerialization = new HashSet<>();
+ // annotations:
+ private Map> customAnnotationsMapping = new HashMap<>();
+ private Map> directiveAnnotationsMapping = new HashMap<>();
+ private Set resolverArgumentAnnotations = new HashSet<>();
+ private Set parametrizedResolverAnnotations = new HashSet<>();
+
+ private Map customTypesMapping = new HashMap<>();
+
private Set typesAsInterfaces = new HashSet<>();
private boolean generateModelOpenClasses;
@@ -179,6 +184,8 @@ public void combine(MappingConfig source) {
customTypesMapping = combineMap(customTypesMapping, source.customTypesMapping);
customAnnotationsMapping = combineMap(customAnnotationsMapping, source.customAnnotationsMapping);
directiveAnnotationsMapping = combineMap(directiveAnnotationsMapping, source.directiveAnnotationsMapping);
+ resolverArgumentAnnotations = combineSet(resolverArgumentAnnotations, source.resolverArgumentAnnotations);
+ parametrizedResolverAnnotations = combineSet(parametrizedResolverAnnotations, source.parametrizedResolverAnnotations);
generateAllMethodInProjection = getValueOrDefaultToThis(source,
GraphQLCodegenConfiguration::getGenerateAllMethodInProjection);
responseProjectionMaxDepth = getValueOrDefaultToThis(source,
@@ -641,6 +648,24 @@ public void setUseObjectMapperForRequestSerialization(Set useObjectMappe
this.useObjectMapperForRequestSerialization = useObjectMapperForRequestSerialization;
}
+ @Override
+ public Set getResolverArgumentAnnotations() {
+ return resolverArgumentAnnotations;
+ }
+
+ public void setResolverArgumentAnnotations(Set resolverArgumentAnnotations) {
+ this.resolverArgumentAnnotations = resolverArgumentAnnotations;
+ }
+
+ @Override
+ public Set getParametrizedResolverAnnotations() {
+ return parametrizedResolverAnnotations;
+ }
+
+ public void setParametrizedResolverAnnotations(Set parametrizedResolverAnnotations) {
+ this.parametrizedResolverAnnotations = parametrizedResolverAnnotations;
+ }
+
@Override
public Set getTypesAsInterfaces() {
return typesAsInterfaces;
diff --git a/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingConfigConstants.java b/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingConfigConstants.java
index df3499cde..8bd113789 100644
--- a/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingConfigConstants.java
+++ b/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingConfigConstants.java
@@ -8,6 +8,7 @@ public class MappingConfigConstants {
public static final String DEFAULT_VALIDATION_ANNOTATION = "javax.validation.constraints.NotNull";
public static final String PARENT_INTERFACE_TYPE_PLACEHOLDER = "{{TYPE}}";
+ public static final String TYPE_NAME_PLACEHOLDER = "{{TYPE_NAME}}";
public static final boolean DEFAULT_GENERATE_APIS = true;
public static final String DEFAULT_GENERATE_APIS_STRING = "true";
public static final boolean DEFAULT_BUILDER = true;
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 8b780d4d5..679b6fa89 100644
--- a/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingContext.java
+++ b/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingContext.java
@@ -2,14 +2,17 @@
import com.kobylynskyi.graphql.codegen.mapper.DataModelMapper;
import com.kobylynskyi.graphql.codegen.mapper.DataModelMapperFactory;
+import com.kobylynskyi.graphql.codegen.mapper.FieldDefinitionToParameterMapper;
import com.kobylynskyi.graphql.codegen.model.definitions.ExtendedDefinition;
import com.kobylynskyi.graphql.codegen.model.definitions.ExtendedDocument;
import com.kobylynskyi.graphql.codegen.model.definitions.ExtendedEnumTypeDefinition;
import com.kobylynskyi.graphql.codegen.model.definitions.ExtendedFieldDefinition;
import com.kobylynskyi.graphql.codegen.model.definitions.ExtendedInterfaceTypeDefinition;
+import com.kobylynskyi.graphql.codegen.model.definitions.ExtendedObjectTypeDefinition;
import java.io.File;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -26,11 +29,13 @@ public class MappingContext implements GraphQLCodegenConfiguration {
private final ExtendedDocument document;
private final Set typesUnionsInterfacesNames;
private final Set interfacesName;
+ private final Set operationsName;
private final Map> interfaceChildren;
private final GeneratedInformation generatedInformation;
private final DataModelMapperFactory dataModelMapperFactory;
private Set enumImportItSelfInScala;
private Map> parentInterfaceProperties;
+ private Set fieldNamesWithResolvers;
private MappingContext(File outputDirectory,
MappingConfig mappingConfig,
@@ -44,6 +49,7 @@ private MappingContext(File outputDirectory,
this.interfacesName = document.getInterfacesNames();
this.interfaceChildren = document.getInterfaceChildren();
this.generatedInformation = generatedInformation;
+ this.operationsName = document.getOperationsNames();
this.dataModelMapperFactory = dataModelMapperFactory;
}
@@ -63,7 +69,6 @@ public Boolean isInitializeNullableTypes() {
}
-
@Override
public Boolean isGenerateSealedInterfaces() {
return config.isGenerateSealedInterfaces();
@@ -309,6 +314,16 @@ public Set getTypesAsInterfaces() {
return config.getTypesAsInterfaces();
}
+ @Override
+ public Set getResolverArgumentAnnotations() {
+ return config.getResolverArgumentAnnotations();
+ }
+
+ @Override
+ public Set getParametrizedResolverAnnotations() {
+ return config.getParametrizedResolverAnnotations();
+ }
+
@Override
public Boolean isSupportUnknownFields() {
return config.isSupportUnknownFields();
@@ -331,6 +346,10 @@ public Set getInterfacesName() {
return interfacesName;
}
+ public Set getOperationsName() {
+ return operationsName;
+ }
+
public Map> getInterfaceChildren() {
return interfaceChildren;
}
@@ -381,6 +400,25 @@ public Map> getParentInterfaceProperties() {
return parentInterfaceProperties;
}
+ public Set getFieldNamesWithResolvers() {
+ if (fieldNamesWithResolvers == null) {
+ fieldNamesWithResolvers = new HashSet<>();
+ for (ExtendedObjectTypeDefinition definition : document.getTypeDefinitions()) {
+ definition.getFieldDefinitions().stream()
+ .filter(fieldDef -> FieldDefinitionToParameterMapper.generateResolversForField(
+ this, fieldDef, definition))
+ .forEach(fieldDef -> fieldNamesWithResolvers.add(definition.getName() + "." + fieldDef.getName()));
+ }
+ for (ExtendedInterfaceTypeDefinition definition : document.getInterfaceDefinitions()) {
+ definition.getFieldDefinitions().stream()
+ .filter(fieldDef -> FieldDefinitionToParameterMapper.generateResolversForField(
+ this, fieldDef, definition))
+ .forEach(fieldDef -> fieldNamesWithResolvers.add(definition.getName() + "." + fieldDef.getName()));
+ }
+ }
+ return fieldNamesWithResolvers;
+ }
+
private String getModelClassNameWithPrefixAndSuffix(ExtendedEnumTypeDefinition extendedEnumTypeDefinition) {
return DataModelMapper.getModelClassNameWithPrefixAndSuffix(this, extendedEnumTypeDefinition.getName());
}
diff --git a/src/main/java/com/kobylynskyi/graphql/codegen/model/definitions/ExtendedDocument.java b/src/main/java/com/kobylynskyi/graphql/codegen/model/definitions/ExtendedDocument.java
index f8e089dca..a758e8090 100644
--- a/src/main/java/com/kobylynskyi/graphql/codegen/model/definitions/ExtendedDocument.java
+++ b/src/main/java/com/kobylynskyi/graphql/codegen/model/definitions/ExtendedDocument.java
@@ -1,16 +1,26 @@
package com.kobylynskyi.graphql.codegen.model.definitions;
+import com.kobylynskyi.graphql.codegen.generators.FreeMarkerTemplateFilesCreator;
+import com.kobylynskyi.graphql.codegen.generators.FreeMarkerTemplateType;
+import com.kobylynskyi.graphql.codegen.mapper.FieldDefinitionToParameterMapper;
+import graphql.language.FieldDefinition;
import graphql.language.Type;
import graphql.language.TypeName;
+import java.io.File;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
+import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
+import static java.util.stream.Collectors.toList;
+
/**
* GraphQL document that holds all extended definitions
*/
@@ -87,6 +97,14 @@ public Set getInterfacesNames() {
.collect(Collectors.toSet());
}
+ public Set getOperationsNames() {
+ return operationDefinitions.stream()
+ .map(ExtendedObjectTypeDefinition::getFieldDefinitions)
+ .flatMap(Collection::stream)
+ .map(FieldDefinition::getName)
+ .collect(Collectors.toSet());
+ }
+
public Collection getOperationDefinitions() {
return operationDefinitions;
}
diff --git a/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenAnnotationsTest.java b/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenAnnotationsTest.java
index bfd231fdf..baa5d0ab5 100644
--- a/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenAnnotationsTest.java
+++ b/src/test/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenAnnotationsTest.java
@@ -17,6 +17,7 @@
import static com.kobylynskyi.graphql.codegen.TestUtils.assertFileContainsElements;
import static com.kobylynskyi.graphql.codegen.TestUtils.assertSameTrimmedContent;
import static com.kobylynskyi.graphql.codegen.TestUtils.getFileByName;
+import static java.util.Collections.singleton;
import static java.util.Collections.singletonList;
import static java.util.Collections.singletonMap;
@@ -202,6 +203,40 @@ void generate_CustomAnnotationMappings_Multiple() throws Exception {
"public class AcceptTopicSuggestionPayload ");
}
+ @Test
+ void generate_ResolverArgumentAnnotations() throws Exception {
+ mappingConfig.setGenerateDataFetchingEnvironmentArgumentInApis(true);
+ mappingConfig.setResolverArgumentAnnotations(singleton(
+ "@org.springframework.graphql.data.method.annotation.Argument"));
+
+ new JavaGraphQLCodegen(singletonList("src/test/resources/schemas/test.graphqls"),
+ outputBuildDir, mappingConfig, TestUtils.getStaticGeneratedInfo()).generate();
+
+ File[] files = Objects.requireNonNull(outputJavaClassesDir.listFiles());
+ assertSameTrimmedContent(
+ new File("src/test/resources/expected-classes/annotation/CreateEventMutationResolver_ArgumentAnnotations.java.txt"),
+ getFileByName(files, "CreateEventMutationResolver.java"));
+ assertSameTrimmedContent(
+ new File("src/test/resources/expected-classes/annotation/QueryResolver_ArgumentAnnotations.java.txt"),
+ getFileByName(files, "QueryResolver.java"));
+ }
+
+ @Test
+ void generate_ParametrizedResolverAnnotations() throws Exception {
+ mappingConfig.setModelNameSuffix("TO");
+ mappingConfig.setFieldsWithResolvers(singleton("@customResolver"));
+ mappingConfig.setParametrizedResolverAnnotations(singleton(
+ "@org.springframework.graphql.data.method.annotation.SchemaMapping(typeName=\"{{TYPE_NAME}}\")"));
+
+ new JavaGraphQLCodegen(singletonList("src/test/resources/schemas/test.graphqls"),
+ outputBuildDir, mappingConfig, TestUtils.getStaticGeneratedInfo()).generate();
+
+ File[] files = Objects.requireNonNull(outputJavaClassesDir.listFiles());
+ assertSameTrimmedContent(
+ new File("src/test/resources/expected-classes/annotation/EventPropertyResolver_ParametrizedResolverAnnotations.java.txt"),
+ getFileByName(files, "EventPropertyResolver.java"));
+ }
+
@Test
void generate_CustomAnnotationMappings_RequestResponseClasses() throws Exception {
Map> customAnnotationsMapping = new HashMap<>();
@@ -259,11 +294,11 @@ void generate_Directives() throws Exception {
new File("src/test/resources/expected-classes/annotation/MutationResolver.java.txt"),
getFileByName(files, "MutationResolver.java"));
assertSameTrimmedContent(
- new File("src/test/resources/expected-classes/annotation/EventProperty.java.txt"),
- getFileByName(files, "EventProperty.java"));
+ new File("src/test/resources/expected-classes/annotation/EventProperty.java.txt"),
+ getFileByName(files, "EventProperty.java"));
assertSameTrimmedContent(
- new File("src/test/resources/expected-classes/annotation/User.java.txt"),
- getFileByName(files, "User.java"));
+ new File("src/test/resources/expected-classes/annotation/User.java.txt"),
+ getFileByName(files, "User.java"));
}
@Test
diff --git a/src/test/java/com/kobylynskyi/graphql/codegen/model/MappingConfigTest.java b/src/test/java/com/kobylynskyi/graphql/codegen/model/MappingConfigTest.java
index 70695a1d7..a2cea64b4 100644
--- a/src/test/java/com/kobylynskyi/graphql/codegen/model/MappingConfigTest.java
+++ b/src/test/java/com/kobylynskyi/graphql/codegen/model/MappingConfigTest.java
@@ -62,6 +62,8 @@ private static MappingConfig buildMappingConfig() {
config.setTypeResolverPrefix("11");
config.setTypeResolverSuffix("12");
config.setTypesAsInterfaces(new HashSet<>(singletonList("User")));
+ config.setResolverArgumentAnnotations(new HashSet<>(singletonList("Ann1")));
+ config.setParametrizedResolverAnnotations(new HashSet<>(singletonList("PAnn1")));
RelayConfig relayConfig = new RelayConfig();
relayConfig.setDirectiveArgumentName("key");
config.setRelayConfig(relayConfig);
@@ -106,6 +108,8 @@ private static MappingConfig buildMappingConfig2() {
config.setTypeResolverPrefix("1111");
config.setTypeResolverSuffix("1212");
config.setTypesAsInterfaces(new HashSet<>(singletonList("User2")));
+ config.setResolverArgumentAnnotations(new HashSet<>(singletonList("Ann2")));
+ config.setParametrizedResolverAnnotations(new HashSet<>(singletonList("PAnn2")));
RelayConfig relayConfig = new RelayConfig();
relayConfig.setDirectiveArgumentName("for");
config.setRelayConfig(relayConfig);
@@ -163,6 +167,9 @@ private static void compareMappingConfigs(MappingConfig mappingConfig, MappingCo
assertEquals(expectedMappingConfig.getUseOptionalForNullableReturnTypes(),
mappingConfig.getUseOptionalForNullableReturnTypes());
assertEquals(expectedMappingConfig.getRelayConfig(), mappingConfig.getRelayConfig());
+ assertEquals(expectedMappingConfig.getTypesAsInterfaces(), mappingConfig.getTypesAsInterfaces());
+ assertEquals(expectedMappingConfig.getResolverArgumentAnnotations(), mappingConfig.getResolverArgumentAnnotations());
+ assertEquals(expectedMappingConfig.getParametrizedResolverAnnotations(), mappingConfig.getParametrizedResolverAnnotations());
}
@Test
@@ -222,6 +229,8 @@ void combineDefaultWithCustom() {
assertEquals("12", mappingConfig.getTypeResolverSuffix());
assertEquals("key", mappingConfig.getRelayConfig().getDirectiveArgumentName());
assertEquals(singleton("User"), mappingConfig.getTypesAsInterfaces());
+ assertEquals(singleton("Ann1"), mappingConfig.getResolverArgumentAnnotations());
+ assertEquals(singleton("PAnn1"), mappingConfig.getParametrizedResolverAnnotations());
}
@Test
@@ -266,6 +275,8 @@ void combineCustomWithDefault() {
assertEquals("12", mappingConfig.getTypeResolverSuffix());
assertEquals("key", mappingConfig.getRelayConfig().getDirectiveArgumentName());
assertEquals(singleton("User"), mappingConfig.getTypesAsInterfaces());
+ assertEquals(singleton("Ann1"), mappingConfig.getResolverArgumentAnnotations());
+ assertEquals(singleton("PAnn1"), mappingConfig.getParametrizedResolverAnnotations());
}
@Test
@@ -315,6 +326,8 @@ void combineCustomWithCustom() {
assertEquals("1212", mappingConfig.getTypeResolverSuffix());
assertEquals("for", mappingConfig.getRelayConfig().getDirectiveArgumentName());
assertEquals(new HashSet<>(Arrays.asList("User", "User2")), mappingConfig.getTypesAsInterfaces());
+ assertEquals(new HashSet<>(Arrays.asList("Ann1", "Ann2")), mappingConfig.getResolverArgumentAnnotations());
+ assertEquals(new HashSet<>(Arrays.asList("PAnn1", "PAnn2")), mappingConfig.getParametrizedResolverAnnotations());
}
}
diff --git a/src/test/resources/expected-classes/annotation/CreateEventMutationResolver_ArgumentAnnotations.java.txt b/src/test/resources/expected-classes/annotation/CreateEventMutationResolver_ArgumentAnnotations.java.txt
new file mode 100644
index 000000000..f9e29a6ea
--- /dev/null
+++ b/src/test/resources/expected-classes/annotation/CreateEventMutationResolver_ArgumentAnnotations.java.txt
@@ -0,0 +1,19 @@
+package com.kobylynskyi.graphql.test1;
+
+
+/**
+ * Create a new event.
+ */
+@javax.annotation.Generated(
+ value = "com.kobylynskyi.graphql.codegen.GraphQLCodegen",
+ date = "2020-12-31T23:59:59-0500"
+)
+public interface CreateEventMutationResolver {
+
+ /**
+ * Create a new event.
+ */
+ @javax.validation.constraints.NotNull
+ Event createEvent(@javax.validation.constraints.NotNull @org.springframework.graphql.data.method.annotation.Argument String categoryId, @org.springframework.graphql.data.method.annotation.Argument String createdBy, graphql.schema.DataFetchingEnvironment env) throws Exception;
+
+}
\ No newline at end of file
diff --git a/src/test/resources/expected-classes/annotation/EventPropertyResolver_ParametrizedResolverAnnotations.java.txt b/src/test/resources/expected-classes/annotation/EventPropertyResolver_ParametrizedResolverAnnotations.java.txt
new file mode 100644
index 000000000..d71e0c0df
--- /dev/null
+++ b/src/test/resources/expected-classes/annotation/EventPropertyResolver_ParametrizedResolverAnnotations.java.txt
@@ -0,0 +1,50 @@
+package com.kobylynskyi.graphql.test1;
+
+
+/**
+ * Resolver for EventProperty
+ */
+@javax.annotation.Generated(
+ value = "com.kobylynskyi.graphql.codegen.GraphQLCodegen",
+ date = "2020-12-31T23:59:59-0500"
+)
+public interface EventPropertyResolver {
+
+ /**
+ * Float property
+ * with multiline comment
+ */
+ @org.springframework.graphql.data.method.annotation.SchemaMapping(typeName="EventProperty")
+ Double floatVal(EventPropertyTO eventProperty) throws Exception;
+
+ @org.springframework.graphql.data.method.annotation.SchemaMapping(typeName="EventProperty")
+ Boolean booleanVal(EventPropertyTO eventProperty) throws Exception;
+
+ @org.springframework.graphql.data.method.annotation.SchemaMapping(typeName="EventProperty")
+ int intVal(EventPropertyTO eventProperty) throws Exception;
+
+ /**
+ * primitive should not be generated
+ */
+ @org.springframework.graphql.data.method.annotation.SchemaMapping(typeName="EventProperty")
+ java.util.List intVals(EventPropertyTO eventProperty) throws Exception;
+
+ /**
+ * String comment
+ */
+ @org.springframework.graphql.data.method.annotation.SchemaMapping(typeName="EventProperty")
+ String stringVal(EventPropertyTO eventProperty) throws Exception;
+
+ /**
+ * Properties
+ */
+ @org.springframework.graphql.data.method.annotation.SchemaMapping(typeName="EventProperty")
+ java.util.List child(EventPropertyTO eventProperty, Integer first, Integer last) throws Exception;
+
+ /**
+ * Parent event of the property
+ */
+ @org.springframework.graphql.data.method.annotation.SchemaMapping(typeName="EventProperty")
+ EventTO parent(EventPropertyTO eventProperty, EventStatusTO withStatus, String createdAfter) throws Exception;
+
+}
\ No newline at end of file
diff --git a/src/test/resources/expected-classes/annotation/QueryResolver_ArgumentAnnotations.java.txt b/src/test/resources/expected-classes/annotation/QueryResolver_ArgumentAnnotations.java.txt
new file mode 100644
index 000000000..ed4597fe3
--- /dev/null
+++ b/src/test/resources/expected-classes/annotation/QueryResolver_ArgumentAnnotations.java.txt
@@ -0,0 +1,34 @@
+package com.kobylynskyi.graphql.test1;
+
+
+@javax.annotation.Generated(
+ value = "com.kobylynskyi.graphql.codegen.GraphQLCodegen",
+ date = "2020-12-31T23:59:59-0500"
+)
+public interface QueryResolver {
+
+ /**
+ * Version of the application.
+ */
+ @javax.validation.constraints.NotNull
+ String version(graphql.schema.DataFetchingEnvironment env) throws Exception;
+
+ /**
+ * List of events of a specified category.
+ */
+ @javax.validation.constraints.NotNull
+ java.util.List eventsByCategoryAndStatus(@javax.validation.constraints.NotNull @org.springframework.graphql.data.method.annotation.Argument String categoryId, @org.springframework.graphql.data.method.annotation.Argument EventStatus status, graphql.schema.DataFetchingEnvironment env) throws Exception;
+
+ /**
+ * Single event by ID.
+ */
+ @javax.validation.constraints.NotNull
+ Event eventById(@javax.validation.constraints.NotNull @org.springframework.graphql.data.method.annotation.Argument String id, graphql.schema.DataFetchingEnvironment env) throws Exception;
+
+ /**
+ * Events by IDs.
+ */
+ @javax.validation.constraints.NotNull
+ java.util.List eventsByIds(@javax.validation.constraints.NotNull @org.springframework.graphql.data.method.annotation.Argument java.util.List ids, graphql.schema.DataFetchingEnvironment env) throws Exception;
+
+}
\ No newline at end of file
From 4edf8790d41e930c3a5bd5199e590113cf371bb1 Mon Sep 17 00:00:00 2001
From: Bogdan Kobylynskyi <92bogdan@gmail.com>
Date: Sun, 31 Jul 2022 16:42:12 -0400
Subject: [PATCH 2/2] Fix imports and markdown table styling
---
docs/codegen-options.md | 120 +++++++++---------
.../impl/FieldResolversGenerator.java | 1 -
.../graphql/codegen/model/MappingConfig.java | 1 -
.../model/definitions/ExtendedDocument.java | 9 --
4 files changed, 60 insertions(+), 71 deletions(-)
diff --git a/docs/codegen-options.md b/docs/codegen-options.md
index 54abc7da8..ab795aaaa 100644
--- a/docs/codegen-options.md
+++ b/docs/codegen-options.md
@@ -1,66 +1,66 @@
# 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. |
-| `addGeneratedAnnotation` | Boolean | True | Specifies whether generated classes should have `@Generated` annotation. |
-| `generateJacksonTypeIdResolver` | Boolean | False | Specifies whether generated union interfaces should be annotated with a custom Jackson type id resolver generated in model package. |
-| `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)* |
-| `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`. |
-| `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}}")` |
-| `generateParameterizedFieldsR`
`esolvers` | 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. |
-| `generateExtensionFieldsResol`
`vers` | 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`. |
-| `useOptionalForNullableReturn`
`Types` | 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. |
-| `generateApisWithThrowsExcept`
`ion` | Boolean | True | Specifies whether api interface methods should have `throws Exception` in signature. |
-| `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. |
-| `typesAsInterfaces` | Set(String) | Empty | Types that must generated as interfaces should be defined here in format: `TypeName` or `@directive`. E.g.: `User`, `@asInterface`. |
+| 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. |
+| `addGeneratedAnnotation` | Boolean | True | Specifies whether generated classes should have `@Generated` annotation. |
+| `generateJacksonTypeIdResolver` | Boolean | False | Specifies whether generated union interfaces should be annotated with a custom Jackson type id resolver generated in model package. |
+| `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)* |
+| `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`. |
+| `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}}")` |
+| `generateParameterizedFieldsR`
`esolvers` | 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. |
+| `generateExtensionFieldsResol`
`vers` | 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`. |
+| `useOptionalForNullableReturn`
`Types` | 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. |
+| `generateApisWithThrowsExcept`
`ion` | Boolean | True | Specifies whether api interface methods should have `throws Exception` in signature. |
+| `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. |
+| `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 |
+| `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 |
### Option `graphqlSchemas`
diff --git a/src/main/java/com/kobylynskyi/graphql/codegen/generators/impl/FieldResolversGenerator.java b/src/main/java/com/kobylynskyi/graphql/codegen/generators/impl/FieldResolversGenerator.java
index e96eb8d9e..583475be4 100644
--- a/src/main/java/com/kobylynskyi/graphql/codegen/generators/impl/FieldResolversGenerator.java
+++ b/src/main/java/com/kobylynskyi/graphql/codegen/generators/impl/FieldResolversGenerator.java
@@ -4,7 +4,6 @@
import com.kobylynskyi.graphql.codegen.generators.FreeMarkerTemplateFilesCreator;
import com.kobylynskyi.graphql.codegen.generators.FreeMarkerTemplateType;
import com.kobylynskyi.graphql.codegen.mapper.DataModelMapperFactory;
-import com.kobylynskyi.graphql.codegen.mapper.FieldDefinitionToParameterMapper;
import com.kobylynskyi.graphql.codegen.mapper.FieldDefinitionsToResolverDataModelMapper;
import com.kobylynskyi.graphql.codegen.model.MappingContext;
import com.kobylynskyi.graphql.codegen.model.definitions.ExtendedDefinition;
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 50397b9a1..792e1c5c2 100644
--- a/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingConfig.java
+++ b/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingConfig.java
@@ -1,6 +1,5 @@
package com.kobylynskyi.graphql.codegen.model;
-import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
diff --git a/src/main/java/com/kobylynskyi/graphql/codegen/model/definitions/ExtendedDocument.java b/src/main/java/com/kobylynskyi/graphql/codegen/model/definitions/ExtendedDocument.java
index a758e8090..7a694c7dd 100644
--- a/src/main/java/com/kobylynskyi/graphql/codegen/model/definitions/ExtendedDocument.java
+++ b/src/main/java/com/kobylynskyi/graphql/codegen/model/definitions/ExtendedDocument.java
@@ -1,26 +1,17 @@
package com.kobylynskyi.graphql.codegen.model.definitions;
-import com.kobylynskyi.graphql.codegen.generators.FreeMarkerTemplateFilesCreator;
-import com.kobylynskyi.graphql.codegen.generators.FreeMarkerTemplateType;
-import com.kobylynskyi.graphql.codegen.mapper.FieldDefinitionToParameterMapper;
import graphql.language.FieldDefinition;
import graphql.language.Type;
import graphql.language.TypeName;
-import java.io.File;
-import java.util.ArrayList;
import java.util.Collection;
-import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
-import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
-import static java.util.stream.Collectors.toList;
-
/**
* GraphQL document that holds all extended definitions
*/