Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spring request mapping mode #13838

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions bin/configs/spring-boot-oas3.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ additionalProperties:
artifactId: springboot
snapshotVersion: "true"
hideGenerationTimestamp: "true"
requestMappingMode: api_interface
1 change: 1 addition & 0 deletions docs/generators/java-camel.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|performBeanValidation|Use Bean Validation Impl. to perform BeanValidation| |false|
|prependFormOrBodyParameters|Add form or body parameters to the beginning of the parameter list.| |false|
|reactive|wrap responses in Mono/Flux Reactor types (spring-boot only)| |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|
|responseWrapper|wrap the responses in given type (Future, Callable, CompletableFuture,ListenableFuture, DeferredResult, RxObservable, RxSingle or fully qualified type)| |null|
|returnSuccessCode|Generated server returns 2xx code| |false|
|scmConnection|SCM connection in generated pom.xml| |scm:git:[email protected]:openapitools/openapi-generator.git|
Expand Down
1 change: 1 addition & 0 deletions docs/generators/spring.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|performBeanValidation|Use Bean Validation Impl. to perform BeanValidation| |false|
|prependFormOrBodyParameters|Add form or body parameters to the beginning of the parameter list.| |false|
|reactive|wrap responses in Mono/Flux Reactor types (spring-boot only)| |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|
|responseWrapper|wrap the responses in given type (Future, Callable, CompletableFuture,ListenableFuture, DeferredResult, RxObservable, RxSingle or fully qualified type)| |null|
|returnSuccessCode|Generated server returns 2xx code| |false|
|scmConnection|SCM connection in generated pom.xml| |scm:git:[email protected]:openapitools/openapi-generator.git|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@
import java.util.Set;
import java.util.regex.Matcher;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.apache.commons.lang3.tuple.Pair;
import org.openapitools.codegen.CliOption;
Expand Down Expand Up @@ -107,6 +106,25 @@ public class SpringCodegen extends AbstractJavaCodegen
public static final String UNHANDLED_EXCEPTION_HANDLING = "unhandledException";
public static final String USE_SPRING_BOOT3 = "useSpringBoot3";
public static final String USE_JAKARTA_EE = "useJakartaEe";
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;
}
}

public static final String OPEN_BRACE = "{";
public static final String CLOSE_BRACE = "}";
Expand All @@ -116,7 +134,6 @@ public class SpringCodegen extends AbstractJavaCodegen
protected String basePackage = "org.openapitools";
protected boolean interfaceOnly = false;
protected boolean useFeignClientUrl = true;
protected boolean useFeignClient = false;
protected boolean delegatePattern = false;
protected boolean delegateMethod = false;
protected boolean singleContentTypes = false;
Expand All @@ -136,6 +153,7 @@ public class SpringCodegen extends AbstractJavaCodegen
protected boolean useSpringController = false;
protected boolean useSwaggerUI = true;
protected boolean useSpringBoot3 = false;
protected RequestMappingMode requestMappingMode = RequestMappingMode.controller;

public SpringCodegen() {
super();
Expand Down Expand Up @@ -208,6 +226,15 @@ public SpringCodegen() {
cliOptions
.add(CliOption.newBoolean(RETURN_SUCCESS_CODE, "Generated server returns 2xx code", returnSuccessCode));
cliOptions.add(CliOption.newBoolean(SPRING_CONTROLLER, "Annotate the generated API as a Spring Controller", useSpringController));

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);

cliOptions.add(CliOption.newBoolean(UNHANDLED_EXCEPTION_HANDLING,
"Declare operation methods to throw a generic exception and allow unhandled exceptions (useful for Spring `@ControllerAdvice` directives).",
unhandledException));
Expand Down Expand Up @@ -304,6 +331,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);
}

useOneOfInterfaces = true;
legacyDiscriminatorBehavior = false;

Expand Down Expand Up @@ -498,8 +532,9 @@ public void processOpts() {
additionalProperties.put(SINGLE_CONTENT_TYPES, "true");
this.setSingleContentTypes(true);
}
// @RequestMapping not supported with spring cloud openfeign.
setRequestMappingMode(RequestMappingMode.none);
additionalProperties.put(USE_FEIGN_CLIENT, "true");
this.setUseFeignClient(true);
} else {
apiTemplateFiles.put("apiController.mustache", "Controller.java");
if (containsEnums()) {
Expand Down Expand Up @@ -582,6 +617,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;
}

// add lambda for mustache templates
additionalProperties.put("lambdaRemoveDoubleQuote", (Mustache.Lambda) (fragment, writer) -> writer
.write(fragment.execute().replaceAll("\"", Matcher.quoteReplacement(""))));
Expand Down Expand Up @@ -873,10 +921,6 @@ public void setSingleContentTypes(boolean singleContentTypes) {
this.singleContentTypes = singleContentTypes;
}

public void setUseFeignClient( boolean useFeignClient ) {
this.useFeignClient = useFeignClient;
}

public void setSkipDefaultInterface(boolean skipDefaultInterface) {
this.skipDefaultInterface = skipDefaultInterface;
}
Expand Down Expand Up @@ -1121,4 +1165,12 @@ public boolean isUseSpringBoot3() {
public void setUseSpringBoot3(boolean useSpringBoot3) {
this.useSpringBoot3 = useSpringBoot3;
}

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 @@ -96,11 +96,11 @@ import javax.annotation.Generated;
{{#virtualService}}
@VirtualService
{{/virtualService}}
{{^useFeignClient}}
{{#useRequestMappingOnInterface}}
{{=<% %>=}}
@RequestMapping("${openapi.<%title%>.base-path:<%>defaultBasePath%>}")
<%={{ }}=%>
{{/useFeignClient}}
{{/useRequestMappingOnInterface}}
public interface {{classname}} {
{{#jdk8-default-interface}}
{{^isDelegate}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ import javax.annotation.Generated;

{{>generatedAnnotation}}
@Controller
{{#useRequestMappingOnController}}
{{=<% %>=}}
@RequestMapping("${openapi.<%title%>.base-path:<%>defaultBasePath%>}")
<%={{ }}=%>
{{/useRequestMappingOnController}}
{{#operations}}
public class {{classname}}Controller implements {{classname}} {
{{#isDelegate}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ package {{package}};
import org.springframework.cloud.openfeign.FeignClient;
import {{configPackage}}.ClientConfiguration;

{{=<% %>=}}
@FeignClient(name="${<%classVarName%>.name:<%classVarName%>}", url="${<%classVarName%>.url:<%basePath%>}", configuration = ClientConfiguration.class)
<%={{ }}=%>
@FeignClient(name="${{openbrace}}{{classVarName}}.name:{{classVarName}}{{closebrace}}", {{#useFeignClientUrl}}url="${{openbrace}}{{classVarName}}.url:{{basePath}}{{closebrace}}", {{/useFeignClientUrl}}configuration = ClientConfiguration.class)
public interface {{classname}}Client extends {{classname}} {
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.openapitools.codegen.TestUtils.assertFileContains;
import static org.openapitools.codegen.TestUtils.assertFileNotContains;
import static org.openapitools.codegen.languages.SpringCodegen.INTERFACE_ONLY;
import static org.openapitools.codegen.languages.SpringCodegen.REQUEST_MAPPING_OPTION;
import static org.openapitools.codegen.languages.SpringCodegen.RESPONSE_WRAPPER;
import static org.openapitools.codegen.languages.SpringCodegen.SPRING_BOOT;
import static org.openapitools.codegen.languages.features.DocumentationProviderFeatures.DOCUMENTATION_PROVIDER;
Expand All @@ -44,7 +46,6 @@
import java.util.function.Function;
import java.util.stream.Collectors;

import org.assertj.core.api.Assertions;
import org.openapitools.codegen.java.assertions.JavaFileAssert;
import org.openapitools.codegen.CliOption;
import org.openapitools.codegen.ClientOptInput;
Expand Down Expand Up @@ -107,10 +108,9 @@ public void doAnnotateDatesOnModelParameters() throws IOException {

JavaFileAssert.assertThat(Paths.get(outputPath + "/src/main/java/org/openapitools/api/ZebrasApi.java"))
.assertTypeAnnotations()
.hasSize(4)
.hasSize(3)
.containsWithName("Validated")
.containsWithName("Generated")
.containsWithName("RequestMapping")
.containsWithNameAndAttributes("Generated", ImmutableMap.of(
"value", "\"org.openapitools.codegen.languages.SpringCodegen\""
))
Expand Down Expand Up @@ -661,6 +661,7 @@ public void testMultipartCloud() throws IOException {
public void testRequestMappingAnnotation() throws IOException {
final SpringCodegen codegen = new SpringCodegen();
codegen.setLibrary("spring-boot");
codegen.additionalProperties().put(REQUEST_MAPPING_OPTION, SpringCodegen.RequestMappingMode.api_interface);

final Map<String, File> files = generateFiles(codegen, "src/test/resources/2_0/petstore.yaml");

Expand All @@ -674,7 +675,7 @@ public void testRequestMappingAnnotation() throws IOException {
}

@Test
public void testNoRequestMappingAnnotation() throws IOException {
public void testNoRequestMappingAnnotation_spring_cloud_default() throws IOException {
final SpringCodegen codegen = new SpringCodegen();
codegen.setLibrary( "spring-cloud" );

Expand All @@ -687,6 +688,21 @@ public void testNoRequestMappingAnnotation() throws IOException {

}

@Test
public void testNoRequestMappingAnnotation() throws IOException {
final SpringCodegen codegen = new SpringCodegen();
codegen.setLibrary( "spring-cloud" );
codegen.additionalProperties().put(INTERFACE_ONLY, "true");
codegen.additionalProperties().put(REQUEST_MAPPING_OPTION, SpringCodegen.RequestMappingMode.none);

final Map<String, File> files = generateFiles( codegen, "src/test/resources/2_0/petstore.yaml" );

// Check that the @RequestMapping annotation is not generated in the Api file
final File petApiFile = files.get( "PetApi.java" );
JavaFileAssert.assertThat( petApiFile ).assertTypeAnnotations().hasSize( 3 ).containsWithName( "Validated" )
.containsWithName( "Generated" ).containsWithName( "Tag" );
}

@Test
public void testSettersForConfigValues() throws Exception {
final SpringCodegen codegen = new SpringCodegen();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
@Generated(value = "org.openapitools.codegen.languages.SpringCodegen")
@Validated
@Api(value = "Default", description = "the Default API")
@RequestMapping("${openapi.apiDocumentation.base-path:}")
public interface DefaultApi {

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
import org.springframework.cloud.openfeign.FeignClient;
import org.openapitools.configuration.ClientConfiguration;

@FeignClient(name="${pet.name:pet}", url="${pet.url:http://petstore.swagger.io/v2}", configuration = ClientConfiguration.class)
@FeignClient(name="${pet.name:pet}", configuration = ClientConfiguration.class)
public interface PetApiClient extends PetApi {
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
import org.springframework.cloud.openfeign.FeignClient;
import org.openapitools.configuration.ClientConfiguration;

@FeignClient(name="${store.name:store}", url="${store.url:http://petstore.swagger.io/v2}", configuration = ClientConfiguration.class)
@FeignClient(name="${store.name:store}", configuration = ClientConfiguration.class)
public interface StoreApiClient extends StoreApi {
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
import org.springframework.cloud.openfeign.FeignClient;
import org.openapitools.configuration.ClientConfiguration;

@FeignClient(name="${user.name:user}", url="${user.url:http://petstore.swagger.io/v2}", configuration = ClientConfiguration.class)
@FeignClient(name="${user.name:user}", configuration = ClientConfiguration.class)
public interface UserApiClient extends UserApi {
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
@Generated(value = "org.openapitools.codegen.languages.SpringCodegen")
@Validated
@Tag(name = "Pet", description = "Everything about your Pets")
@RequestMapping("${openapi.openAPIPetstore.base-path:/v2}")
public interface PetApi {

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
@Generated(value = "org.openapitools.codegen.languages.SpringCodegen")
@Validated
@Tag(name = "Store", description = "Access to Petstore orders")
@RequestMapping("${openapi.openAPIPetstore.base-path:/v2}")
public interface StoreApi {

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
@Generated(value = "org.openapitools.codegen.languages.SpringCodegen")
@Validated
@Tag(name = "User", description = "Operations about user")
@RequestMapping("${openapi.openAPIPetstore.base-path:/v2}")
public interface UserApi {

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
@Generated(value = "org.openapitools.codegen.languages.SpringCodegen")
@Validated
@Tag(name = "Default", description = "the Default API")
@RequestMapping("${openapi.apiDocumentation.base-path:}")
public interface DefaultApi {

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
@Generated(value = "org.openapitools.codegen.languages.SpringCodegen")
@Validated
@Tag(name = "AnotherFake", description = "the AnotherFake API")
@RequestMapping("${openapi.openAPIPetstore.base-path:/v2}")
public interface AnotherFakeApi {

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@
@Generated(value = "org.openapitools.codegen.languages.SpringCodegen")
@Validated
@Tag(name = "Fake", description = "the Fake API")
@RequestMapping("${openapi.openAPIPetstore.base-path:/v2}")
public interface FakeApi {

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
@Generated(value = "org.openapitools.codegen.languages.SpringCodegen")
@Validated
@Tag(name = "FakeClassnameTags123", description = "the FakeClassnameTags123 API")
@RequestMapping("${openapi.openAPIPetstore.base-path:/v2}")
public interface FakeClassnameTags123Api {

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
@Generated(value = "org.openapitools.codegen.languages.SpringCodegen")
@Validated
@Tag(name = "Pet", description = "Everything about your Pets")
@RequestMapping("${openapi.openAPIPetstore.base-path:/v2}")
public interface PetApi {

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
@Generated(value = "org.openapitools.codegen.languages.SpringCodegen")
@Validated
@Tag(name = "Store", description = "Access to Petstore orders")
@RequestMapping("${openapi.openAPIPetstore.base-path:/v2}")
public interface StoreApi {

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
@Generated(value = "org.openapitools.codegen.languages.SpringCodegen")
@Validated
@Tag(name = "User", description = "Operations about user")
@RequestMapping("${openapi.openAPIPetstore.base-path:/v2}")
public interface UserApi {

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
@Generated(value = "org.openapitools.codegen.languages.SpringCodegen")
@Validated
@Tag(name = "Pet", description = "Everything about your Pets")
@RequestMapping("${openapi.openAPIPetstore.base-path:/v2}")
public interface PetApi {

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
@Generated(value = "org.openapitools.codegen.languages.SpringCodegen")
@Validated
@Tag(name = "Store", description = "Access to Petstore orders")
@RequestMapping("${openapi.openAPIPetstore.base-path:/v2}")
public interface StoreApi {

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
@Generated(value = "org.openapitools.codegen.languages.SpringCodegen")
@Validated
@Tag(name = "User", description = "Operations about user")
@RequestMapping("${openapi.openAPIPetstore.base-path:/v2}")
public interface UserApi {

/**
Expand Down
Loading