Skip to content

Commit

Permalink
requestMappingMode: Explicit configuration to control the location of…
Browse files Browse the repository at this point in the history
… the generated class level RequestMapping annotation

Based on OpenAPITools#13838 but for kotlin-spring.

Fixes OpenAPITools#18884
  • Loading branch information
pstorch committed Jun 10, 2024
1 parent 0cc9644 commit 597b208
Show file tree
Hide file tree
Showing 27 changed files with 140 additions and 21 deletions.
1 change: 1 addition & 0 deletions bin/configs/kotlin-spring-boot-3.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ additionalProperties:
serializableModel: "true"
beanValidations: "true"
useSpringBoot3: "true"
requestMappingMode: api_interface
1 change: 1 addition & 0 deletions bin/configs/kotlin-spring-boot-delegate.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ additionalProperties:
useSwaggerUI: "true"
delegatePattern: "true"
beanValidations: "true"
requestMappingMode: none
1 change: 1 addition & 0 deletions bin/configs/kotlin-spring-boot.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ additionalProperties:
serviceImplementation: "true"
serializableModel: "true"
beanValidations: "true"
requestMappingMode: controller
1 change: 1 addition & 0 deletions docs/generators/kotlin-spring.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|packageName|Generated artifact package name.| |org.openapitools|
|parcelizeModels|toggle "@Parcelize" for generated models| |null|
|reactive|use coroutines for reactive behavior| |false|
|requestMappingMode|Where to generate the class level @RequestMapping annotation.|<dl><dt>**api_interface**</dt><dd>Generate the @RequestMapping annotation on the generated Api Interface.</dd><dt>**controller**</dt><dd>Generate the @RequestMapping annotation on the generated Api Controller Implementation.</dd><dt>**none**</dt><dd>Do not add a class level @RequestMapping annotation.</dd></dl>|controller|
|serializableModel|boolean - toggle &quot;implements Serializable&quot; for generated models| |null|
|serverPort|configuration the port in which the sever is to run on| |8080|
|serviceImplementation|generate stub service implementations that extends service interfaces. If this is set to true service interfaces will also be generated| |false|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,25 @@ public class KotlinSpringServerCodegen extends AbstractKotlinCodegen

public static final String USE_SPRING_BOOT3 = "useSpringBoot3";
public static final String APPEND_REQUEST_TO_HANDLER = "appendRequestToHandler";
public static final String REQUEST_MAPPING_OPTION = "requestMappingMode";
public static final String USE_REQUEST_MAPPING_ON_CONTROLLER = "useRequestMappingOnController";
public static final String USE_REQUEST_MAPPING_ON_INTERFACE = "useRequestMappingOnInterface";

public enum RequestMappingMode {
api_interface("Generate the @RequestMapping annotation on the generated Api Interface."),
controller("Generate the @RequestMapping annotation on the generated Api Controller Implementation."),
none("Do not add a class level @RequestMapping annotation.");

public String getDescription() {
return description;
}

private String description;

RequestMappingMode(String description) {
this.description = description;
}
}

@Getter @Setter
private String basePackage;
Expand Down Expand Up @@ -131,6 +150,7 @@ public class KotlinSpringServerCodegen extends AbstractKotlinCodegen

@Getter @Setter
protected boolean useSpringBoot3 = false;
protected RequestMappingMode requestMappingMode = RequestMappingMode.controller;
private DocumentationProvider documentationProvider;
private AnnotationLibrary annotationLibrary;

Expand Down Expand Up @@ -222,6 +242,14 @@ public KotlinSpringServerCodegen() {
cliOpt.setEnum(supportedLibraries);
cliOptions.add(cliOpt);

CliOption requestMappingOpt = new CliOption(REQUEST_MAPPING_OPTION,
"Where to generate the class level @RequestMapping annotation.")
.defaultValue(requestMappingMode.name());
for (RequestMappingMode mode: RequestMappingMode.values()) {
requestMappingOpt.addEnum(mode.name(), mode.getDescription());
}
cliOptions.add(requestMappingOpt);

if (null != defaultDocumentationProvider()) {
CliOption documentationProviderCliOption = new CliOption(DOCUMENTATION_PROVIDER,
"Select the OpenAPI documentation provider.")
Expand Down Expand Up @@ -433,6 +461,13 @@ public void processOpts() {
LOGGER.info("Set base package to invoker package ({})", basePackage);
}

if (additionalProperties.containsKey(REQUEST_MAPPING_OPTION)) {
RequestMappingMode optValue = RequestMappingMode.valueOf(
String.valueOf(additionalProperties.get(REQUEST_MAPPING_OPTION)));
setRequestMappingMode(optValue);
additionalProperties.remove(REQUEST_MAPPING_OPTION);
}

if (additionalProperties.containsKey(CONFIG_PACKAGE)) {
this.setConfigPackage((String) additionalProperties.get(CONFIG_PACKAGE));
} else {
Expand Down Expand Up @@ -639,6 +674,9 @@ public void processOpts() {
supportingFiles.add(new SupportingFile("settingsGradle.mustache", "settings.gradle"));
}

// @RequestMapping not supported with spring cloud openfeign.
setRequestMappingMode(RequestMappingMode.none);

supportingFiles.add(new SupportingFile("apiKeyRequestInterceptor.mustache",
(sourceFolder + File.separator + configPackage).replace(".", java.io.File.separator),
"ApiKeyRequestInterceptor.kt"));
Expand All @@ -662,6 +700,19 @@ public void processOpts() {
}
}

switch (getRequestMappingMode()) {
case api_interface:
additionalProperties.put(USE_REQUEST_MAPPING_ON_INTERFACE, true);
break;
case controller:
additionalProperties.put(USE_REQUEST_MAPPING_ON_CONTROLLER, true);
break;
case none:
additionalProperties.put(USE_REQUEST_MAPPING_ON_INTERFACE, false);
additionalProperties.put(USE_REQUEST_MAPPING_ON_CONTROLLER, false);
break;
}

// spring uses the jackson lib, and we disallow configuration.
additionalProperties.put("jackson", "true");

Expand Down Expand Up @@ -922,4 +973,13 @@ protected boolean needToImport(String type) {
static class RequestCodegenParameter extends CodegenParameter {
boolean isRequestObject;
}

public RequestMappingMode getRequestMappingMode() {
return requestMappingMode;
}

public void setRequestMappingMode(RequestMappingMode requestMappingMode) {
this.requestMappingMode = requestMappingMode;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,11 @@ import kotlin.collections.Map
{{#swagger1AnnotationLibrary}}
@Api(value = "{{{baseName}}}", description = "The {{{baseName}}} API")
{{/swagger1AnnotationLibrary}}
{{#useRequestMappingOnController}}
{{=<% %>=}}
@RequestMapping("\${api.base-path:<%contextPath%>}")
<%={{ }}=%>
{{/useRequestMappingOnController}}
{{#operations}}
class {{classname}}Controller({{#serviceInterface}}@Autowired(required = true) val service: {{classname}}Service{{/serviceInterface}}) {
{{#operation}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ import java.util.Optional

{{>generatedAnnotation}}
@Controller{{#beanQualifiers}}("{{package}}.{{classname}}Controller"){{/beanQualifiers}}
{{#useRequestMappingOnController}}
{{=<% %>=}}
@RequestMapping("\${openapi.<%title%>.base-path:<%>defaultBasePath%>}")
<%={{ }}=%>
{{/useRequestMappingOnController}}
{{#operations}}
class {{classname}}Controller(
@org.springframework.beans.factory.annotation.Autowired(required = false) delegate: {{classname}}Delegate?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,11 @@ import kotlin.collections.Map
{{#swagger1AnnotationLibrary}}
@Api(value = "{{{baseName}}}", description = "The {{{baseName}}} API")
{{/swagger1AnnotationLibrary}}
{{^useFeignClient}}
{{#useRequestMappingOnInterface}}
{{=<% %>=}}
@RequestMapping("\${api.base-path:<%contextPath%>}")
<%={{ }}=%>
{{/useFeignClient}}
{{/useRequestMappingOnInterface}}
{{#operations}}
interface {{classname}} {
{{#isDelegate}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import io.swagger.v3.parser.core.models.ParseOptions;
import org.apache.commons.io.FileUtils;
import org.assertj.core.api.Assertions;
import org.jetbrains.annotations.NotNull;
import org.openapitools.codegen.ClientOptInput;
import org.openapitools.codegen.CodegenConstants;
import org.openapitools.codegen.DefaultGenerator;
Expand Down Expand Up @@ -82,7 +83,7 @@ public void testInitialConfigValues() throws Exception {
}

@Test
public void testNoRequestMappingAnnotation() throws IOException {
public void testNoRequestMappingAnnotation_spring_cloud_default() throws IOException {
File output = Files.createTempDirectory("test").toFile().getCanonicalFile();
output.deleteOnExit();

Expand All @@ -102,6 +103,74 @@ public void testNoRequestMappingAnnotation() throws IOException {
);
}

@Test
public void testNoRequestMappingAnnotationNone() throws IOException {
File output = generatePetstoreWithRequestMappingMode(KotlinSpringServerCodegen.RequestMappingMode.none);

// Check that the @RequestMapping annotation is not generated in the Api file
assertFileNotContains(
Paths.get(output + "/src/main/kotlin/org/openapitools/api/PetApi.kt"),
"@RequestMapping(\"\\${"
);
// Check that the @RequestMapping annotation is not generated in the ApiController file
assertFileNotContains(
Paths.get(output + "/src/main/kotlin/org/openapitools/api/PetApiController.kt"),
"@RequestMapping(\"\\${"
);
}

@Test
public void testNoRequestMappingAnnotationController() throws IOException {
File output = generatePetstoreWithRequestMappingMode(KotlinSpringServerCodegen.RequestMappingMode.controller);

// Check that the @RequestMapping annotation is not generated in the Api file
assertFileNotContains(
Paths.get(output + "/src/main/kotlin/org/openapitools/api/PetApi.kt"),
"@RequestMapping(\"\\${"
);
// Check that the @RequestMapping annotation is generated in the ApiController file
assertFileContains(
Paths.get(output + "/src/main/kotlin/org/openapitools/api/PetApiController.kt"),
"@RequestMapping(\"\\${"
);
}

@Test
public void testNoRequestMappingAnnotationApiInterface() throws IOException {
File output = generatePetstoreWithRequestMappingMode(KotlinSpringServerCodegen.RequestMappingMode.api_interface);

// Check that the @RequestMapping annotation is generated in the Api file
assertFileContains(
Paths.get(output + "/src/main/kotlin/org/openapitools/api/PetApi.kt"),
"@RequestMapping(\"\\${"
);
// Check that the @RequestMapping annotation is not generated in the ApiController file
assertFileNotContains(
Paths.get(output + "/src/main/kotlin/org/openapitools/api/PetApiController.kt"),
"@RequestMapping(\"\\${"
);
}

private static @NotNull File generatePetstoreWithRequestMappingMode(KotlinSpringServerCodegen.RequestMappingMode requestMappingMode) throws IOException {
File output = Files.createTempDirectory("test").toFile().getCanonicalFile();
output.deleteOnExit();

KotlinSpringServerCodegen codegen = new KotlinSpringServerCodegen();
codegen.setOutputDir(output.getAbsolutePath());
codegen.additionalProperties().put(KotlinSpringServerCodegen.DELEGATE_PATTERN, true);
codegen.additionalProperties().put(KotlinSpringServerCodegen.USE_TAGS, true);
codegen.additionalProperties().put(KotlinSpringServerCodegen.REQUEST_MAPPING_OPTION, requestMappingMode);

new DefaultGenerator()
.opts(
new ClientOptInput()
.openAPI(TestUtils.parseSpec("src/test/resources/3_0/kotlin/petstore.yaml"))
.config(codegen)
)
.generate();
return output;
}

@Test
public void testSettersForConfigValues() throws Exception {
final KotlinSpringServerCodegen codegen = new KotlinSpringServerCodegen();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import kotlin.collections.Map

@RestController
@Validated
@RequestMapping("\${api.base-path:/v2}")
class PetApiController(@Autowired(required = true) val service: PetApiService) {


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import kotlin.collections.Map

@RestController
@Validated
@RequestMapping("\${api.base-path:/v2}")
class StoreApiController(@Autowired(required = true) val service: StoreApiService) {


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import kotlin.collections.Map

@RestController
@Validated
@RequestMapping("\${api.base-path:/v2}")
class UserApiController(@Autowired(required = true) val service: UserApiService) {


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ import kotlin.collections.List
import kotlin.collections.Map

@Validated
@RequestMapping("\${api.base-path:/v2}")
interface PetApi {

fun getDelegate(): PetApiDelegate = object: PetApiDelegate {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import java.util.Optional

@javax.annotation.Generated(value = ["org.openapitools.codegen.languages.KotlinSpringServerCodegen"], comments = "Generator version: 7.7.0-SNAPSHOT")
@Controller
@RequestMapping("\${openapi.openAPIPetstore.base-path:/v2}")
class PetApiController(
@org.springframework.beans.factory.annotation.Autowired(required = false) delegate: PetApiDelegate?
) : PetApi {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ import kotlin.collections.List
import kotlin.collections.Map

@Validated
@RequestMapping("\${api.base-path:/v2}")
interface StoreApi {

fun getDelegate(): StoreApiDelegate = object: StoreApiDelegate {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import java.util.Optional

@javax.annotation.Generated(value = ["org.openapitools.codegen.languages.KotlinSpringServerCodegen"], comments = "Generator version: 7.7.0-SNAPSHOT")
@Controller
@RequestMapping("\${openapi.openAPIPetstore.base-path:/v2}")
class StoreApiController(
@org.springframework.beans.factory.annotation.Autowired(required = false) delegate: StoreApiDelegate?
) : StoreApi {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ import kotlin.collections.List
import kotlin.collections.Map

@Validated
@RequestMapping("\${api.base-path:/v2}")
interface UserApi {

fun getDelegate(): UserApiDelegate = object: UserApiDelegate {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import java.util.Optional

@javax.annotation.Generated(value = ["org.openapitools.codegen.languages.KotlinSpringServerCodegen"], comments = "Generator version: 7.7.0-SNAPSHOT")
@Controller
@RequestMapping("\${openapi.openAPIPetstore.base-path:/v2}")
class UserApiController(
@org.springframework.beans.factory.annotation.Autowired(required = false) delegate: UserApiDelegate?
) : UserApi {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ import kotlin.collections.List
import kotlin.collections.Map

@Validated
@RequestMapping("\${api.base-path:/v2}")
interface FakeApi {

@Operation(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ import kotlin.collections.List
import kotlin.collections.Map

@Validated
@RequestMapping("\${api.base-path:/v2}")
interface FakeClassnameTestApi {

@Operation(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ import kotlin.collections.List
import kotlin.collections.Map

@Validated
@RequestMapping("\${api.base-path:/v2}")
interface FooApi {

@Operation(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ import kotlin.collections.List
import kotlin.collections.Map

@Validated
@RequestMapping("\${api.base-path:/v2}")
interface PetApi {

@Operation(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ import kotlin.collections.List
import kotlin.collections.Map

@Validated
@RequestMapping("\${api.base-path:/v2}")
interface StoreApi {

@Operation(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ import kotlin.collections.List
import kotlin.collections.Map

@Validated
@RequestMapping("\${api.base-path:/v2}")
interface UserApi {

@Operation(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ import kotlin.collections.List
import kotlin.collections.Map

@Validated
@RequestMapping("\${api.base-path:/v2}")
interface PetApi {

@Operation(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ import kotlin.collections.List
import kotlin.collections.Map

@Validated
@RequestMapping("\${api.base-path:/v2}")
interface StoreApi {

@Operation(
Expand Down
Loading

0 comments on commit 597b208

Please sign in to comment.