diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/serializer/ByteArraySerializer.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/serializer/ByteArraySerializer.java
new file mode 100644
index 000000000000..d6714798f369
--- /dev/null
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/serializer/ByteArraySerializer.java
@@ -0,0 +1,31 @@
+package org.openapitools.codegen.serializer;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * Serializes {@code byte[]} as a UTF-8 string, preserving the original base64 representation
+ * of an OpenAPI {@code format: byte} example. swagger-parser stores {@code format: byte}
+ * examples as the raw bytes of the input base64 string (not the decoded content), so writing
+ * those bytes back as a string round-trips to the user's original value. This prevents
+ * Jackson's default YAML behavior of emitting a {@code !!binary} block with a re-encoded payload.
+ *
+ *
Load-bearing assumption: this only round-trips correctly because swagger-parser stores the
+ * raw input bytes. If swagger-parser ever decodes {@code format: byte} examples internally, this
+ * serializer must switch to {@code Base64.getEncoder().encodeToString(value)}.
+ */
+public class ByteArraySerializer extends StdSerializer {
+
+ public ByteArraySerializer() {
+ super(byte[].class);
+ }
+
+ @Override
+ public void serialize(byte[] value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
+ gen.writeString(new String(value, StandardCharsets.UTF_8));
+ }
+}
diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/serializer/SerializerUtils.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/serializer/SerializerUtils.java
index 833ad2e24180..2799f9828d61 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/serializer/SerializerUtils.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/serializer/SerializerUtils.java
@@ -66,6 +66,7 @@ public static String toJsonString(OpenAPI openAPI) {
private static SimpleModule createModule() {
SimpleModule module = new SimpleModule("OpenAPIModule");
module.addSerializer(OpenAPI.class, new OpenAPISerializer());
+ module.addSerializer(byte[].class, new ByteArraySerializer());
return module;
}
}
diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/yaml/YamlGeneratorTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/yaml/YamlGeneratorTest.java
index 6c26f20f50f3..1bbc8dc39fce 100644
--- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/yaml/YamlGeneratorTest.java
+++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/yaml/YamlGeneratorTest.java
@@ -18,6 +18,8 @@
package org.openapitools.codegen.yaml;
import io.swagger.v3.oas.models.OpenAPI;
+import io.swagger.v3.oas.models.media.Schema;
+import io.swagger.v3.oas.models.parameters.Parameter;
import org.openapitools.codegen.ClientOptInput;
import org.openapitools.codegen.DefaultGenerator;
import org.openapitools.codegen.TestUtils;
@@ -27,6 +29,7 @@
import org.testng.annotations.Test;
import java.io.File;
+import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
@@ -149,4 +152,37 @@ public void testIssue18622() throws Exception {
Assert.assertEquals(actual.getComponents().getSchemas().get("myresponse").getExample(),
expected.getComponents().getSchemas().get("myresponse").getExample());
}
+
+ @Test
+ public void testIssue19929() throws Exception {
+ Map properties = new HashMap<>();
+ properties.put(OpenAPIYamlGenerator.OUTPUT_NAME, "issue_19929.yaml");
+
+ File output = Files.createTempDirectory("issue_19929").toFile();
+ output.deleteOnExit();
+
+ final CodegenConfigurator configurator = new CodegenConfigurator()
+ .setGeneratorName("openapi-yaml")
+ .setAdditionalProperties(properties)
+ .setInputSpec("src/test/resources/3_0/issue_19929.yaml")
+ .setOutputDir(output.getAbsolutePath().replace("\\", "/"));
+
+ final ClientOptInput clientOptInput = configurator.toClientOptInput();
+ DefaultGenerator generator = new DefaultGenerator();
+ generator.opts(clientOptInput).generate();
+
+ Path generated = Path.of(output.getAbsolutePath(), "issue_19929.yaml");
+ String generatedYaml = new String(Files.readAllBytes(generated), StandardCharsets.UTF_8);
+
+ Assert.assertFalse(generatedYaml.contains("!!binary"),
+ "openapi-yaml output must not emit !!binary for format: byte examples. Output was:\n" + generatedYaml);
+ Assert.assertTrue(generatedYaml.contains("aGVsbG8K"),
+ "openapi-yaml output should preserve the original base64 example. Output was:\n" + generatedYaml);
+
+ OpenAPI roundTripped = TestUtils.parseSpec(generated.toString());
+ Parameter coordinates = roundTripped.getPaths().get("/operationsTest/").getGet().getParameters().get(0);
+ Schema> dataSchema = (Schema>) coordinates.getContent().get("application/json").getSchema().getProperties().get("data");
+ byte[] exampleBytes = (byte[]) dataSchema.getExample();
+ Assert.assertEquals(new String(exampleBytes, StandardCharsets.UTF_8), "aGVsbG8K");
+ }
}
diff --git a/modules/openapi-generator/src/test/resources/3_0/issue_19929.yaml b/modules/openapi-generator/src/test/resources/3_0/issue_19929.yaml
new file mode 100644
index 000000000000..0aa33bcb0c95
--- /dev/null
+++ b/modules/openapi-generator/src/test/resources/3_0/issue_19929.yaml
@@ -0,0 +1,24 @@
+openapi: 3.0.3
+info:
+ title: TestRestService2.v2
+ description: Hello
+ version: 2.2.2
+paths:
+ /operationsTest/:
+ get:
+ responses:
+ '200':
+ description: Empty response.
+ parameters:
+ - in: query
+ name: coordinates
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ data:
+ type: string
+ format: byte
+ description: 'Base64 encoded JSON with description of audited operation.'
+ example: 'aGVsbG8K'