diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java index 1ab10fd19d09..4ab57fff15fe 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java @@ -977,6 +977,16 @@ public void preprocessOpenAPI(OpenAPI openAPI) { @Override public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List allModels) { + // A model named `Tag` collides with io.swagger.v3.oas.annotations.tags.Tag. When this file + // imports the model, importing the annotation too is a duplicate single-type-import, which + // javac rejects outright. Reference the annotation by its fully qualified name instead and + // skip its import -- only for the files that actually hit the clash. + final String tagModelImport = modelPackage() + ".Tag"; + if (objs.getImports() != null + && objs.getImports().stream().anyMatch(imp -> tagModelImport.equals(imp.get("import")))) { + objs.put("qualifySwaggerTagAnnotation", true); + } + final OperationMap operations = objs.getOperations(); if (operations != null) { final List ops = operations.getOperation(); diff --git a/modules/openapi-generator/src/main/resources/JavaSpring/api.mustache b/modules/openapi-generator/src/main/resources/JavaSpring/api.mustache index 77ce7fd59757..c0be360863e6 100644 --- a/modules/openapi-generator/src/main/resources/JavaSpring/api.mustache +++ b/modules/openapi-generator/src/main/resources/JavaSpring/api.mustache @@ -17,7 +17,9 @@ import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.security.SecurityRequirement; +{{^qualifySwaggerTagAnnotation}} import io.swagger.v3.oas.annotations.tags.Tag; +{{/qualifySwaggerTagAnnotation}} import io.swagger.v3.oas.annotations.enums.ParameterIn; import io.swagger.v3.oas.annotations.media.ExampleObject; {{/swagger2AnnotationLibrary}} @@ -106,7 +108,7 @@ import {{javaxPackage}}.annotation.Generated; {{/useResponseEntity}} {{/useSpringController}} {{#swagger2AnnotationLibrary}} -@Tag(name = "{{{tagName}}}", description = {{#tagDescription}}"{{{.}}}"{{/tagDescription}}{{^tagDescription}}"the {{{tagName}}} API"{{/tagDescription}}) +{{#qualifySwaggerTagAnnotation}}@io.swagger.v3.oas.annotations.tags.Tag{{/qualifySwaggerTagAnnotation}}{{^qualifySwaggerTagAnnotation}}@Tag{{/qualifySwaggerTagAnnotation}}(name = "{{{tagName}}}", description = {{#tagDescription}}"{{{.}}}"{{/tagDescription}}{{^tagDescription}}"the {{{tagName}}} API"{{/tagDescription}}) {{/swagger2AnnotationLibrary}} {{#swagger1AnnotationLibrary}} @Api(value = "{{{tagName}}}", description = {{#tagDescription}}"{{{.}}}"{{/tagDescription}}{{^tagDescription}}"the {{{tagName}}} API"{{/tagDescription}}) diff --git a/modules/openapi-generator/src/main/resources/JavaSpring/apiController.mustache b/modules/openapi-generator/src/main/resources/JavaSpring/apiController.mustache index 7de0ac763bcf..0ebab4e5cfb8 100644 --- a/modules/openapi-generator/src/main/resources/JavaSpring/apiController.mustache +++ b/modules/openapi-generator/src/main/resources/JavaSpring/apiController.mustache @@ -11,7 +11,9 @@ import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.security.SecurityRequirement; +{{^qualifySwaggerTagAnnotation}} import io.swagger.v3.oas.annotations.tags.Tag; +{{/qualifySwaggerTagAnnotation}} {{/swagger2AnnotationLibrary}} {{#swagger1AnnotationLibrary}} import io.swagger.annotations.*; diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/spring/SpringCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/spring/SpringCodegenTest.java index 2193ee5c9f9f..ce51c20830ee 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/spring/SpringCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/spring/SpringCodegenTest.java @@ -1206,6 +1206,35 @@ public void shouldGenerateExclusiveMinMaxForOAS31() throws IOException { } + @Test + public void modelNamedTagDoesNotClashWithSwaggerTagAnnotation() throws IOException { + // A model named `Tag` collides with io.swagger.v3.oas.annotations.tags.Tag. Importing both + // is a duplicate single-type-import, which javac rejects outright, so the generated api + // must fall back to the fully qualified annotation name and skip the import. + File output = Files.createTempDirectory("test").toFile().getCanonicalFile(); + output.deleteOnExit(); + + OpenAPI openAPI = new OpenAPIParser() + .readLocation("src/test/resources/3_0/spring/model-named-tag.yaml", null, new ParseOptions()) + .getOpenAPI(); + SpringCodegen codegen = new SpringCodegen(); + codegen.setOutputDir(output.getAbsolutePath()); + codegen.additionalProperties().put(INTERFACE_ONLY, "true"); + + ClientOptInput input = new ClientOptInput().openAPI(openAPI).config(codegen); + DefaultGenerator generator = new DefaultGenerator(); + generator.setGenerateMetadata(false); + + Map files = generator.opts(input).generate().stream() + .collect(Collectors.toMap(File::getName, Function.identity())); + + Path api = files.get("TagApi.java").toPath(); + assertFileNotContains(api, "import io.swagger.v3.oas.annotations.tags.Tag;"); + assertFileContains(api, "@io.swagger.v3.oas.annotations.tags.Tag(name = \"pets\""); + // the model import must still be there -- that is the type actually used in signatures + assertFileContains(api, "import org.openapitools.model.Tag;"); + } + @Test public void shouldUseTagsForClassname() throws IOException { File output = Files.createTempDirectory("test").toFile().getCanonicalFile(); diff --git a/modules/openapi-generator/src/test/resources/3_0/spring/model-named-tag.yaml b/modules/openapi-generator/src/test/resources/3_0/spring/model-named-tag.yaml new file mode 100644 index 000000000000..d7e34d7f834f --- /dev/null +++ b/modules/openapi-generator/src/test/resources/3_0/spring/model-named-tag.yaml @@ -0,0 +1,25 @@ +openapi: 3.0.3 +info: + title: model named Tag + version: 1.0.0 +tags: + - name: pets +paths: + /tag: + get: + tags: + - pets + operationId: getTag + responses: + "200": + description: ok + content: + application/json: + schema: + $ref: "#/components/schemas/Tag" +components: + schemas: + Tag: + properties: + id: + type: string