Skip to content

Commit 0afdff5

Browse files
committed
write OpenAPI document
1 parent 1d2967f commit 0afdff5

10 files changed

Lines changed: 307 additions & 0 deletions

File tree

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* Copyright 2025 https://github.com/openapi-processor/openapi-parser
3+
* PDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.openapiprocessor.interfaces;
7+
8+
import java.io.IOException;
9+
10+
/**
11+
* write a document. Should handle security if required.
12+
*/
13+
public interface Writer {
14+
15+
/**
16+
* write a document.
17+
*
18+
* @param document the document
19+
* @throws IOException if writing fails.
20+
*/
21+
22+
void write(Object document) throws IOException;
23+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright 2025 https://github.com/openapi-processor/openapi-parser
3+
* PDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.openapiprocessor.jackson;
7+
8+
import com.fasterxml.jackson.core.JsonFactory;
9+
import com.fasterxml.jackson.databind.ObjectMapper;
10+
import io.openapiprocessor.interfaces.Writer;
11+
12+
import java.io.IOException;
13+
14+
public class JacksonJsonWriter implements Writer {
15+
private final java.io.Writer writer;
16+
private final ObjectMapper mapper;
17+
18+
public JacksonJsonWriter(java.io.Writer writer) {
19+
this.writer = writer;
20+
21+
JsonFactory json = JsonFactory.builder()
22+
.build();
23+
24+
mapper = new ObjectMapper(json);
25+
}
26+
27+
public JacksonJsonWriter(java.io.Writer writer, JsonFactory json) {
28+
this.writer = writer;
29+
mapper = new ObjectMapper(json);
30+
}
31+
32+
@Override
33+
public void write(Object document) throws IOException {
34+
mapper.writerWithDefaultPrettyPrinter()
35+
.writeValue(writer, document);
36+
}
37+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright 2025 https://github.com/openapi-processor/openapi-parser
3+
* PDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.openapiprocessor.jackson;
7+
8+
import com.fasterxml.jackson.databind.ObjectMapper;
9+
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
10+
import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator;
11+
import io.openapiprocessor.interfaces.Writer;
12+
13+
import java.io.IOException;
14+
15+
public class JacksonYamlWriter implements Writer {
16+
private final java.io.Writer writer;
17+
private final ObjectMapper mapper;
18+
19+
public JacksonYamlWriter(java.io.Writer writer) {
20+
this.writer = writer;
21+
22+
YAMLFactory yaml = YAMLFactory.builder()
23+
.disable(YAMLGenerator.Feature.WRITE_DOC_START_MARKER)
24+
.enable(YAMLGenerator.Feature.MINIMIZE_QUOTES)
25+
.build();
26+
27+
mapper = new ObjectMapper(yaml);
28+
}
29+
30+
public JacksonYamlWriter(java.io.Writer writer, YAMLFactory yaml) {
31+
this.writer = writer;
32+
mapper = new ObjectMapper(yaml);
33+
}
34+
35+
@Override
36+
public void write(Object document) throws IOException {
37+
mapper.writerWithDefaultPrettyPrinter()
38+
.writeValue(writer, document);
39+
}
40+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
* Copyright 2025 https://github.com/openapi-processor/openapi-parser
3+
* PDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.openapiprocessor.jackson
7+
8+
import io.kotest.core.spec.style.StringSpec
9+
import io.kotest.matchers.shouldBe
10+
import java.io.StringWriter
11+
12+
class JacksonJsonWriterSpec : StringSpec({
13+
14+
"writes document to json" {
15+
val document = mapOf<String, Any>(
16+
"openapi" to "3.1.0",
17+
"info" to mapOf(
18+
"title" to "this is a title",
19+
"version" to "1.0"),
20+
"paths" to mapOf(
21+
"/foo" to mapOf(
22+
"get" to mapOf(
23+
"responses" to mapOf(
24+
"204" to mapOf(
25+
"description" to "this is a description"
26+
))))))
27+
28+
val out = StringWriter()
29+
val writer = JacksonJsonWriter(out)
30+
writer.write(document)
31+
32+
out.toString() shouldBe """
33+
{
34+
"openapi" : "3.1.0",
35+
"info" : {
36+
"title" : "this is a title",
37+
"version" : "1.0"
38+
},
39+
"paths" : {
40+
"/foo" : {
41+
"get" : {
42+
"responses" : {
43+
"204" : {
44+
"description" : "this is a description"
45+
}
46+
}
47+
}
48+
}
49+
}
50+
}
51+
""".trimIndent()
52+
}
53+
})
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright 2025 https://github.com/openapi-processor/openapi-parser
3+
* PDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.openapiprocessor.jackson
7+
8+
import io.kotest.core.spec.style.StringSpec
9+
import io.kotest.matchers.shouldBe
10+
import java.io.StringWriter
11+
12+
class JacksonYamlWriterSpec : StringSpec({
13+
14+
"writes document to yaml" {
15+
val document = mapOf<String, Any>(
16+
"openapi" to "3.1.0",
17+
"info" to mapOf(
18+
"title" to "this is a title",
19+
"version" to "1.0"),
20+
"paths" to mapOf(
21+
"/foo" to mapOf(
22+
"get" to mapOf(
23+
"responses" to mapOf(
24+
"204" to mapOf(
25+
"description" to "this is a description"
26+
))))))
27+
28+
val out = StringWriter()
29+
val writer = JacksonYamlWriter(out)
30+
writer.write(document)
31+
32+
out.toString() shouldBe """
33+
openapi: 3.1.0
34+
info:
35+
title: this is a title
36+
version: 1.0
37+
paths:
38+
/foo:
39+
get:
40+
responses:
41+
"204":
42+
description: this is a description
43+
44+
""".trimIndent()
45+
}
46+
})
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Copyright 2025 https://github.com/openapi-processor/openapi-parser
3+
* PDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.openapiprocessor.snakeyaml;
7+
8+
import io.openapiprocessor.interfaces.Writer;
9+
import org.yaml.snakeyaml.DumperOptions;
10+
import org.yaml.snakeyaml.Yaml;
11+
12+
public class SnakeYamlWriter implements Writer {
13+
private final java.io.Writer writer;
14+
private final Yaml yaml;
15+
16+
public SnakeYamlWriter(java.io.Writer writer) {
17+
this.writer = writer;
18+
19+
DumperOptions options = new DumperOptions();
20+
options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
21+
options.setPrettyFlow(true);
22+
options.setIndent(2);
23+
yaml = new Yaml(options);
24+
}
25+
26+
public SnakeYamlWriter(java.io.Writer writer, Yaml yaml) {
27+
this.writer = writer;
28+
this.yaml = yaml;
29+
}
30+
31+
@Override
32+
public void write(Object document) {
33+
yaml.dump(document, writer);
34+
}
35+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* Copyright 2025 https://github.com/openapi-processor/openapi-parser
3+
* PDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.openapiprocessor.snakeyaml
7+
8+
import io.kotest.core.spec.style.StringSpec
9+
import io.kotest.matchers.shouldBe
10+
import java.io.StringWriter
11+
12+
class SnakeYamlWriterSpec : StringSpec({
13+
14+
"writes document to yaml" {
15+
val document = mapOf<String, Any>(
16+
"openapi" to "3.1.0",
17+
"info" to mapOf(
18+
"title" to "this is a title",
19+
"version" to "1.0"),
20+
"paths" to mapOf(
21+
"/foo" to mapOf(
22+
"get" to mapOf(
23+
"responses" to mapOf(
24+
"204" to mapOf(
25+
"description" to "this is a description"
26+
))))))
27+
28+
val out = StringWriter()
29+
val writer = SnakeYamlWriter(out)
30+
writer.write(document)
31+
32+
// can't get it to write same output as jackson
33+
// - jackson doesn't quote the version value
34+
// - jackson uses double quotes for the response status code
35+
out.toString() shouldBe """
36+
openapi: 3.1.0
37+
info:
38+
title: this is a title
39+
version: '1.0'
40+
paths:
41+
/foo:
42+
get:
43+
responses:
44+
'204':
45+
description: this is a description
46+
47+
""".trimIndent()
48+
}
49+
})

openapi-parser/src/main/java/io/openapiparser/OpenApiResult.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@
55

66
package io.openapiparser;
77

8+
import io.openapiprocessor.interfaces.Writer;
89
import io.openapiprocessor.jsonschema.schema.SchemaStore;
910
import io.openapiprocessor.jsonschema.validator.Validator;
1011

12+
import java.io.IOException;
1113
import java.util.Collection;
1214

1315
/**
@@ -45,6 +47,14 @@ enum Version { V30, V31 }
4547
*/
4648
Object bundle();
4749

50+
/**
51+
* Experimental. Write the document. This will produce useful results only if the document is a single file
52+
* document. Bundling can be used to create a single file document.
53+
*
54+
* @param writer the target writer
55+
*/
56+
void write(Writer writer) throws IOException;
57+
4858
/**
4959
* apply an OpenAPI overlay to the OpenAPI document.
5060
* @param overlay the overlay document

openapi-parser/src/main/java/io/openapiparser/OpenApiResult30.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,14 @@
66
package io.openapiparser;
77

88
import io.openapiparser.model.v30.OpenApi;
9+
import io.openapiprocessor.interfaces.Writer;
910
import io.openapiprocessor.jsonschema.ouput.OutputConverter;
1011
import io.openapiprocessor.jsonschema.ouput.OutputUnit;
1112
import io.openapiprocessor.jsonschema.schema.*;
1213
import io.openapiprocessor.jsonschema.validator.Validator;
1314
import io.openapiprocessor.jsonschema.validator.steps.ValidationStep;
1415

16+
import java.io.IOException;
1517
import java.util.Collection;
1618
import java.util.Collections;
1719
import java.util.List;
@@ -54,6 +56,11 @@ public Object bundle () {
5456
return new OpenApiBundler (context, documents, root).bundle ();
5557
}
5658

59+
@Override
60+
public void write(Writer writer) throws IOException {
61+
writer.write(root.getRawValues());
62+
}
63+
5764
@Override
5865
public void apply(OverlayResult overlayResult) {
5966
// todo

openapi-parser/src/main/java/io/openapiparser/OpenApiResult31.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import com.jayway.jsonpath.JsonPath;
99
import io.openapiparser.model.ov10.Overlay;
1010
import io.openapiparser.model.v31.OpenApi;
11+
import io.openapiprocessor.interfaces.Writer;
1112
import io.openapiprocessor.jsonschema.ouput.OutputConverter;
1213
import io.openapiprocessor.jsonschema.ouput.OutputUnit;
1314
import io.openapiprocessor.jsonschema.schema.*;
@@ -16,6 +17,7 @@
1617
import org.slf4j.Logger;
1718
import org.slf4j.LoggerFactory;
1819

20+
import java.io.IOException;
1921
import java.util.Collection;
2022
import java.util.Collections;
2123
import java.util.List;
@@ -60,6 +62,11 @@ public Object bundle () {
6062
return new OpenApiBundler (context, documents, root).bundle ();
6163
}
6264

65+
@Override
66+
public void write(Writer writer) throws IOException {
67+
writer.write(root.getRawValues());
68+
}
69+
6370
@Override
6471
public void apply(OverlayResult overlayResult) {
6572
Overlay overlay = overlayResult.getModel(Overlay.class);

0 commit comments

Comments
 (0)