[java][client] fix: Add static modifier to inner class in Java when useSingleRequestParameter=true (#20590)

* fix: Add static modifier to inner class

* Apply suggestions from code review

Co-authored-by: martin-mfg <2026226+martin-mfg@users.noreply.github.com>

* fix: Remove unintended whitespace

* fix: Add default=false for useSingleRequestParameter

---------

Co-authored-by: martin-mfg <2026226+martin-mfg@users.noreply.github.com>
This commit is contained in:
Carlos Chacin 2025-02-17 04:02:01 -08:00 committed by GitHub
parent 4ba87ae0e7
commit a6280d9b58
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 58 additions and 19 deletions

View File

@ -100,7 +100,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|useRuntimeException|Use RuntimeException instead of Exception. Only jersey2, jersey3, okhttp-gson, vertx, microprofile support this option.| |false|
|useRxJava2|Whether to use the RxJava2 adapter with the retrofit2 library. IMPORTANT: This option has been deprecated.| |false|
|useRxJava3|Whether to use the RxJava3 adapter with the retrofit2 library. IMPORTANT: This option has been deprecated.| |false|
|useSingleRequestParameter|Setting this property to true will generate functions with a single argument containing all API endpoint parameters instead of one argument per parameter. ONLY jersey2, jersey3, okhttp-gson, microprofile, Spring RestClient, Spring WebClient support this option.| |false|
|useSingleRequestParameter|Setting this property to &quot;true&quot; will generate functions with a single argument containing all API endpoint parameters instead of one argument per parameter. ONLY jersey2, jersey3, okhttp-gson, microprofile, Spring RestClient, Spring WebClient support this option. Setting this property to &quot;static&quot; does the same as &quot;true&quot;, but also makes the generated arguments class static. Only WebClient supports this option.| |false|
|webclientBlockingOperations|Making all WebClient operations blocking(sync). Note that if on operation 'x-webclient-blocking: false' then such operation won't be sync| |false|
|withAWSV4Signature|whether to include AWS v4 signature support (only available for okhttp-gson library)| |false|
|withXml|whether to include support for application/xml content type and include XML annotations in the model (works with libraries that provide support for JSON and XML)| |false|

View File

@ -100,7 +100,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|useRuntimeException|Use RuntimeException instead of Exception. Only jersey2, jersey3, okhttp-gson, vertx, microprofile support this option.| |false|
|useRxJava2|Whether to use the RxJava2 adapter with the retrofit2 library. IMPORTANT: This option has been deprecated.| |false|
|useRxJava3|Whether to use the RxJava3 adapter with the retrofit2 library. IMPORTANT: This option has been deprecated.| |false|
|useSingleRequestParameter|Setting this property to true will generate functions with a single argument containing all API endpoint parameters instead of one argument per parameter. ONLY jersey2, jersey3, okhttp-gson, microprofile, Spring RestClient, Spring WebClient support this option.| |false|
|useSingleRequestParameter|Setting this property to &quot;true&quot; will generate functions with a single argument containing all API endpoint parameters instead of one argument per parameter. ONLY jersey2, jersey3, okhttp-gson, microprofile, Spring RestClient, Spring WebClient support this option. Setting this property to &quot;static&quot; does the same as &quot;true&quot;, but also makes the generated arguments class static. Only WebClient supports this option.| |false|
|webclientBlockingOperations|Making all WebClient operations blocking(sync). Note that if on operation 'x-webclient-blocking: false' then such operation won't be sync| |false|
|withAWSV4Signature|whether to include AWS v4 signature support (only available for okhttp-gson library)| |false|
|withXml|whether to include support for application/xml content type and include XML annotations in the model (works with libraries that provide support for JSON and XML)| |false|

View File

@ -144,7 +144,7 @@ public class JavaClientCodegen extends AbstractJavaCodegen
@Setter protected boolean useOneOfDiscriminatorLookup = false; // use oneOf discriminator's mapping for model lookup
protected String rootJavaEEPackage;
protected Map<String, MpRestClientVersion> mpRestClientVersions = new LinkedHashMap<>();
@Setter(AccessLevel.PRIVATE) protected boolean useSingleRequestParameter = false;
@Setter(AccessLevel.PRIVATE) protected String useSingleRequestParameter = "false";
protected boolean webclientBlockingOperations = false;
@Setter protected boolean generateClientAsBean = false;
@Setter protected boolean useEnumCaseInsensitive = false;
@ -237,7 +237,7 @@ public class JavaClientCodegen extends AbstractJavaCodegen
cliOptions.add(CliOption.newString(CONFIG_KEY_FROM_CLASS_NAME, "If true, set tag as key in @RegisterRestClient. Default to false. Only `microprofile` supports this option."));
cliOptions.add(CliOption.newBoolean(CodegenConstants.USE_ONEOF_DISCRIMINATOR_LOOKUP, CodegenConstants.USE_ONEOF_DISCRIMINATOR_LOOKUP_DESC + " Only jersey2, jersey3, native, okhttp-gson support this option."));
cliOptions.add(CliOption.newString(MICROPROFILE_REST_CLIENT_VERSION, "Version of MicroProfile Rest Client API."));
cliOptions.add(CliOption.newBoolean(CodegenConstants.USE_SINGLE_REQUEST_PARAMETER, "Setting this property to true will generate functions with a single argument containing all API endpoint parameters instead of one argument per parameter. ONLY jersey2, jersey3, okhttp-gson, microprofile, Spring RestClient, Spring WebClient support this option."));
cliOptions.add(CliOption.newString(CodegenConstants.USE_SINGLE_REQUEST_PARAMETER, "Setting this property to \"true\" will generate functions with a single argument containing all API endpoint parameters instead of one argument per parameter. ONLY jersey2, jersey3, okhttp-gson, microprofile, Spring RestClient, Spring WebClient support this option. Setting this property to \"static\" does the same as \"true\", but also makes the generated arguments class static. Only WebClient supports this option.").defaultValue("false"));
cliOptions.add(CliOption.newBoolean(WEBCLIENT_BLOCKING_OPERATIONS, "Making all WebClient operations blocking(sync). Note that if on operation 'x-webclient-blocking: false' then such operation won't be sync", this.webclientBlockingOperations));
cliOptions.add(CliOption.newBoolean(GENERATE_CLIENT_AS_BEAN, "For resttemplate, configure whether to create `ApiClient.java` and Apis clients as bean (with `@Component` annotation).", this.generateClientAsBean));
cliOptions.add(CliOption.newBoolean(SUPPORT_URL_QUERY, "Generate toUrlQueryString in POJO (default to true). Available on `native`, `apache-httpclient` libraries."));
@ -334,7 +334,9 @@ public class JavaClientCodegen extends AbstractJavaCodegen
convertPropertyToBooleanAndWriteBack(USE_RX_JAVA3, this::setUseRxJava3);
convertPropertyToBooleanAndWriteBack(USE_RX_JAVA2, this::setUseRxJava2);
}
convertPropertyToBooleanAndWriteBack(CodegenConstants.USE_SINGLE_REQUEST_PARAMETER, this::setUseSingleRequestParameter);
convertPropertyToStringAndWriteBack(CodegenConstants.USE_SINGLE_REQUEST_PARAMETER, this::setUseSingleRequestParameter);
writePropertyBack("singleRequestParameter", getSingleRequestParameter());
writePropertyBack("staticRequest", getStaticRequest());
if (!useRxJava && !useRxJava2 && !useRxJava3) {
additionalProperties.put(DO_NOT_USE_RX, true);
@ -757,7 +759,7 @@ public class JavaClientCodegen extends AbstractJavaCodegen
public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List<ModelMap> allModels) {
super.postProcessOperationsWithModels(objs, allModels);
if (useSingleRequestParameter && (JERSEY2.equals(getLibrary()) || JERSEY3.equals(getLibrary()) || OKHTTP_GSON.equals(getLibrary()))) {
if (this.getSingleRequestParameter() && (JERSEY2.equals(getLibrary()) || JERSEY3.equals(getLibrary()) || OKHTTP_GSON.equals(getLibrary()))) {
// loop through operations to set x-group-parameters extension to true if useSingleRequestParameter option is enabled
OperationMap operations = objs.getOperations();
if (operations != null) {
@ -1116,7 +1118,15 @@ public class JavaClientCodegen extends AbstractJavaCodegen
return this.useOneOfDiscriminatorLookup;
}
private boolean getUseSingleRequestParameter() {
public boolean getSingleRequestParameter() {
return "true".equals(getUseSingleRequestParameter()) || "static".equals(getUseSingleRequestParameter());
}
public boolean getStaticRequest() {
return "static".equals(this.getUseSingleRequestParameter());
}
private String getUseSingleRequestParameter() {
return useSingleRequestParameter;
}

View File

@ -71,10 +71,10 @@ public interface {{classname}} {
{{#hasProduces}}
@Produces({ {{#produces}}"{{{mediaType}}}"{{^-last}}, {{/-last}}{{/produces}} })
{{/hasProduces}}
{{^useSingleRequestParameter}}
{{^singleRequestParameter}}
{{^vendorExtensions.x-java-is-response-void}}{{#microprofileServer}}{{> server_operation}}{{/microprofileServer}}{{^microprofileServer}}{{> client_operation}}{{/microprofileServer}}{{/vendorExtensions.x-java-is-response-void}}{{#vendorExtensions.x-java-is-response-void}}{{#microprofileMutiny}}Uni<Void>{{/microprofileMutiny}}{{^microprofileMutiny}}void{{/microprofileMutiny}}{{/vendorExtensions.x-java-is-response-void}} {{nickname}}({{#allParams}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{^-last}}, {{/-last}}{{/allParams}}) throws ApiException, ProcessingException;
{{/useSingleRequestParameter}}
{{#useSingleRequestParameter}}
{{/singleRequestParameter}}
{{#singleRequestParameter}}
{{^vendorExtensions.x-java-is-response-void}}{{#microprofileMutiny}}Uni<{{{returnType}}}>{{/microprofileMutiny}}{{^microprofileMutiny}}{{{returnType}}}{{/microprofileMutiny}}{{/vendorExtensions.x-java-is-response-void}}{{#vendorExtensions.x-java-is-response-void}}{{#microprofileMutiny}}Uni<Void>{{/microprofileMutiny}}{{^microprofileMutiny}}void{{/microprofileMutiny}}{{/vendorExtensions.x-java-is-response-void}} {{nickname}}({{#hasNonBodyParams}}@BeanParam {{operationIdCamelCase}}Request request{{/hasNonBodyParams}}{{#bodyParams}}{{#hasNonBodyParams}}, {{/hasNonBodyParams}}{{>bodyParams}}{{/bodyParams}}) throws ApiException, ProcessingException;
{{#hasNonBodyParams}}
public class {{operationIdCamelCase}}Request {
@ -114,7 +114,7 @@ public interface {{classname}} {
{{/allParams}}
}
{{/hasNonBodyParams}}
{{/useSingleRequestParameter}}
{{/singleRequestParameter}}
{{/operation}}
}
{{/operations}}

View File

@ -52,7 +52,7 @@ public class {{classname}} {
}
{{#operation}}
{{#useSingleRequestParameter}}
{{#singleRequestParameter}}
{{#hasParams}}
{{^hasSingleParam}}
@ -108,7 +108,7 @@ public class {{classname}} {
{{/hasSingleParam}}
{{/hasParams}}
{{/useSingleRequestParameter}}
{{/singleRequestParameter}}
/**
* {{summary}}
* {{notes}}

View File

@ -53,8 +53,8 @@ public class {{classname}} {
this.apiClient = apiClient;
}
{{#operation}}{{#useSingleRequestParameter}}{{#hasParams}}{{^hasSingleParam}}
public class {{#lambda.titlecase}}{{operationId}}{{/lambda.titlecase}}Request {
{{#operation}}{{#singleRequestParameter}}{{#hasParams}}{{^hasSingleParam}}
public {{#staticRequest}}static {{/staticRequest}}class {{#lambda.titlecase}}{{operationId}}{{/lambda.titlecase}}Request {
{{#allParams}}
private final {{#isFile}}{{#useAbstractionForFiles}}{{#collectionFormat}}java.util.Collection<org.springframework.core.io.AbstractResource>{{/collectionFormat}}{{^collectionFormat}}org.springframework.core.io.AbstractResource{{/collectionFormat}}{{/useAbstractionForFiles}}{{^useAbstractionForFiles}}{{{dataType}}}{{/useAbstractionForFiles}}{{/isFile}}{{^isFile}}{{{dataType}}}{{/isFile}} {{paramName}};
{{/allParams}}
@ -120,7 +120,7 @@ public class {{classname}} {
return this.{{operationId}}WithResponseSpec({{#allParams}}requestParameters.{{paramName}}(){{^-last}}, {{/-last}}{{/allParams}});
}
{{/hasSingleParam}}{{/hasParams}}{{/useSingleRequestParameter}}
{{/hasSingleParam}}{{/hasParams}}{{/singleRequestParameter}}
/**
* {{summary}}
* {{notes}}

View File

@ -3187,7 +3187,7 @@ public class JavaClientCodegenTest {
.setLibrary(JavaClientCodegen.RESTCLIENT)
.setAdditionalProperties(Map.of(
CodegenConstants.API_PACKAGE, "xyz.abcdef.api",
CodegenConstants.USE_SINGLE_REQUEST_PARAMETER, true
CodegenConstants.USE_SINGLE_REQUEST_PARAMETER, "true"
))
.setInputSpec("src/test/resources/3_1/java/petstore.yaml")
.setOutputDir(output.toString().replace("\\", "/"));
@ -3215,7 +3215,7 @@ public class JavaClientCodegenTest {
.setLibrary(JavaClientCodegen.RESTCLIENT)
.setAdditionalProperties(Map.of(
CodegenConstants.API_PACKAGE, "xyz.abcdef.api",
CodegenConstants.USE_SINGLE_REQUEST_PARAMETER, true
CodegenConstants.USE_SINGLE_REQUEST_PARAMETER, "true"
))
.setInputSpec("src/test/resources/3_0/duplicated_operationid.yaml")
.setOutputDir(output.toString().replace("\\", "/"));
@ -3250,7 +3250,7 @@ public class JavaClientCodegenTest {
.setLibrary(JavaClientCodegen.WEBCLIENT)
.setAdditionalProperties(Map.of(
CodegenConstants.API_PACKAGE, "xyz.abcdef.api",
CodegenConstants.USE_SINGLE_REQUEST_PARAMETER, true
CodegenConstants.USE_SINGLE_REQUEST_PARAMETER, "true"
))
.setInputSpec("src/test/resources/3_1/java/petstore.yaml")
.setOutputDir(output.toString().replace("\\", "/"));
@ -3272,6 +3272,35 @@ public class JavaClientCodegenTest {
);
}
@Test public void testWebClientWithUseSingleRequestParameter_static() {
final Path output = newTempFolder();
final CodegenConfigurator configurator = new CodegenConfigurator()
.setGeneratorName("java")
.setLibrary(JavaClientCodegen.WEBCLIENT)
.setAdditionalProperties(Map.of(
CodegenConstants.API_PACKAGE, "xyz.abcdef.api",
CodegenConstants.USE_SINGLE_REQUEST_PARAMETER, "static"
))
.setInputSpec("src/test/resources/3_1/java/petstore.yaml")
.setOutputDir(output.toString().replace("\\", "/"));
new DefaultGenerator().opts(configurator.toClientOptInput()).generate();
TestUtils.assertFileContains(
output.resolve("src/main/java/xyz/abcdef/api/PetApi.java"),
"public static class DeletePetRequest {",
"DeletePetRequest(Long petId, String apiKey)",
"Long petId()",
"String apiKey()",
"public Mono<Void> deletePet(DeletePetRequest requestParameters) throws WebClientResponseException {",
"public Mono<ResponseEntity<Void>> deletePetWithHttpInfo(DeletePetRequest requestParameters) throws WebClientResponseException {",
"public ResponseSpec deletePetWithResponseSpec(DeletePetRequest requestParameters) throws WebClientResponseException {",
"public Mono<Void> deletePet(Long petId, String apiKey) throws WebClientResponseException {",
"public Mono<ResponseEntity<Void>> deletePetWithHttpInfo(Long petId, String apiKey) throws WebClientResponseException {",
"public ResponseSpec deletePetWithResponseSpec(Long petId, String apiKey) throws WebClientResponseException {"
);
}
@Test
public void testGenerateParameterId() {
final Path output = newTempFolder();