diff --git a/docs/customization.md b/docs/customization.md index e8ef4ca6b852..15d70d3c6619 100644 --- a/docs/customization.md +++ b/docs/customization.md @@ -194,6 +194,18 @@ To control the specific files being generated, you can pass a CSV list of what y --global-property models=User,supportingFiles=StringUtil.java ``` +An explicit list is an allow-list, not an addition: anything missing from it is skipped. That makes it +fragile across upgrades, because supporting files frequently reference one another and a newer version +of a generator may add files the older list does not mention. For example, the `ApiClient` of the Java +generator's `restclient` library refers to `ServerConfiguration`, `ServerVariable` and +`ExceptionProvider`, so listing `supportingFiles=ApiClient.java` on its own produces sources that do +not compile. Each skipped file is logged at `INFO` level as +`Skipped (Skipped by supportingFiles options supplied by user.)`; a run without the option lists +the full set a generator produces in `.openapi-generator/FILES`. + +Prefer the [`.openapi-generator-ignore` file](#ignore-file-format) to exclude the handful of files you +do not want: new files are then generated by default, and only what you explicitly ignored is left out. + To control generation of docs and tests for api and models, pass false to the option. For api, these options are `--global-property apiTests=false,apiDocs=false`. For models, `--global-property modelTests=false,modelDocs=false`. These options default to true and don't limit the generation of the feature options listed above (like `--global-property api`): diff --git a/docs/global-properties.md b/docs/global-properties.md index fc672db05ef4..f2b9eee13fff 100644 --- a/docs/global-properties.md +++ b/docs/global-properties.md @@ -23,6 +23,11 @@ title: Global Properties | modelTests | Allows the user to define if model tests will be generated. Prefer using the more robust `.openapi-generator-ignore`. | `true` or `false` | | splitOperationsByContentType | Generates one operation per request/response content-type when an operation exposes several with different schemas | `true` or `false` | +Note that `supportingFiles`, `models` and `apis` take an allow-list: when one of them is set, only the +names it lists are generated. For `supportingFiles` this also means that supporting files added by a +newer version of a generator are not generated unless the list mentions them, which can break the +generated code — see [Selective generation](./customization.md#selective-generation). + ## Note on splitOperationsByContentType diff --git a/modules/openapi-generator-maven-plugin/README.md b/modules/openapi-generator-maven-plugin/README.md index 4c5637e16a74..d24529647975 100644 --- a/modules/openapi-generator-maven-plugin/README.md +++ b/modules/openapi-generator-maven-plugin/README.md @@ -103,7 +103,7 @@ mvn clean compile | `generateModels` | `openapi.generator.maven.plugin.generateModels` | generate the models (`true` by default). Specific models may be defined as a CSV via `modelsToGenerate`. | | `modelsToGenerate` | `openapi.generator.maven.plugin.modelsToGenerate` | A comma separated list of models to generate. All models is the default. | | `generateSupportingFiles` | `openapi.generator.maven.plugin.generateSupportingFiles` | generate the supporting files (`true` by default) | -| `supportingFilesToGenerate` | `openapi.generator.maven.plugin.supportingFilesToGenerate` | A comma separated list of supporting files to generate. All files is the default. | +| `supportingFilesToGenerate` | `openapi.generator.maven.plugin.supportingFilesToGenerate` | A comma separated list of supporting files to generate. All files is the default. The list is a fixed allow-list, so supporting files added by a later version of the generator are not generated unless they are added here; prefer `.openapi-generator-ignore` instead. | | `generateModelTests` | `openapi.generator.maven.plugin.generateModelTests` | generate the model tests (`true` by default. Only available if `generateModels` is `true`) | | `generateModelDocumentation` | `openapi.generator.maven.plugin.generateModelDocumentation` | generate the model documentation (`true` by default. Only available if `generateModels` is `true`) | | `generateApiTests` | `openapi.generator.maven.plugin.generateApiTests` | generate the api tests (`true` by default. Only available if `generateApis` is `true`) | 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 7cb3c174f28b..8d66eed95fd5 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 @@ -518,7 +518,11 @@ public class CodeGenMojo extends AbstractMojo { private Boolean generateSupportingFiles = true; /** - * A comma separated list of models to generate. All models is the default. + * A comma separated list of supporting files to generate. All supporting files are the default. + *

+ * The list is a fixed allow-list: supporting files added by a later version of the generator are + * not generated unless they are added here, which can leave the generated sources uncompilable. + * Prefer {@code .openapi-generator-ignore} to exclude the few files you do not want. */ @Parameter(name = "supportingFilesToGenerate", property = "openapi.generator.maven.plugin.supportingFilesToGenerate") private String supportingFilesToGenerate = ""; diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/JavaClientCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/JavaClientCodegenTest.java index 33e78b1e4847..0be74ad5d842 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/JavaClientCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/JavaClientCodegenTest.java @@ -37,6 +37,7 @@ import org.junit.jupiter.api.Assertions; import org.openapitools.codegen.*; import org.openapitools.codegen.config.CodegenConfigurator; +import org.openapitools.codegen.config.GlobalSettings; import org.openapitools.codegen.java.assertions.JavaFileAssert; import org.openapitools.codegen.languages.AbstractJavaCodegen; import org.openapitools.codegen.languages.JavaClientCodegen; @@ -3886,6 +3887,57 @@ public void testRestClientJackson3RegistersDefaults_issue_24587() { } + @Test(description = "Regression test for the premise of issue #22238: the restclient ApiClient refers to" + + " ServerConfiguration, ServerVariable and ExceptionProvider, which live in the invoker" + + " package, so a default run must generate them next to it.") + public void testRestClientDefaultGenerationIncludesCompanionFiles() { + final Path output = newTempFolder(); + final CodegenConfigurator configurator = new CodegenConfigurator() + .setGeneratorName(JAVA_GENERATOR) + .setLibrary(JavaClientCodegen.RESTCLIENT) + .addAdditionalProperty(CodegenConstants.API_PACKAGE, "xyz.abcdef.api") + .addAdditionalProperty(CodegenConstants.INVOKER_PACKAGE, "xyz.abcdef") + .setInputSpec("src/test/resources/3_1/java/petstore.yaml") + .setOutputDir(output.toString().replace("\\", "/")); + + List files = new DefaultGenerator().opts(configurator.toClientOptInput()).generate(); + + validateJavaSourceFiles(files); + assertFileExists(output.resolve("src/main/java/xyz/abcdef/ApiClient.java")); + assertFileExists(output.resolve("src/main/java/xyz/abcdef/ServerConfiguration.java")); + assertFileExists(output.resolve("src/main/java/xyz/abcdef/ServerVariable.java")); + assertFileExists(output.resolve("src/main/java/xyz/abcdef/ExceptionProvider.java")); + } + + @Test(description = "Issue #22238: the supportingFiles global property is an allow-list, so asking for" + + " ApiClient.java alone silently skips the ServerConfiguration, ServerVariable and" + + " ExceptionProvider it references, leaving sources that do not compile.") + public void testRestClientSupportingFilesAllowListSkipsApiClientCompanions_issue_22238() { + final Path output = newTempFolder(); + final CodegenConfigurator configurator = new CodegenConfigurator() + .setGeneratorName(JAVA_GENERATOR) + .setLibrary(JavaClientCodegen.RESTCLIENT) + .addAdditionalProperty(CodegenConstants.API_PACKAGE, "xyz.abcdef.api") + .addAdditionalProperty(CodegenConstants.INVOKER_PACKAGE, "xyz.abcdef") + .setInputSpec("src/test/resources/3_1/java/petstore.yaml") + .setOutputDir(output.toString().replace("\\", "/")); + + GlobalSettings.setProperty(CodegenConstants.SUPPORTING_FILES, "ApiClient.java"); + try { + new DefaultGenerator().opts(configurator.toClientOptInput()).generate(); + } finally { + GlobalSettings.reset(); + } + + assertFileExists(output.resolve("src/main/java/xyz/abcdef/ApiClient.java")); + assertFileNotExists(output.resolve("src/main/java/xyz/abcdef/ServerConfiguration.java")); + assertFileNotExists(output.resolve("src/main/java/xyz/abcdef/ServerVariable.java")); + assertFileNotExists(output.resolve("src/main/java/xyz/abcdef/ExceptionProvider.java")); + assertThat(output.resolve("src/main/java/xyz/abcdef/ApiClient.java")).content() + .contains("List servers") + .contains("ExceptionProvider"); + } + @Test public void testRestClientWithUseSingleRequestParameter_issue_19406() { final Path output = newTempFolder();