[java][Microprofile] add config options to disable usage of ApiExceptionMapper (#20762)

* [java][Microprofile] add config options to disable usage of ApiExceptionMapper

* 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>

---------

Co-authored-by: martin-mfg <2026226+martin-mfg@users.noreply.github.com>
This commit is contained in:
JacobOJ 2025-07-16 10:14:23 +02:00 committed by GitHub
parent c4a7c14c8f
commit 63c56f00b7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 134 additions and 1 deletions

View File

@ -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 &quot;kumuluzee&quot;| |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|

View File

@ -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 &quot;kumuluzee&quot;| |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|

View File

@ -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";
@ -120,6 +122,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;
@ -229,6 +233,8 @@ public class JavaClientCodegen extends AbstractJavaCodegen
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));
@ -380,6 +386,12 @@ public class JavaClientCodegen extends AbstractJavaCodegen
}
convertPropertyToStringAndWriteBack(MICROPROFILE_FRAMEWORK, this::setMicroprofileFramework);
convertPropertyToBooleanAndWriteBack(MICROPROFILE_GLOBAL_EXCEPTION_MAPPER, this::setMicroProfileGlobalExceptionMapper);
convertPropertyToBooleanAndWriteBack(MICROPROFILE_REGISTER_EXCEPTION_MAPPER, this::setMicroProfileRegisterExceptionMapper);
additionalProperties.put(MICROPROFILE_REGISTER_EXCEPTION_MAPPER, microProfileRegisterExceptionMapper);
additionalProperties.put(MICROPROFILE_GLOBAL_EXCEPTION_MAPPER, microProfileGlobalExceptionMapper);
convertPropertyToBooleanAndWriteBack(MICROPROFILE_MUTINY, this::setMicroprofileMutiny);
convertPropertyToStringAndWriteBack(MICROPROFILE_REST_CLIENT_VERSION, value -> microprofileRestClientVersion = value);

View File

@ -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}}

View File

@ -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<ApiException> {

View File

@ -7,6 +7,7 @@ import org.openapitools.codegen.ClientOptInput;
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 class JavaMicroprofileServerCodegenTest {
.assertInnerClass("GetCustomerRequest")
.assertMethod("cookieParameter");
}
@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<File> files = new DefaultGenerator().opts(input).generate();
Map<String, File> 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<File> files = new DefaultGenerator().opts(input).generate();
Map<String, File> 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<File> files = new DefaultGenerator().opts(input).generate();
Map<String, File> 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<File> files = new DefaultGenerator().opts(input).generate();
Map<String, File> filesMap = files.stream()
.collect(Collectors.toMap(File::getName, Function.identity()));
validateJavaSourceFiles(files);
JavaFileAssert.assertThat(filesMap.get("ApiExceptionMapper.java"))
.assertTypeAnnotations()
.doesNotContainWithName("Provider");
}
}