From 97eb95f1dbe6d59a7d66c2f630461610dd639a44 Mon Sep 17 00:00:00 2001 From: Auke Schrijnen Date: Fri, 13 May 2022 12:38:41 +0200 Subject: [PATCH] [java-micronaut] Return HTTP 501 in default implementation The default controller implementation returns an empty response. This might result in unexpected behavior when an operation isn't implemented, as a consumer of the API there is no way to notice the difference between an unimplemented method and an actual empty response. By changing the default behavior to return HTTP 501 Not Implemented the user will be made aware of unimplemented methods. The former default behavior, returning an empty response by default, can be activated with a configuration option. --- bin/configs/java-micronaut-server.yaml | 2 ++ docs/generators/java-micronaut-server.md | 1 + .../languages/JavaMicronautServerCodegen.java | 12 ++++++++- .../java-micronaut/server/controller.mustache | 9 +++++-- .../server/controllerOperationBody.mustache | 5 ++++ .../controller/PetController.java | 26 +++++++++++++------ .../controller/StoreController.java | 14 +++++++--- .../controller/UserController.java | 26 +++++++++++++------ 8 files changed, 72 insertions(+), 23 deletions(-) diff --git a/bin/configs/java-micronaut-server.yaml b/bin/configs/java-micronaut-server.yaml index d0c4df9ac5e6..15b9ba58b327 100644 --- a/bin/configs/java-micronaut-server.yaml +++ b/bin/configs/java-micronaut-server.yaml @@ -8,3 +8,5 @@ additionalProperties: test: "spock" requiredPropertiesInConstructor: "true" useAuth: "false" + generateControllerAsAbstract: "false" + generateOperationsToReturnNotImplemented: "true" diff --git a/docs/generators/java-micronaut-server.md b/docs/generators/java-micronaut-server.md index b006e2579dc9..6a6655585f9c 100644 --- a/docs/generators/java-micronaut-server.md +++ b/docs/generators/java-micronaut-server.md @@ -44,6 +44,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl |fullJavaUtil|whether to use fully qualified name for classes under java.util. This option only works for Java API client| |false| |generateControllerAsAbstract|Generate an abstract class for controller to be extended. (apiPackage is then used for the abstract class, and controllerPackage is used for implementation that extends it.)| |false| |generateControllerFromExamples|Generate the implementation of controller and tests from parameter and return examples that will verify that the api works as desired (for testing)| |false| +|generateOperationsToReturnNotImplemented|Return HTTP 501 Not Implemented instead of an empty response in the generated controller methods.| |true| |groupId|groupId in generated pom.xml| |org.openapitools| |hideGenerationTimestamp|Hides the generation timestamp when files are generated.| |false| |ignoreAnyOfInEnum|Ignore anyOf keyword in enum| |false| diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaMicronautServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaMicronautServerCodegen.java index 95764efd2cd0..6d1a3b3785b1 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaMicronautServerCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaMicronautServerCodegen.java @@ -12,7 +12,6 @@ import java.io.File; import java.util.Collections; import java.util.List; -import java.util.Map; import java.util.stream.Collectors; @@ -20,6 +19,7 @@ public class JavaMicronautServerCodegen extends JavaMicronautAbstractCodegen { public static final String OPT_CONTROLLER_PACKAGE = "controllerPackage"; public static final String OPT_GENERATE_CONTROLLER_FROM_EXAMPLES = "generateControllerFromExamples"; public static final String OPT_GENERATE_CONTROLLER_AS_ABSTRACT = "generateControllerAsAbstract"; + public static final String OPT_GENERATE_OPERATIONS_TO_RETURN_NOT_IMPLEMENTED = "generateOperationsToReturnNotImplemented"; public static final String EXTENSION_ROLES = "x-roles"; public static final String ANONYMOUS_ROLE_KEY = "isAnonymous()"; @@ -35,6 +35,7 @@ public class JavaMicronautServerCodegen extends JavaMicronautAbstractCodegen { protected String controllerPackage = "org.openapitools.controller"; protected boolean generateControllerAsAbstract = false; + protected boolean generateOperationsToReturnNotImplemented = true; protected boolean generateControllerFromExamples = false; protected boolean useAuth = true; @@ -65,6 +66,10 @@ public JavaMicronautServerCodegen() { " is then used for the abstract class, and " + OPT_CONTROLLER_PACKAGE + " is used for implementation that extends it.)", generateControllerAsAbstract)); + cliOptions.add(CliOption.newBoolean(OPT_GENERATE_OPERATIONS_TO_RETURN_NOT_IMPLEMENTED, + "Return HTTP 501 Not Implemented instead of an empty response in the generated controller methods.", + generateOperationsToReturnNotImplemented)); + cliOptions.add(CliOption.newBoolean(OPT_USE_AUTH, "Whether to import authorization and to annotate controller methods accordingly", useAuth)); // Set the type mappings @@ -96,6 +101,11 @@ public void processOpts() { } writePropertyBack(OPT_GENERATE_CONTROLLER_AS_ABSTRACT, generateControllerAsAbstract); + if (additionalProperties.containsKey(OPT_GENERATE_OPERATIONS_TO_RETURN_NOT_IMPLEMENTED)) { + generateOperationsToReturnNotImplemented = convertPropertyToBoolean(OPT_GENERATE_OPERATIONS_TO_RETURN_NOT_IMPLEMENTED); + } + writePropertyBack(OPT_GENERATE_OPERATIONS_TO_RETURN_NOT_IMPLEMENTED, generateOperationsToReturnNotImplemented); + if (additionalProperties.containsKey(OPT_CONTROLLER_PACKAGE)) { controllerPackage = (String) additionalProperties.get(OPT_CONTROLLER_PACKAGE); } else if (!generateControllerAsAbstract && additionalProperties.containsKey(CodegenConstants.API_PACKAGE)) { diff --git a/modules/openapi-generator/src/main/resources/java-micronaut/server/controller.mustache b/modules/openapi-generator/src/main/resources/java-micronaut/server/controller.mustache index 771e57b915dd..336177927e99 100644 --- a/modules/openapi-generator/src/main/resources/java-micronaut/server/controller.mustache +++ b/modules/openapi-generator/src/main/resources/java-micronaut/server/controller.mustache @@ -14,6 +14,10 @@ import reactor.core.publisher.Mono; {{#wrapInHttpResponse}} import io.micronaut.http.HttpResponse; {{/wrapInHttpResponse}} +{{#generateOperationsToReturnNotImplemented}} +import io.micronaut.http.HttpStatus; +import io.micronaut.http.exceptions.HttpStatusException; +{{/generateOperationsToReturnNotImplemented}} {{#imports}} import {{import}}; {{/imports}} @@ -119,8 +123,9 @@ public {{#generateControllerAsAbstract}}abstract {{/generateControllerAsAbstract * * This method will be delegated to when the controller gets a request */ - public abstract {{>common/operationReturnType}} {{nickname}}({{#allParams}}{{{dataType}}} {{paramName}}{{^-last}}, {{/-last}}{{/allParams}}); - {{/generateControllerAsAbstract}} + public {{^generateOperationsToReturnNotImplemented}}abstract {{/generateOperationsToReturnNotImplemented}}{{>common/operationReturnType}} {{nickname}}({{#allParams}}{{{dataType}}} {{paramName}}{{^-last}}, {{/-last}}{{/allParams}}){{^generateOperationsToReturnNotImplemented}};{{/generateOperationsToReturnNotImplemented}}{{#generateOperationsToReturnNotImplemented}} {{openbrace}} + {{>server/controllerOperationBody}} + {{closebrace}}{{/generateOperationsToReturnNotImplemented}}{{/generateControllerAsAbstract}} {{^-last}} {{/-last}} diff --git a/modules/openapi-generator/src/main/resources/java-micronaut/server/controllerOperationBody.mustache b/modules/openapi-generator/src/main/resources/java-micronaut/server/controllerOperationBody.mustache index cbfe9e504c0c..d16aa20f513a 100644 --- a/modules/openapi-generator/src/main/resources/java-micronaut/server/controllerOperationBody.mustache +++ b/modules/openapi-generator/src/main/resources/java-micronaut/server/controllerOperationBody.mustache @@ -1,7 +1,12 @@ {{^generateControllerFromExamples}} {{!The body needs to be implemented by user}} // TODO implement {{nickname}}(); + {{^generateOperationsToReturnNotImplemented}} {{#reactive}}{{#wrapInHttpResponse}}return Mono.fromCallable(HttpResponse::ok);{{/wrapInHttpResponse}}{{^wrapInHttpResponse}}return Mono.empty();{{/wrapInHttpResponse}}{{/reactive}}{{^reactive}}{{#wrapInHttpResponse}}return HttpResponse.ok();{{/wrapInHttpResponse}}{{^wrapInHttpResponse}}{{#returnType}}return null;{{/returnType}}{{/wrapInHttpResponse}}{{/reactive}} + {{/generateOperationsToReturnNotImplemented}} + {{#generateOperationsToReturnNotImplemented}} + {{#reactive}}{{#wrapInHttpResponse}}return Mono.just(HttpResponse.status(HttpStatus.NOT_IMPLEMENTED));{{/wrapInHttpResponse}}{{^wrapInHttpResponse}}return Mono.error(new HttpStatusException(HttpStatus.NOT_IMPLEMENTED, null));{{/wrapInHttpResponse}}{{/reactive}}{{^reactive}}{{#wrapInHttpResponse}}return HttpResponse.status(HttpStatus.NOT_IMPLEMENTED);{{/wrapInHttpResponse}}{{^wrapInHttpResponse}}throw new HttpStatusException(HttpStatus.NOT_IMPLEMENTED, null);{{/wrapInHttpResponse}}{{/reactive}} + {{/generateOperationsToReturnNotImplemented}} {{/generateControllerFromExamples}} {{#generateControllerFromExamples}} {{!The body is generated to verify that example values are passed correctly}} diff --git a/samples/server/petstore/java-micronaut-server/src/main/java/org/openapitools/controller/PetController.java b/samples/server/petstore/java-micronaut-server/src/main/java/org/openapitools/controller/PetController.java index 5e39bc8a7f24..bb301d721f1e 100644 --- a/samples/server/petstore/java-micronaut-server/src/main/java/org/openapitools/controller/PetController.java +++ b/samples/server/petstore/java-micronaut-server/src/main/java/org/openapitools/controller/PetController.java @@ -16,6 +16,8 @@ import io.micronaut.core.annotation.Nullable; import io.micronaut.core.convert.format.Format; import reactor.core.publisher.Mono; +import io.micronaut.http.HttpStatus; +import io.micronaut.http.exceptions.HttpStatusException; import io.micronaut.http.multipart.CompletedFileUpload; import org.openapitools.model.ModelApiResponse; import org.openapitools.model.Pet; @@ -60,9 +62,10 @@ public Mono addPet( @Body @NotNull @Valid Pet pet ) { // TODO implement addPet(); - return Mono.empty(); + return Mono.error(new HttpStatusException(HttpStatus.NOT_IMPLEMENTED, null)); } + /** * Deletes a pet * @@ -90,9 +93,10 @@ public Mono deletePet( @Header(value="api_key") @Nullable String apiKey ) { // TODO implement deletePet(); - return Mono.empty(); + return Mono.error(new HttpStatusException(HttpStatus.NOT_IMPLEMENTED, null)); } + /** * Finds Pets by status * Multiple status values can be provided with comma separated strings @@ -121,9 +125,10 @@ public Mono> findPetsByStatus( @QueryValue(value="status") @NotNull List status ) { // TODO implement findPetsByStatus(); - return Mono.empty(); + return Mono.error(new HttpStatusException(HttpStatus.NOT_IMPLEMENTED, null)); } + /** * Finds Pets by tags * Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing. @@ -152,9 +157,10 @@ public Mono> findPetsByTags( @QueryValue(value="tags") @NotNull List tags ) { // TODO implement findPetsByTags(); - return Mono.empty(); + return Mono.error(new HttpStatusException(HttpStatus.NOT_IMPLEMENTED, null)); } + /** * Find pet by ID * Returns a single pet @@ -181,9 +187,10 @@ public Mono getPetById( @PathVariable(value="petId") @NotNull Long petId ) { // TODO implement getPetById(); - return Mono.empty(); + return Mono.error(new HttpStatusException(HttpStatus.NOT_IMPLEMENTED, null)); } + /** * Update an existing pet * @@ -215,9 +222,10 @@ public Mono updatePet( @Body @NotNull @Valid Pet pet ) { // TODO implement updatePet(); - return Mono.empty(); + return Mono.error(new HttpStatusException(HttpStatus.NOT_IMPLEMENTED, null)); } + /** * Updates a pet in the store with form data * @@ -248,9 +256,10 @@ public Mono updatePetWithForm( @Nullable String status ) { // TODO implement updatePetWithForm(); - return Mono.empty(); + return Mono.error(new HttpStatusException(HttpStatus.NOT_IMPLEMENTED, null)); } + /** * uploads an image * @@ -283,6 +292,7 @@ public Mono uploadFile( @Nullable CompletedFileUpload _file ) { // TODO implement uploadFile(); - return Mono.empty(); + return Mono.error(new HttpStatusException(HttpStatus.NOT_IMPLEMENTED, null)); } + } diff --git a/samples/server/petstore/java-micronaut-server/src/main/java/org/openapitools/controller/StoreController.java b/samples/server/petstore/java-micronaut-server/src/main/java/org/openapitools/controller/StoreController.java index 4b1364e8fb7d..fdb2469c3eae 100644 --- a/samples/server/petstore/java-micronaut-server/src/main/java/org/openapitools/controller/StoreController.java +++ b/samples/server/petstore/java-micronaut-server/src/main/java/org/openapitools/controller/StoreController.java @@ -16,6 +16,8 @@ import io.micronaut.core.annotation.Nullable; import io.micronaut.core.convert.format.Format; import reactor.core.publisher.Mono; +import io.micronaut.http.HttpStatus; +import io.micronaut.http.exceptions.HttpStatusException; import org.openapitools.model.Order; import javax.annotation.Generated; import java.util.ArrayList; @@ -50,9 +52,10 @@ public Mono deleteOrder( @PathVariable(value="orderId") @NotNull String orderId ) { // TODO implement deleteOrder(); - return Mono.empty(); + return Mono.error(new HttpStatusException(HttpStatus.NOT_IMPLEMENTED, null)); } + /** * Returns pet inventories by status * Returns a map of status codes to quantities @@ -75,9 +78,10 @@ public Mono deleteOrder( @Produces(value = {"application/json"}) public Mono> getInventory() { // TODO implement getInventory(); - return Mono.empty(); + return Mono.error(new HttpStatusException(HttpStatus.NOT_IMPLEMENTED, null)); } + /** * Find purchase order by ID * For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions @@ -102,9 +106,10 @@ public Mono getOrderById( @PathVariable(value="orderId") @NotNull @Min(1L) @Max(5L) Long orderId ) { // TODO implement getOrderById(); - return Mono.empty(); + return Mono.error(new HttpStatusException(HttpStatus.NOT_IMPLEMENTED, null)); } + /** * Place an order for a pet * @@ -129,6 +134,7 @@ public Mono placeOrder( @Body @NotNull @Valid Order order ) { // TODO implement placeOrder(); - return Mono.empty(); + return Mono.error(new HttpStatusException(HttpStatus.NOT_IMPLEMENTED, null)); } + } diff --git a/samples/server/petstore/java-micronaut-server/src/main/java/org/openapitools/controller/UserController.java b/samples/server/petstore/java-micronaut-server/src/main/java/org/openapitools/controller/UserController.java index 9e7a6456025d..39a8061982a7 100644 --- a/samples/server/petstore/java-micronaut-server/src/main/java/org/openapitools/controller/UserController.java +++ b/samples/server/petstore/java-micronaut-server/src/main/java/org/openapitools/controller/UserController.java @@ -16,6 +16,8 @@ import io.micronaut.core.annotation.Nullable; import io.micronaut.core.convert.format.Format; import reactor.core.publisher.Mono; +import io.micronaut.http.HttpStatus; +import io.micronaut.http.exceptions.HttpStatusException; import java.time.OffsetDateTime; import org.openapitools.model.User; import javax.annotation.Generated; @@ -53,9 +55,10 @@ public Mono createUser( @Body @NotNull @Valid User user ) { // TODO implement createUser(); - return Mono.empty(); + return Mono.error(new HttpStatusException(HttpStatus.NOT_IMPLEMENTED, null)); } + /** * Creates list of users with given input array * @@ -79,9 +82,10 @@ public Mono createUsersWithArrayInput( @Body @NotNull List user ) { // TODO implement createUsersWithArrayInput(); - return Mono.empty(); + return Mono.error(new HttpStatusException(HttpStatus.NOT_IMPLEMENTED, null)); } + /** * Creates list of users with given input array * @@ -105,9 +109,10 @@ public Mono createUsersWithListInput( @Body @NotNull List user ) { // TODO implement createUsersWithListInput(); - return Mono.empty(); + return Mono.error(new HttpStatusException(HttpStatus.NOT_IMPLEMENTED, null)); } + /** * Delete user * This can only be done by the logged in user. @@ -131,9 +136,10 @@ public Mono deleteUser( @PathVariable(value="username") @NotNull String username ) { // TODO implement deleteUser(); - return Mono.empty(); + return Mono.error(new HttpStatusException(HttpStatus.NOT_IMPLEMENTED, null)); } + /** * Get user by user name * @@ -158,9 +164,10 @@ public Mono getUserByName( @PathVariable(value="username") @NotNull String username ) { // TODO implement getUserByName(); - return Mono.empty(); + return Mono.error(new HttpStatusException(HttpStatus.NOT_IMPLEMENTED, null)); } + /** * Logs user into the system * @@ -186,9 +193,10 @@ public Mono loginUser( @QueryValue(value="password") @NotNull String password ) { // TODO implement loginUser(); - return Mono.empty(); + return Mono.error(new HttpStatusException(HttpStatus.NOT_IMPLEMENTED, null)); } + /** * Logs out current logged in user session * @@ -208,9 +216,10 @@ public Mono loginUser( @Produces(value = {}) public Mono logoutUser() { // TODO implement logoutUser(); - return Mono.empty(); + return Mono.error(new HttpStatusException(HttpStatus.NOT_IMPLEMENTED, null)); } + /** * Updated user * This can only be done by the logged in user. @@ -237,6 +246,7 @@ public Mono updateUser( @Body @NotNull @Valid User user ) { // TODO implement updateUser(); - return Mono.empty(); + return Mono.error(new HttpStatusException(HttpStatus.NOT_IMPLEMENTED, null)); } + }