From c9d86e5d817c7afb89c8ba20fce9688bd26005e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacob=20Overg=C3=A5rd=20Jensen?= Date: Mon, 3 Mar 2025 10:15:29 +0100 Subject: [PATCH 1/2] [java][Microprofile] add config options to disable usage of ApiExceptionMapper --- docs/generators/java-microprofile.md | 2 + docs/generators/java.md | 2 + .../codegen/languages/JavaClientCodegen.java | 17 +++ .../Java/libraries/microprofile/api.mustache | 4 + .../api_exception_mapper.mustache | 4 + .../JavaMicroprofileServerCodegenTest.java | 111 +++++++++++++++++- 6 files changed, 139 insertions(+), 1 deletion(-) diff --git a/docs/generators/java-microprofile.md b/docs/generators/java-microprofile.md index d46dc94cf1c0..82fbd065f5aa 100644 --- a/docs/generators/java-microprofile.md +++ b/docs/generators/java-microprofile.md @@ -66,7 +66,9 @@ These options may be applied as additional-properties (cli) or configOptions (pl |licenseName|The name of the license| |Unlicense| |licenseUrl|The URL of the license| |http://unlicense.org| |microprofileFramework|Framework for microprofile. Possible values "kumuluzee"| |null| +|microprofileGlobalExceptionMapper|Should ApiExceptionMapper be annotated with @Provider making it a global exception mapper| |true| |microprofileMutiny|Whether to use async types for microprofile (currently only Smallrye Mutiny is supported).| |null| +|microprofileRegisterExceptionMapper|Should generated API Clients be annotated with @RegisterProvider(ApiExceptionMapper.class).| |true| |microprofileRestClientVersion|Version of MicroProfile Rest Client API.| |null| |modelPackage|package for generated models| |org.openapitools.client.model| |openApiNullable|Enable OpenAPI Jackson Nullable library. Not supported by `microprofile` library.| |true| diff --git a/docs/generators/java.md b/docs/generators/java.md index d89024f923d0..eebb10956147 100644 --- a/docs/generators/java.md +++ b/docs/generators/java.md @@ -66,7 +66,9 @@ These options may be applied as additional-properties (cli) or configOptions (pl |licenseName|The name of the license| |Unlicense| |licenseUrl|The URL of the license| |http://unlicense.org| |microprofileFramework|Framework for microprofile. Possible values "kumuluzee"| |null| +|microprofileGlobalExceptionMapper|Should ApiExceptionMapper be annotated with @Provider making it a global exception mapper| |true| |microprofileMutiny|Whether to use async types for microprofile (currently only Smallrye Mutiny is supported).| |null| +|microprofileRegisterExceptionMapper|Should generated API Clients be annotated with @RegisterProvider(ApiExceptionMapper.class).| |true| |microprofileRestClientVersion|Version of MicroProfile Rest Client API.| |null| |modelPackage|package for generated models| |org.openapitools.client.model| |openApiNullable|Enable OpenAPI Jackson Nullable library. Not supported by `microprofile` library.| |true| diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaClientCodegen.java index 8f328e474043..1f0898c26b7d 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaClientCodegen.java @@ -70,6 +70,8 @@ public class JavaClientCodegen extends AbstractJavaCodegen public static final String CASE_INSENSITIVE_RESPONSE_HEADERS = "caseInsensitiveResponseHeaders"; public static final String MICROPROFILE_FRAMEWORK = "microprofileFramework"; public static final String MICROPROFILE_MUTINY = "microprofileMutiny"; + public static final String MICROPROFILE_GLOBAL_EXCEPTION_MAPPER = "microprofileGlobalExceptionMapper"; + public static final String MICROPROFILE_REGISTER_EXCEPTION_MAPPER = "microprofileRegisterExceptionMapper"; public static final String USE_ABSTRACTION_FOR_FILES = "useAbstractionForFiles"; public static final String DYNAMIC_OPERATIONS = "dynamicOperations"; public static final String SUPPORT_STREAMING = "supportStreaming"; @@ -118,6 +120,8 @@ public class JavaClientCodegen extends AbstractJavaCodegen @Setter protected String microprofileFramework = MICROPROFILE_DEFAULT; @Setter protected String microprofileRestClientVersion = MICROPROFILE_REST_CLIENT_DEFAULT_VERSION; @Setter protected boolean microprofileMutiny = false; + @Setter protected boolean microProfileGlobalExceptionMapper = true; + @Setter protected boolean microProfileRegisterExceptionMapper = true; @Setter protected String configKey = null; @Setter(AccessLevel.PRIVATE) protected boolean configKeyFromClassName = false; @@ -226,6 +230,8 @@ public JavaClientCodegen() { cliOptions.add(CliOption.newBoolean(CASE_INSENSITIVE_RESPONSE_HEADERS, "Make API response's headers case-insensitive. Available on " + OKHTTP_GSON + ", " + JERSEY2 + " libraries")); cliOptions.add(CliOption.newString(MICROPROFILE_FRAMEWORK, "Framework for microprofile. Possible values \"kumuluzee\"")); cliOptions.add(CliOption.newString(MICROPROFILE_MUTINY, "Whether to use async types for microprofile (currently only Smallrye Mutiny is supported).")); + cliOptions.add(CliOption.newString(MICROPROFILE_REGISTER_EXCEPTION_MAPPER, "Should generated API Clients be annotated with @RegisterProvider(ApiExceptionMapper.class).").defaultValue("true")); + cliOptions.add(CliOption.newString(MICROPROFILE_GLOBAL_EXCEPTION_MAPPER, "Should ApiExceptionMapper be annotated with @Provider making it a global exception mapper").defaultValue("true")); cliOptions.add(CliOption.newBoolean(USE_ABSTRACTION_FOR_FILES, "Use alternative types instead of java.io.File to allow passing bytes without a file on disk. Available on resttemplate, webclient, restclient, libraries")); cliOptions.add(CliOption.newBoolean(DYNAMIC_OPERATIONS, "Generate operations dynamically at runtime from an OAS", this.dynamicOperations)); cliOptions.add(CliOption.newBoolean(SUPPORT_STREAMING, "Support streaming endpoint (beta)", this.supportStreaming)); @@ -375,6 +381,17 @@ public void processOpts() { } convertPropertyToStringAndWriteBack(MICROPROFILE_FRAMEWORK, this::setMicroprofileFramework); + convertPropertyToBooleanAndWriteBack(MICROPROFILE_GLOBAL_EXCEPTION_MAPPER, this::setMicroProfileGlobalExceptionMapper); + convertPropertyToBooleanAndWriteBack(MICROPROFILE_REGISTER_EXCEPTION_MAPPER, this::setMicroProfileRegisterExceptionMapper); + + if (!additionalProperties.containsKey(MICROPROFILE_REGISTER_EXCEPTION_MAPPER)) { + additionalProperties.put(MICROPROFILE_REGISTER_EXCEPTION_MAPPER, true); + } + + if (!additionalProperties.containsKey(MICROPROFILE_GLOBAL_EXCEPTION_MAPPER)) { + additionalProperties.put(MICROPROFILE_GLOBAL_EXCEPTION_MAPPER, true); + } + convertPropertyToBooleanAndWriteBack(MICROPROFILE_MUTINY, this::setMicroprofileMutiny); convertPropertyToStringAndWriteBack(MICROPROFILE_REST_CLIENT_VERSION, value->microprofileRestClientVersion=value); diff --git a/modules/openapi-generator/src/main/resources/Java/libraries/microprofile/api.mustache b/modules/openapi-generator/src/main/resources/Java/libraries/microprofile/api.mustache index 0b0a7c4badd4..a77a8e1a1e75 100644 --- a/modules/openapi-generator/src/main/resources/Java/libraries/microprofile/api.mustache +++ b/modules/openapi-generator/src/main/resources/Java/libraries/microprofile/api.mustache @@ -24,7 +24,9 @@ import {{rootJavaEEPackage}}.validation.constraints.*; import {{rootJavaEEPackage}}.validation.Valid; {{/useBeanValidation}} +{{#microprofileRegisterExceptionMapper}} import org.eclipse.microprofile.rest.client.annotation.RegisterProvider; +{{/microprofileRegisterExceptionMapper}} import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; {{#appName}} @@ -41,7 +43,9 @@ import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; {{^microprofileServer}} @RegisterRestClient{{#configKey}}(configKey="{{configKey}}"){{/configKey}}{{#configKeyFromClassName}}{{#operations}}(configKey="{{configKey}}"){{/operations}}{{/configKeyFromClassName}} {{/microprofileServer}} +{{#microprofileRegisterExceptionMapper}} @RegisterProvider(ApiExceptionMapper.class) +{{/microprofileRegisterExceptionMapper}} @Path("{{#useAnnotatedBasePath}}{{contextPath}}{{/useAnnotatedBasePath}}{{commonPath}}") public interface {{classname}} { {{#operations}} diff --git a/modules/openapi-generator/src/main/resources/Java/libraries/microprofile/api_exception_mapper.mustache b/modules/openapi-generator/src/main/resources/Java/libraries/microprofile/api_exception_mapper.mustache index 12988f5ed9db..2842b1c87a72 100644 --- a/modules/openapi-generator/src/main/resources/Java/libraries/microprofile/api_exception_mapper.mustache +++ b/modules/openapi-generator/src/main/resources/Java/libraries/microprofile/api_exception_mapper.mustache @@ -3,10 +3,14 @@ package {{apiPackage}}; import {{rootJavaEEPackage}}.ws.rs.core.MultivaluedMap; import {{rootJavaEEPackage}}.ws.rs.core.Response; +{{#microprofileGlobalExceptionMapper}} import {{rootJavaEEPackage}}.ws.rs.ext.Provider; +{{/microprofileGlobalExceptionMapper}} import org.eclipse.microprofile.rest.client.ext.ResponseExceptionMapper; +{{#microprofileGlobalExceptionMapper}} @Provider +{{/microprofileGlobalExceptionMapper}} public class ApiExceptionMapper implements ResponseExceptionMapper { diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/microprofile/JavaMicroprofileServerCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/microprofile/JavaMicroprofileServerCodegenTest.java index a90546f7cdb0..06cb837baa6d 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/microprofile/JavaMicroprofileServerCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/microprofile/JavaMicroprofileServerCodegenTest.java @@ -7,6 +7,7 @@ import org.openapitools.codegen.CodegenConstants; import org.openapitools.codegen.DefaultGenerator; import org.openapitools.codegen.java.assertions.JavaFileAssert; +import org.openapitools.codegen.languages.JavaClientCodegen; import org.openapitools.codegen.languages.JavaMicroprofileServerCodegen; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; @@ -127,4 +128,112 @@ public void testMicroprofileCanHandleCookieParamsSingleRequest() throws Exceptio .assertInnerClass("GetCustomerRequest") .assertMethod("cookieParameter"); } -} \ No newline at end of file + + @Test + public void testGeneratedApiHasApiExceptionMapperRegisteredWhenUsingDefaultConfiguration() throws Exception { + File output = Files.createTempDirectory("test").toFile().getCanonicalFile(); + output.deleteOnExit(); + + OpenAPI openAPI = new OpenAPIParser() + .readLocation("src/test/resources/bugs/microprofile_cookie.yaml", null, new ParseOptions()).getOpenAPI(); + + codegen.setOutputDir(output.getAbsolutePath()); + + ClientOptInput input = new ClientOptInput() + .openAPI(openAPI) + .config(codegen); + + List files = new DefaultGenerator().opts(input).generate(); + + Map filesMap = files.stream() + .collect(Collectors.toMap(File::getName, Function.identity())); + + validateJavaSourceFiles(files); + + JavaFileAssert.assertThat(filesMap.get("DefaultApi.java")) + .assertTypeAnnotations() + .containsWithName("RegisterProvider") + .containsWithNameAndAttributes("RegisterProvider", Map.of("value", "ApiExceptionMapper.class")); + } + + @Test + public void testGeneratedApiDoesNotHaveApiExceptionMapperRegisteredWhenDisablingItInConfiguration() throws Exception { + File output = Files.createTempDirectory("test").toFile().getCanonicalFile(); + output.deleteOnExit(); + + OpenAPI openAPI = new OpenAPIParser() + .readLocation("src/test/resources/bugs/microprofile_cookie.yaml", null, new ParseOptions()).getOpenAPI(); + + codegen.setOutputDir(output.getAbsolutePath()); + codegen.additionalProperties().put(JavaClientCodegen.MICROPROFILE_REGISTER_EXCEPTION_MAPPER, "false"); + + ClientOptInput input = new ClientOptInput() + .openAPI(openAPI) + .config(codegen); + + List files = new DefaultGenerator().opts(input).generate(); + + Map filesMap = files.stream() + .collect(Collectors.toMap(File::getName, Function.identity())); + + validateJavaSourceFiles(files); + + JavaFileAssert.assertThat(filesMap.get("DefaultApi.java")) + .assertTypeAnnotations() + .doesNotContainWithName("RegisterProvider"); + } + + @Test + public void testGeneratedApiExceptionMapperHasProviderAnnotationWhenUsingDefaultConfiguration() throws Exception { + File output = Files.createTempDirectory("test").toFile().getCanonicalFile(); + output.deleteOnExit(); + + OpenAPI openAPI = new OpenAPIParser() + .readLocation("src/test/resources/bugs/microprofile_cookie.yaml", null, new ParseOptions()).getOpenAPI(); + + codegen.setOutputDir(output.getAbsolutePath()); + + ClientOptInput input = new ClientOptInput() + .openAPI(openAPI) + .config(codegen); + + List files = new DefaultGenerator().opts(input).generate(); + + Map filesMap = files.stream() + .collect(Collectors.toMap(File::getName, Function.identity())); + + validateJavaSourceFiles(files); + + JavaFileAssert.assertThat(filesMap.get("ApiExceptionMapper.java")) + .assertTypeAnnotations() + .containsWithName("Provider"); + } + + @Test + public void testGeneratedApiExceptionMapperDoesNotHaveProviderAnnotationWhenDisablingItInConfiguration() throws Exception { + File output = Files.createTempDirectory("test").toFile().getCanonicalFile(); + output.deleteOnExit(); + + OpenAPI openAPI = new OpenAPIParser() + .readLocation("src/test/resources/bugs/microprofile_cookie.yaml", null, new ParseOptions()).getOpenAPI(); + + codegen.setOutputDir(output.getAbsolutePath()); + codegen.additionalProperties().put(JavaClientCodegen.MICROPROFILE_GLOBAL_EXCEPTION_MAPPER, "false"); + + ClientOptInput input = new ClientOptInput() + .openAPI(openAPI) + .config(codegen); + + List files = new DefaultGenerator().opts(input).generate(); + + Map filesMap = files.stream() + .collect(Collectors.toMap(File::getName, Function.identity())); + + validateJavaSourceFiles(files); + + JavaFileAssert.assertThat(filesMap.get("ApiExceptionMapper.java")) + .assertTypeAnnotations() + .doesNotContainWithName("Provider"); + } +} + From 8db111d4125cf8e55c3bb33a934a67d718de0308 Mon Sep 17 00:00:00 2001 From: JacobOJ Date: Thu, 13 Mar 2025 12:22:30 +0100 Subject: [PATCH 2/2] Update modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaClientCodegen.java Co-authored-by: martin-mfg <2026226+martin-mfg@users.noreply.github.com> --- .../codegen/languages/JavaClientCodegen.java | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaClientCodegen.java index 1f0898c26b7d..2da58d6587a8 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaClientCodegen.java @@ -384,13 +384,8 @@ public void processOpts() { convertPropertyToBooleanAndWriteBack(MICROPROFILE_GLOBAL_EXCEPTION_MAPPER, this::setMicroProfileGlobalExceptionMapper); convertPropertyToBooleanAndWriteBack(MICROPROFILE_REGISTER_EXCEPTION_MAPPER, this::setMicroProfileRegisterExceptionMapper); - if (!additionalProperties.containsKey(MICROPROFILE_REGISTER_EXCEPTION_MAPPER)) { - additionalProperties.put(MICROPROFILE_REGISTER_EXCEPTION_MAPPER, true); - } - - if (!additionalProperties.containsKey(MICROPROFILE_GLOBAL_EXCEPTION_MAPPER)) { - additionalProperties.put(MICROPROFILE_GLOBAL_EXCEPTION_MAPPER, true); - } + additionalProperties.put(MICROPROFILE_REGISTER_EXCEPTION_MAPPER, microProfileRegisterExceptionMapper); + additionalProperties.put(MICROPROFILE_GLOBAL_EXCEPTION_MAPPER, microProfileGlobalExceptionMapper); convertPropertyToBooleanAndWriteBack(MICROPROFILE_MUTINY, this::setMicroprofileMutiny);