Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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.
*
* <p>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<byte[]> {

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));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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<String, Object> 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");
}
}
24 changes: 24 additions & 0 deletions modules/openapi-generator/src/test/resources/3_0/issue_19929.yaml
Original file line number Diff line number Diff line change
@@ -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'
Loading