From c8173e6c3e393dfd8be3268c3f09502e9107fffb Mon Sep 17 00:00:00 2001
From: Oleh Kurpiak <oleh.kurpiak@gmail.com>
Date: Mon, 21 Nov 2022 10:20:35 +0200
Subject: [PATCH 1/2] [Java][WebClient] global blocking operations config

---
 docs/generators/java.md                       |  1 +
 .../codegen/languages/JavaClientCodegen.java  | 18 ++++++++++++
 .../codegen/java/JavaClientCodegenTest.java   | 29 +++++++++++++++++++
 ...ith-fake-endpoints-models-for-testing.yaml |  1 +
 .../petstore/java/feign/api/openapi.yaml      |  1 +
 .../petstore/java/webclient/api/openapi.yaml  |  1 +
 .../src/main/resources/META-INF/openapi.yml   |  1 +
 .../src/main/resources/META-INF/openapi.yml   |  1 +
 8 files changed, 53 insertions(+)

diff --git a/docs/generators/java.md b/docs/generators/java.md
index 63e46d8ed38..43a723d2ed5 100644
--- a/docs/generators/java.md
+++ b/docs/generators/java.md
@@ -90,6 +90,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
 |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 support 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|
 |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|
 
 ## SUPPORTED VENDOR EXTENSIONS
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 a0aae6cc179..b1b3e007e06 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
@@ -91,6 +91,7 @@ public class JavaClientCodegen extends AbstractJavaCodegen
     public static final String MICROPROFILE_REST_CLIENT_DEFAULT_ROOT_PACKAGE = "javax";
     public static final String MICROPROFILE_DEFAULT = "default";
     public static final String MICROPROFILE_KUMULUZEE = "kumuluzee";
+    public static final String WEBCLIENT_BLOCKING_OPERATIONS = "webclientBlockingOperations";
 
     public static final String SERIALIZATION_LIBRARY_GSON = "gson";
     public static final String SERIALIZATION_LIBRARY_JACKSON = "jackson";
@@ -126,6 +127,7 @@ public class JavaClientCodegen extends AbstractJavaCodegen
     protected String rootJavaEEPackage;
     protected Map<String, MpRestClientVersion> mpRestClientVersions = new HashMap<>();
     protected boolean useSingleRequestParameter = false;
+    protected boolean webclientBlockingOperations = false;
 
     private static class MpRestClientVersion {
         public final String rootPackage;
@@ -204,6 +206,7 @@ public class JavaClientCodegen extends AbstractJavaCodegen
         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 support this option."));
+        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));
 
         supportedLibraries.put(JERSEY1, "HTTP client: Jersey client 1.19.x. JSON processing: Jackson 2.9.x. Enable gzip request encoding using '-DuseGzipFeature=true'. IMPORTANT NOTE: jersey 1.x is no longer actively maintained so please upgrade to 'jersey3' or other HTTP libraries instead.");
         supportedLibraries.put(JERSEY2, "HTTP client: Jersey client 2.25.1. JSON processing: Jackson 2.9.x");
@@ -413,6 +416,9 @@ public class JavaClientCodegen extends AbstractJavaCodegen
             this.setErrorObjectType(additionalProperties.get(ERROR_OBJECT_TYPE).toString());
         }
         additionalProperties.put(ERROR_OBJECT_TYPE, errorObjectType);
+        if (additionalProperties.containsKey(WEBCLIENT_BLOCKING_OPERATIONS)) {
+            this.webclientBlockingOperations = Boolean.parseBoolean(additionalProperties.get(WEBCLIENT_BLOCKING_OPERATIONS).toString());
+        }
 
         final String invokerFolder = (sourceFolder + '/' + invokerPackage).replace(".", "/");
         final String apiFolder = (sourceFolder + '/' + apiPackage).replace(".", "/");
@@ -799,6 +805,18 @@ public class JavaClientCodegen extends AbstractJavaCodegen
             objs = AbstractJavaJAXRSServerCodegen.jaxrsPostProcessOperations(objs);
         }
 
+        if (WEBCLIENT.equals(getLibrary())) {
+            OperationMap operations = objs.getOperations();
+            if (operations != null) {
+                List<CodegenOperation> ops = operations.getOperation();
+                for (CodegenOperation operation : ops) {
+                    if (!operation.vendorExtensions.containsKey(VendorExtension.X_WEBCLIENT_BLOCKING.getName()) && webclientBlockingOperations) {
+                        operation.vendorExtensions.put(VendorExtension.X_WEBCLIENT_BLOCKING.getName(), true);
+                    }
+                }
+            }
+        }
+
         return objs;
     }
 
diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/JavaClientCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/JavaClientCodegenTest.java
index 81bdccd09a6..9efb3922036 100644
--- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/JavaClientCodegenTest.java
+++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/JavaClientCodegenTest.java
@@ -993,6 +993,35 @@ public class JavaClientCodegenTest {
         );
     }
 
+    @Test
+    public void shouldGenerateBlockingAndNoBlockingOperationsForWebClient() throws IOException {
+        Map<String, Object> properties = new HashMap<>();
+        properties.put(CodegenConstants.API_PACKAGE, "xyz.abcdef.api");
+        properties.put(JavaClientCodegen.WEBCLIENT_BLOCKING_OPERATIONS, true);
+
+        File output = Files.createTempDirectory("test").toFile();
+        output.deleteOnExit();
+
+        final CodegenConfigurator configurator = new CodegenConfigurator()
+            .setGeneratorName("java")
+            .setLibrary(JavaClientCodegen.WEBCLIENT)
+            .setAdditionalProperties(properties)
+            .setInputSpec("src/test/resources/3_0/petstore-with-fake-endpoints-models-for-testing.yaml")
+            .setOutputDir(output.getAbsolutePath().replace("\\", "/"));
+
+        DefaultGenerator generator = new DefaultGenerator();
+        Map<String, File> files = generator.opts(configurator.toClientOptInput()).generate().stream()
+            .collect(Collectors.toMap(File::getName, Function.identity()));
+
+        JavaFileAssert.assertThat(files.get("StoreApi.java"))
+            .assertMethod("getInventory").hasReturnType("Mono<Map<String, Integer>>") //explicit 'x-webclient-blocking: false' which overrides global config
+            .toFileAssert()
+            .assertMethod("placeOrder").hasReturnType("Order"); // use global config
+
+        JavaFileAssert.assertThat(files.get("PetApi.java"))
+            .assertMethod("findPetsByStatus").hasReturnType("List<Pet>"); // explicit 'x-webclient-blocking: true' which overrides global config
+    }
+
     @Test
     public void testAllowModelWithNoProperties() throws Exception {
         File output = Files.createTempDirectory("test").toFile();
diff --git a/modules/openapi-generator/src/test/resources/3_0/petstore-with-fake-endpoints-models-for-testing.yaml b/modules/openapi-generator/src/test/resources/3_0/petstore-with-fake-endpoints-models-for-testing.yaml
index 2401e56127f..6ec5b66e0e6 100644
--- a/modules/openapi-generator/src/test/resources/3_0/petstore-with-fake-endpoints-models-for-testing.yaml
+++ b/modules/openapi-generator/src/test/resources/3_0/petstore-with-fake-endpoints-models-for-testing.yaml
@@ -318,6 +318,7 @@ paths:
       summary: Returns pet inventories by status
       description: Returns a map of status codes to quantities
       operationId: getInventory
+      x-webclient-blocking: false
       responses:
         '200':
           description: successful operation
diff --git a/samples/client/petstore/java/feign/api/openapi.yaml b/samples/client/petstore/java/feign/api/openapi.yaml
index f9cbedf1e42..2828944e554 100644
--- a/samples/client/petstore/java/feign/api/openapi.yaml
+++ b/samples/client/petstore/java/feign/api/openapi.yaml
@@ -358,6 +358,7 @@ paths:
       summary: Returns pet inventories by status
       tags:
       - store
+      x-webclient-blocking: false
       x-accepts: application/json
   /store/order:
     post:
diff --git a/samples/client/petstore/java/webclient/api/openapi.yaml b/samples/client/petstore/java/webclient/api/openapi.yaml
index f9cbedf1e42..2828944e554 100644
--- a/samples/client/petstore/java/webclient/api/openapi.yaml
+++ b/samples/client/petstore/java/webclient/api/openapi.yaml
@@ -358,6 +358,7 @@ paths:
       summary: Returns pet inventories by status
       tags:
       - store
+      x-webclient-blocking: false
       x-accepts: application/json
   /store/order:
     post:
diff --git a/samples/server/petstore/java-helidon-server/mp/src/main/resources/META-INF/openapi.yml b/samples/server/petstore/java-helidon-server/mp/src/main/resources/META-INF/openapi.yml
index 7a9042f14f1..6667e32d34c 100644
--- a/samples/server/petstore/java-helidon-server/mp/src/main/resources/META-INF/openapi.yml
+++ b/samples/server/petstore/java-helidon-server/mp/src/main/resources/META-INF/openapi.yml
@@ -358,6 +358,7 @@ paths:
       summary: Returns pet inventories by status
       tags:
       - store
+      x-webclient-blocking: false
       x-accepts: application/json
   /store/order:
     post:
diff --git a/samples/server/petstore/java-helidon-server/se/src/main/resources/META-INF/openapi.yml b/samples/server/petstore/java-helidon-server/se/src/main/resources/META-INF/openapi.yml
index 7a9042f14f1..6667e32d34c 100644
--- a/samples/server/petstore/java-helidon-server/se/src/main/resources/META-INF/openapi.yml
+++ b/samples/server/petstore/java-helidon-server/se/src/main/resources/META-INF/openapi.yml
@@ -358,6 +358,7 @@ paths:
       summary: Returns pet inventories by status
       tags:
       - store
+      x-webclient-blocking: false
       x-accepts: application/json
   /store/order:
     post:
-- 
GitLab


From c3489a916b78096c845439c9b27816054b130139 Mon Sep 17 00:00:00 2001
From: Oleh Kurpiak <oleh.kurpiak@gmail.com>
Date: Mon, 5 Dec 2022 22:18:12 +0200
Subject: [PATCH 2/2] update samples

---
 samples/client/petstore/java/apache-httpclient/api/openapi.yaml | 1 +
 samples/client/petstore/java/native-async/api/openapi.yaml      | 1 +
 samples/client/petstore/java/native/api/openapi.yaml            | 1 +
 3 files changed, 3 insertions(+)

diff --git a/samples/client/petstore/java/apache-httpclient/api/openapi.yaml b/samples/client/petstore/java/apache-httpclient/api/openapi.yaml
index f9cbedf1e42..2828944e554 100644
--- a/samples/client/petstore/java/apache-httpclient/api/openapi.yaml
+++ b/samples/client/petstore/java/apache-httpclient/api/openapi.yaml
@@ -358,6 +358,7 @@ paths:
       summary: Returns pet inventories by status
       tags:
       - store
+      x-webclient-blocking: false
       x-accepts: application/json
   /store/order:
     post:
diff --git a/samples/client/petstore/java/native-async/api/openapi.yaml b/samples/client/petstore/java/native-async/api/openapi.yaml
index f9cbedf1e42..2828944e554 100644
--- a/samples/client/petstore/java/native-async/api/openapi.yaml
+++ b/samples/client/petstore/java/native-async/api/openapi.yaml
@@ -358,6 +358,7 @@ paths:
       summary: Returns pet inventories by status
       tags:
       - store
+      x-webclient-blocking: false
       x-accepts: application/json
   /store/order:
     post:
diff --git a/samples/client/petstore/java/native/api/openapi.yaml b/samples/client/petstore/java/native/api/openapi.yaml
index f9cbedf1e42..2828944e554 100644
--- a/samples/client/petstore/java/native/api/openapi.yaml
+++ b/samples/client/petstore/java/native/api/openapi.yaml
@@ -358,6 +358,7 @@ paths:
       summary: Returns pet inventories by status
       tags:
       - store
+      x-webclient-blocking: false
       x-accepts: application/json
   /store/order:
     post:
-- 
GitLab