diff --git a/build.gradle b/build.gradle
index e50415ad2a86fa0f6fac8d99336449b67147a0a3..1275e32b7c383d3d5e650ef39e12afcadf0b6c71 100644
--- a/build.gradle
+++ b/build.gradle
@@ -20,7 +20,7 @@ repositories {
dependencies {
implementation "org.freemarker:freemarker:2.3.30"
implementation "com.graphql-java:graphql-java:15.0"
- implementation "com.fasterxml.jackson.core:jackson-databind:2.11.0"
+ implementation "com.fasterxml.jackson.core:jackson-databind:2.11.1"
implementation "org.projectlombok:lombok:1.18.12"
annotationProcessor "org.projectlombok:lombok:1.18.12"
@@ -46,6 +46,19 @@ task codeCoverageReport(type: JacocoReport) {
}
}
+test {
+ testLogging {
+ events "failed"
+
+ showExceptions true
+ exceptionFormat "full"
+ showCauses true
+ showStackTraces true
+
+ showStandardStreams = false
+ }
+}
+
codeCoverageReport.dependsOn test
diff --git a/docs/codegen-options.md b/docs/codegen-options.md
index 46de1f4067339d6d7098311d61fad6db18a2dcb3..9992e62cc86054003868685233967d921f560bdc 100644
--- a/docs/codegen-options.md
+++ b/docs/codegen-options.md
@@ -17,18 +17,21 @@
| `generateImmutableModels` | Boolean | False | Specifies whether generated model classes should be immutable. |
| `generateToString` | Boolean | False | Specifies whether generated model classes should have toString method defined. |
| `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). |
+| `apiNameSuffix` | String | `Resolver` | Sets the suffix for GraphQL api classes (query, mutation, subscription). |
| `apiRootInterfaceStrategy` | *See [ApiRootInterfaceStrategy](#option-apirootinterfacestrategy)* | `SINGLE_INTERFACE` | |
| `apiNamePrefixStrategy` | *See [ApiNamePrefixStrategy](#option-apinameprefixstrategy)* | `CONSTANT` | |
| `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 | Can be used to supply custom mappings for scalars.
Supports:
* Map of (GraphqlObjectName.fieldName) to (JavaType)
* Map of (GraphqlType) to (JavaType) |
| `customAnnotationsMapping` | Map(String,String) | Empty | Can be used to supply custom annotations (serializers) for scalars.
Supports:
* Map of (GraphqlObjectName.fieldName) to (JavaAnnotation)
* Map of (GraphqlType) to (JavaAnnotation) |
| `fieldsWithResolvers` | Set(String) | Empty | Fields that require Resolvers should be defined here in format: `TypeName.fieldName` or `TypeName`. |
| `fieldsWithoutResolvers` | Set(String) | Empty | Fields that DO NOT require Resolvers should be defined here in format: `TypeName.fieldName` or `TypeName`. Can be used in conjunction with `generateExtensionFieldsResolvers` option. |
| `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`. |
| `subscriptionReturnType` | String | Empty | Return type for subscription methods. For example: `org.reactivestreams.Publisher`, `io.reactivex.Observable`, etc. |
| `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. |
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 d3a2e576ff5dd5daf40d0bc0e3417e69a074f23a..3437ca998fea39bd501e82c810072126c83c775c 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
@@ -50,7 +50,9 @@ public class GraphQLCodegenGradleTask extends DefaultTask implements GraphQLCode
private ApiNamePrefixStrategy apiNamePrefixStrategy = MappingConfigConstants.DEFAULT_API_NAME_PREFIX_STRATEGY;
private ApiRootInterfaceStrategy apiRootInterfaceStrategy = MappingConfigConstants.DEFAULT_API_ROOT_INTERFACE_STRATEGY;
private String apiNamePrefix;
- private String apiNameSuffix;
+ private String apiNameSuffix = MappingConfigConstants.DEFAULT_RESOLVER_SUFFIX;;
+ private String typeResolverPrefix;
+ private String typeResolverSuffix = MappingConfigConstants.DEFAULT_RESOLVER_SUFFIX;
private String modelPackageName;
private String modelNamePrefix;
private String modelNameSuffix;
@@ -65,6 +67,7 @@ public class GraphQLCodegenGradleTask extends DefaultTask implements GraphQLCode
private Boolean generateParameterizedFieldsResolvers = MappingConfigConstants.DEFAULT_GENERATE_PARAMETERIZED_FIELDS_RESOLVERS;
private Boolean generateExtensionFieldsResolvers = MappingConfigConstants.DEFAULT_GENERATE_EXTENSION_FIELDS_RESOLVERS;
private Boolean generateDataFetchingEnvironmentArgumentInApis = MappingConfigConstants.DEFAULT_GENERATE_DATA_FETCHING_ENV;
+ private Boolean generateModelsForRootTypes = MappingConfigConstants.DEFAULT_GENERATE_MODELS_FOR_ROOT_TYPES;
private Set fieldsWithResolvers = new HashSet<>();
private Set fieldsWithoutResolvers = new HashSet<>();
@@ -86,7 +89,7 @@ public class GraphQLCodegenGradleTask extends DefaultTask implements GraphQLCode
public void generate() throws Exception {
MappingConfig mappingConfig = new MappingConfig();
mappingConfig.setPackageName(packageName);
- mappingConfig.setCustomTypesMapping(customTypesMapping);
+ mappingConfig.setCustomTypesMapping(customTypesMapping != null ? customTypesMapping : new HashMap<>());
mappingConfig.setApiNameSuffix(apiNameSuffix);
mappingConfig.setApiNamePrefix(apiNamePrefix);
mappingConfig.setApiRootInterfaceStrategy(apiRootInterfaceStrategy);
@@ -97,18 +100,21 @@ public class GraphQLCodegenGradleTask extends DefaultTask implements GraphQLCode
mappingConfig.setModelPackageName(modelPackageName);
mappingConfig.setGenerateBuilder(generateBuilder);
mappingConfig.setGenerateApis(generateApis);
+ mappingConfig.setTypeResolverSuffix(typeResolverSuffix);
+ mappingConfig.setTypeResolverPrefix(typeResolverPrefix);
mappingConfig.setModelValidationAnnotation(modelValidationAnnotation);
- mappingConfig.setSubscriptionReturnType(subscriptionReturnType);
- mappingConfig.setCustomAnnotationsMapping(customAnnotationsMapping);
+ mappingConfig.setCustomAnnotationsMapping(customAnnotationsMapping != null ? customAnnotationsMapping : new HashMap<>());
mappingConfig.setGenerateEqualsAndHashCode(generateEqualsAndHashCode);
mappingConfig.setGenerateImmutableModels(generateImmutableModels);
mappingConfig.setGenerateToString(generateToString);
+ mappingConfig.setSubscriptionReturnType(subscriptionReturnType);
mappingConfig.setGenerateAsyncApi(generateAsyncApi);
mappingConfig.setGenerateParameterizedFieldsResolvers(generateParameterizedFieldsResolvers);
- mappingConfig.setGenerateExtensionFieldsResolvers(generateExtensionFieldsResolvers);
mappingConfig.setGenerateDataFetchingEnvironmentArgumentInApis(generateDataFetchingEnvironmentArgumentInApis);
- mappingConfig.setFieldsWithResolvers(fieldsWithResolvers);
- mappingConfig.setFieldsWithoutResolvers(fieldsWithoutResolvers);
+ mappingConfig.setGenerateExtensionFieldsResolvers(generateExtensionFieldsResolvers);
+ mappingConfig.setGenerateModelsForRootTypes(generateModelsForRootTypes);
+ mappingConfig.setFieldsWithResolvers(fieldsWithResolvers != null ? fieldsWithResolvers : new HashSet<>());
+ mappingConfig.setFieldsWithoutResolvers(fieldsWithoutResolvers != null ? fieldsWithoutResolvers : new HashSet<>());
mappingConfig.setGenerateClient(generateClient);
mappingConfig.setRequestSuffix(requestSuffix);
mappingConfig.setResponseSuffix(responseSuffix);
@@ -328,6 +334,17 @@ public class GraphQLCodegenGradleTask extends DefaultTask implements GraphQLCode
this.generateApis = generateApis;
}
+ @Input
+ @Optional
+ @Override
+ public Boolean getGenerateModelsForRootTypes() {
+ return generateModelsForRootTypes;
+ }
+
+ public void setGenerateModelsForRootTypes(Boolean generateModelsForRootTypes) {
+ this.generateModelsForRootTypes = generateModelsForRootTypes;
+ }
+
@Input
@Optional
@Override
@@ -416,6 +433,28 @@ public class GraphQLCodegenGradleTask extends DefaultTask implements GraphQLCode
this.generateParameterizedFieldsResolvers = generateParameterizedFieldsResolvers;
}
+ @Input
+ @Optional
+ @Override
+ public String getTypeResolverPrefix() {
+ return typeResolverPrefix;
+ }
+
+ public void setTypeResolverPrefix(String typeResolverPrefix) {
+ this.typeResolverPrefix = typeResolverPrefix;
+ }
+
+ @Input
+ @Optional
+ @Override
+ public String getTypeResolverSuffix() {
+ return typeResolverSuffix;
+ }
+
+ public void setTypeResolverSuffix(String typeResolverSuffix) {
+ this.typeResolverSuffix = typeResolverSuffix;
+ }
+
@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 50485e3677f12f3054158583afe9cfa3be3cffc9..cd805361a4e0fc7527275652a2b474fbfa601975 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
@@ -71,7 +71,7 @@ public class GraphQLCodegenMojo extends AbstractMojo implements GraphQLCodegenCo
@Parameter
private String apiNamePrefix;
- @Parameter(defaultValue = MappingConfigConstants.DEFAULT_API_NAME_SUFFIX)
+ @Parameter(defaultValue = MappingConfigConstants.DEFAULT_RESOLVER_SUFFIX)
private String apiNameSuffix;
@Parameter
@@ -83,6 +83,12 @@ public class GraphQLCodegenMojo extends AbstractMojo implements GraphQLCodegenCo
@Parameter
private String modelNameSuffix;
+ @Parameter
+ private String typeResolverPrefix;
+
+ @Parameter(defaultValue = MappingConfigConstants.DEFAULT_RESOLVER_SUFFIX)
+ private String typeResolverSuffix;
+
@Parameter
private String subscriptionReturnType;
@@ -107,6 +113,9 @@ public class GraphQLCodegenMojo extends AbstractMojo implements GraphQLCodegenCo
@Parameter(defaultValue = MappingConfigConstants.DEFAULT_GENERATE_DATA_FETCHING_ENV_STRING)
private boolean generateDataFetchingEnvironmentArgumentInApis;
+ @Parameter(defaultValue = MappingConfigConstants.DEFAULT_GENERATE_MODELS_FOR_ROOT_TYPES_STRING)
+ private boolean generateModelsForRootTypes;
+
@Parameter
private Set fieldsWithResolvers = new HashSet<>();
@@ -125,7 +134,7 @@ public class GraphQLCodegenMojo extends AbstractMojo implements GraphQLCodegenCo
@Parameter(defaultValue = MappingConfigConstants.DEFAULT_RESPONSE_PROJECTION_SUFFIX)
private String responseProjectionSuffix;
- @Parameter(defaultValue = MappingConfigConstants.DEFAULT_PARAMETRIZED_INPUT_SUFIX)
+ @Parameter(defaultValue = MappingConfigConstants.DEFAULT_PARAMETRIZED_INPUT_SUFFIX)
private String parametrizedInputSuffix;
@Parameter
@@ -157,6 +166,8 @@ public class GraphQLCodegenMojo extends AbstractMojo implements GraphQLCodegenCo
mappingConfig.setModelPackageName(modelPackageName);
mappingConfig.setGenerateBuilder(generateBuilder);
mappingConfig.setGenerateApis(generateApis);
+ mappingConfig.setTypeResolverSuffix(typeResolverSuffix);
+ mappingConfig.setTypeResolverPrefix(typeResolverPrefix);
mappingConfig.setModelValidationAnnotation(modelValidationAnnotation);
mappingConfig.setCustomAnnotationsMapping(customAnnotationsMapping != null ? customAnnotationsMapping : new HashMap<>());
mappingConfig.setGenerateEqualsAndHashCode(generateEqualsAndHashCode);
@@ -167,6 +178,7 @@ public class GraphQLCodegenMojo extends AbstractMojo implements GraphQLCodegenCo
mappingConfig.setGenerateParameterizedFieldsResolvers(generateParameterizedFieldsResolvers);
mappingConfig.setGenerateDataFetchingEnvironmentArgumentInApis(generateDataFetchingEnvironmentArgumentInApis);
mappingConfig.setGenerateExtensionFieldsResolvers(generateExtensionFieldsResolvers);
+ mappingConfig.setGenerateModelsForRootTypes(generateModelsForRootTypes);
mappingConfig.setFieldsWithResolvers(fieldsWithResolvers != null ? fieldsWithResolvers : new HashSet<>());
mappingConfig.setFieldsWithoutResolvers(fieldsWithoutResolvers != null ? fieldsWithoutResolvers : new HashSet<>());
mappingConfig.setGenerateClient(generateClient);
@@ -359,6 +371,15 @@ public class GraphQLCodegenMojo extends AbstractMojo implements GraphQLCodegenCo
this.generateApis = generateApis;
}
+ @Override
+ public Boolean getGenerateModelsForRootTypes() {
+ return generateModelsForRootTypes;
+ }
+
+ public void setGenerateModelsForRootTypes(boolean generateModelsForRootTypes) {
+ this.generateModelsForRootTypes = generateModelsForRootTypes;
+ }
+
@Override
public Boolean getGenerateEqualsAndHashCode() {
return generateEqualsAndHashCode;
@@ -422,6 +443,24 @@ public class GraphQLCodegenMojo extends AbstractMojo implements GraphQLCodegenCo
this.generateParameterizedFieldsResolvers = generateParameterizedFieldsResolvers;
}
+ @Override
+ public String getTypeResolverPrefix() {
+ return typeResolverPrefix;
+ }
+
+ public void setTypeResolverPrefix(String typeResolverPrefix) {
+ this.typeResolverPrefix = typeResolverPrefix;
+ }
+
+ @Override
+ public String getTypeResolverSuffix() {
+ return typeResolverSuffix;
+ }
+
+ public void setTypeResolverSuffix(String typeResolverSuffix) {
+ this.typeResolverSuffix = typeResolverSuffix;
+ }
+
@Override
public Boolean getGenerateDataFetchingEnvironmentArgumentInApis() {
return generateDataFetchingEnvironmentArgumentInApis;
diff --git a/src/main/java/com/kobylynskyi/graphql/codegen/GraphQLCodegen.java b/src/main/java/com/kobylynskyi/graphql/codegen/GraphQLCodegen.java
index 0b69b2dbd25f29395b1cb57ca083b1e212ff383a..c172b4aef2328711901b12b299b1678734a7bbea 100644
--- a/src/main/java/com/kobylynskyi/graphql/codegen/GraphQLCodegen.java
+++ b/src/main/java/com/kobylynskyi/graphql/codegen/GraphQLCodegen.java
@@ -82,10 +82,11 @@ public class GraphQLCodegen {
this.mappingConfig = mappingConfig;
this.mappingConfig.combine(externalMappingConfigSupplier != null ? externalMappingConfigSupplier.get() : null);
initDefaultValues(mappingConfig);
+ validateConfigs(mappingConfig);
this.generatedInformation = generatedInformation;
}
- private void initDefaultValues(MappingConfig mappingConfig) {
+ private static void initDefaultValues(MappingConfig mappingConfig) {
if (mappingConfig.getModelValidationAnnotation() == null) {
mappingConfig.setModelValidationAnnotation(MappingConfigConstants.DEFAULT_VALIDATION_ANNOTATION);
}
@@ -108,7 +109,7 @@ public class GraphQLCodegen {
mappingConfig.setResponseProjectionSuffix(MappingConfigConstants.DEFAULT_RESPONSE_PROJECTION_SUFFIX);
}
if (mappingConfig.getParametrizedInputSuffix() == null) {
- mappingConfig.setParametrizedInputSuffix(MappingConfigConstants.DEFAULT_PARAMETRIZED_INPUT_SUFIX);
+ mappingConfig.setParametrizedInputSuffix(MappingConfigConstants.DEFAULT_PARAMETRIZED_INPUT_SUFFIX);
}
if (mappingConfig.getGenerateImmutableModels() == null) {
mappingConfig.setGenerateImmutableModels(MappingConfigConstants.DEFAULT_GENERATE_IMMUTABLE_MODELS);
@@ -120,7 +121,10 @@ public class GraphQLCodegen {
mappingConfig.setGenerateApis(MappingConfigConstants.DEFAULT_GENERATE_APIS);
}
if (mappingConfig.getApiNameSuffix() == null) {
- mappingConfig.setApiNameSuffix(MappingConfigConstants.DEFAULT_API_NAME_SUFFIX);
+ mappingConfig.setApiNameSuffix(MappingConfigConstants.DEFAULT_RESOLVER_SUFFIX);
+ }
+ if (mappingConfig.getTypeResolverSuffix() == null) {
+ mappingConfig.setTypeResolverSuffix(MappingConfigConstants.DEFAULT_RESOLVER_SUFFIX);
}
if (mappingConfig.getGenerateAsyncApi() == null) {
mappingConfig.setGenerateAsyncApi(MappingConfigConstants.DEFAULT_GENERATE_ASYNC_APIS);
@@ -134,6 +138,9 @@ public class GraphQLCodegen {
if (mappingConfig.getGenerateDataFetchingEnvironmentArgumentInApis() == null) {
mappingConfig.setGenerateDataFetchingEnvironmentArgumentInApis(MappingConfigConstants.DEFAULT_GENERATE_DATA_FETCHING_ENV);
}
+ if (mappingConfig.getGenerateModelsForRootTypes() == null) {
+ mappingConfig.setGenerateModelsForRootTypes(MappingConfigConstants.DEFAULT_GENERATE_MODELS_FOR_ROOT_TYPES);
+ }
if (mappingConfig.getApiNamePrefixStrategy() == null) {
mappingConfig.setApiNamePrefixStrategy(MappingConfigConstants.DEFAULT_API_NAME_PREFIX_STRATEGY);
}
@@ -144,11 +151,30 @@ public class GraphQLCodegen {
// required for request serialization
mappingConfig.setGenerateToString(true);
}
+ }
+
+ private static void validateConfigs(MappingConfig mappingConfig) {
if (mappingConfig.getApiRootInterfaceStrategy() == ApiRootInterfaceStrategy.INTERFACE_PER_SCHEMA &&
mappingConfig.getApiNamePrefixStrategy() == ApiNamePrefixStrategy.CONSTANT) {
- // that's because we will have a conflict in case there is "type Query" in multiple graphql schema files
+ // we will have a conflict in case there is "type Query" in multiple graphql schema files
throw new IllegalArgumentException("API prefix should not be CONSTANT for INTERFACE_PER_SCHEMA option");
}
+ if (mappingConfig.getGenerateApis() &&
+ mappingConfig.getGenerateModelsForRootTypes() &&
+ mappingConfig.getApiNamePrefixStrategy() == ApiNamePrefixStrategy.CONSTANT) {
+ // checking for conflict between root type model classes and api interfaces
+ if (Utils.stringsEqualIgnoreSpaces(mappingConfig.getApiNamePrefix(), mappingConfig.getModelNamePrefix()) &&
+ Utils.stringsEqualIgnoreSpaces(mappingConfig.getApiNameSuffix(), mappingConfig.getModelNameSuffix())) {
+ // we will have a conflict between model pojo (Query.java) and api interface (Query.java)
+ throw new IllegalArgumentException("Either disable APIs generation or set different Prefix/Suffix for API classes and model classes");
+ }
+ // checking for conflict between root type model resolver classes and api interfaces
+ if (Utils.stringsEqualIgnoreSpaces(mappingConfig.getApiNamePrefix(), mappingConfig.getTypeResolverPrefix()) &&
+ Utils.stringsEqualIgnoreSpaces(mappingConfig.getApiNameSuffix(), mappingConfig.getTypeResolverSuffix())) {
+ // we will have a conflict between model resolver interface (QueryResolver.java) and api interface resolver (QueryResolver.java)
+ throw new IllegalArgumentException("Either disable APIs generation or set different Prefix/Suffix for API classes and type resolver classes");
+ }
+ }
}
public List generate() throws IOException {
@@ -156,7 +182,7 @@ public class GraphQLCodegen {
long startTime = System.currentTimeMillis();
List generatedFiles = Collections.emptyList();
if (!schemas.isEmpty()) {
- ExtendedDocument document = GraphQLDocumentParser.getDocument(schemas);
+ ExtendedDocument document = GraphQLDocumentParser.getDocument(mappingConfig, schemas);
initCustomTypeMappings(document.getScalarDefinitions());
generatedFiles = processDefinitions(document);
}
diff --git a/src/main/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenValidate.java b/src/main/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenValidate.java
index 965e17832cd559c739d6920c36b6db8daf3a3f38..6c342227c02c69635cf1223a579e9dbcc4fb2cec 100644
--- a/src/main/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenValidate.java
+++ b/src/main/java/com/kobylynskyi/graphql/codegen/GraphQLCodegenValidate.java
@@ -2,6 +2,8 @@ package com.kobylynskyi.graphql.codegen;
import com.kobylynskyi.graphql.codegen.model.exception.SchemaValidationException;
import graphql.GraphQLException;
+import graphql.parser.MultiSourceReader;
+import graphql.parser.Parser;
import lombok.AllArgsConstructor;
import java.io.IOException;
@@ -18,16 +20,15 @@ public class GraphQLCodegenValidate {
private final List schemas;
public void validate() throws IOException {
- for (String schema : schemas) {
- try {
- long startTime = System.currentTimeMillis();
- GraphQLDocumentParser.getDocument(schema);
- System.out.println(String.format("Validated schema '%s' in %d ms",
- schema, System.currentTimeMillis() - startTime));
- } catch (GraphQLException e) {
- throw new SchemaValidationException(e.getMessage());
- }
+ long startTime = System.currentTimeMillis();
+ try (MultiSourceReader reader = GraphQLDocumentParser.createMultiSourceReader(schemas)) {
+ new Parser().parseDocument(reader);
+ System.out.println(String.format("Validated schemas '%s' in %d ms",
+ schemas, System.currentTimeMillis() - startTime));
+ } catch (GraphQLException e) {
+ throw new SchemaValidationException(e.getMessage());
}
+
}
}
diff --git a/src/main/java/com/kobylynskyi/graphql/codegen/GraphQLDocumentParser.java b/src/main/java/com/kobylynskyi/graphql/codegen/GraphQLDocumentParser.java
index 72637340cfede492b492ad7e7ff7991cb9889ac5..283f5dfba3fdced790a3de02b536c015287060ee 100644
--- a/src/main/java/com/kobylynskyi/graphql/codegen/GraphQLDocumentParser.java
+++ b/src/main/java/com/kobylynskyi/graphql/codegen/GraphQLDocumentParser.java
@@ -1,5 +1,6 @@
package com.kobylynskyi.graphql.codegen;
+import com.kobylynskyi.graphql.codegen.model.MappingConfig;
import com.kobylynskyi.graphql.codegen.model.definitions.ExtendedDefinition;
import com.kobylynskyi.graphql.codegen.model.definitions.ExtendedDocument;
import com.kobylynskyi.graphql.codegen.model.definitions.ExtendedEnumTypeDefinition;
@@ -28,7 +29,6 @@ import graphql.parser.MultiSourceReader;
import graphql.parser.Parser;
import java.io.IOException;
-import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -41,11 +41,7 @@ class GraphQLDocumentParser {
private GraphQLDocumentParser() {
}
- static ExtendedDocument getDocument(String schemaFilePath) throws IOException {
- return getDocument(Collections.singletonList(schemaFilePath));
- }
-
- static ExtendedDocument getDocument(List schemaPaths) throws IOException {
+ static ExtendedDocument getDocument(MappingConfig mappingConfig, List schemaPaths) throws IOException {
Document document = readDocument(schemaPaths);
Map operationDefinitions = new HashMap<>();
@@ -68,6 +64,11 @@ class GraphQLDocumentParser {
populateDefinition(operationDefinitions, definition, definitionName,
ObjectTypeDefinition.class, ObjectTypeExtensionDefinition.class,
s -> new ExtendedObjectTypeDefinition());
+ if (Boolean.TRUE.equals(mappingConfig.getGenerateModelsForRootTypes())) {
+ populateDefinition(typeDefinitions, definition, definitionName,
+ ObjectTypeDefinition.class, ObjectTypeExtensionDefinition.class,
+ s -> new ExtendedObjectTypeDefinition());
+ }
} else {
populateDefinition(typeDefinitions, definition, definitionName,
ObjectTypeDefinition.class, ObjectTypeExtensionDefinition.class,
@@ -108,12 +109,15 @@ class GraphQLDocumentParser {
}
@SuppressWarnings("unchecked")
- private static , B extends NamedNode, E extends B> void populateDefinition(Map definitionsMap,
- Definition> definition,
- String definitionName,
- Class baseDefinitionClass,
- Class extensionDefinitionClass,
- Function mappingFunction) {
+ private static <
+ D extends ExtendedDefinition,
+ B extends NamedNode,
+ E extends B> void populateDefinition(Map definitionsMap,
+ Definition> definition,
+ String definitionName,
+ Class baseDefinitionClass,
+ Class extensionDefinitionClass,
+ Function mappingFunction) {
D extendedDefinition = definitionsMap.computeIfAbsent(definitionName, mappingFunction);
if (extensionDefinitionClass.isAssignableFrom(definition.getClass())) {
extendedDefinition.getExtensions().add((E) definition);
@@ -128,7 +132,10 @@ class GraphQLDocumentParser {
}
}
- private static MultiSourceReader createMultiSourceReader(List schemaPaths) throws IOException {
+ public static MultiSourceReader createMultiSourceReader(List schemaPaths) throws IOException {
+ if (schemaPaths == null) {
+ return MultiSourceReader.newMultiSourceReader().build();
+ }
MultiSourceReader.Builder builder = MultiSourceReader.newMultiSourceReader();
for (String path : schemaPaths) {
// appending EOL to ensure that schema tokens are not mixed in case files are not properly ended with EOL
diff --git a/src/main/java/com/kobylynskyi/graphql/codegen/mapper/FieldDefinitionsToResolverDataModelMapper.java b/src/main/java/com/kobylynskyi/graphql/codegen/mapper/FieldDefinitionsToResolverDataModelMapper.java
index 78917aced3fa765066f2e93dc4e2bc93796becfd..fc92f85ec3b0068eed9ec098beeccd224031d747 100644
--- a/src/main/java/com/kobylynskyi/graphql/codegen/mapper/FieldDefinitionsToResolverDataModelMapper.java
+++ b/src/main/java/com/kobylynskyi/graphql/codegen/mapper/FieldDefinitionsToResolverDataModelMapper.java
@@ -48,7 +48,7 @@ public class FieldDefinitionsToResolverDataModelMapper {
List fieldDefs,
String parentTypeName) {
// Example: PersonResolver
- String className = parentTypeName + "Resolver";
+ String className = MapperUtils.getTypeResolverClassNameWithPrefixAndSuffix(mappingContext, parentTypeName);
return mapToResolverModel(mappingContext, parentTypeName, className, fieldDefs,
singletonList("Resolver for " + parentTypeName),
getParentInterface(mappingContext, parentTypeName));
diff --git a/src/main/java/com/kobylynskyi/graphql/codegen/mapper/MapperUtils.java b/src/main/java/com/kobylynskyi/graphql/codegen/mapper/MapperUtils.java
index 1fb40e69be7e31e33ec6f85af0c7b9f23f669d38..07a1d42ba24e1035ea7008792e1e3c93d3a99c8f 100644
--- a/src/main/java/com/kobylynskyi/graphql/codegen/mapper/MapperUtils.java
+++ b/src/main/java/com/kobylynskyi/graphql/codegen/mapper/MapperUtils.java
@@ -82,6 +82,25 @@ class MapperUtils {
return classNameBuilder.toString();
}
+ /**
+ * Generates a type resolver class name including prefix and suffix (if any)
+ *
+ * @param mappingContext Global mapping context
+ * @param typeName GraphQL type name
+ * @return Class name of GraphQL type resolver
+ */
+ static String getTypeResolverClassNameWithPrefixAndSuffix(MappingContext mappingContext, String typeName) {
+ StringBuilder classNameBuilder = new StringBuilder();
+ if (Utils.isNotBlank(mappingContext.getTypeResolverPrefix())) {
+ classNameBuilder.append(mappingContext.getTypeResolverPrefix());
+ }
+ classNameBuilder.append(Utils.capitalize(typeName));
+ if (Utils.isNotBlank(mappingContext.getTypeResolverSuffix())) {
+ classNameBuilder.append(mappingContext.getTypeResolverSuffix());
+ }
+ return classNameBuilder.toString();
+ }
+
/**
* Generates an api class name including prefix and suffix (if any)
* Examples: CreateEventMutationResolver, EventsQueryResolver, EventsByIdsQueryResolver (rootTypeName is "Query" or the likes)
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 cef2653f87d207696db330f42f105834c60a8d94..e82887e626f8017fccac711c423719e2915664c4 100644
--- a/src/main/java/com/kobylynskyi/graphql/codegen/model/GraphQLCodegenConfiguration.java
+++ b/src/main/java/com/kobylynskyi/graphql/codegen/model/GraphQLCodegenConfiguration.java
@@ -42,6 +42,13 @@ public interface GraphQLCodegenConfiguration {
*/
Boolean getGenerateApis();
+ /**
+ * Specifies whether model classes should be generated for Query/Subscription/Mutation.
+ *
+ * @return true is model classes (POJOs) should be generated for GraphQL root types.
+ */
+ Boolean getGenerateModelsForRootTypes();
+
/**
* Specifies the strategy of generating root api interface.
*
@@ -164,6 +171,20 @@ public interface GraphQLCodegenConfiguration {
*/
Boolean getGenerateParameterizedFieldsResolvers();
+ /**
+ * Sets the prefix for GraphQL type resolver classes.
+ *
+ * @return The prefix for GraphQL type resolver classes.
+ */
+ String getTypeResolverPrefix();
+
+ /**
+ * Sets the suffix for GraphQL type resolver classes.
+ *
+ * @return The suffix for GraphQL type resolver classes.
+ */
+ String getTypeResolverSuffix();
+
/**
* Whether all fields in extensions (extend type
and extend interface
) should be present
* in Resolver interface instead of the type class itself.
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 10bd3ab65c965c076e375f878c9e1ca39aac91ea..8cc920d831f65aa0745f0b73d5baad7d35a921f1 100644
--- a/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingConfig.java
+++ b/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingConfig.java
@@ -29,6 +29,8 @@ public class MappingConfig implements GraphQLCodegenConfiguration, Combinable fieldsWithResolvers = new HashSet<>();
@@ -87,6 +90,8 @@ public class MappingConfig implements GraphQLCodegenConfiguration, Combinable
<#if generatedInfo.getGeneratedType()?has_content>
-@${generatedInfo.getGeneratedType()}{
+@${generatedInfo.getGeneratedType()}(
value = "com.kobylynskyi.graphql.codegen.GraphQLCodegen",
date = "${generatedInfo.getDateTime()}"
-}
+)
#if>
public enum ${className}<#if implements?has_content> implements <#list implements as interface>${interface}<#if interface_has_next>, #if>#list>#if> {
diff --git a/src/main/resources/templates/javaClassGraphqlInterface.ftl b/src/main/resources/templates/javaClassGraphqlInterface.ftl
index 3512064fef6b7b328c98cd1d1273094c6f567d4a..c6ddc8b3f7de6cf71740105946a4f5a1436bd7c2 100644
--- a/src/main/resources/templates/javaClassGraphqlInterface.ftl
+++ b/src/main/resources/templates/javaClassGraphqlInterface.ftl
@@ -16,10 +16,10 @@ import ${import}.*;
*/
#if>
<#if generatedInfo.getGeneratedType()?has_content>
-@${generatedInfo.getGeneratedType()}{
+@${generatedInfo.getGeneratedType()}(
value = "com.kobylynskyi.graphql.codegen.GraphQLCodegen",
date = "${generatedInfo.getDateTime()}"
-}
+)
#if>
public interface ${className} <#if implements?has_content>extends <#list implements as interface>${interface}<#if interface_has_next>, #if>#list>#if>{
diff --git a/src/main/resources/templates/javaClassGraphqlOperations.ftl b/src/main/resources/templates/javaClassGraphqlOperations.ftl
index 790556e8e911ee4dd04774ef77c56675694e1a3b..48da119f4855c649a5a3099b78e91595abd39fde 100644
--- a/src/main/resources/templates/javaClassGraphqlOperations.ftl
+++ b/src/main/resources/templates/javaClassGraphqlOperations.ftl
@@ -14,10 +14,10 @@ import ${import}.*;
*/
#if>
<#if generatedInfo.getGeneratedType()?has_content>
-@${generatedInfo.getGeneratedType()}{
+@${generatedInfo.getGeneratedType()}(
value = "com.kobylynskyi.graphql.codegen.GraphQLCodegen",
date = "${generatedInfo.getDateTime()}"
-}
+)
#if>
public interface ${className}<#if implements?has_content> extends <#list implements as interface>${interface}<#if interface_has_next>, #if>#list>#if> {
diff --git a/src/main/resources/templates/javaClassGraphqlParametrizedInput.ftl b/src/main/resources/templates/javaClassGraphqlParametrizedInput.ftl
index 86f01293000f3ac3310f795c217a862ba54b5211..c7b87a58561c44aa392cdf4e82db43289196cbb7 100644
--- a/src/main/resources/templates/javaClassGraphqlParametrizedInput.ftl
+++ b/src/main/resources/templates/javaClassGraphqlParametrizedInput.ftl
@@ -17,10 +17,10 @@ import java.util.Objects;
*/
#if>
<#if generatedInfo.getGeneratedType()?has_content>
-@${generatedInfo.getGeneratedType()}{
+@${generatedInfo.getGeneratedType()}(
value = "com.kobylynskyi.graphql.codegen.GraphQLCodegen",
date = "${generatedInfo.getDateTime()}"
-}
+)
#if>
public class ${className} implements GraphQLParametrizedInput {
diff --git a/src/main/resources/templates/javaClassGraphqlRequest.ftl b/src/main/resources/templates/javaClassGraphqlRequest.ftl
index bb57e7428c9d932142dc7ebdf839fed3e6bcb87f..31ca56088c72cc65f26c25457ffd4322954fbb06 100644
--- a/src/main/resources/templates/javaClassGraphqlRequest.ftl
+++ b/src/main/resources/templates/javaClassGraphqlRequest.ftl
@@ -18,10 +18,10 @@ import java.util.Objects;
*/
#if>
<#if generatedInfo.getGeneratedType()?has_content>
-@${generatedInfo.getGeneratedType()}{
+@${generatedInfo.getGeneratedType()}(
value = "com.kobylynskyi.graphql.codegen.GraphQLCodegen",
date = "${generatedInfo.getDateTime()}"
-}
+)
#if>
public class ${className} implements GraphQLOperationRequest {
diff --git a/src/main/resources/templates/javaClassGraphqlResponse.ftl b/src/main/resources/templates/javaClassGraphqlResponse.ftl
index 8c822d615dcf9e1bd396478b98dca56482e3d82e..a605e1924a5b49f1870cd680e16f1f4eb10bc8df 100644
--- a/src/main/resources/templates/javaClassGraphqlResponse.ftl
+++ b/src/main/resources/templates/javaClassGraphqlResponse.ftl
@@ -13,10 +13,10 @@ import java.util.Map;
*/
#if>
<#if generatedInfo.getGeneratedType()?has_content>
-@${generatedInfo.getGeneratedType()}{
+@${generatedInfo.getGeneratedType()}(
value = "com.kobylynskyi.graphql.codegen.GraphQLCodegen",
date = "${generatedInfo.getDateTime()}"
-}
+)
#if>
public class ${className} extends GraphQLResult