GraphQLCodegen.java 27.6 KB
Newer Older
1 2
package com.kobylynskyi.graphql.codegen;

3 4 5 6 7 8 9 10
import com.kobylynskyi.graphql.codegen.mapper.EnumDefinitionToDataModelMapper;
import com.kobylynskyi.graphql.codegen.mapper.FieldDefinitionToParameterMapper;
import com.kobylynskyi.graphql.codegen.mapper.FieldDefinitionsToResolverDataModelMapper;
import com.kobylynskyi.graphql.codegen.mapper.InputDefinitionToDataModelMapper;
import com.kobylynskyi.graphql.codegen.mapper.InterfaceDefinitionToDataModelMapper;
import com.kobylynskyi.graphql.codegen.mapper.RequestResponseDefinitionToDataModelMapper;
import com.kobylynskyi.graphql.codegen.mapper.TypeDefinitionToDataModelMapper;
import com.kobylynskyi.graphql.codegen.mapper.UnionDefinitionToDataModelMapper;
11
import com.kobylynskyi.graphql.codegen.model.ApiInterfaceStrategy;
12 13
import com.kobylynskyi.graphql.codegen.model.ApiNamePrefixStrategy;
import com.kobylynskyi.graphql.codegen.model.ApiRootInterfaceStrategy;
14
import com.kobylynskyi.graphql.codegen.model.GeneratedInformation;
15
import com.kobylynskyi.graphql.codegen.model.GeneratedLanguage;
16
import com.kobylynskyi.graphql.codegen.model.MappingConfig;
17
import com.kobylynskyi.graphql.codegen.model.MappingConfigConstants;
18
import com.kobylynskyi.graphql.codegen.model.MappingContext;
19
import com.kobylynskyi.graphql.codegen.model.definitions.ExtendedDefinition;
20 21 22 23 24 25 26 27
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.ExtendedInputObjectTypeDefinition;
import com.kobylynskyi.graphql.codegen.model.definitions.ExtendedInterfaceTypeDefinition;
import com.kobylynskyi.graphql.codegen.model.definitions.ExtendedObjectTypeDefinition;
import com.kobylynskyi.graphql.codegen.model.definitions.ExtendedScalarTypeDefinition;
import com.kobylynskyi.graphql.codegen.model.definitions.ExtendedUnionTypeDefinition;
A
Alberto Valiña 已提交
28
import com.kobylynskyi.graphql.codegen.supplier.MappingConfigSupplier;
29
import com.kobylynskyi.graphql.codegen.utils.Utils;
30 31
import graphql.language.FieldDefinition;
import graphql.language.ScalarTypeExtensionDefinition;
32 33

import java.io.File;
B
Bogdan Kobylynskyi 已提交
34
import java.io.IOException;
35 36 37 38 39 40
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
41

42 43
import static java.util.stream.Collectors.toList;

44 45
/**
 * Generator of:
46 47 48
 * - Interface for each GraphQL query, mutation, subscription, union and field resolvers
 * - POJO Class for each GraphQL type and input
 * - Enum Class for each GraphQL enum
49 50
 *
 * @author kobylynskyi
A
Alberto Valiña 已提交
51
 * @author valinhadev
52
 */
53
public class GraphQLCodegen {
54

55
    private final List<String> schemas;
56
    private final String introspectionResult;
57 58 59
    private final File outputDir;
    private final MappingConfig mappingConfig;
    private final GeneratedInformation generatedInformation;
60

61
    // used in tests
62 63 64 65
    public GraphQLCodegen(List<String> schemas,
                          File outputDir,
                          MappingConfig mappingConfig,
                          GeneratedInformation generatedInformation) {
66
        this(schemas, null, outputDir, mappingConfig, null, generatedInformation);
A
Alberto Valiña 已提交
67 68
    }

69 70 71 72 73 74 75 76 77
    // used in tests
    public GraphQLCodegen(String introspectionResult,
                          File outputDir,
                          MappingConfig mappingConfig,
                          GeneratedInformation generatedInformation) {
        this(null, introspectionResult, outputDir, mappingConfig, null, generatedInformation);
    }

    // used in plugins
78
    public GraphQLCodegen(List<String> schemas,
79
                          String introspectionResult,
80 81 82
                          File outputDir,
                          MappingConfig mappingConfig,
                          MappingConfigSupplier externalMappingConfigSupplier) {
83
        this(schemas, introspectionResult, outputDir, mappingConfig, externalMappingConfigSupplier, new GeneratedInformation());
84 85
    }

86
    // used by other constructors
87
    public GraphQLCodegen(List<String> schemas,
88
                          String introspectionResult,
89 90 91 92
                          File outputDir,
                          MappingConfig mappingConfig,
                          MappingConfigSupplier externalMappingConfigSupplier,
                          GeneratedInformation generatedInformation) {
93
        this.schemas = schemas;
94
        this.introspectionResult = introspectionResult;
95 96
        this.outputDir = outputDir;
        this.mappingConfig = mappingConfig;
A
Alberto Valiña 已提交
97 98
        this.mappingConfig.combine(externalMappingConfigSupplier != null ? externalMappingConfigSupplier.get() : null);
        initDefaultValues(mappingConfig);
99
        validateConfigs(mappingConfig);
100
        sanitizeValues(mappingConfig);
101
        this.generatedInformation = generatedInformation;
A
Alberto Valiña 已提交
102 103
    }

104
    private static void initDefaultValues(MappingConfig mappingConfig) {
A
Alberto Valiña 已提交
105
        if (mappingConfig.getModelValidationAnnotation() == null) {
106
            mappingConfig.setModelValidationAnnotation(MappingConfigConstants.DEFAULT_VALIDATION_ANNOTATION);
A
Alberto Valiña 已提交
107
        }
108
        if (mappingConfig.getGenerateBuilder() == null) {
109
            mappingConfig.setGenerateBuilder(MappingConfigConstants.DEFAULT_BUILDER);
110
        }
A
Alberto Valiña 已提交
111
        if (mappingConfig.getGenerateEqualsAndHashCode() == null) {
112
            mappingConfig.setGenerateEqualsAndHashCode(MappingConfigConstants.DEFAULT_EQUALS_AND_HASHCODE);
A
Alberto Valiña 已提交
113
        }
114 115
        if (mappingConfig.getGenerateClient() == null) {
            mappingConfig.setGenerateClient(MappingConfigConstants.DEFAULT_GENERATE_CLIENT);
116 117
        }
        if (mappingConfig.getRequestSuffix() == null) {
118
            mappingConfig.setRequestSuffix(MappingConfigConstants.DEFAULT_REQUEST_SUFFIX);
119
        }
120 121 122
        if (mappingConfig.getResponseSuffix() == null) {
            mappingConfig.setResponseSuffix(MappingConfigConstants.DEFAULT_RESPONSE_SUFFIX);
        }
123
        if (mappingConfig.getResponseProjectionSuffix() == null) {
124
            mappingConfig.setResponseProjectionSuffix(MappingConfigConstants.DEFAULT_RESPONSE_PROJECTION_SUFFIX);
125
        }
126
        if (mappingConfig.getParametrizedInputSuffix() == null) {
127
            mappingConfig.setParametrizedInputSuffix(MappingConfigConstants.DEFAULT_PARAMETRIZED_INPUT_SUFFIX);
128
        }
129
        if (mappingConfig.getGenerateImmutableModels() == null) {
130 131 132 133 134 135
            if (GeneratedLanguage.SCALA.equals(mappingConfig.getGeneratedLanguage())) {
                // functional expression
                mappingConfig.setGenerateImmutableModels(true);
            } else {
                mappingConfig.setGenerateImmutableModels(MappingConfigConstants.DEFAULT_GENERATE_IMMUTABLE_MODELS);
            }
136
        }
A
Alberto Valiña 已提交
137
        if (mappingConfig.getGenerateToString() == null) {
138
            mappingConfig.setGenerateToString(MappingConfigConstants.DEFAULT_TO_STRING);
A
Alberto Valiña 已提交
139 140
        }
        if (mappingConfig.getGenerateApis() == null) {
141
            mappingConfig.setGenerateApis(MappingConfigConstants.DEFAULT_GENERATE_APIS);
A
Alberto Valiña 已提交
142
        }
143
        if (mappingConfig.getApiNameSuffix() == null) {
144 145 146 147
            mappingConfig.setApiNameSuffix(MappingConfigConstants.DEFAULT_RESOLVER_SUFFIX);
        }
        if (mappingConfig.getTypeResolverSuffix() == null) {
            mappingConfig.setTypeResolverSuffix(MappingConfigConstants.DEFAULT_RESOLVER_SUFFIX);
148
        }
149
        if (mappingConfig.getGenerateParameterizedFieldsResolvers() == null) {
150
            mappingConfig.setGenerateParameterizedFieldsResolvers(MappingConfigConstants.DEFAULT_GENERATE_PARAMETERIZED_FIELDS_RESOLVERS);
151
        }
152
        if (mappingConfig.getGenerateExtensionFieldsResolvers() == null) {
153
            mappingConfig.setGenerateExtensionFieldsResolvers(MappingConfigConstants.DEFAULT_GENERATE_EXTENSION_FIELDS_RESOLVERS);
154
        }
155
        if (mappingConfig.getGenerateDataFetchingEnvironmentArgumentInApis() == null) {
156
            mappingConfig.setGenerateDataFetchingEnvironmentArgumentInApis(MappingConfigConstants.DEFAULT_GENERATE_DATA_FETCHING_ENV);
157
        }
158 159 160
        if (mappingConfig.getGenerateModelsForRootTypes() == null) {
            mappingConfig.setGenerateModelsForRootTypes(MappingConfigConstants.DEFAULT_GENERATE_MODELS_FOR_ROOT_TYPES);
        }
161 162 163
        if (mappingConfig.getGenerateApisWithThrowsException() == null) {
            mappingConfig.setGenerateApisWithThrowsException(MappingConfigConstants.DEFAULT_GENERATE_APIS_WITH_THROWS_EXCEPTION);
        }
164 165 166
        if (mappingConfig.getUseOptionalForNullableReturnTypes() == null) {
            mappingConfig.setUseOptionalForNullableReturnTypes(MappingConfigConstants.DEFAULT_USE_OPTIONAL_FOR_NULLABLE_RETURN_TYPES);
        }
167 168 169 170 171 172
        if (mappingConfig.getApiNamePrefixStrategy() == null) {
            mappingConfig.setApiNamePrefixStrategy(MappingConfigConstants.DEFAULT_API_NAME_PREFIX_STRATEGY);
        }
        if (mappingConfig.getApiRootInterfaceStrategy() == null) {
            mappingConfig.setApiRootInterfaceStrategy(MappingConfigConstants.DEFAULT_API_ROOT_INTERFACE_STRATEGY);
        }
173 174 175
        if (mappingConfig.getApiInterfaceStrategy() == null) {
            mappingConfig.setApiInterfaceStrategy(MappingConfigConstants.DEFAULT_API_INTERFACE_STRATEGY);
        }
B
Bogdan Kobylynskyi 已提交
176
        if (Boolean.TRUE.equals(mappingConfig.getGenerateClient())) {
177 178 179
            // required for request serialization
            mappingConfig.setGenerateToString(true);
        }
180 181 182
        if (mappingConfig.getResponseProjectionMaxDepth() == null) {
            mappingConfig.setResponseProjectionMaxDepth(MappingConfigConstants.DEFAULT_RESPONSE_PROJECTION_MAX_DEPTH);
        }
183 184 185
        if (mappingConfig.getGeneratedLanguage() == null) {
            mappingConfig.setGeneratedLanguage(MappingConfigConstants.DEFAULT_GENERATED_LANGUAGE);
        }
186 187
    }

188 189 190 191 192 193
    private void validateConfigs(MappingConfig mappingConfig) {
        if (!Utils.isEmpty(schemas) && introspectionResult != null ||
                (Utils.isEmpty(schemas) && introspectionResult == null)) {
            // either schemas or introspection result should be provided
            throw new IllegalArgumentException("Either graphql schema path or introspection result path should be supplied");
        }
194 195
        if (mappingConfig.getApiRootInterfaceStrategy() == ApiRootInterfaceStrategy.INTERFACE_PER_SCHEMA &&
                mappingConfig.getApiNamePrefixStrategy() == ApiNamePrefixStrategy.CONSTANT) {
196
            // we will have a conflict in case there is "type Query" in multiple graphql schema files
197 198
            throw new IllegalArgumentException("API prefix should not be CONSTANT for INTERFACE_PER_SCHEMA option");
        }
199
        if (Boolean.TRUE.equals(mappingConfig.getGenerateApis()) &&
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
                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");
            }
        }
215 216
    }

217 218 219 220
    private static void sanitizeValues(MappingConfig mappingConfig) {
        mappingConfig.setModelValidationAnnotation(
                Utils.replaceLeadingAtSign(mappingConfig.getModelValidationAnnotation()));

221
        Map<String, List<String>> customAnnotationsMapping = mappingConfig.getCustomAnnotationsMapping();
222
        if (customAnnotationsMapping != null) {
223 224 225 226
            for (Map.Entry<String, List<String>> entry : customAnnotationsMapping.entrySet()) {
                if (entry.getValue() != null) {
                    entry.setValue(entry.getValue().stream().map(Utils::replaceLeadingAtSign).collect(toList()));
                }
227 228
            }
        }
229
        Map<String, List<String>> directiveAnnotationsMapping = mappingConfig.getDirectiveAnnotationsMapping();
230
        if (directiveAnnotationsMapping != null) {
231 232 233 234
            for (Map.Entry<String, List<String>> entry : directiveAnnotationsMapping.entrySet()) {
                if (entry.getValue() != null) {
                    entry.setValue(entry.getValue().stream().map(Utils::replaceLeadingAtSign).collect(toList()));
                }
235 236
            }
        }
237 238
    }

B
Bogdan Kobylynskyi 已提交
239
    public List<File> generate() throws IOException {
240
        GraphQLCodegenFileCreator.prepareOutputDir(outputDir);
241
        long startTime = System.currentTimeMillis();
242
        List<File> generatedFiles = Collections.emptyList();
243 244 245 246
        if (!Utils.isEmpty(schemas)) {
            ExtendedDocument document = GraphQLDocumentParser.getDocumentFromSchemas(mappingConfig, schemas);
            initCustomTypeMappings(document.getScalarDefinitions());
            generatedFiles = processDefinitions(document);
247 248
            System.out.printf("Finished processing %d schema(s) in %d ms%n", schemas.size(),
                    System.currentTimeMillis() - startTime);
249 250
        } else if (introspectionResult != null) {
            ExtendedDocument document = GraphQLDocumentParser.getDocumentFromIntrospectionResult(mappingConfig, introspectionResult);
251
            initCustomTypeMappings(document.getScalarDefinitions());
252
            generatedFiles = processDefinitions(document);
253 254
            System.out.printf("Finished processing introspection result in %d ms%n",
                    System.currentTimeMillis() - startTime);
255
        }
256

257
        return generatedFiles;
258 259
    }

260
    private List<File> processDefinitions(ExtendedDocument document) {
261
        MappingContext context = new MappingContext(mappingConfig, document, generatedInformation);
262

263
        List<File> generatedFiles = new ArrayList<>();
264 265 266
        for (ExtendedEnumTypeDefinition extendedEnumTypeDefinition : document.getEnumDefinitions()) {
            generatedFiles.add(generateEnum(context, extendedEnumTypeDefinition));
        }
267
        for (ExtendedObjectTypeDefinition extendedObjectTypeDefinition : document.getTypeDefinitions()) {
268
            generatedFiles.addAll(generateType(context, extendedObjectTypeDefinition));
269 270
        }
        for (ExtendedObjectTypeDefinition extendedObjectTypeDefinition : document.getTypeDefinitions()) {
271
            generateFieldResolver(context, extendedObjectTypeDefinition.getFieldDefinitions(), extendedObjectTypeDefinition)
272 273 274
                    .ifPresent(generatedFiles::add);
        }
        for (ExtendedObjectTypeDefinition extendedObjectTypeDefinition : document.getOperationDefinitions()) {
B
Bogdan Kobylynskyi 已提交
275
            if (Boolean.TRUE.equals(mappingConfig.getGenerateApis())) {
276 277
                generatedFiles.addAll(generateServerOperations(context, extendedObjectTypeDefinition));
            }
B
Bogdan Kobylynskyi 已提交
278
            if (Boolean.TRUE.equals(mappingConfig.getGenerateClient())) {
279 280
                generatedFiles.addAll(generateClient(context, extendedObjectTypeDefinition));
            }
281 282
        }
        for (ExtendedInputObjectTypeDefinition extendedInputObjectTypeDefinition : document.getInputDefinitions()) {
283
            generatedFiles.add(generateInput(context, extendedInputObjectTypeDefinition));
284 285
        }
        for (ExtendedUnionTypeDefinition extendedUnionTypeDefinition : document.getUnionDefinitions()) {
286
            generatedFiles.addAll(generateUnion(context, extendedUnionTypeDefinition));
287 288
        }
        for (ExtendedInterfaceTypeDefinition extendedInterfaceTypeDefinition : document.getInterfaceDefinitions()) {
289
            generatedFiles.addAll(generateInterface(context, extendedInterfaceTypeDefinition));
290 291
        }
        for (ExtendedInterfaceTypeDefinition definition : document.getInterfaceDefinitions()) {
292
            generateFieldResolver(context, definition.getFieldDefinitions(), definition).ifPresent(generatedFiles::add);
293
        }
294
        System.out.printf("Generated %d definition classes in folder %s%n", generatedFiles.size(), outputDir.getAbsolutePath());
295
        return generatedFiles;
296 297
    }

298 299
    private List<File> generateUnion(MappingContext mappingContext, ExtendedUnionTypeDefinition definition) {
        List<File> generatedFiles = new ArrayList<>();
300
        Map<String, Object> dataModel = UnionDefinitionToDataModelMapper.map(mappingContext, definition);
301
        generatedFiles.add(GraphQLCodegenFileCreator.generateFile(mappingContext, "unionTemplate", dataModel, outputDir));
302 303 304

        if (Boolean.TRUE.equals(mappingConfig.getGenerateClient())) {
            Map<String, Object> responseProjDataModel = RequestResponseDefinitionToDataModelMapper.mapResponseProjection(mappingContext, definition);
305
            generatedFiles.add(GraphQLCodegenFileCreator.generateFile(mappingContext, "responseProjectionTemplate", responseProjDataModel, outputDir));
306 307
        }
        return generatedFiles;
308 309
    }

310 311
    private List<File> generateInterface(MappingContext mappingContext, ExtendedInterfaceTypeDefinition definition) {
        List<File> generatedFiles = new ArrayList<>();
312
        Map<String, Object> dataModel = InterfaceDefinitionToDataModelMapper.map(mappingContext, definition);
313
        generatedFiles.add(GraphQLCodegenFileCreator.generateFile(mappingContext, "interfaceTemplate", dataModel, outputDir));
314 315 316

        if (Boolean.TRUE.equals(mappingConfig.getGenerateClient())) {
            Map<String, Object> responseProjDataModel = RequestResponseDefinitionToDataModelMapper.mapResponseProjection(mappingContext, definition);
317
            generatedFiles.add(GraphQLCodegenFileCreator.generateFile(mappingContext, "responseProjectionTemplate", responseProjDataModel, outputDir));
318 319 320 321

            for (ExtendedFieldDefinition fieldDefinition : definition.getFieldDefinitions()) {
                if (!Utils.isEmpty(fieldDefinition.getInputValueDefinitions())) {
                    Map<String, Object> fieldProjDataModel = RequestResponseDefinitionToDataModelMapper.mapParametrizedInput(mappingContext, fieldDefinition, definition);
322
                    generatedFiles.add(GraphQLCodegenFileCreator.generateFile(mappingContext, "parametrizedInputTemplate", fieldProjDataModel, outputDir));
323 324
                }
            }
325 326
        }
        return generatedFiles;
327 328
    }

329
    private List<File> generateServerOperations(MappingContext mappingContext, ExtendedObjectTypeDefinition definition) {
330
        List<File> generatedFiles = new ArrayList<>();
331 332 333 334 335 336 337 338
        // Generate a root interface with all operations inside
        // Relates to https://github.com/facebook/relay/issues/112
        switch (mappingContext.getApiRootInterfaceStrategy()) {
            case INTERFACE_PER_SCHEMA:
                for (ExtendedObjectTypeDefinition defInFile : definition.groupBySourceLocationFile().values()) {
                    generatedFiles.add(generateRootApi(mappingContext, defInFile));
                }
                break;
339 340
            case DO_NOT_GENERATE:
                break;
341 342 343 344 345 346
            case SINGLE_INTERFACE:
            default:
                generatedFiles.add(generateRootApi(mappingContext, definition));
                break;
        }

347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365
        if (mappingContext.getApiInterfaceStrategy() == ApiInterfaceStrategy.INTERFACE_PER_OPERATION) {
            // Generate separate interfaces for all queries, mutations and subscriptions
            List<String> fieldNames = definition.getFieldDefinitions().stream().map(FieldDefinition::getName).collect(toList());
            switch (mappingContext.getApiNamePrefixStrategy()) {
                case FOLDER_NAME_AS_PREFIX:
                    for (ExtendedObjectTypeDefinition fileDef : definition.groupBySourceLocationFolder().values()) {
                        generatedFiles.addAll(generateApis(mappingContext, fileDef, fieldNames));
                    }
                    break;
                case FILE_NAME_AS_PREFIX:
                    for (ExtendedObjectTypeDefinition fileDef : definition.groupBySourceLocationFile().values()) {
                        generatedFiles.addAll(generateApis(mappingContext, fileDef, fieldNames));
                    }
                    break;
                case CONSTANT:
                default:
                    generatedFiles.addAll(generateApis(mappingContext, definition, fieldNames));
                    break;
            }
366
        }
367 368
        return generatedFiles;
    }
369

370 371 372 373 374
    private List<File> generateClient(MappingContext mappingContext, ExtendedObjectTypeDefinition definition) {
        List<File> generatedFiles = new ArrayList<>();
        List<String> fieldNames = definition.getFieldDefinitions().stream().map(FieldDefinition::getName).collect(toList());
        for (ExtendedFieldDefinition operationDef : definition.getFieldDefinitions()) {
            Map<String, Object> requestDataModel = RequestResponseDefinitionToDataModelMapper.mapRequest(mappingContext, operationDef, definition.getName(), fieldNames);
375
            generatedFiles.add(GraphQLCodegenFileCreator.generateFile(mappingContext, "requestTemplate", requestDataModel, outputDir));
376

377
            Map<String, Object> responseDataModel = RequestResponseDefinitionToDataModelMapper.mapResponse(mappingContext, operationDef, definition.getName(), fieldNames);
378
            generatedFiles.add(GraphQLCodegenFileCreator.generateFile(mappingContext, "responseTemplate", responseDataModel, outputDir));
379
        }
380
        return generatedFiles;
381 382
    }

383 384 385 386
    private List<File> generateApis(MappingContext mappingContext, ExtendedObjectTypeDefinition definition, List<String> fieldNames) {
        List<File> generatedFiles = new ArrayList<>();
        for (ExtendedFieldDefinition operationDef : definition.getFieldDefinitions()) {
            Map<String, Object> dataModel = FieldDefinitionsToResolverDataModelMapper.mapRootTypeField(mappingContext, operationDef, definition.getName(), fieldNames);
387
            generatedFiles.add(GraphQLCodegenFileCreator.generateFile(mappingContext, "operationsTemplate", dataModel, outputDir));
388 389 390 391 392 393
        }
        return generatedFiles;
    }

    private File generateRootApi(MappingContext mappingContext, ExtendedObjectTypeDefinition definition) {
        Map<String, Object> dataModel = FieldDefinitionsToResolverDataModelMapper.mapRootTypeFields(mappingContext, definition);
394
        return GraphQLCodegenFileCreator.generateFile(mappingContext, "operationsTemplate", dataModel, outputDir);
395 396
    }

397
    private List<File> generateType(MappingContext mappingContext, ExtendedObjectTypeDefinition definition) {
398
        List<File> generatedFiles = new ArrayList<>();
399
        Map<String, Object> dataModel = TypeDefinitionToDataModelMapper.map(mappingContext, definition);
400
        generatedFiles.add(GraphQLCodegenFileCreator.generateFile(mappingContext, "typeTemplate", dataModel, outputDir));
401

B
Bogdan Kobylynskyi 已提交
402
        if (Boolean.TRUE.equals(mappingConfig.getGenerateClient())) {
403
            Map<String, Object> responseProjDataModel = RequestResponseDefinitionToDataModelMapper.mapResponseProjection(mappingContext, definition);
404
            generatedFiles.add(GraphQLCodegenFileCreator.generateFile(mappingContext, "responseProjectionTemplate", responseProjDataModel, outputDir));
405 406 407

            for (ExtendedFieldDefinition fieldDefinition : definition.getFieldDefinitions()) {
                if (!Utils.isEmpty(fieldDefinition.getInputValueDefinitions())) {
408
                    Map<String, Object> fieldProjDataModel = RequestResponseDefinitionToDataModelMapper.mapParametrizedInput(mappingContext, fieldDefinition, definition);
409
                    generatedFiles.add(GraphQLCodegenFileCreator.generateFile(mappingContext, "parametrizedInputTemplate", fieldProjDataModel, outputDir));
410 411
                }
            }
412
        }
413
        return generatedFiles;
414 415
    }

416 417 418
    private Optional<File> generateFieldResolver(MappingContext mappingContext,
                                                 List<ExtendedFieldDefinition> fieldDefinitions,
                                                 ExtendedDefinition<?, ?> parentDefinition) {
419 420 421 422 423 424
        if (Boolean.TRUE.equals(mappingConfig.getGenerateApis())) {
            List<ExtendedFieldDefinition> fieldDefsWithResolvers = fieldDefinitions.stream()
                    .filter(fieldDef -> FieldDefinitionToParameterMapper.generateResolversForField(mappingContext, fieldDef, parentDefinition))
                    .collect(toList());
            if (!fieldDefsWithResolvers.isEmpty()) {
                Map<String, Object> dataModel = FieldDefinitionsToResolverDataModelMapper.mapToTypeResolver(mappingContext, fieldDefsWithResolvers, parentDefinition.getName());
425
                return Optional.of(GraphQLCodegenFileCreator.generateFile(mappingContext, "operationsTemplate", dataModel, outputDir));
426
            }
427
        }
428
        return Optional.empty();
429 430
    }

431 432
    private File generateInput(MappingContext mappingContext, ExtendedInputObjectTypeDefinition definition) {
        Map<String, Object> dataModel = InputDefinitionToDataModelMapper.map(mappingContext, definition);
433
        return GraphQLCodegenFileCreator.generateFile(mappingContext, "typeTemplate", dataModel, outputDir);
434 435
    }

436 437
    private File generateEnum(MappingContext mappingContext, ExtendedEnumTypeDefinition definition) {
        Map<String, Object> dataModel = EnumDefinitionToDataModelMapper.map(mappingContext, definition);
438
        return GraphQLCodegenFileCreator.generateFile(mappingContext, "enumTemplate", dataModel, outputDir);
439 440
    }

441 442
    private void initCustomTypeMappings(Collection<ExtendedScalarTypeDefinition> scalarTypeDefinitions) {
        for (ExtendedScalarTypeDefinition definition : scalarTypeDefinitions) {
443 444 445
            if (definition.getDefinition() != null) {
                mappingConfig.putCustomTypeMappingIfAbsent(definition.getDefinition().getName(), "String");
            }
446 447
            for (ScalarTypeExtensionDefinition extension : definition.getExtensions()) {
                mappingConfig.putCustomTypeMappingIfAbsent(extension.getName(), "String");
448 449
            }
        }
450 451
        mappingConfig.putCustomTypeMappingIfAbsent("ID", "String");
        mappingConfig.putCustomTypeMappingIfAbsent("String", "String");
452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467
        if (GeneratedLanguage.JAVA.equals(mappingConfig.getGeneratedLanguage())) {
            mappingConfig.putCustomTypeMappingIfAbsent("Int", "Integer");
            mappingConfig.putCustomTypeMappingIfAbsent("Int!", "int");
            mappingConfig.putCustomTypeMappingIfAbsent("Float", "Double");
            mappingConfig.putCustomTypeMappingIfAbsent("Float!", "double");
            mappingConfig.putCustomTypeMappingIfAbsent("Boolean", "Boolean");
            mappingConfig.putCustomTypeMappingIfAbsent("Boolean!", "boolean");
        } else if (GeneratedLanguage.SCALA.equals(mappingConfig.getGeneratedLanguage())) {
            // scala primitive cannot be null, so use not null primitive type as java type
            mappingConfig.putCustomTypeMappingIfAbsent("Int", "java.lang.Integer");
            mappingConfig.putCustomTypeMappingIfAbsent("Int!", "Int");
            mappingConfig.putCustomTypeMappingIfAbsent("Float", "java.lang.Double");
            mappingConfig.putCustomTypeMappingIfAbsent("Float!", "Double");
            mappingConfig.putCustomTypeMappingIfAbsent("Boolean", "java.lang.Boolean");
            mappingConfig.putCustomTypeMappingIfAbsent("Boolean!", "Boolean");
        }
468
    }
469

470
}