From eb5a8cc752a855ecc05914d502129ffd9469c95e Mon Sep 17 00:00:00 2001 From: andreas-eternach Date: Sun, 4 Nov 2018 10:07:33 +0100 Subject: [PATCH] feat: OpenApi-generation from within eclipse (#509) (#1332) * feat: OpenApi-generation from within eclipse (#509) * Added life-cycle-mapping for recognition by M2E * Make BuildContext injectable by M2E in oder to detect if json-source has been modified and a regeneration is required. * core: fix indentation problems, remove commented code --- .../openapi-generator-maven-plugin/pom.xml | 5 + .../codegen/plugin/CodeGenMojo.java | 436 ++++++++++-------- .../m2e/lifecycle-mapping-metadata.xml | 17 + 3 files changed, 258 insertions(+), 200 deletions(-) create mode 100644 modules/openapi-generator-maven-plugin/src/main/resources/META-INF/m2e/lifecycle-mapping-metadata.xml diff --git a/modules/openapi-generator-maven-plugin/pom.xml b/modules/openapi-generator-maven-plugin/pom.xml index cc34f637b34f..c22f5180546c 100644 --- a/modules/openapi-generator-maven-plugin/pom.xml +++ b/modules/openapi-generator-maven-plugin/pom.xml @@ -15,6 +15,11 @@ UTF-8 + + org.sonatype.plexus + plexus-build-api + 0.0.7 + org.apache.maven maven-core diff --git a/modules/openapi-generator-maven-plugin/src/main/java/org/openapitools/codegen/plugin/CodeGenMojo.java b/modules/openapi-generator-maven-plugin/src/main/java/org/openapitools/codegen/plugin/CodeGenMojo.java index a46e58849d7c..2c213bb4a891 100644 --- a/modules/openapi-generator-maven-plugin/src/main/java/org/openapitools/codegen/plugin/CodeGenMojo.java +++ b/modules/openapi-generator-maven-plugin/src/main/java/org/openapitools/codegen/plugin/CodeGenMojo.java @@ -42,6 +42,7 @@ 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.plugins.annotations.Component; import org.apache.maven.project.MavenProject; import org.openapitools.codegen.CliOption; @@ -50,6 +51,8 @@ import org.openapitools.codegen.CodegenConstants; import org.openapitools.codegen.DefaultGenerator; import org.openapitools.codegen.config.CodegenConfigurator; +import org.sonatype.plexus.build.incremental.BuildContext; +import org.sonatype.plexus.build.incremental.DefaultBuildContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -61,6 +64,13 @@ public class CodeGenMojo extends AbstractMojo { private static final Logger LOGGER = LoggerFactory.getLogger(CodeGenMojo.class); + /** + * The build context is only avail when running from within eclipse. + * It is used to update the eclipse-m2e-layer when the plugin is executed inside the IDE. + */ + @Component + private BuildContext buildContext = new DefaultBuildContext(); + @Parameter(name="validateSpec", required = false, defaultValue = "true") private Boolean validateSpec; @@ -329,274 +339,300 @@ public class CodeGenMojo extends AbstractMojo { @Parameter(readonly = true, required = true, defaultValue = "${project}") private MavenProject project; - + public void setBuildContext(BuildContext buildContext) { + this.buildContext = buildContext; + } @Override public void execute() throws MojoExecutionException { + File inputSpecFile = new File(inputSpec); + addCompileSourceRootIfConfigured(); - if (skip) { - getLog().info("Code generation is skipped."); - // Even when no new sources are generated, the existing ones should - // still be compiled if needed. - addCompileSourceRootIfConfigured(); - return; - } - - // attempt to read from config file - CodegenConfigurator configurator = CodegenConfigurator.fromFile(configurationFile); - - // if a config file wasn't specified or we were unable to read it - if (configurator == null) { - configurator = new CodegenConfigurator(); - } - - configurator.setVerbose(verbose); - - // now override with any specified parameters - if (validateSpec != null) { - configurator.setValidateSpec(validateSpec); - } - - if (skipOverwrite != null) { - configurator.setSkipOverwrite(skipOverwrite); - } + try { + if (skip) { + getLog().info("Code generation is skipped."); + return; + } - if (removeOperationIdPrefix != null) { - configurator.setRemoveOperationIdPrefix(removeOperationIdPrefix); - } + if (buildContext != null) { + if (buildContext.isIncremental()) { + if (inputSpec != null) { + if (inputSpecFile.exists()) { + if (!buildContext.hasDelta(inputSpecFile)) { + getLog().info( + "Code generation is skipped in delta-build because source-json was not modified."); + return; + } + } + } + } + } - if (isNotEmpty(inputSpec)) { - configurator.setInputSpec(inputSpec); - } + // attempt to read from config file + CodegenConfigurator configurator = CodegenConfigurator.fromFile(configurationFile); - if (isNotEmpty(gitUserId)) { - configurator.setGitUserId(gitUserId); - } + // if a config file wasn't specified or we were unable to read it + if (configurator == null) { + configurator = new CodegenConfigurator(); + } - if (isNotEmpty(gitRepoId)) { - configurator.setGitRepoId(gitRepoId); - } + configurator.setVerbose(verbose); - if (isNotEmpty(ignoreFileOverride)) { - configurator.setIgnoreFileOverride(ignoreFileOverride); - } + // now override with any specified parameters + if (validateSpec != null) { + configurator.setValidateSpec(validateSpec); + } - // TODO: After 3.0.0 release (maybe for 3.1.0): Fully deprecate lang. - if (isNotEmpty(generatorName)) { - configurator.setGeneratorName(generatorName); - - // check if generatorName & language are set together, inform user this needs to be updated to prevent future issues. - if (isNotEmpty(language)) { - LOGGER.warn("The 'language' option is deprecated and was replaced by 'generatorName'. Both can not be set together"); - throw new MojoExecutionException("Illegal configuration: 'language' and 'generatorName' can not be set both, remove 'language' from your configuration"); - } - } else if (isNotEmpty(language)) { - LOGGER.warn("The 'language' option is deprecated and may reference language names only in the next major release (4.0). Please use 'generatorName' instead."); - configurator.setGeneratorName(language); - } else { - LOGGER.error("A generator name (generatorName) is required."); - throw new MojoExecutionException("The generator requires 'generatorName'. Refer to documentation for a list of options."); - } + if (skipOverwrite != null) { + configurator.setSkipOverwrite(skipOverwrite); + } + if (removeOperationIdPrefix != null) { + configurator.setRemoveOperationIdPrefix(removeOperationIdPrefix); + } - configurator.setOutputDir(output.getAbsolutePath()); + if (isNotEmpty(inputSpec)) { + configurator.setInputSpec(inputSpec); + } - if (isNotEmpty(auth)) { - configurator.setAuth(auth); - } + if (isNotEmpty(gitUserId)) { + configurator.setGitUserId(gitUserId); + } - if (isNotEmpty(apiPackage)) { - configurator.setApiPackage(apiPackage); - } + if (isNotEmpty(gitRepoId)) { + configurator.setGitRepoId(gitRepoId); + } - if (isNotEmpty(modelPackage)) { - configurator.setModelPackage(modelPackage); - } + if (isNotEmpty(ignoreFileOverride)) { + configurator.setIgnoreFileOverride(ignoreFileOverride); + } - if (isNotEmpty(invokerPackage)) { - configurator.setInvokerPackage(invokerPackage); - } + // TODO: After 3.0.0 release (maybe for 3.1.0): Fully deprecate lang. + if (isNotEmpty(generatorName)) { + configurator.setGeneratorName(generatorName); - if (isNotEmpty(groupId)) { - configurator.setGroupId(groupId); - } + // check if generatorName & language are set together, inform user this needs to be updated to prevent future issues. + if (isNotEmpty(language)) { + LOGGER.warn("The 'language' option is deprecated and was replaced by 'generatorName'. Both can not be set together"); + throw new MojoExecutionException( + "Illegal configuration: 'language' and 'generatorName' can not be set both, remove 'language' from your configuration"); + } + } else if (isNotEmpty(language)) { + LOGGER.warn( + "The 'language' option is deprecated and may reference language names only in the next major release (4.0). Please use 'generatorName' instead."); + configurator.setGeneratorName(language); + } else { + LOGGER.error("A generator name (generatorName) is required."); + throw new MojoExecutionException("The generator requires 'generatorName'. Refer to documentation for a list of options."); + } - if (isNotEmpty(artifactId)) { - configurator.setArtifactId(artifactId); - } + configurator.setOutputDir(output.getAbsolutePath()); - if (isNotEmpty(artifactVersion)) { - configurator.setArtifactVersion(artifactVersion); - } + if (isNotEmpty(auth)) { + configurator.setAuth(auth); + } - if (isNotEmpty(library)) { - configurator.setLibrary(library); - } + if (isNotEmpty(apiPackage)) { + configurator.setApiPackage(apiPackage); + } - if (isNotEmpty(modelNamePrefix)) { - configurator.setModelNamePrefix(modelNamePrefix); - } + if (isNotEmpty(modelPackage)) { + configurator.setModelPackage(modelPackage); + } - if (isNotEmpty(modelNameSuffix)) { - configurator.setModelNameSuffix(modelNameSuffix); - } + if (isNotEmpty(invokerPackage)) { + configurator.setInvokerPackage(invokerPackage); + } - if (null != templateDirectory) { - configurator.setTemplateDir(templateDirectory.getAbsolutePath()); - } + if (isNotEmpty(groupId)) { + configurator.setGroupId(groupId); + } - // Set generation options - if (null != generateApis && generateApis) { - System.setProperty(CodegenConstants.APIS, ""); - } else { - System.clearProperty(CodegenConstants.APIS); - } + if (isNotEmpty(artifactId)) { + configurator.setArtifactId(artifactId); + } - if (null != generateModels && generateModels) { - System.setProperty(CodegenConstants.MODELS, modelsToGenerate); - } else { - System.clearProperty(CodegenConstants.MODELS); - } + if (isNotEmpty(artifactVersion)) { + configurator.setArtifactVersion(artifactVersion); + } - if (null != generateSupportingFiles && generateSupportingFiles) { - System.setProperty(CodegenConstants.SUPPORTING_FILES, supportingFilesToGenerate); - } else { - System.clearProperty(CodegenConstants.SUPPORTING_FILES); - } + if (isNotEmpty(library)) { + configurator.setLibrary(library); + } - System.setProperty(CodegenConstants.MODEL_TESTS, generateModelTests.toString()); - System.setProperty(CodegenConstants.MODEL_DOCS, generateModelDocumentation.toString()); - System.setProperty(CodegenConstants.API_TESTS, generateApiTests.toString()); - System.setProperty(CodegenConstants.API_DOCS, generateApiDocumentation.toString()); - System.setProperty(CodegenConstants.WITH_XML, withXml.toString()); + if (isNotEmpty(modelNamePrefix)) { + configurator.setModelNamePrefix(modelNamePrefix); + } - if (configOptions != null) { - // Retained for backwards-compataibility with configOptions -> instantiation-types - if (instantiationTypes == null && configOptions.containsKey("instantiation-types")) { - applyInstantiationTypesKvp(configOptions.get("instantiation-types").toString(), - configurator); + if (isNotEmpty(modelNameSuffix)) { + configurator.setModelNameSuffix(modelNameSuffix); } - // Retained for backwards-compataibility with configOptions -> import-mappings - if (importMappings == null && configOptions.containsKey("import-mappings")) { - applyImportMappingsKvp(configOptions.get("import-mappings").toString(), - configurator); + if (null != templateDirectory) { + configurator.setTemplateDir(templateDirectory.getAbsolutePath()); } - // Retained for backwards-compataibility with configOptions -> type-mappings - if (typeMappings == null && configOptions.containsKey("type-mappings")) { - applyTypeMappingsKvp(configOptions.get("type-mappings").toString(), configurator); + // Set generation options + if (null != generateApis && generateApis) { + System.setProperty(CodegenConstants.APIS, ""); + } else { + System.clearProperty(CodegenConstants.APIS); } - // Retained for backwards-compataibility with configOptions -> language-specific-primitives - if (languageSpecificPrimitives == null && configOptions.containsKey("language-specific-primitives")) { - applyLanguageSpecificPrimitivesCsv(configOptions - .get("language-specific-primitives").toString(), configurator); + if (null != generateModels && generateModels) { + System.setProperty(CodegenConstants.MODELS, modelsToGenerate); + } else { + System.clearProperty(CodegenConstants.MODELS); } - // Retained for backwards-compataibility with configOptions -> additional-properties - if (additionalProperties == null && configOptions.containsKey("additional-properties")) { - applyAdditionalPropertiesKvp(configOptions.get("additional-properties").toString(), - configurator); + if (null != generateSupportingFiles && generateSupportingFiles) { + System.setProperty(CodegenConstants.SUPPORTING_FILES, supportingFilesToGenerate); + } else { + System.clearProperty(CodegenConstants.SUPPORTING_FILES); } - // Retained for backwards-compataibility with configOptions -> reserved-words-mappings - if (reservedWordsMappings == null && configOptions.containsKey("reserved-words-mappings")) { - applyReservedWordsMappingsKvp(configOptions.get("reserved-words-mappings") - .toString(), configurator); + System.setProperty(CodegenConstants.MODEL_TESTS, generateModelTests.toString()); + System.setProperty(CodegenConstants.MODEL_DOCS, generateModelDocumentation.toString()); + System.setProperty(CodegenConstants.API_TESTS, generateApiTests.toString()); + System.setProperty(CodegenConstants.API_DOCS, generateApiDocumentation.toString()); + System.setProperty(CodegenConstants.WITH_XML, withXml.toString()); + + if (configOptions != null) { + // Retained for backwards-compataibility with configOptions -> instantiation-types + if (instantiationTypes == null && configOptions.containsKey("instantiation-types")) { + applyInstantiationTypesKvp(configOptions.get("instantiation-types").toString(), + configurator); + } + + // Retained for backwards-compataibility with configOptions -> import-mappings + if (importMappings == null && configOptions.containsKey("import-mappings")) { + applyImportMappingsKvp(configOptions.get("import-mappings").toString(), + configurator); + } + + // Retained for backwards-compataibility with configOptions -> type-mappings + if (typeMappings == null && configOptions.containsKey("type-mappings")) { + applyTypeMappingsKvp(configOptions.get("type-mappings").toString(), configurator); + } + + // Retained for backwards-compataibility with configOptions -> language-specific-primitives + if (languageSpecificPrimitives == null && configOptions.containsKey("language-specific-primitives")) { + applyLanguageSpecificPrimitivesCsv(configOptions + .get("language-specific-primitives").toString(), configurator); + } + + // Retained for backwards-compataibility with configOptions -> additional-properties + if (additionalProperties == null && configOptions.containsKey("additional-properties")) { + applyAdditionalPropertiesKvp(configOptions.get("additional-properties").toString(), + configurator); + } + + // Retained for backwards-compataibility with configOptions -> reserved-words-mappings + if (reservedWordsMappings == null && configOptions.containsKey("reserved-words-mappings")) { + applyReservedWordsMappingsKvp(configOptions.get("reserved-words-mappings") + .toString(), configurator); + } } - } - //Apply Instantiation Types - if (instantiationTypes != null && (configOptions == null || !configOptions.containsKey("instantiation-types"))) { - applyInstantiationTypesKvpList(instantiationTypes, configurator); - } + // Apply Instantiation Types + if (instantiationTypes != null && (configOptions == null || !configOptions.containsKey("instantiation-types"))) { + applyInstantiationTypesKvpList(instantiationTypes, configurator); + } - //Apply Import Mappings - if (importMappings != null && (configOptions == null || !configOptions.containsKey("import-mappings"))) { - applyImportMappingsKvpList(importMappings, configurator); - } + // Apply Import Mappings + if (importMappings != null && (configOptions == null || !configOptions.containsKey("import-mappings"))) { + applyImportMappingsKvpList(importMappings, configurator); + } - //Apply Type Mappings - if (typeMappings != null && (configOptions == null || !configOptions.containsKey("type-mappings"))) { - applyTypeMappingsKvpList(typeMappings, configurator); - } + // Apply Type Mappings + if (typeMappings != null && (configOptions == null || !configOptions.containsKey("type-mappings"))) { + applyTypeMappingsKvpList(typeMappings, configurator); + } - //Apply Language Specific Primitives - if (languageSpecificPrimitives != null && (configOptions == null || !configOptions.containsKey("language-specific-primitives"))) { - applyLanguageSpecificPrimitivesCsvList(languageSpecificPrimitives, configurator); - } + // Apply Language Specific Primitives + if (languageSpecificPrimitives != null + && (configOptions == null || !configOptions.containsKey("language-specific-primitives"))) { + applyLanguageSpecificPrimitivesCsvList(languageSpecificPrimitives, configurator); + } - //Apply Additional Properties - if (additionalProperties != null && (configOptions == null || !configOptions.containsKey("additional-properties"))) { - applyAdditionalPropertiesKvpList(additionalProperties, configurator); - } + // Apply Additional Properties + if (additionalProperties != null && (configOptions == null || !configOptions.containsKey("additional-properties"))) { + applyAdditionalPropertiesKvpList(additionalProperties, configurator); + } - //Apply Reserved Words Mappings - if (reservedWordsMappings != null && (configOptions == null || !configOptions.containsKey("reserved-words-mappings"))) { - applyReservedWordsMappingsKvpList(reservedWordsMappings, configurator); - } + // Apply Reserved Words Mappings + if (reservedWordsMappings != null && (configOptions == null || !configOptions.containsKey("reserved-words-mappings"))) { + applyReservedWordsMappingsKvpList(reservedWordsMappings, configurator); + } - if (environmentVariables != null) { + if (environmentVariables != null) { - for (String key : environmentVariables.keySet()) { - originalEnvironmentVariables.put(key, System.getProperty(key)); - String value = environmentVariables.get(key); - if (value == null) { - // don't put null values - value = ""; + for (String key : environmentVariables.keySet()) { + originalEnvironmentVariables.put(key, System.getProperty(key)); + String value = environmentVariables.get(key); + if (value == null) { + // don't put null values + value = ""; + } + System.setProperty(key, value); + configurator.addSystemProperty(key, value); } - System.setProperty(key, value); - configurator.addSystemProperty(key, value); } - } - final ClientOptInput input = configurator.toClientOptInput(); - final CodegenConfig config = input.getConfig(); + final ClientOptInput input = configurator.toClientOptInput(); + final CodegenConfig config = input.getConfig(); - if (configOptions != null) { - for (CliOption langCliOption : config.cliOptions()) { - if (configOptions.containsKey(langCliOption.getOpt())) { - input.getConfig().additionalProperties() - .put(langCliOption.getOpt(), configOptions.get(langCliOption.getOpt())); + if (configOptions != null) { + for (CliOption langCliOption : config.cliOptions()) { + if (configOptions.containsKey(langCliOption.getOpt())) { + input.getConfig().additionalProperties() + .put(langCliOption.getOpt(), configOptions.get(langCliOption.getOpt())); + } } } - } - if (configHelp) { - for (CliOption langCliOption : config.cliOptions()) { - System.out.println("\t" + langCliOption.getOpt()); - System.out.println("\t " - + langCliOption.getOptionHelp().replaceAll("\n", "\n\t ")); - System.out.println(); + if (configHelp) { + for (CliOption langCliOption : config.cliOptions()) { + System.out.println("\t" + langCliOption.getOpt()); + System.out.println("\t " + + langCliOption.getOptionHelp().replaceAll("\n", "\n\t ")); + System.out.println(); + } + return; } - return; - } - adjustAdditionalProperties(config); - try { + adjustAdditionalProperties(config); new DefaultGenerator().opts(input).generate(); + + if (buildContext != null) { + buildContext.refresh(new File(getCompileSourceRoot())); + } } catch (Exception e) { // Maven logs exceptions thrown by plugins only if invoked with -e // I find it annoying to jump through hoops to get basic diagnostic information, // so let's log it in any case: + if (buildContext != null) { + buildContext.addError(inputSpecFile, 0, 0, "unexpected error in Open-API generation", e); + } getLog().error(e); throw new MojoExecutionException( "Code generation failed. See above for the full exception."); } - - addCompileSourceRootIfConfigured(); + } + + private String getCompileSourceRoot() { + final Object sourceFolderObject = + configOptions == null ? null : configOptions + .get(CodegenConstants.SOURCE_FOLDER); + final String sourceFolder = + sourceFolderObject == null ? "src/main/java" : sourceFolderObject.toString(); + + String sourceJavaFolder = output.toString() + "/" + sourceFolder; + return sourceJavaFolder; } private void addCompileSourceRootIfConfigured() { if (addCompileSourceRoot) { - final Object sourceFolderObject = - configOptions == null ? null : configOptions - .get(CodegenConstants.SOURCE_FOLDER); - final String sourceFolder = - sourceFolderObject == null ? "src/main/java" : sourceFolderObject.toString(); - - String sourceJavaFolder = output.toString() + "/" + sourceFolder; - project.addCompileSourceRoot(sourceJavaFolder); + project.addCompileSourceRoot(getCompileSourceRoot()); } // Reset all environment variables to their original value. This prevents unexpected diff --git a/modules/openapi-generator-maven-plugin/src/main/resources/META-INF/m2e/lifecycle-mapping-metadata.xml b/modules/openapi-generator-maven-plugin/src/main/resources/META-INF/m2e/lifecycle-mapping-metadata.xml new file mode 100644 index 000000000000..bbb0518d4f52 --- /dev/null +++ b/modules/openapi-generator-maven-plugin/src/main/resources/META-INF/m2e/lifecycle-mapping-metadata.xml @@ -0,0 +1,17 @@ + + + + + + generate + + + + + true + true + + + + + \ No newline at end of file