Repository: OpenAPITools/openapi-generator (language: python)

Issue:
[BUG]  [JAVA] content type in feign client is url-escaped, charset=utf-8 doesn't work properly
#### Bug Report Checklist

- [x] Have you provided a full/minimal spec to reproduce the issue?
- [x] Have you validated the input using an OpenAPI validator ([example](https://apidevtools.org/swagger-parser/online/))?
- [x] Have you [tested with the latest master](https://github.com/OpenAPITools/openapi-generator/wiki/FAQ#how-to-test-with-the-latest-master-of-openapi-generator) to confirm the issue still exists?
- [x] Have you searched for related issues/PRs?
- [x] What's the actual output vs expected output?
- [ ] [Optional] Sponsorship to speed up the bug fix or feature request ([example](https://github.com/OpenAPITools/openapi-generator/issues/6178))

<!--
Please follow the issue template below for bug reports.
Also please indicate in the issue title which language/library is concerned. Eg:  [BUG][JAVA] Bug generating foo with bar 
-->

##### Description

This Bug is analog to the one Mentioned [here](https://github.com/OpenAPITools/openapi-generator/issues/17864)

##### Generation Details
generator run:

`java -jar openapi-generator-cli-<version>.jar generate -g java -i test_yaml.yaml -p library=feign`

Output is: 
`  @Headers({
    "Content-Type: application/json;charset&#x3D;utf-8",
    "Accept: application/json;charset&#x3D;utf-8"
  })`
  
This throws a NullpointerException:
  
`java.lang.NullPointerException: Cannot invoke "okhttp3.MediaType.charset(java.nio.charset.Charset)" because "mediaType" is null
`
##### Steps to reproduce

<!-- unambiguous set of steps to reproduce the bug.-->

##### Related issues/PRs

 [This Issue](https://github.com/OpenAPITools/openapi-generator/issues/17864)

##### Suggest a fix
Expected Output:
`  @Headers({
    "Content-Type: application/json;charset=utf-8",
    "Accept: application/json;charset=utf-8"
  })`



Discussion / hints:

Fix patch:
diff --git a/modules/openapi-generator/src/main/resources/Java/libraries/feign/api.mustache b/modules/openapi-generator/src/main/resources/Java/libraries/feign/api.mustache
index 3d34681ea3f6..d67de9a28dad 100644
--- a/modules/openapi-generator/src/main/resources/Java/libraries/feign/api.mustache
+++ b/modules/openapi-generator/src/main/resources/Java/libraries/feign/api.mustache
@@ -47,8 +47,8 @@ public interface {{classname}} extends ApiClient.Api {
 {{/isDeprecated}}
   @RequestLine("{{httpMethod}} {{{path}}}{{#hasQueryParams}}?{{/hasQueryParams}}{{#queryParams}}{{baseName}}={{=<% %>=}}{<%paramName%>}<%={{ }}=%>{{^-last}}&{{/-last}}{{/queryParams}}")
   @Headers({
-{{#vendorExtensions.x-content-type}}    "Content-Type: {{vendorExtensions.x-content-type}}",
-{{/vendorExtensions.x-content-type}}    "Accept: {{#vendorExtensions.x-accepts}}{{.}}{{^-last}},{{/-last}}{{/vendorExtensions.x-accepts}}",{{#headerParams}}
+{{#vendorExtensions.x-content-type}}    "Content-Type: {{{vendorExtensions.x-content-type}}}",
+{{/vendorExtensions.x-content-type}}    "Accept: {{#vendorExtensions.x-accepts}}{{{.}}}{{^-last}},{{/-last}}{{/vendorExtensions.x-accepts}}",{{#headerParams}}
     "{{baseName}}: {{=<% %>=}}{<%paramName%>}<%={{ }}=%>"{{^-last}},
     {{/-last}}{{/headerParams}}
   })
@@ -77,8 +77,8 @@ public interface {{classname}} extends ApiClient.Api {
 {{/isDeprecated}}
   @RequestLine("{{httpMethod}} {{{path}}}{{#hasQueryParams}}?{{/hasQueryParams}}{{#queryParams}}{{baseName}}={{=<% %>=}}{<%paramName%>}<%={{ }}=%>{{^-last}}&{{/-last}}{{/queryParams}}")
   @Headers({
-{{#vendorExtensions.x-content-type}}    "Content-Type: {{vendorExtensions.x-content-type}}",
-{{/vendorExtensions.x-content-type}}    "Accept: {{#vendorExtensions.x-accepts}}{{.}}{{^-last}},{{/-last}}{{/vendorExtensions.x-accepts}}",{{#headerParams}}
+{{#vendorExtensions.x-content-type}}    "Content-Type: {{{vendorExtensions.x-content-type}}}",
+{{/vendorExtensions.x-content-type}}    "Accept: {{#vendorExtensions.x-accepts}}{{{.}}}{{^-last}},{{/-last}}{{/vendorExtensions.x-accepts}}",{{#headerParams}}
     "{{baseName}}: {{=<% %>=}}{<%paramName%>}<%={{ }}=%>"{{^-last}},
     {{/-last}}{{/headerParams}}
   })
@@ -122,8 +122,8 @@ public interface {{classname}} extends ApiClient.Api {
   {{/isDeprecated}}
   @RequestLine("{{httpMethod}} {{{path}}}?{{#queryParams}}{{baseName}}={{=<% %>=}}{<%paramName%>}<%={{ }}=%>{{^-last}}&{{/-last}}{{/queryParams}}")
   @Headers({
-{{#vendorExtensions.x-content-type}}  "Content-Type: {{vendorExtensions.x-content-type}}",
-{{/vendorExtensions.x-content-type}}  "Accept: {{#vendorExtensions.x-accepts}}{{.}}{{^-last}},{{/-last}}{{/vendorExtensions.x-accepts}}",{{#headerParams}}
+{{#vendorExtensions.x-content-type}}  "Content-Type: {{{vendorExtensions.x-content-type}}}",
+{{/vendorExtensions.x-content-type}}  "Accept: {{#vendorExtensions.x-accepts}}{{{.}}}{{^-last}},{{/-last}}{{/vendorExtensions.x-accepts}}",{{#headerParams}}
       "{{baseName}}: {{=<% %>=}}{<%paramName%>}<%={{ }}=%>"{{^-last}},
       {{/-last}}{{/headerParams}}
   })
@@ -162,8 +162,8 @@ public interface {{classname}} extends ApiClient.Api {
   {{/isDeprecated}}
       @RequestLine("{{httpMethod}} {{{path}}}?{{#queryParams}}{{baseName}}={{=<% %>=}}{<%paramName%>}<%={{ }}=%>{{^-last}}&{{/-last}}{{/queryParams}}")
       @Headers({
-  {{#vendorExtensions.x-content-type}}  "Content-Type: {{vendorExtensions.x-content-type}}",
-  {{/vendorExtensions.x-content-type}}  "Accept: {{#vendorExtensions.x-accepts}}{{.}}{{^-last}},{{/-last}}{{/vendorExtensions.x-accepts}}",{{#headerParams}}
+  {{#vendorExtensions.x-content-type}}  "Content-Type: {{{vendorExtensions.x-content-type}}}",
+  {{/vendorExtensions.x-content-type}}  "Accept: {{#vendorExtensions.x-accepts}}{{{.}}}{{^-last}},{{/-last}}{{/vendorExtensions.x-accepts}}",{{#headerParams}}
           "{{baseName}}: {{=<% %>=}}{<%paramName%>}<%={{ }}=%>"{{^-last}},
       {{/-last}}{{/headerParams}}
       })


Test patch:
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 42dc774e8546..1bbd795f6510 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
@@ -1273,6 +1273,34 @@ private Optional<CodegenOperation> getByCriteria(List<CodegenOperation> codegenO
             );
     }
 
+    /**
+     * see https://github.com/OpenAPITools/openapi-generator/issues/19895
+     */
+    @Test public void testCharsetInContentTypeCorrectlyEncodedForFeignApi_issue19895() {
+        final Path output = newTempFolder();
+        final CodegenConfigurator configurator = new CodegenConfigurator()
+                .setGeneratorName("java")
+                .setLibrary(FEIGN)
+                .setInputSpec("src/test/resources/3_0/issue_19895.yaml")
+                .setOutputDir(output.toString().replace("\\", "/"));
+
+        final ClientOptInput clientOptInput = configurator.toClientOptInput();
+        DefaultGenerator generator = new DefaultGenerator();
+        List<File> files = generator.opts(clientOptInput).generate();
+
+        validateJavaSourceFiles(files);
+        var defaultApiFile = output.resolve("src/main/java/org/openapitools/client/api/DefaultApi.java");
+        assertThat(files).contains(defaultApiFile.toFile());
+        assertThat(defaultApiFile).content()
+                .doesNotContain(
+                        "Content-Type: application/json;charset&#x3D;utf-8",
+                        "Accept: application/json;charset&#x3D;utf-8")
+                .contains(
+                        "Content-Type: application/json;charset=utf-8",
+                        "Accept: application/json;charset=utf-8"
+                );
+    }
+
     /**
      * See https://github.com/OpenAPITools/openapi-generator/issues/6715
      * <p>
diff --git a/modules/openapi-generator/src/test/resources/3_0/issue_19895.yaml b/modules/openapi-generator/src/test/resources/3_0/issue_19895.yaml
new file mode 100644
index 000000000000..ba20dcd10dbc
--- /dev/null
+++ b/modules/openapi-generator/src/test/resources/3_0/issue_19895.yaml
@@ -0,0 +1,54 @@
+openapi: 3.0.1
+info:
+  title: sample spec
+  description: "Sample spec"
+  version: 0.0.1
+
+paths:
+  /v1/sample:
+    post:
+      operationId: samplePost
+      requestBody:
+        content:
+          application/json;charset=utf-8:
+            schema:
+              properties:
+                name:
+                  type: string
+              type: object
+      responses:
+        200:
+          description: success
+          content:
+            application/json;charset=utf-8:
+              schema:
+                properties:
+                  response:
+                    type: object
+                type: object
+    put:
+      operationId: samplePut
+      parameters:
+        - in: query
+          name: limit
+          schema:
+              type: string
+      requestBody:
+        content:
+          application/json;charset=utf-8:
+            schema:
+              properties:
+                name:
+                  type: string
+              type: object
+      responses:
+        200:
+          description: success
+          content:
+            application/json;charset=utf-8:
+              schema:
+                properties:
+                  response:
+                    type: object
+                type: object
+