Skip to content

Commit 60ef743

Browse files
authored
[JAVA-SPRING;KOTLIN-SPRING] feature - add support for 'substituteGenericPagedModel' also for 'spring-cloud' libraries (#23690)
* feat(java-spring, kotlin-spring): add support for substituting generic PagedModel also in spring-cloud code generation * update documentation * Revert "update documentation" This reverts commit 66b8213. * Reapply "update documentation" This reverts commit 06e0e3d. * Revert "Reapply "update documentation"" This reverts commit 16d2319. * Reapply "Reapply "update documentation"" This reverts commit 78b2528. * Revert "Reapply "Reapply "update documentation""" This reverts commit a94fedf. * Reapply "Reapply "Reapply "update documentation""" This reverts commit 1f89ecd. * Add retry logic for apt-get installations to handle transient errors * Revert "Add retry logic for apt-get installations to handle transient errors" This reverts commit 4de69f8.
1 parent ed3acc8 commit 60ef743

7 files changed

Lines changed: 131 additions & 11 deletions

File tree

docs/generators/java-camel.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
104104
|sortParamsByRequiredFlag|Sort method arguments to place required parameters before optional parameters.| |true|
105105
|sourceFolder|source folder for generated code| |src/main/java|
106106
|springApiVersion|Value for 'version' attribute in @RequestMapping (for Spring 7 and above).| |null|
107-
|substituteGenericPagedModel|Detect schemas that represent paginated responses (an object with a 'content' array property and a 'page' pagination-metadata property) and replace their generated references with PagedModel<T>. By default this uses a generated type in the config package (default 'org.openapitools.configuration'), but `importMappings.PagedModel` can override it to a custom/FQCN-mapped type. The detected page schemas and the pagination metadata schema are suppressed from code generation. Only applies when library=spring-boot or spring-http-interface.| |false|
107+
|substituteGenericPagedModel|Detect schemas that represent paginated responses (an object with a 'content' array property and a 'page' pagination-metadata property) and replace their generated references with PagedModel<T>. By default this uses a generated type in the config package (default 'org.openapitools.configuration'), but `importMappings.PagedModel` can override it to a custom/FQCN-mapped type. The detected page schemas and the pagination metadata schema are suppressed from code generation.| |false|
108108
|testOutput|Set output folder for models and APIs tests| |${project.build.directory}/generated-test-sources/openapi|
109109
|title|server title name or client service name| |OpenAPI Spring|
110110
|unhandledException|Declare operation methods to throw a generic exception and allow unhandled exceptions (useful for Spring `@ControllerAdvice` directives).| |false|

docs/generators/kotlin-spring.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
5858
|sortModelPropertiesByRequiredFlag|Sort model properties to place required parameters before optional parameters.| |null|
5959
|sortParamsByRequiredFlag|Sort method arguments to place required parameters before optional parameters.| |null|
6060
|sourceFolder|source folder for generated code| |src/main/kotlin|
61-
|substituteGenericPagedModel|Detect schemas that represent paginated responses (an object with a 'content' array property and a 'page' pagination-metadata property) and replace their generated references with PagedModel<T>. By default this uses a generated type in the config package (default 'org.openapitools.configuration'), but `importMappings.PagedModel` can override it to a custom/FQCN-mapped type. The detected page schemas and the pagination metadata schema are suppressed from code generation. Only applies when library=spring-boot or spring-declarative-http-interface.| |false|
61+
|substituteGenericPagedModel|Detect schemas that represent paginated responses (an object with a 'content' array property and a 'page' pagination-metadata property) and replace their generated references with PagedModel<T>. By default this uses a generated type in the config package (default 'org.openapitools.configuration'), but `importMappings.PagedModel` can override it to a custom/FQCN-mapped type. The detected page schemas and the pagination metadata schema are suppressed from code generation.| |false|
6262
|title|server title name or client service name| |OpenAPI Kotlin Spring|
6363
|useBeanValidation|Use BeanValidation API annotations to validate data types| |true|
6464
|useFeignClientUrl|Whether to generate Feign client with url parameter.| |true|

docs/generators/spring.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
9797
|sortParamsByRequiredFlag|Sort method arguments to place required parameters before optional parameters.| |true|
9898
|sourceFolder|source folder for generated code| |src/main/java|
9999
|springApiVersion|Value for 'version' attribute in @RequestMapping (for Spring 7 and above).| |null|
100-
|substituteGenericPagedModel|Detect schemas that represent paginated responses (an object with a 'content' array property and a 'page' pagination-metadata property) and replace their generated references with PagedModel<T>. By default this uses a generated type in the config package (default 'org.openapitools.configuration'), but `importMappings.PagedModel` can override it to a custom/FQCN-mapped type. The detected page schemas and the pagination metadata schema are suppressed from code generation. Only applies when library=spring-boot or spring-http-interface.| |false|
100+
|substituteGenericPagedModel|Detect schemas that represent paginated responses (an object with a 'content' array property and a 'page' pagination-metadata property) and replace their generated references with PagedModel<T>. By default this uses a generated type in the config package (default 'org.openapitools.configuration'), but `importMappings.PagedModel` can override it to a custom/FQCN-mapped type. The detected page schemas and the pagination metadata schema are suppressed from code generation.| |false|
101101
|testOutput|Set output folder for models and APIs tests| |${project.build.directory}/generated-test-sources/openapi|
102102
|title|server title name or client service name| |OpenAPI Spring|
103103
|unhandledException|Declare operation methods to throw a generic exception and allow unhandled exceptions (useful for Spring `@ControllerAdvice` directives).| |false|

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ public KotlinSpringServerCodegen() {
308308
"Detect schemas that represent paginated responses (an object with a 'content' array property and a 'page' "
309309
+ "pagination-metadata property) and replace their generated references with "
310310
+ "PagedModel<T>. By default this uses a generated type in the config package (default 'org.openapitools.configuration'), but `importMappings.PagedModel` can override it to a custom/FQCN-mapped type. The detected page schemas and the pagination metadata "
311-
+ "schema are suppressed from code generation. Only applies when library=spring-boot or spring-declarative-http-interface.",
311+
+ "schema are suppressed from code generation.",
312312
substituteGenericPagedModel);
313313
addSwitch(COMPANION_OBJECT, "Whether to generate companion objects in data classes, enabling companion extensions.", companionObject);
314314
supportedLibraries.put(SPRING_BOOT, "Spring-boot Server application.");
@@ -750,7 +750,7 @@ public void processOpts() {
750750
this.setGeneratePageableConstraintValidation(convertPropertyToBoolean(GENERATE_PAGEABLE_CONSTRAINT_VALIDATION));
751751
}
752752
writePropertyBack(GENERATE_PAGEABLE_CONSTRAINT_VALIDATION, generatePageableConstraintValidation);
753-
if (additionalProperties.containsKey(SUBSTITUTE_GENERIC_PAGED_MODEL) && (library.equals(SPRING_BOOT) || library.equals(SPRING_DECLARATIVE_HTTP_INTERFACE_LIBRARY))) {
753+
if (additionalProperties.containsKey(SUBSTITUTE_GENERIC_PAGED_MODEL)) {
754754
this.setSubstituteGenericPagedModel(convertPropertyToBoolean(SUBSTITUTE_GENERIC_PAGED_MODEL));
755755
}
756756
writePropertyBack(SUBSTITUTE_GENERIC_PAGED_MODEL, substituteGenericPagedModel);
@@ -1211,7 +1211,7 @@ public void preprocessOpenAPI(OpenAPI openAPI) {
12111211
}
12121212
}
12131213

1214-
if ((SPRING_BOOT.equals(library) || SPRING_DECLARATIVE_HTTP_INTERFACE_LIBRARY.equals(library)) && substituteGenericPagedModel) {
1214+
if (substituteGenericPagedModel) {
12151215
pagedModelRegistry = PagedModelScanUtils.scanPagedModels(openAPI);
12161216
if (!pagedModelRegistry.isEmpty()) {
12171217
boolean customMapping = importMapping.containsKey("PagedModel");

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,7 @@ public SpringCodegen() {
380380
"Detect schemas that represent paginated responses (an object with a 'content' array property and a 'page' "
381381
+ "pagination-metadata property) and replace their generated references with "
382382
+ "PagedModel<T>. By default this uses a generated type in the config package (default 'org.openapitools.configuration'), but `importMappings.PagedModel` can override it to a custom/FQCN-mapped type. The detected page schemas and the pagination metadata "
383-
+ "schema are suppressed from code generation. Only applies when library=spring-boot or spring-http-interface.",
383+
+ "schema are suppressed from code generation.",
384384
substituteGenericPagedModel));
385385

386386
}
@@ -591,9 +591,7 @@ public void processOpts() {
591591

592592
convertPropertyToBooleanAndWriteBack(ADDITIONAL_NOT_NULL_ANNOTATIONS, this::setAdditionalNotNullAnnotations);
593593

594-
if (SPRING_BOOT.equals(library) || SPRING_HTTP_INTERFACE.equals(library)) {
595-
convertPropertyToBooleanAndWriteBack(SUBSTITUTE_GENERIC_PAGED_MODEL, this::setSubstituteGenericPagedModel);
596-
}
594+
convertPropertyToBooleanAndWriteBack(SUBSTITUTE_GENERIC_PAGED_MODEL, this::setSubstituteGenericPagedModel);
597595

598596
if (SPRING_BOOT.equals(library)) {
599597
convertPropertyToBooleanAndWriteBack(AUTO_X_SPRING_PAGINATED, this::setAutoXSpringPaginated);
@@ -873,7 +871,7 @@ public void preprocessOpenAPI(OpenAPI openAPI) {
873871
}
874872
}
875873

876-
if ((SPRING_BOOT.equals(library) || SPRING_HTTP_INTERFACE.equals(library)) && substituteGenericPagedModel) {
874+
if (substituteGenericPagedModel) {
877875
pagedModelRegistry = PagedModelScanUtils.scanPagedModels(openAPI);
878876
if (!pagedModelRegistry.isEmpty()) {
879877
boolean customMapping = importMapping.containsKey("PagedModel");

modules/openapi-generator/src/test/java/org/openapitools/codegen/java/spring/SpringCodegenTest.java

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7527,6 +7527,61 @@ private Map<String, Object> springHttpInterfacePagedModelProps() {
75277527
return props;
75287528
}
75297529

7530+
// -------------------------------------------------------------------------
7531+
// substituteGenericPagedModel — spring-cloud
7532+
// -------------------------------------------------------------------------
7533+
7534+
@Test
7535+
public void substituteGenericPagedModel_springCloud_replacesReturnTypeInOperation() throws IOException {
7536+
Map<String, File> files = generateFromContract(
7537+
"src/test/resources/3_0/spring/petstore-paged-model.yaml", SPRING_CLOUD_LIBRARY,
7538+
springCloudPagedModelProps());
7539+
7540+
JavaFileAssert.assertThat(files.get("UserApi.java"))
7541+
.assertMethod("listUsers")
7542+
.hasReturnType("ResponseEntity<PagedModel<User>>");
7543+
}
7544+
7545+
@Test
7546+
public void substituteGenericPagedModel_springCloud_generatesPagedModelSupportingFile() throws IOException {
7547+
Map<String, File> files = generateFromContract(
7548+
"src/test/resources/3_0/spring/petstore-paged-model.yaml", SPRING_CLOUD_LIBRARY,
7549+
springCloudPagedModelProps());
7550+
7551+
assertThat(files).containsKey("PagedModel.java");
7552+
}
7553+
7554+
@Test
7555+
public void substituteGenericPagedModel_springCloud_doesNotGeneratePagedModelFileWhenCustomMapping() throws IOException {
7556+
Map<String, File> files = generateFromContract(
7557+
"src/test/resources/3_0/spring/petstore-paged-model.yaml", SPRING_CLOUD_LIBRARY,
7558+
springCloudPagedModelProps(),
7559+
configurator -> configurator.addImportMapping("PagedModel", "com.example.custom.MyPagedModel"));
7560+
7561+
assertThat(files).doesNotContainKey("PagedModel.java");
7562+
}
7563+
7564+
@Test
7565+
public void substituteGenericPagedModel_springCloud_respectsCustomImportMappingClassName() throws IOException {
7566+
Map<String, File> files = generateFromContract(
7567+
"src/test/resources/3_0/spring/petstore-paged-model.yaml", SPRING_CLOUD_LIBRARY,
7568+
springCloudPagedModelProps(),
7569+
configurator -> configurator.addImportMapping("PagedModel", "com.example.custom.MyPagedModel"));
7570+
7571+
JavaFileAssert.assertThat(files.get("UserApi.java"))
7572+
.hasImports("com.example.custom.MyPagedModel")
7573+
.assertMethod("listUsers")
7574+
.hasReturnType("ResponseEntity<MyPagedModel<User>>");
7575+
}
7576+
7577+
/** Common properties for substituteGenericPagedModel tests using spring-cloud. */
7578+
private Map<String, Object> springCloudPagedModelProps() {
7579+
Map<String, Object> props = new HashMap<>();
7580+
props.put(SpringCodegen.USE_TAGS, "true");
7581+
props.put(SpringCodegen.SUBSTITUTE_GENERIC_PAGED_MODEL, "true");
7582+
return props;
7583+
}
7584+
75307585

75317586
@DataProvider(name = "replaceOneOf")
75327587
public Object[][] replaceOneOf() {

modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/spring/KotlinSpringServerCodegenTest.java

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5833,6 +5833,73 @@ private Map<String, Object> commonDeclarativeHttpInterfacePagedModelProps() {
58335833
return props;
58345834
}
58355835

5836+
// -------------------------------------------------------------------------
5837+
// substituteGenericPagedModel — spring-cloud
5838+
// -------------------------------------------------------------------------
5839+
5840+
@Test
5841+
public void substituteGenericPagedModel_springCloud_replacesReturnTypeInOperation() throws IOException {
5842+
Map<String, File> files = generateFromContract(
5843+
"src/test/resources/3_0/spring/petstore-paged-model.yaml",
5844+
springCloudKotlinPagedModelProps(),
5845+
new HashMap<>(),
5846+
configurator -> configurator.setLibrary(SPRING_CLOUD_LIBRARY));
5847+
5848+
File userApi = files.get("UserApi.kt");
5849+
assertThat(userApi).isNotNull();
5850+
String content = Files.readString(userApi.toPath());
5851+
assertThat(content).contains("PagedModel<User>");
5852+
}
5853+
5854+
@Test
5855+
public void substituteGenericPagedModel_springCloud_generatesPagedModelSupportingFile() throws IOException {
5856+
Map<String, File> files = generateFromContract(
5857+
"src/test/resources/3_0/spring/petstore-paged-model.yaml",
5858+
springCloudKotlinPagedModelProps(),
5859+
new HashMap<>(),
5860+
configurator -> configurator.setLibrary(SPRING_CLOUD_LIBRARY));
5861+
5862+
assertThat(files).containsKey("PagedModel.kt");
5863+
}
5864+
5865+
@Test
5866+
public void substituteGenericPagedModel_springCloud_doesNotGeneratePagedModelFileWhenCustomMapping() throws IOException {
5867+
Map<String, File> files = generateFromContract(
5868+
"src/test/resources/3_0/spring/petstore-paged-model.yaml",
5869+
springCloudKotlinPagedModelProps(),
5870+
new HashMap<>(),
5871+
configurator -> configurator
5872+
.setLibrary(SPRING_CLOUD_LIBRARY)
5873+
.addImportMapping("PagedModel", "com.example.custom.MyPagedModel"));
5874+
5875+
assertThat(files).doesNotContainKey("PagedModel.kt");
5876+
}
5877+
5878+
@Test
5879+
public void substituteGenericPagedModel_springCloud_respectsCustomImportMappingClassName() throws IOException {
5880+
Map<String, File> files = generateFromContract(
5881+
"src/test/resources/3_0/spring/petstore-paged-model.yaml",
5882+
springCloudKotlinPagedModelProps(),
5883+
new HashMap<>(),
5884+
configurator -> configurator
5885+
.setLibrary(SPRING_CLOUD_LIBRARY)
5886+
.addImportMapping("PagedModel", "com.example.custom.MyPagedModel"));
5887+
5888+
File userApi = files.get("UserApi.kt");
5889+
assertThat(userApi).isNotNull();
5890+
String content = Files.readString(userApi.toPath());
5891+
assertThat(content).contains("MyPagedModel<User>");
5892+
assertThat(content).contains("import com.example.custom.MyPagedModel");
5893+
}
5894+
5895+
/** Common properties for substituteGenericPagedModel tests using spring-cloud. */
5896+
private Map<String, Object> springCloudKotlinPagedModelProps() {
5897+
Map<String, Object> props = new HashMap<>();
5898+
props.put(USE_TAGS, "true");
5899+
props.put(SUBSTITUTE_GENERIC_PAGED_MODEL, "true");
5900+
return props;
5901+
}
5902+
58365903
@Test(description = "oneOf with discriminator generates thin sealed interface with Jackson annotations")
58375904
public void testOneOfWithDiscriminatorGeneratesThinInterface() throws IOException {
58385905
File output = Files.createTempDirectory("test").toFile().getCanonicalFile();

0 commit comments

Comments
 (0)