Skip to content

Commit

Permalink
feat(core): handle map schemas (#839)
Browse files Browse the repository at this point in the history
* feat(core): handle map schemas

* fix(core): handle examples in xml schemas
  • Loading branch information
timonback authored Jul 12, 2024
1 parent 21f4d54 commit b57bfd2
Show file tree
Hide file tree
Showing 14 changed files with 108 additions and 24 deletions.
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" ]
}
}
}

0 comments on commit b57bfd2

Please sign in to comment.