Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(core): handle map schemas #839

Merged
merged 2 commits into from
Jul 12, 2024
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
Expand Up @@ -2,6 +2,7 @@
package io.github.springwolf.core.asyncapi.components.examples.walkers;

import io.github.springwolf.asyncapi.v3.model.channel.message.MessageReference;
import io.swagger.v3.oas.models.media.MapSchema;
import io.swagger.v3.oas.models.media.Schema;
import io.swagger.v3.oas.models.media.StringSchema;
import lombok.RequiredArgsConstructor;
Expand All @@ -28,6 +29,7 @@ public class DefaultSchemaWalker<T, R> implements SchemaWalker<R> {

Boolean DEFAULT_BOOLEAN_EXAMPLE = true;

String DEFAULT_MAP_KEY_EXAMPLE = "key";
String DEFAULT_STRING_EXAMPLE = "string";
Integer DEFAULT_INTEGER_EXAMPLE = 0;
Double DEFAULT_NUMBER_EXAMPLE = 1.1;
Expand Down Expand Up @@ -215,10 +217,11 @@ private Optional<T> buildFromObjectSchema(

final Optional<T> exampleValue;

Map<String, Schema> properties = schema.getProperties();
List<Schema> schemasAllOf = schema.getAllOf();
List<Schema> schemasAnyOf = schema.getAnyOf();
List<Schema> schemasOneOf = schema.getOneOf();
final Map<String, Schema> properties = schema.getProperties();
final Object additionalProperties = schema.getAdditionalProperties();
final List<Schema> schemasAllOf = schema.getAllOf();
final List<Schema> schemasAnyOf = schema.getAnyOf();
final List<Schema> schemasOneOf = schema.getOneOf();
if (properties != null) {
exampleValue = buildFromObjectSchemaWithProperties(name, properties, definitions, visited);
} else if (!CollectionUtils.isEmpty(schemasAllOf)) {
Expand All @@ -227,8 +230,9 @@ private Optional<T> buildFromObjectSchema(
exampleValue = buildExample(name, schemasAnyOf.get(0), definitions, visited);
} else if (!CollectionUtils.isEmpty(schemasOneOf)) {
exampleValue = buildExample(name, schemasOneOf.get(0), definitions, visited);
} else if (schema instanceof MapSchema && additionalProperties instanceof Schema<?>) {
exampleValue = buildMapExample(name, (Schema) additionalProperties, definitions, visited);
} else {
// i.e. A MapSchema is type=object, but has properties=null
exampleValue = exampleValueGenerator.createEmptyObjectExample();
}

Expand All @@ -237,6 +241,17 @@ private Optional<T> buildFromObjectSchema(
return exampleValue;
}

private Optional<T> buildMapExample(
String name, Schema additionalProperties, Map<String, Schema> definitions, Set<Schema> visited) {
T object = exampleValueGenerator.startObject(name);
Map<String, Schema> mapProperties = Map.of(DEFAULT_MAP_KEY_EXAMPLE, additionalProperties);
exampleValueGenerator.addPropertyExamples(
object, buildPropertyExampleListFromSchema(mapProperties, definitions, visited));
exampleValueGenerator.endObject();

return Optional.of(object);
}

private Optional<T> buildFromObjectSchemaWithProperties(
String name, Map<String, Schema> properties, Map<String, Schema> definitions, Set<Schema> visited) {
T object = exampleValueGenerator.startObject(name);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.Text;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
Expand All @@ -19,6 +20,7 @@
import javax.xml.transform.TransformerException;

import java.io.IOException;
import java.io.StringReader;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -223,7 +225,9 @@ private Document createDocument() throws ParserConfigurationException {
private Node readXmlString(String xmlString) {
try {
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
return documentBuilder.parse(xmlString);
InputSource is = new InputSource(new StringReader(xmlString));
Element element = documentBuilder.parse(is).getDocumentElement();
return document.importNode(element, true);
} catch (SAXException | IOException | ParserConfigurationException e) {
log.info("Unable to convert example to XMl Node: {}", xmlString, e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ private static class DocumentedSimpleFoo {
@Schema(description = "List without example")
private List<String> ls_plain;

@Schema(description = "Map with example", example = "<key1>value1</key1>")
@Schema(description = "Map with example", example = "<mss><key1>value1</key1></mss>")
private Map<String, String> mss;

@Schema(description = "Map without example")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import io.swagger.v3.oas.models.media.DateTimeSchema;
import io.swagger.v3.oas.models.media.EmailSchema;
import io.swagger.v3.oas.models.media.IntegerSchema;
import io.swagger.v3.oas.models.media.MapSchema;
import io.swagger.v3.oas.models.media.NumberSchema;
import io.swagger.v3.oas.models.media.ObjectSchema;
import io.swagger.v3.oas.models.media.PasswordSchema;
Expand Down Expand Up @@ -442,6 +443,20 @@ void object_with_allOf(TestInfo testInfo) throws JsonProcessingException {
assertThat(actualString).isEqualTo("{\"allOfField\":{\"field1\":\"string\",\"field2\":1.1}}");
}

@Test
void object_with_map(TestInfo testInfo) throws JsonProcessingException {
MapSchema mapSchema = new MapSchema();
mapSchema.setName(testInfo.getDisplayName());

Schema propertySchema = new StringSchema();
mapSchema.setAdditionalProperties(propertySchema);

JsonNode actual = jsonSchemaWalker.fromSchema(mapSchema, Map.of("Nested", propertySchema));
String actualString = jsonMapper.writeValueAsString(actual);

assertThat(actualString).isEqualTo("{\"key\":\"string\"}");
}

@Test
void schema_with_problematic_object_toString_example(TestInfo testInfo) throws JsonProcessingException {
ObjectSchema schema = new ObjectSchema();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,18 @@ void object_with_allOf() {
"<object_with_allOf><allOfField><field1>string</field1><field2>1.1</field2></allOfField></object_with_allOf>");
}

@Test
void object_with_map() {
MapSchema mapSchema = new MapSchema();
mapSchema.setName("object_with_map");

Schema propertySchema = new StringSchema();
mapSchema.setAdditionalProperties(propertySchema);

String actual = xmlSchemaWalker.fromSchema(mapSchema, Map.of("Nested", propertySchema));
assertThat(actual).isEqualTo("<object_with_map><key>string</key></object_with_map>");
}

@Test
void schema_with_problematic_object_toString_example() {
ObjectSchema schema = new ObjectSchema();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import io.swagger.v3.oas.models.media.DateTimeSchema;
import io.swagger.v3.oas.models.media.EmailSchema;
import io.swagger.v3.oas.models.media.IntegerSchema;
import io.swagger.v3.oas.models.media.MapSchema;
import io.swagger.v3.oas.models.media.NumberSchema;
import io.swagger.v3.oas.models.media.ObjectSchema;
import io.swagger.v3.oas.models.media.PasswordSchema;
Expand Down Expand Up @@ -490,6 +491,19 @@ void object_with_allOf(TestInfo testInfo) {
""");
}

@Test
void object_with_map(TestInfo testInfo) {
MapSchema mapSchema = new MapSchema();
mapSchema.setName(testInfo.getDisplayName());

Schema propertySchema = new StringSchema();
mapSchema.setAdditionalProperties(propertySchema);

String actualString = jsonSchemaWalker.fromSchema(mapSchema, Map.of("Nested", propertySchema));

assertThat(actualString).isEqualTo("key: \"string\"\n");
}

@Test
void schema_with_problematic_object_toString_example(TestInfo testInfo) {
ObjectSchema schema = new ObjectSchema();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import org.w3c.dom.Node;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertNotNull;

class ExampleXmlValueGeneratorTest {

Expand Down Expand Up @@ -63,4 +64,17 @@ void cacheShouldStoreExampleBySchemaName() {

assertThat(exampleFromCache).isNull();
}

@Test
void shouldCreateRawFromXmlString() {
// given
ExampleXmlValueGenerator generator = new ExampleXmlValueGenerator(new DefaultExampleXmlValueSerializer());
generator.initialize();

// when
Node result = generator.createRaw("<xml>example</xml>");

// then
assertNotNull(result);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,11 @@
"cyclic" : { }
},
"nli" : [ 0 ],
"nmfm" : { },
"nmfm" : {
"key" : {
"s" : "string"
}
},
"ns" : "string",
"nsm" : [ {
"s" : "string"
Expand Down Expand Up @@ -94,7 +98,11 @@
"cyclic" : { }
},
"nli" : [ 0 ],
"nmfm" : { },
"nmfm" : {
"key" : {
"s" : "string"
}
},
"ns" : "string",
"nsm" : [ {
"s" : "string"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,9 @@
"mss" : {
"key1" : "value1"
},
"mss_plain" : { },
"mss_plain" : {
"key" : "string"
},
"s" : "s value"
} ],
"required" : [ "dt", "f", "s" ]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"type" : "string"
}
},
"examples" : [ "<ComplexAttributesFoo b=\"true\" d=\"1.1\" dt=\"2015-07-20T15:49:04-07:00\" f=\"1.1\" i=\"0\" s=\"string\"><n ns=\"string\"><nli>0</nli><nmfm/><nsm><MyClassWithAttribute s_attribute=\"string\"><s_elem>string</s_elem></MyClassWithAttribute></nsm></n></ComplexAttributesFoo>" ]
"examples" : [ "<ComplexAttributesFoo b=\"true\" d=\"1.1\" dt=\"2015-07-20T15:49:04-07:00\" f=\"1.1\" i=\"0\" s=\"string\"><n ns=\"string\"><nli>0</nli><nmfm><key s_attribute=\"string\"><s_elem>string</s_elem></key></nmfm><nsm><MyClassWithAttribute s_attribute=\"string\"><s_elem>string</s_elem></MyClassWithAttribute></nsm></n></ComplexAttributesFoo>" ]
},
"io.github.springwolf.core.asyncapi.components.DefaultXmlComponentsServiceTest$ComplexAttributesFoo$Nested" : {
"type" : "string",
Expand Down Expand Up @@ -57,7 +57,7 @@
"uniqueItems" : true
}
},
"examples" : [ "<NestedWithAttribute ns=\"string\"><nli>0</nli><nmfm/><nsm><MyClassWithAttribute s_attribute=\"string\"><s_elem>string</s_elem></MyClassWithAttribute></nsm></NestedWithAttribute>" ]
"examples" : [ "<NestedWithAttribute ns=\"string\"><nli>0</nli><nmfm><key s_attribute=\"string\"><s_elem>string</s_elem></key></nmfm><nsm><MyClassWithAttribute s_attribute=\"string\"><s_elem>string</s_elem></MyClassWithAttribute></nsm></NestedWithAttribute>" ]
},
"io.github.springwolf.core.asyncapi.components.DefaultXmlComponentsServiceTest$ComplexAttributesFoo$Nested$MyClassWithAttribute" : {
"type" : "string",
Expand All @@ -71,4 +71,4 @@
},
"examples" : [ "<MyClassWithAttribute s_attribute=\"string\"><s_elem>string</s_elem></MyClassWithAttribute>" ]
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"type" : "string"
}
},
"examples" : [ "<ComplexFoo><b>true</b><d>1.1</d><dt>2015-07-20T15:49:04-07:00</dt><f>1.1</f><i>0</i><n><nba>YmFzZTY0LWV4YW1wbGU=</nba><nc><cyclic/></nc><nli>0</nli><nmfm/><ns>string</ns><nsm><MyClass><s>string</s></MyClass></nsm><nu>3fa85f64-5717-4562-b3fc-2c963f66afa6</nu></n><s>string</s></ComplexFoo>" ]
"examples" : [ "<ComplexFoo><b>true</b><d>1.1</d><dt>2015-07-20T15:49:04-07:00</dt><f>1.1</f><i>0</i><n><nba>YmFzZTY0LWV4YW1wbGU=</nba><nc><cyclic/></nc><nli>0</nli><nmfm><key><s>string</s></key></nmfm><ns>string</ns><nsm><MyClass><s>string</s></MyClass></nsm><nu>3fa85f64-5717-4562-b3fc-2c963f66afa6</nu></n><s>string</s></ComplexFoo>" ]
},
"io.github.springwolf.core.asyncapi.components.DefaultXmlComponentsServiceTest$ComplexFoo$Nested" : {
"type" : "string",
Expand Down Expand Up @@ -68,7 +68,7 @@
"format" : "uuid"
}
},
"examples" : [ "<Nested><nba>YmFzZTY0LWV4YW1wbGU=</nba><nc><cyclic/></nc><nli>0</nli><nmfm/><ns>string</ns><nsm><MyClass><s>string</s></MyClass></nsm><nu>3fa85f64-5717-4562-b3fc-2c963f66afa6</nu></Nested>" ]
"examples" : [ "<Nested><nba>YmFzZTY0LWV4YW1wbGU=</nba><nc><cyclic/></nc><nli>0</nli><nmfm><key><s>string</s></key></nmfm><ns>string</ns><nsm><MyClass><s>string</s></MyClass></nsm><nu>3fa85f64-5717-4562-b3fc-2c963f66afa6</nu></Nested>" ]
},
"io.github.springwolf.core.asyncapi.components.DefaultXmlComponentsServiceTest$ComplexFoo$Nested$Cyclic" : {
"type" : "string",
Expand All @@ -88,4 +88,4 @@
},
"examples" : [ "<MyClass><s>string</s></MyClass>" ]
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@
"mss" : {
"type" : "object",
"description" : "Map with example",
"examples" : [ "<key1>value1</key1>" ],
"examples" : [ "<mss><key1>value1</key1></mss>" ],
"additionalProperties" : {
"type" : "string",
"description" : "Map with example",
"examples" : [ "<key1>value1</key1>" ]
"examples" : [ "<mss><key1>value1</key1></mss>" ]
}
},
"mss_plain" : {
Expand All @@ -51,7 +51,7 @@
}
},
"description" : "foo model",
"examples" : [ "<DocumentedSimpleFoo><bi>0</bi><dt>2000-01-01T02:00:00+02:00</dt><f><b>true</b><s>string</s></f><ld>2024-04-24</ld><ls_plain>string</ls_plain><mss/><mss_plain/><s>s value</s></DocumentedSimpleFoo>" ],
"examples" : [ "<DocumentedSimpleFoo><bi>0</bi><dt>2000-01-01T02:00:00+02:00</dt><f><b>true</b><s>string</s></f><ld>2024-04-24</ld><ls_plain>string</ls_plain><mss><key1>value1</key1></mss><mss_plain><key>string</key></mss_plain><s>s value</s></DocumentedSimpleFoo>" ],
"required" : [ "dt", "f", "s" ]
},
"io.github.springwolf.core.asyncapi.components.DefaultXmlComponentsServiceTest$SimpleFoo" : {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"type" : "string"
}
},
"examples" : [ "b: true\nd: 1.1\ndt: \"2015-07-20T15:49:04-07:00\"\nf: 1.1\ni: 0\n\"n\":\n nba: \"YmFzZTY0LWV4YW1wbGU=\"\n nc:\n cyclic: {}\n nli:\n - 0\n nmfm: {}\n ns: \"string\"\n nsm:\n - s: \"string\"\n nu: \"3fa85f64-5717-4562-b3fc-2c963f66afa6\"\ns: \"string\"\n" ]
"examples" : [ "b: true\nd: 1.1\ndt: \"2015-07-20T15:49:04-07:00\"\nf: 1.1\ni: 0\n\"n\":\n nba: \"YmFzZTY0LWV4YW1wbGU=\"\n nc:\n cyclic: {}\n nli:\n - 0\n nmfm:\n key:\n s: \"string\"\n ns: \"string\"\n nsm:\n - s: \"string\"\n nu: \"3fa85f64-5717-4562-b3fc-2c963f66afa6\"\ns: \"string\"\n" ]
},
"io.github.springwolf.core.asyncapi.components.DefaultYamlComponentsServiceTest$ComplexFoo$Nested" : {
"type" : "string",
Expand Down Expand Up @@ -68,7 +68,7 @@
"format" : "uuid"
}
},
"examples" : [ "nba: \"YmFzZTY0LWV4YW1wbGU=\"\nnc:\n cyclic: {}\nnli:\n- 0\nnmfm: {}\nns: \"string\"\nnsm:\n- s: \"string\"\nnu: \"3fa85f64-5717-4562-b3fc-2c963f66afa6\"\n" ]
"examples" : [ "nba: \"YmFzZTY0LWV4YW1wbGU=\"\nnc:\n cyclic: {}\nnli:\n- 0\nnmfm:\n key:\n s: \"string\"\nns: \"string\"\nnsm:\n- s: \"string\"\nnu: \"3fa85f64-5717-4562-b3fc-2c963f66afa6\"\n" ]
},
"io.github.springwolf.core.asyncapi.components.DefaultYamlComponentsServiceTest$ComplexFoo$Nested$Cyclic" : {
"type" : "string",
Expand All @@ -88,4 +88,4 @@
},
"examples" : [ "s: \"string\"\n" ]
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
}
},
"description" : "foo model",
"examples" : [ "bi: 0\ndt: \"2000-01-01T02:00:00+02:00\"\nf:\n b: true\n s: \"string\"\nld: \"2024-04-24\"\nls_plain:\n- \"string\"\nmss:\n key1: \"value1\"\nmss_plain: {}\ns: \"s value\"\n" ],
"examples" : [ "bi: 0\ndt: \"2000-01-01T02:00:00+02:00\"\nf:\n b: true\n s: \"string\"\nld: \"2024-04-24\"\nls_plain:\n- \"string\"\nmss:\n key1: \"value1\"\nmss_plain:\n key: \"string\"\ns: \"s value\"\n" ],
"required" : [ "dt", "f", "s" ]
},
"io.github.springwolf.core.asyncapi.components.DefaultYamlComponentsServiceTest$SimpleFoo" : {
Expand All @@ -68,4 +68,4 @@
},
"examples" : [ "b: true\ns: \"string\"\n" ]
}
}
}