From 40a312ce4be767f6a042eacf1ccddb986e411c3a Mon Sep 17 00:00:00 2001 From: George Gastaldi Date: Sat, 7 Oct 2023 14:06:44 -0300 Subject: [PATCH] Bring your own `ObjectWriter` to serialize the OpenAPI model (#1603) - Relates to #1600 --- .../openapi/runtime/io/OpenApiSerializer.java | 62 ++++++++++++++----- .../io/OpenApiParserAndSerializerTest.java | 28 +++++++++ 2 files changed, 75 insertions(+), 15 deletions(-) diff --git a/core/src/main/java/io/smallrye/openapi/runtime/io/OpenApiSerializer.java b/core/src/main/java/io/smallrye/openapi/runtime/io/OpenApiSerializer.java index b68066ac4..af135ace0 100644 --- a/core/src/main/java/io/smallrye/openapi/runtime/io/OpenApiSerializer.java +++ b/core/src/main/java/io/smallrye/openapi/runtime/io/OpenApiSerializer.java @@ -6,6 +6,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectWriter; import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator; @@ -22,6 +23,25 @@ public class OpenApiSerializer { private OpenApiSerializer() { } + /** + * Creates an {@link ObjectWriter} for the given format with the appropriate settings. + * + * @param objectMapper the {@link ObjectMapper} to use + * @param format the serialization format + * @return the {@link ObjectWriter} with the appropriate settings + */ + public static ObjectWriter createObjectWriter(ObjectMapper objectMapper, Format format) { + if (format == Format.JSON) { + return objectMapper.writerWithDefaultPrettyPrinter(); + } else { + YAMLFactory factory = new YAMLFactory(); + factory.enable(YAMLGenerator.Feature.MINIMIZE_QUOTES); + factory.enable(YAMLGenerator.Feature.ALWAYS_QUOTE_NUMBERS_AS_STRINGS); + factory.enable(YAMLGenerator.Feature.ALLOW_LONG_KEYS); + return objectMapper.writer().with(factory); + } + } + /** * Serializes the given OpenAPI object into either JSON or YAML and returns it as a string. * @@ -30,27 +50,39 @@ private OpenApiSerializer() { * @return OpenAPI object as a String * @throws IOException Errors in processing the JSON */ - public static final String serialize(OpenAPI openApi, Format format) throws IOException { + public static String serialize(OpenAPI openApi, Format format) throws IOException { + return serialize(openApi, new ObjectMapper(), format); + } + /** + * Serializes the given OpenAPI object into either JSON or YAML and returns it as a string. + * + * @param openApi the OpenAPI object + * @param objectMapper the {@link ObjectMapper} to use + * @param format the serialization format + * @return OpenAPI object as a String + * @throws IOException Errors in processing the JSON + */ + public static String serialize(OpenAPI openApi, ObjectMapper objectMapper, Format format) throws IOException { + ObjectWriter writer = createObjectWriter(objectMapper, format); + return serialize(openApi, writer); + } + + /** + * Serializes the given OpenAPI object using the provided {@link ObjectWriter} and returns it as a string. + * + * @param openApi the OpenAPI object + * @param writer the {@link ObjectWriter} to use + * @return OpenAPI object as a String + * @throws IOException Errors in processing the model + */ + public static String serialize(OpenAPI openApi, ObjectWriter writer) throws IOException { try { ObjectNode tree = JsonUtil.objectNode(); DefinitionWriter.writeOpenAPI(tree, openApi); - - ObjectMapper mapper; - if (format == Format.JSON) { - mapper = new ObjectMapper(); - return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(tree); - } else { - YAMLFactory factory = new YAMLFactory(); - factory.enable(YAMLGenerator.Feature.MINIMIZE_QUOTES); - factory.enable(YAMLGenerator.Feature.ALWAYS_QUOTE_NUMBERS_AS_STRINGS); - factory.enable(YAMLGenerator.Feature.ALLOW_LONG_KEYS); - mapper = new ObjectMapper(factory); - return mapper.writer().writeValueAsString(tree); - } + return writer.writeValueAsString(tree); } catch (JsonProcessingException e) { throw new IOException(e); } } - } diff --git a/core/src/test/java/io/smallrye/openapi/runtime/io/OpenApiParserAndSerializerTest.java b/core/src/test/java/io/smallrye/openapi/runtime/io/OpenApiParserAndSerializerTest.java index bec7f760b..91e394536 100644 --- a/core/src/test/java/io/smallrye/openapi/runtime/io/OpenApiParserAndSerializerTest.java +++ b/core/src/test/java/io/smallrye/openapi/runtime/io/OpenApiParserAndSerializerTest.java @@ -21,7 +21,11 @@ import org.junit.jupiter.api.Test; import org.skyscreamer.jsonassert.JSONAssert; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectWriter; import com.fasterxml.jackson.dataformat.yaml.JacksonYAMLParseException; +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; +import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator; import io.smallrye.openapi.api.constants.OpenApiConstants; @@ -581,4 +585,28 @@ void testSerializeExtraLongKeyConvertsToExplicit() throws IOException { String yaml = OpenApiSerializer.serialize(doc, Format.YAML); assertTrue(yaml.indexOf('?') >= 0); } + + @Test + void testJsonObjectWriter() throws Exception { + ObjectMapper objectMapper = new ObjectMapper(); + ObjectWriter writer = objectMapper.writer(); + OpenAPI doc = OASFactory.createOpenAPI(); + doc.addExtension("x-foo", "bar"); + String json = OpenApiSerializer.serialize(doc, writer); + assertJsonEquals("{\"x-foo\":\"bar\"}", json); + } + + @Test + void testYamlObjectWriter() throws Exception { + YAMLFactory factory = new YAMLFactory(); + factory.enable(YAMLGenerator.Feature.MINIMIZE_QUOTES); + factory.enable(YAMLGenerator.Feature.ALWAYS_QUOTE_NUMBERS_AS_STRINGS); + factory.enable(YAMLGenerator.Feature.ALLOW_LONG_KEYS); + ObjectMapper mapper = new ObjectMapper(factory); + ObjectWriter writer = mapper.writer(); + OpenAPI doc = OASFactory.createOpenAPI(); + doc.addExtension("x-foo", "bar"); + String yaml = OpenApiSerializer.serialize(doc, writer); + assertYamlEquals("x-foo: bar", yaml); + } }