GraphQLCodegenMojo.java 20.5 KB
Newer Older
1 2
package io.github.kobylynskyi.graphql.codegen;

3
import com.kobylynskyi.graphql.codegen.GraphQLCodegen;
4
import com.kobylynskyi.graphql.codegen.java.JavaGraphQLCodegen;
梦境迷离's avatar
梦境迷离 已提交
5
import com.kobylynskyi.graphql.codegen.kotlin.KotlinGraphQLCodegen;
6 7 8 9 10 11 12 13 14 15
import com.kobylynskyi.graphql.codegen.model.ApiInterfaceStrategy;
import com.kobylynskyi.graphql.codegen.model.ApiNamePrefixStrategy;
import com.kobylynskyi.graphql.codegen.model.ApiRootInterfaceStrategy;
import com.kobylynskyi.graphql.codegen.model.GeneratedLanguage;
import com.kobylynskyi.graphql.codegen.model.GraphQLCodegenConfiguration;
import com.kobylynskyi.graphql.codegen.model.MappingConfig;
import com.kobylynskyi.graphql.codegen.model.MappingConfigConstants;
import com.kobylynskyi.graphql.codegen.model.RelayConfig;
import com.kobylynskyi.graphql.codegen.model.exception.LanguageNotSupportedException;
import com.kobylynskyi.graphql.codegen.scala.ScalaGraphQLCodegen;
16 17
import com.kobylynskyi.graphql.codegen.supplier.JsonMappingConfigSupplier;
import com.kobylynskyi.graphql.codegen.supplier.MappingConfigSupplier;
18
import com.kobylynskyi.graphql.codegen.supplier.SchemaFinder;
19
import org.apache.maven.model.Resource;
20 21 22 23 24 25 26 27
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;

import java.io.File;
28
import java.io.IOException;
29
import java.nio.file.Path;
30
import java.nio.file.Paths;
31
import java.util.ArrayList;
32
import java.util.Arrays;
33
import java.util.Collection;
34
import java.util.Collections;
35 36 37 38 39
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
40
import java.util.Properties;
41
import java.util.Set;
42

43
@Mojo(name = "generate", defaultPhase = LifecyclePhase.GENERATE_SOURCES, threadSafe = true)
44
public class GraphQLCodegenMojo extends AbstractMojo implements GraphQLCodegenConfiguration {
45

46
    @Parameter
47 48
    private String[] graphqlSchemaPaths;

49 50 51
    @Parameter
    private String graphqlQueryIntrospectionResultPath;

52 53 54
    @Parameter
    private SchemaFinderConfig graphqlSchemas = new SchemaFinderConfig();

55 56 57 58
    @Parameter(required = true)
    private File outputDir;

    @Parameter
59
    private Properties customTypesMapping = new Properties();
60

61
    @Parameter
62
    private Map<String, Properties> customAnnotationsMapping;
63

64
    @Parameter
65
    private Map<String, Properties> directiveAnnotationsMapping;
66

67 68 69
    @Parameter
    private String packageName;

70
    @Parameter(defaultValue = MappingConfigConstants.DEFAULT_BUILDER_STRING)
71 72
    private boolean generateBuilder;

73
    @Parameter(defaultValue = MappingConfigConstants.DEFAULT_GENERATE_APIS_STRING)
74 75
    private boolean generateApis;

76
    @Parameter(defaultValue = MappingConfigConstants.DEFAULT_EQUALS_AND_HASHCODE_STRING)
77 78
    private boolean generateEqualsAndHashCode;

79 80 81
    @Parameter(defaultValue = MappingConfigConstants.DEFAULT_GENERATE_IMMUTABLE_MODELS_STRING)
    private boolean generateImmutableModels;

82
    @Parameter(defaultValue = MappingConfigConstants.DEFAULT_TO_STRING_STRING)
83 84 85 86
    private boolean generateToString;

    @Parameter
    private String apiPackageName;
87

88 89 90
    @Parameter
    private String apiNamePrefix;

91
    @Parameter(defaultValue = MappingConfigConstants.DEFAULT_RESOLVER_SUFFIX)
92 93
    private String apiNameSuffix;

94 95
    @Parameter
    private String modelPackageName;
96

97 98
    @Parameter
    private String modelNamePrefix;
99

100 101
    @Parameter
    private String modelNameSuffix;
102

103 104 105 106 107 108
    @Parameter
    private String typeResolverPrefix;

    @Parameter(defaultValue = MappingConfigConstants.DEFAULT_RESOLVER_SUFFIX)
    private String typeResolverSuffix;

109 110
    @Parameter
    private String apiReturnType;
111 112

    @Parameter
113
    private String apiReturnListType;
114

115 116 117
    @Parameter
    private String subscriptionReturnType;

118 119 120
    @Parameter(defaultValue = MappingConfigConstants.DEFAULT_API_ROOT_INTERFACE_STRATEGY_STRING)
    private ApiRootInterfaceStrategy apiRootInterfaceStrategy;

121 122 123
    @Parameter(defaultValue = MappingConfigConstants.DEFAULT_API_INTERFACE_STRATEGY_STRING)
    private ApiInterfaceStrategy apiInterfaceStrategy;

124 125 126
    @Parameter(defaultValue = MappingConfigConstants.DEFAULT_API_NAME_PREFIX_STRATEGY_STRING)
    private ApiNamePrefixStrategy apiNamePrefixStrategy;

127
    @Parameter(defaultValue = MappingConfigConstants.DEFAULT_VALIDATION_ANNOTATION)
128 129
    private String modelValidationAnnotation;

130
    @Parameter(defaultValue = MappingConfigConstants.DEFAULT_GENERATE_PARAMETERIZED_FIELDS_RESOLVERS_STRING)
131 132
    private boolean generateParameterizedFieldsResolvers;

133
    @Parameter(defaultValue = MappingConfigConstants.DEFAULT_GENERATE_EXTENSION_FIELDS_RESOLVERS_STRING)
134 135
    private boolean generateExtensionFieldsResolvers;

136
    @Parameter(defaultValue = MappingConfigConstants.DEFAULT_GENERATE_DATA_FETCHING_ENV_STRING)
137 138
    private boolean generateDataFetchingEnvironmentArgumentInApis;

139 140 141
    @Parameter(defaultValue = MappingConfigConstants.DEFAULT_GENERATE_MODELS_FOR_ROOT_TYPES_STRING)
    private boolean generateModelsForRootTypes;

142 143 144
    @Parameter(defaultValue = MappingConfigConstants.DEFAULT_USE_OPTIONAL_FOR_NULLABLE_RETURN_TYPES_STRING)
    private boolean useOptionalForNullableReturnTypes;

145 146 147
    @Parameter(defaultValue = MappingConfigConstants.DEFAULT_GENERATE_APIS_WITH_THROWS_EXCEPTION_STRING)
    private boolean generateApisWithThrowsException;

148 149 150
    @Parameter(defaultValue = MappingConfigConstants.DEFAULT_ADD_GENERATED_ANNOTATION_STRING)
    private boolean addGeneratedAnnotation;

151
    @Parameter
152
    private String[] fieldsWithResolvers;
153

154
    @Parameter
155
    private String[] fieldsWithoutResolvers;
156

157 158 159
    @Parameter
    private RelayConfig relayConfig = new RelayConfig();

160 161 162
    @Parameter(defaultValue = MappingConfigConstants.DEFAULT_GENERATE_CLIENT_STRING)
    private boolean generateClient;

163
    @Parameter(defaultValue = MappingConfigConstants.DEFAULT_REQUEST_SUFFIX)
164 165
    private String requestSuffix;

166 167 168
    @Parameter(defaultValue = MappingConfigConstants.DEFAULT_RESPONSE_SUFFIX)
    private String responseSuffix;

169
    @Parameter(defaultValue = MappingConfigConstants.DEFAULT_RESPONSE_PROJECTION_SUFFIX)
170 171
    private String responseProjectionSuffix;

172
    @Parameter(defaultValue = MappingConfigConstants.DEFAULT_PARAMETRIZED_INPUT_SUFFIX)
173 174
    private String parametrizedInputSuffix;

B
Bogdan Kobylynskyi 已提交
175
    @Parameter
176
    private String[] useObjectMapperForRequestSerialization;
B
Bogdan Kobylynskyi 已提交
177

178 179
    @Parameter(defaultValue = MappingConfigConstants.DEFAULT_RESPONSE_PROJECTION_MAX_DEPTH_STRING)
    private int responseProjectionMaxDepth;
180

181 182 183
    @Parameter
    private ParentInterfacesConfig parentInterfaces = new ParentInterfacesConfig();

184 185 186
    @Parameter(defaultValue = MappingConfigConstants.DEFAULT_GENERATED_LANGUAGE_STRING)
    private GeneratedLanguage generatedLanguage;

187 188 189
    @Parameter
    private String jsonConfigurationFile;

190 191 192 193 194 195
    /**
     * The project being built.
     */
    @Parameter(readonly = true, required = true, defaultValue = "${project}")
    private MavenProject project;

196 197 198
    @Parameter(defaultValue = MappingConfigConstants.DEFAULT_GENERATE_MODEL_OPEN_CLASSES_STRING)
    private boolean generateModelOpenClasses;

199 200 201 202 203 204
    @Override
    public void execute() throws MojoExecutionException {
        addCompileSourceRootIfConfigured();

        MappingConfig mappingConfig = new MappingConfig();
        mappingConfig.setPackageName(packageName);
205
        mappingConfig.setCustomTypesMapping(convertToMap(customTypesMapping));
206 207
        mappingConfig.setCustomAnnotationsMapping(convertToListsMap(customAnnotationsMapping));
        mappingConfig.setDirectiveAnnotationsMapping(convertToListsMap(directiveAnnotationsMapping));
208 209
        mappingConfig.setApiNameSuffix(apiNameSuffix);
        mappingConfig.setApiNamePrefix(apiNamePrefix);
210
        mappingConfig.setApiRootInterfaceStrategy(apiRootInterfaceStrategy);
211
        mappingConfig.setApiInterfaceStrategy(apiInterfaceStrategy);
212
        mappingConfig.setApiNamePrefixStrategy(apiNamePrefixStrategy);
213 214 215 216
        mappingConfig.setModelNamePrefix(modelNamePrefix);
        mappingConfig.setModelNameSuffix(modelNameSuffix);
        mappingConfig.setApiPackageName(apiPackageName);
        mappingConfig.setModelPackageName(modelPackageName);
217
        mappingConfig.setGenerateBuilder(generateBuilder);
218
        mappingConfig.setGenerateApis(generateApis);
219 220
        mappingConfig.setTypeResolverSuffix(typeResolverSuffix);
        mappingConfig.setTypeResolverPrefix(typeResolverPrefix);
221 222
        mappingConfig.setModelValidationAnnotation(modelValidationAnnotation);
        mappingConfig.setGenerateEqualsAndHashCode(generateEqualsAndHashCode);
223
        mappingConfig.setGenerateImmutableModels(generateImmutableModels);
224
        mappingConfig.setGenerateToString(generateToString);
225 226
        mappingConfig.setApiReturnType(apiReturnType);
        mappingConfig.setApiReturnListType(apiReturnListType);
227
        mappingConfig.setSubscriptionReturnType(subscriptionReturnType);
228
        mappingConfig.setGenerateParameterizedFieldsResolvers(generateParameterizedFieldsResolvers);
229
        mappingConfig.setGenerateDataFetchingEnvironmentArgumentInApis(generateDataFetchingEnvironmentArgumentInApis);
230
        mappingConfig.setGenerateExtensionFieldsResolvers(generateExtensionFieldsResolvers);
231
        mappingConfig.setGenerateModelsForRootTypes(generateModelsForRootTypes);
232
        mappingConfig.setUseOptionalForNullableReturnTypes(useOptionalForNullableReturnTypes);
233
        mappingConfig.setGenerateApisWithThrowsException(generateApisWithThrowsException);
234
        mappingConfig.setAddGeneratedAnnotation(addGeneratedAnnotation);
235 236
        mappingConfig.setFieldsWithResolvers(mapToHashSet(fieldsWithResolvers));
        mappingConfig.setFieldsWithoutResolvers(mapToHashSet(fieldsWithoutResolvers));
237 238
        mappingConfig.setRelayConfig(relayConfig);

239
        mappingConfig.setGenerateClient(generateClient);
240
        mappingConfig.setRequestSuffix(requestSuffix);
241
        mappingConfig.setResponseSuffix(responseSuffix);
242
        mappingConfig.setResponseProjectionSuffix(responseProjectionSuffix);
243
        mappingConfig.setParametrizedInputSuffix(parametrizedInputSuffix);
244 245 246
        mappingConfig.setResponseProjectionMaxDepth(responseProjectionMaxDepth);
        mappingConfig.setUseObjectMapperForRequestSerialization(mapToHashSet(useObjectMapperForRequestSerialization));

247 248 249 250
        mappingConfig.setResolverParentInterface(getResolverParentInterface());
        mappingConfig.setQueryResolverParentInterface(getQueryResolverParentInterface());
        mappingConfig.setMutationResolverParentInterface(getMutationResolverParentInterface());
        mappingConfig.setSubscriptionResolverParentInterface(getSubscriptionResolverParentInterface());
251

252
        mappingConfig.setGeneratedLanguage(generatedLanguage);
253
        mappingConfig.setGenerateModelOpenClasses(isGenerateModelOpenClasses());
254 255

        try {
256
            instantiateCodegen(mappingConfig).generate();
257 258 259 260 261 262
        } catch (Exception e) {
            getLog().error(e);
            throw new MojoExecutionException("Code generation failed. See above for the full exception.");
        }
    }

263 264 265 266 267 268
    private GraphQLCodegen instantiateCodegen(MappingConfig mappingConfig) throws IOException {
        switch (generatedLanguage) {
            case JAVA:
                return new JavaGraphQLCodegen(getSchemas(), graphqlQueryIntrospectionResultPath, outputDir, mappingConfig, buildJsonSupplier(jsonConfigurationFile));
            case SCALA:
                return new ScalaGraphQLCodegen(getSchemas(), graphqlQueryIntrospectionResultPath, outputDir, mappingConfig, buildJsonSupplier(jsonConfigurationFile));
梦境迷离's avatar
梦境迷离 已提交
269 270
            case KOTLIN:
                return new KotlinGraphQLCodegen(getSchemas(), graphqlQueryIntrospectionResultPath, outputDir, mappingConfig, buildJsonSupplier(jsonConfigurationFile));
271 272 273 274 275
            default:
                throw new LanguageNotSupportedException(generatedLanguage);
        }
    }

276
    private List<String> getSchemas() throws IOException {
277 278 279
        if (graphqlSchemaPaths != null) {
            return Arrays.asList(graphqlSchemaPaths);
        }
280 281 282
        if (graphqlQueryIntrospectionResultPath != null) {
            return Collections.emptyList();
        }
283 284 285 286 287 288 289 290 291 292 293 294 295
        Path schemasRootDir = getSchemasRootDir();
        SchemaFinder finder = new SchemaFinder(schemasRootDir);
        finder.setRecursive(graphqlSchemas.isRecursive());
        finder.setIncludePattern(graphqlSchemas.getIncludePattern());
        finder.setExcludedFiles(graphqlSchemas.getExcludedFiles());
        return finder.findSchemas();
    }

    private Path getSchemasRootDir() {
        String rootDir = graphqlSchemas.getRootDir();
        if (rootDir == null) {
            return getDefaultResourcesDirectory().orElseThrow(() -> new IllegalStateException(
                    "Default resource folder not found, please provide <rootDir> in <graphqlSchemas>"));
296
        }
297 298 299 300 301
        return Paths.get(rootDir);
    }

    private Optional<Path> getDefaultResourcesDirectory() {
        return project.getResources().stream().findFirst().map(Resource::getDirectory).map(Paths::get);
302 303
    }

304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320
    private MappingConfigSupplier buildJsonSupplier(String jsonConfigurationFile) {
        if (jsonConfigurationFile != null && !jsonConfigurationFile.isEmpty()) {
            return new JsonMappingConfigSupplier(jsonConfigurationFile);
        }
        return null;
    }

    private void addCompileSourceRootIfConfigured() {
        String path = outputDir.getPath();
        getLog().info("Added the following path to the source root: " + path);
        project.addCompileSourceRoot(path);
    }

    public String[] getGraphqlSchemaPaths() {
        return graphqlSchemaPaths;
    }

321 322 323 324
    public String getGraphqlQueryIntrospectionResultPath() {
        return graphqlQueryIntrospectionResultPath;
    }

325 326 327 328
    public SchemaFinderConfig getGraphqlSchemas() {
        return graphqlSchemas;
    }

329 330 331 332
    public File getOutputDir() {
        return outputDir;
    }

333
    @Override
334
    public Map<String, String> getCustomTypesMapping() {
335
        return convertToMap(customTypesMapping);
336 337
    }

338
    @Override
339 340
    public Map<String, List<String>> getCustomAnnotationsMapping() {
        return convertToListsMap(customAnnotationsMapping);
341 342 343
    }

    @Override
344 345
    public Map<String, List<String>> getDirectiveAnnotationsMapping() {
        return convertToListsMap(directiveAnnotationsMapping);
346 347
    }

348
    @Override
349 350 351 352
    public String getPackageName() {
        return packageName;
    }

353
    @Override
354 355 356 357
    public String getApiPackageName() {
        return apiPackageName;
    }

358 359 360 361 362 363 364 365 366 367
    @Override
    public String getApiNamePrefix() {
        return apiNamePrefix;
    }

    @Override
    public String getApiNameSuffix() {
        return apiNameSuffix;
    }

368
    @Override
369 370 371 372
    public String getModelPackageName() {
        return modelPackageName;
    }

373
    @Override
374 375 376 377
    public String getModelNamePrefix() {
        return modelNamePrefix;
    }

378
    @Override
379 380 381 382
    public String getModelNameSuffix() {
        return modelNameSuffix;
    }

383
    @Override
384 385 386 387
    public String getModelValidationAnnotation() {
        return modelValidationAnnotation;
    }

388 389
    @Override
    public Boolean getGenerateBuilder() {
390 391 392
        return generateBuilder;
    }

393 394
    @Override
    public Boolean getGenerateApis() {
395 396 397
        return generateApis;
    }

398 399 400 401 402
    @Override
    public Boolean getGenerateModelsForRootTypes() {
        return generateModelsForRootTypes;
    }

403 404
    @Override
    public Boolean getGenerateEqualsAndHashCode() {
405 406 407
        return generateEqualsAndHashCode;
    }

408 409 410 411 412
    @Override
    public Boolean getGenerateImmutableModels() {
        return generateImmutableModels;
    }

413 414
    @Override
    public Boolean getGenerateToString() {
415 416 417
        return generateToString;
    }

418
    @Override
419 420
    public String getApiReturnType() {
        return apiReturnType;
421 422 423
    }

    @Override
424 425
    public String getApiReturnListType() {
        return apiReturnListType;
426 427
    }

428 429 430
    @Override
    public String getSubscriptionReturnType() {
        return subscriptionReturnType;
431 432
    }

433 434 435
    @Override
    public Boolean getGenerateExtensionFieldsResolvers() {
        return generateExtensionFieldsResolvers;
436
    }
437

438 439
    @Override
    public Boolean getGenerateParameterizedFieldsResolvers() {
440 441 442
        return generateParameterizedFieldsResolvers;
    }

443 444 445 446 447 448 449 450 451 452
    @Override
    public String getTypeResolverPrefix() {
        return typeResolverPrefix;
    }

    @Override
    public String getTypeResolverSuffix() {
        return typeResolverSuffix;
    }

453 454
    @Override
    public Boolean getGenerateDataFetchingEnvironmentArgumentInApis() {
455 456 457
        return generateDataFetchingEnvironmentArgumentInApis;
    }

B
Bogdan Kobylynskyi 已提交
458 459 460 461 462
    @Override
    public RelayConfig getRelayConfig() {
        return relayConfig;
    }

463 464 465 466 467
    @Override
    public Boolean getUseOptionalForNullableReturnTypes() {
        return useOptionalForNullableReturnTypes;
    }

468
    @Override
469 470 471 472
    public Boolean getGenerateApisWithThrowsException() {
        return generateApisWithThrowsException;
    }

473 474 475 476 477
    @Override
    public Boolean getAddGeneratedAnnotation() {
        return addGeneratedAnnotation;
    }

478
    @Override
479 480 481 482
    public ApiRootInterfaceStrategy getApiRootInterfaceStrategy() {
        return apiRootInterfaceStrategy;
    }

483 484 485 486 487
    @Override
    public ApiInterfaceStrategy getApiInterfaceStrategy() {
        return apiInterfaceStrategy;
    }

488 489 490 491 492
    @Override
    public ApiNamePrefixStrategy getApiNamePrefixStrategy() {
        return apiNamePrefixStrategy;
    }

493
    @Override
494
    public Set<String> getFieldsWithResolvers() {
495
        return mapToHashSet(fieldsWithResolvers);
496 497
    }

498 499
    @Override
    public Set<String> getFieldsWithoutResolvers() {
500
        return mapToHashSet(fieldsWithoutResolvers);
501 502
    }

503 504 505 506 507
    @Override
    public Integer getResponseProjectionMaxDepth() {
        return responseProjectionMaxDepth;
    }

508
    @Override
509 510 511 512
    public Boolean getGenerateClient() {
        return generateClient;
    }

513
    @Override
514 515 516 517
    public String getRequestSuffix() {
        return requestSuffix;
    }

518 519 520 521 522
    @Override
    public String getResponseSuffix() {
        return responseSuffix;
    }

523
    @Override
524 525 526 527
    public String getResponseProjectionSuffix() {
        return responseProjectionSuffix;
    }

528 529 530 531 532
    @Override
    public String getParametrizedInputSuffix() {
        return parametrizedInputSuffix;
    }

533 534 535 536 537
    @Override
    public Set<String> getUseObjectMapperForRequestSerialization() {
        return mapToHashSet(useObjectMapperForRequestSerialization);
    }

538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557
    @Override
    public String getQueryResolverParentInterface() {
        return parentInterfaces.getQueryResolver();
    }

    @Override
    public String getMutationResolverParentInterface() {
        return parentInterfaces.getMutationResolver();
    }

    @Override
    public String getSubscriptionResolverParentInterface() {
        return parentInterfaces.getSubscriptionResolver();
    }

    @Override
    public String getResolverParentInterface() {
        return parentInterfaces.getResolver();
    }

558 559 560 561 562
    @Override
    public GeneratedLanguage getGeneratedLanguage() {
        return generatedLanguage;
    }

563 564 565 566 567
    @Override
    public Boolean isGenerateModelOpenClasses() {
        return generateModelOpenClasses;
    }

568 569
    public ParentInterfacesConfig getParentInterfaces() {
        return parentInterfaces;
570 571
    }

572 573
    public String getJsonConfigurationFile() {
        return jsonConfigurationFile;
574 575
    }

576
    private static Map<String, List<String>> convertToListsMap(Map<String, Properties> sourceMap) {
577 578 579
        if (sourceMap == null) {
            return new HashMap<>();
        }
580 581
        Map<String, List<String>> map = new HashMap<>(sourceMap.size());
        for (Map.Entry<String, Properties> e : sourceMap.entrySet()) {
582
            if (e.getValue() != null) {
583 584 585 586 587 588
                Collection<Object> values = e.getValue().values();
                List<String> stringValues = new ArrayList<>(values.size());
                for (Object value : values) {
                    stringValues.add(value.toString());
                }
                map.put(e.getKey(), stringValues);
589 590 591 592 593 594 595 596 597 598 599 600
            }
        }
        return map;
    }

    private static Set<String> mapToHashSet(String[] sourceSet) {
        if (sourceSet == null) {
            return Collections.emptySet();
        }
        return new HashSet<>(Arrays.asList(sourceSet));
    }

601 602 603 604 605 606 607 608 609 610 611
    private static Map<String, String> convertToMap(Properties properties) {
        if (properties == null) {
            return null;
        }
        Map<String, String> result = new HashMap<>(properties.size());
        for (String name : properties.stringPropertyNames()) {
            result.put(name, properties.getProperty(name));
        }
        return result;
    }

612
}