Skip to content

[Spring]Added support for composed annotations (@GetMapping,@PostMapping,@PutMapping,@DeleteMapping). #21118

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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,7 @@ protected ImmutableMap.Builder<String, Lambda> addMustacheLambdas() {
.put("forwardslash", new ForwardSlashLambda())
.put("backslash", new BackSlashLambda())
.put("doublequote", new DoubleQuoteLambda())
.put("composedannotationlambda", new ComposedRequestMappingAnnotationLambda())
.put("indented", new IndentedLambda())
.put("indented_8", new IndentedLambda(8, " ", false, false))
.put("indented_12", new IndentedLambda(12, " ", false, false))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ public class SpringCodegen extends AbstractJavaCodegen
public static final String USE_SEALED = "useSealed";
public static final String OPTIONAL_ACCEPT_NULLABLE = "optionalAcceptNullable";
public static final String USE_SPRING_BUILT_IN_VALIDATION = "useSpringBuiltInValidation";
public static final String USE_API_COMPOSED_ANNOTATION = "useApiComposedAnnotation";
public static final String API_COMPOSED_ANNOTATION_LAMBDA = "apiComposedAnnotationLambda";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not used anywhere, please remove it.


@Getter
public enum RequestMappingMode {
Expand Down Expand Up @@ -157,6 +159,8 @@ public enum RequestMappingMode {
protected boolean optionalAcceptNullable = true;
@Getter @Setter
protected boolean useSpringBuiltInValidation = false;
@Getter @Setter
protected boolean useApiComposedAnnotation = false;

public SpringCodegen() {
super();
Expand Down Expand Up @@ -224,6 +228,9 @@ public SpringCodegen() {
cliOptions.add(CliOption.newBoolean(USE_SPRING_BUILT_IN_VALIDATION,
"Disable `@Validated` at the class level when using built-in validation.",
useSpringBuiltInValidation));
cliOptions.add(CliOption.newBoolean(USE_API_COMPOSED_ANNOTATION,
"Use @<method>Mapping instead of @RequestMapping(method = RequestMethod.<method>) when generating the API interfaces.",
useApiComposedAnnotation));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could even make it true by default. What do you think? @dRbAndrade @wing328

cliOptions.add(CliOption.newBoolean(PERFORM_BEANVALIDATION,
"Use Bean Validation Impl. to perform BeanValidation", performBeanValidation));
cliOptions.add(CliOption.newBoolean(USE_SEALED,
Expand Down Expand Up @@ -435,6 +442,7 @@ public void processOpts() {
convertPropertyToBooleanAndWriteBack(USE_RESPONSE_ENTITY, this::setUseResponseEntity);
convertPropertyToBooleanAndWriteBack(OPTIONAL_ACCEPT_NULLABLE, this::setOptionalAcceptNullable);
convertPropertyToBooleanAndWriteBack(USE_SPRING_BUILT_IN_VALIDATION, this::setUseSpringBuiltInValidation);
convertPropertyToBooleanAndWriteBack(USE_API_COMPOSED_ANNOTATION, this::setUseApiComposedAnnotation);

additionalProperties.put("springHttpStatus", new SpringHttpStatusLambda());

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.openapitools.codegen.templating.mustache;

import com.samskivert.mustache.Mustache;
import com.samskivert.mustache.Template;

import java.io.IOException;
import java.io.Writer;

/**
* Replaces @RequestMapping annotation with the appropriate composed annotation when using <strong>Spring generator</strong>. e.g:
* <p><code>@RequestMapping(method = RequestMethod.GET</code>
* will be replaced with:<code>@GetMapping(</code> as it is defined on the file JavaSpring/api.mustache under
* the {{#useApiComposedAnnotation}} section</p>
*
* Register:
* <pre>
* additionalProperties.put("composedannotationlambda", new ComposedRequestMappingAnnotationLambda());
* </pre>
*
* Use:
* <pre>
* {{#lambda.composedannotationlambda}}{{httpMethod}}{{/lambda.composedannotationlambda}}
* </pre>
*/
public class ComposedRequestMappingAnnotationLambda implements Mustache.Lambda {
@Override
public void execute(Template.Fragment fragment, Writer writer) throws IOException {
String text = fragment.execute();
writer.write(String.format("@%sMapping(",text.substring(0,1).toUpperCase()+text.substring(1).toLowerCase()));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fails if the input String is empty. Would be nice if this case could be handled gracefully.

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -226,8 +226,15 @@ public interface {{classname}} {
})
{{/swagger1AnnotationLibrary}}
{{/implicitHeadersParams.0}}
{{#useApiComposedAnnotation}}
{{#lambda.composedannotationlambda}}{{httpMethod}}{{/lambda.composedannotationlambda}}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please rename it to lambda.composedannotation.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PS: This should also include updating the JavaDoc in ComposedRequestMappingAnnotationLambda.java.

{{/useApiComposedAnnotation}}
{{^useApiComposedAnnotation}}
@RequestMapping(
{{/useApiComposedAnnotation}}
{{^useApiComposedAnnotation}}
Comment on lines +234 to +235
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like you can remove these 2 lines.

method = RequestMethod.{{httpMethod}},
{{/useApiComposedAnnotation}}
value = "{{{path}}}"{{#singleContentTypes}}{{#hasProduces}},
produces = { {{#vendorExtensions.x-accepts}}"{{{.}}}"{{^-last}}, {{/-last}}{{/vendorExtensions.x-accepts}} }{{/hasProduces}}{{#hasConsumes}},
consumes = "{{{vendorExtensions.x-content-type}}}"{{/hasConsumes}}{{/singleContentTypes}}{{^singleContentTypes}}{{#hasProduces}},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5433,6 +5433,104 @@ public void shouldDisableBuiltInValidationOptionByDefault() throws IOException {
.containsWithName("Validated");
}

@Test
public void shouldUseApiComposedAnnotationWhenSetToTrue() throws IOException {
final SpringCodegen codegen = new SpringCodegen();
codegen.additionalProperties().put(USE_API_COMPOSED_ANNOTATION, true);

Map<String, File> files = generateFiles(codegen, "src/test/resources/3_0/petstore.yaml");
var file = files.get("UserApi.java");

JavaFileAssert.assertThat(file)
.assertMethod("getUserByName")
.assertMethodAnnotations()
.containsWithName("GetMapping")
.doesNotContainWithName("RequestMapping");

JavaFileAssert.assertThat(file)
.assertMethod("createUser")
.assertMethodAnnotations()
.containsWithName("PostMapping")
.doesNotContainWithName("RequestMapping");

JavaFileAssert.assertThat(file)
.assertMethod("updateUser")
.assertMethodAnnotations()
.containsWithName("PutMapping")
.doesNotContainWithName("RequestMapping");

JavaFileAssert.assertThat(file)
.assertMethod("deleteUser")
.assertMethodAnnotations()
.containsWithName("DeleteMapping")
.doesNotContainWithName("RequestMapping");
}

@Test
public void shouldNotUseApiComposedAnnotationWhenSetToFalse() throws IOException {
final SpringCodegen codegen = new SpringCodegen();
codegen.additionalProperties().put(USE_API_COMPOSED_ANNOTATION, false);

Map<String, File> files = generateFiles(codegen, "src/test/resources/3_0/petstore.yaml");
var file = files.get("UserApi.java");

JavaFileAssert.assertThat(file)
.assertMethod("getUserByName")
.assertMethodAnnotations()
.containsWithName("RequestMapping")
.doesNotContainWithName("GetMapping");

JavaFileAssert.assertThat(file)
.assertMethod("createUser")
.assertMethodAnnotations()
.containsWithName("RequestMapping")
.doesNotContainWithName("PostMapping");

JavaFileAssert.assertThat(file)
.assertMethod("updateUser")
.assertMethodAnnotations()
.containsWithName("RequestMapping")
.doesNotContainWithName("PutMapping");

JavaFileAssert.assertThat(file)
.assertMethod("deleteUser")
.assertMethodAnnotations()
.containsWithName("RequestMapping")
.doesNotContainWithName("DeleteMapping");
}

@Test
public void shouldNotUseApiComposedAnnotationByDefault() throws IOException {
final SpringCodegen codegen = new SpringCodegen();

Map<String, File> files = generateFiles(codegen, "src/test/resources/3_0/petstore.yaml");
var file = files.get("UserApi.java");

JavaFileAssert.assertThat(file)
.assertMethod("getUserByName")
.assertMethodAnnotations()
.containsWithName("RequestMapping")
.doesNotContainWithName("GetMapping");

JavaFileAssert.assertThat(file)
.assertMethod("createUser")
.assertMethodAnnotations()
.containsWithName("RequestMapping")
.doesNotContainWithName("PostMapping");

JavaFileAssert.assertThat(file)
.assertMethod("updateUser")
.assertMethodAnnotations()
.containsWithName("RequestMapping")
.doesNotContainWithName("PutMapping");

JavaFileAssert.assertThat(file)
.assertMethod("deleteUser")
.assertMethodAnnotations()
.containsWithName("RequestMapping")
.doesNotContainWithName("DeleteMapping");
}

@Test
public void testEnumFieldShouldBeFinal_issue21018() throws IOException {
SpringCodegen codegen = new SpringCodegen();
Expand Down