GraphQLCodegenMojo.java 19.7 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
    @Parameter
149
    private String[] fieldsWithResolvers;
150

151
    @Parameter
152
    private String[] fieldsWithoutResolvers;
153

154 155 156
    @Parameter
    private RelayConfig relayConfig = new RelayConfig();

157 158 159
    @Parameter(defaultValue = MappingConfigConstants.DEFAULT_GENERATE_CLIENT_STRING)
    private boolean generateClient;

160
    @Parameter(defaultValue = MappingConfigConstants.DEFAULT_REQUEST_SUFFIX)
161 162
    private String requestSuffix;

163 164 165
    @Parameter(defaultValue = MappingConfigConstants.DEFAULT_RESPONSE_SUFFIX)
    private String responseSuffix;

166
    @Parameter(defaultValue = MappingConfigConstants.DEFAULT_RESPONSE_PROJECTION_SUFFIX)
167 168
    private String responseProjectionSuffix;

169
    @Parameter(defaultValue = MappingConfigConstants.DEFAULT_PARAMETRIZED_INPUT_SUFFIX)
170 171
    private String parametrizedInputSuffix;

B
Bogdan Kobylynskyi 已提交
172
    @Parameter
173
    private String[] useObjectMapperForRequestSerialization;
B
Bogdan Kobylynskyi 已提交
174

175 176
    @Parameter(defaultValue = MappingConfigConstants.DEFAULT_RESPONSE_PROJECTION_MAX_DEPTH_STRING)
    private int responseProjectionMaxDepth;
177

178 179 180
    @Parameter
    private ParentInterfacesConfig parentInterfaces = new ParentInterfacesConfig();

181 182 183
    @Parameter(defaultValue = MappingConfigConstants.DEFAULT_GENERATED_LANGUAGE_STRING)
    private GeneratedLanguage generatedLanguage;

184 185 186
    @Parameter
    private String jsonConfigurationFile;

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

    @Override
    public void execute() throws MojoExecutionException {
        addCompileSourceRootIfConfigured();

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

232
        mappingConfig.setGenerateClient(generateClient);
233
        mappingConfig.setRequestSuffix(requestSuffix);
234
        mappingConfig.setResponseSuffix(responseSuffix);
235
        mappingConfig.setResponseProjectionSuffix(responseProjectionSuffix);
236
        mappingConfig.setParametrizedInputSuffix(parametrizedInputSuffix);
237 238 239
        mappingConfig.setResponseProjectionMaxDepth(responseProjectionMaxDepth);
        mappingConfig.setUseObjectMapperForRequestSerialization(mapToHashSet(useObjectMapperForRequestSerialization));

240 241 242 243
        mappingConfig.setResolverParentInterface(getResolverParentInterface());
        mappingConfig.setQueryResolverParentInterface(getQueryResolverParentInterface());
        mappingConfig.setMutationResolverParentInterface(getMutationResolverParentInterface());
        mappingConfig.setSubscriptionResolverParentInterface(getSubscriptionResolverParentInterface());
244

245
        mappingConfig.setGeneratedLanguage(generatedLanguage);
246 247

        try {
248
            instantiateCodegen(mappingConfig).generate();
249 250 251 252 253 254
        } catch (Exception e) {
            getLog().error(e);
            throw new MojoExecutionException("Code generation failed. See above for the full exception.");
        }
    }

255 256 257 258 259 260
    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
梦境迷离 已提交
261 262
            case KOTLIN:
                return new KotlinGraphQLCodegen(getSchemas(), graphqlQueryIntrospectionResultPath, outputDir, mappingConfig, buildJsonSupplier(jsonConfigurationFile));
263 264 265 266 267
            default:
                throw new LanguageNotSupportedException(generatedLanguage);
        }
    }

268
    private List<String> getSchemas() throws IOException {
269 270 271
        if (graphqlSchemaPaths != null) {
            return Arrays.asList(graphqlSchemaPaths);
        }
272 273 274 275 276 277 278 279 280 281 282 283 284
        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>"));
285
        }
286 287 288 289 290
        return Paths.get(rootDir);
    }

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

293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309
    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;
    }

310 311 312 313
    public String getGraphqlQueryIntrospectionResultPath() {
        return graphqlQueryIntrospectionResultPath;
    }

314 315 316 317
    public SchemaFinderConfig getGraphqlSchemas() {
        return graphqlSchemas;
    }

318 319 320 321
    public File getOutputDir() {
        return outputDir;
    }

322
    @Override
323
    public Map<String, String> getCustomTypesMapping() {
324
        return convertToMap(customTypesMapping);
325 326
    }

327
    @Override
328 329
    public Map<String, List<String>> getCustomAnnotationsMapping() {
        return convertToListsMap(customAnnotationsMapping);
330 331 332
    }

    @Override
333 334
    public Map<String, List<String>> getDirectiveAnnotationsMapping() {
        return convertToListsMap(directiveAnnotationsMapping);
335 336
    }

337
    @Override
338 339 340 341
    public String getPackageName() {
        return packageName;
    }

342
    @Override
343 344 345 346
    public String getApiPackageName() {
        return apiPackageName;
    }

347 348 349 350 351 352 353 354 355 356
    @Override
    public String getApiNamePrefix() {
        return apiNamePrefix;
    }

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

357
    @Override
358 359 360 361
    public String getModelPackageName() {
        return modelPackageName;
    }

362
    @Override
363 364 365 366
    public String getModelNamePrefix() {
        return modelNamePrefix;
    }

367
    @Override
368 369 370 371
    public String getModelNameSuffix() {
        return modelNameSuffix;
    }

372
    @Override
373 374 375 376
    public String getModelValidationAnnotation() {
        return modelValidationAnnotation;
    }

377 378
    @Override
    public Boolean getGenerateBuilder() {
379 380 381
        return generateBuilder;
    }

382 383
    @Override
    public Boolean getGenerateApis() {
384 385 386
        return generateApis;
    }

387 388 389 390 391
    @Override
    public Boolean getGenerateModelsForRootTypes() {
        return generateModelsForRootTypes;
    }

392 393
    @Override
    public Boolean getGenerateEqualsAndHashCode() {
394 395 396
        return generateEqualsAndHashCode;
    }

397 398 399 400 401
    @Override
    public Boolean getGenerateImmutableModels() {
        return generateImmutableModels;
    }

402 403
    @Override
    public Boolean getGenerateToString() {
404 405 406
        return generateToString;
    }

407
    @Override
408 409
    public String getApiReturnType() {
        return apiReturnType;
410 411 412
    }

    @Override
413 414
    public String getApiReturnListType() {
        return apiReturnListType;
415 416
    }

417 418 419
    @Override
    public String getSubscriptionReturnType() {
        return subscriptionReturnType;
420 421
    }

422 423 424
    @Override
    public Boolean getGenerateExtensionFieldsResolvers() {
        return generateExtensionFieldsResolvers;
425
    }
426

427 428
    @Override
    public Boolean getGenerateParameterizedFieldsResolvers() {
429 430 431
        return generateParameterizedFieldsResolvers;
    }

432 433 434 435 436 437 438 439 440 441
    @Override
    public String getTypeResolverPrefix() {
        return typeResolverPrefix;
    }

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

442 443
    @Override
    public Boolean getGenerateDataFetchingEnvironmentArgumentInApis() {
444 445 446
        return generateDataFetchingEnvironmentArgumentInApis;
    }

B
Bogdan Kobylynskyi 已提交
447 448 449 450 451
    @Override
    public RelayConfig getRelayConfig() {
        return relayConfig;
    }

452 453 454 455 456
    @Override
    public Boolean getUseOptionalForNullableReturnTypes() {
        return useOptionalForNullableReturnTypes;
    }

457
    @Override
458 459 460 461 462
    public Boolean getGenerateApisWithThrowsException() {
        return generateApisWithThrowsException;
    }

    @Override
463 464 465 466
    public ApiRootInterfaceStrategy getApiRootInterfaceStrategy() {
        return apiRootInterfaceStrategy;
    }

467 468 469 470 471
    @Override
    public ApiInterfaceStrategy getApiInterfaceStrategy() {
        return apiInterfaceStrategy;
    }

472 473 474 475 476
    @Override
    public ApiNamePrefixStrategy getApiNamePrefixStrategy() {
        return apiNamePrefixStrategy;
    }

477
    @Override
478
    public Set<String> getFieldsWithResolvers() {
479
        return mapToHashSet(fieldsWithResolvers);
480 481
    }

482 483
    @Override
    public Set<String> getFieldsWithoutResolvers() {
484
        return mapToHashSet(fieldsWithoutResolvers);
485 486
    }

487 488 489 490 491
    @Override
    public Integer getResponseProjectionMaxDepth() {
        return responseProjectionMaxDepth;
    }

492
    @Override
493 494 495 496
    public Boolean getGenerateClient() {
        return generateClient;
    }

497
    @Override
498 499 500 501
    public String getRequestSuffix() {
        return requestSuffix;
    }

502 503 504 505 506
    @Override
    public String getResponseSuffix() {
        return responseSuffix;
    }

507
    @Override
508 509 510 511
    public String getResponseProjectionSuffix() {
        return responseProjectionSuffix;
    }

512 513 514 515 516
    @Override
    public String getParametrizedInputSuffix() {
        return parametrizedInputSuffix;
    }

517 518 519 520 521
    @Override
    public Set<String> getUseObjectMapperForRequestSerialization() {
        return mapToHashSet(useObjectMapperForRequestSerialization);
    }

522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541
    @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();
    }

542 543 544 545 546
    @Override
    public GeneratedLanguage getGeneratedLanguage() {
        return generatedLanguage;
    }

547 548
    public ParentInterfacesConfig getParentInterfaces() {
        return parentInterfaces;
549 550
    }

551 552
    public String getJsonConfigurationFile() {
        return jsonConfigurationFile;
553 554
    }

555
    private static Map<String, List<String>> convertToListsMap(Map<String, Properties> sourceMap) {
556 557 558
        if (sourceMap == null) {
            return new HashMap<>();
        }
559 560
        Map<String, List<String>> map = new HashMap<>(sourceMap.size());
        for (Map.Entry<String, Properties> e : sourceMap.entrySet()) {
561
            if (e.getValue() != null) {
562 563 564 565 566 567
                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);
568 569 570 571 572 573 574 575 576 577 578 579
            }
        }
        return map;
    }

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

580 581 582 583 584 585 586 587 588 589 590
    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;
    }

591
}