Skip to content

Commit

Permalink
fix(core): handle ref in xml example
Browse files Browse the repository at this point in the history
extracted from springwolf#890

Co-authored-by: David Beck <[email protected]>
  • Loading branch information
timonback and David Beck committed Aug 16, 2024
1 parent 8609c89 commit d3f7d0e
Show file tree
Hide file tree
Showing 7 changed files with 62 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public R fromSchema(Schema schema, Map<String, Schema> definitions) {
private Optional<T> buildExample(String name, Schema schema, Map<String, Schema> definitions, Set<Schema> visited) {
log.debug("Building example for schema {}", schema);

Optional<T> exampleValue = getExampleFromSchemaAnnotation(schema);
Optional<T> exampleValue = getExampleFromSchemaAnnotation(name, schema);
if (exampleValue.isPresent()) {
return exampleValue;
}
Expand All @@ -88,19 +88,19 @@ private Optional<T> buildExample(String name, Schema schema, Map<String, Schema>
return example;
}

private Optional<T> getExampleFromSchemaAnnotation(Schema schema) {
return getExampleValueFromSchemaAnnotation(schema, schema.getExample())
.or(() -> getExampleValueFromSchemaAnnotation(schema, schema.getDefault()));
private Optional<T> getExampleFromSchemaAnnotation(String fieldName, Schema schema) {
return getExampleValueFromSchemaAnnotation(fieldName, schema, schema.getExample())
.or(() -> getExampleValueFromSchemaAnnotation(fieldName, schema, schema.getDefault()));
}

private Optional<T> getExampleValueFromSchemaAnnotation(Schema schema, Object exampleValue) {
private Optional<T> getExampleValueFromSchemaAnnotation(String fieldName, Schema schema, Object exampleValue) {
// schema is a map of properties from a nested object, whose example cannot be inferred
if (exampleValue == null) {
return Optional.empty();
}

// Return directly, when we have processed this before
T processedExample = exampleValueGenerator.getExampleOrNull(schema, exampleValue);
T processedExample = exampleValueGenerator.getExampleOrNull(fieldName, schema, exampleValue);
if (processedExample != null) {
return Optional.of(processedExample);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,5 +54,5 @@ default void endObject() {}

T createRaw(Object exampleValueString);

T getExampleOrNull(Schema schema, Object example);
T getExampleOrNull(String fieldName, Schema schema, Object example);
}
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ public JsonNode createRaw(Object exampleValue) {
}

@Override
public JsonNode getExampleOrNull(Schema schema, Object example) {
public JsonNode getExampleOrNull(String fieldName, Schema schema, Object example) {
if (example instanceof JsonNode) {
return (JsonNode) example;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,20 +198,31 @@ public Node createRaw(Object exampleValue) {
}

@Override
public Node getExampleOrNull(Schema schema, Object example) {
public Node getExampleOrNull(String fieldName, Schema schema, Object example) {
String name = getCacheKey(schema);

if (example instanceof Node) {
return (Node) example;
}

if (exampleCache.containsKey(name)) {
return this.document.importNode(exampleCache.get(name), true);
Node oldElement = exampleCache.get(name);
Node newElement = modifyElementFromCacheIfNeeded(oldElement, fieldName);
return this.document.importNode(newElement, true);
}

return null;
}

private Node modifyElementFromCacheIfNeeded(Node oldElement, String fieldName) {
if (oldElement instanceof Element) {
// check if the wrapping xml-tag needs to be different than the example from the cache
Document doc = oldElement.getOwnerDocument();
return doc.renameNode(oldElement, null, fieldName);
}
return oldElement;
}

@Override
public Optional<Node> createEmptyObjectExample() {
return Optional.of(document.createTextNode(""));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ public JsonNode createRaw(Object exampleValueString) {
}

@Override
public JsonNode getExampleOrNull(Schema schema, Object example) {
return this.exampleJsonValueGenerator.getExampleOrNull(schema, example);
public JsonNode getExampleOrNull(String fieldName, Schema schema, Object example) {
return this.exampleJsonValueGenerator.getExampleOrNull(fieldName, schema, example);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,19 @@
import io.swagger.v3.oas.models.media.StringSchema;
import io.swagger.v3.oas.models.media.XML;
import org.junit.jupiter.api.Test;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

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

class ExampleXmlValueGeneratorTest {
private final DefaultExampleXmlValueSerializer serializer = new DefaultExampleXmlValueSerializer();

@Test
void cacheShouldResolveBySchemaName() {
// given
ExampleXmlValueGenerator generator = new ExampleXmlValueGenerator(new DefaultExampleXmlValueSerializer());
ExampleXmlValueGenerator generator = new ExampleXmlValueGenerator(serializer);

StringSchema schema1 = new StringSchema();
schema1.setName("full.a.schema1");
Expand All @@ -31,22 +33,50 @@ void cacheShouldResolveBySchemaName() {
.get();
generator.prepareForSerialization(schema1, example1);

Node cachedExample1 = generator.getExampleOrNull(schema1, "does-not-matter-for-test-1");
Node cachedExample1 = generator.getExampleOrNull("fieldName1", schema1, "does-not-matter-for-test-1");

// when
generator.initialize();
Node exampleFromCache = generator.getExampleOrNull(schema2, "does-not-matter-for-test-2");
Node exampleFromCache = generator.getExampleOrNull("fieldName2", schema2, "does-not-matter-for-test-2");

// then
assertThat(exampleFromCache).isNotEqualTo(cachedExample1);
assertThat(exampleFromCache).isNull();
}

@Test
void cacheShouldStoreExampleBySchemaName() {
void cacheShouldResolveBySchemaNameAndRenameToWrappingField() {
// given
ExampleXmlValueGenerator generator = new ExampleXmlValueGenerator(serializer);

StringSchema schema1 = new StringSchema();
schema1.setName("full.a.schema1");
schema1.setXml(new XML().name("schema1"));

StringSchema schema2 = new StringSchema();
schema2.setName("full.b.schema1");
schema2.setXml(new XML().name("schema1"));

generator.initialize();

ExampleXmlValueGenerator generator = new ExampleXmlValueGenerator(new DefaultExampleXmlValueSerializer());
Node example1 = generator.createRaw("<xml><value>aValue</value></xml>");
generator.prepareForSerialization(schema1, example1);

Node cachedExample1 = generator.getExampleOrNull("fieldName1", schema1, "does-not-matter-for-test-1");

// when
generator.initialize();
Node exampleFromCache = generator.getExampleOrNull("fieldName2", schema2, "does-not-matter-for-test-2");

// then
assertThat(((Element) cachedExample1).getTagName()).isEqualTo("fieldName1");
assertThat(exampleFromCache).isNull();
}

@Test
void cacheShouldStoreExampleBySchemaName() {
// given
ExampleXmlValueGenerator generator = new ExampleXmlValueGenerator(serializer);
StringSchema schema1 = new StringSchema();
schema1.setName("full.a.schema1");
schema1.setXml(new XML().name("schema1"));
Expand All @@ -60,15 +90,15 @@ void cacheShouldStoreExampleBySchemaName() {
generator.prepareForSerialization(schema1, example1);

generator.initialize();
Node exampleFromCache = generator.getExampleOrNull(schema2, "example-string");
Node exampleFromCache = generator.getExampleOrNull("fieldName", schema2, "example-string");

assertThat(exampleFromCache).isNull();
}

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

// when
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
},
"io.github.springwolf.core.asyncapi.components.DefaultXmlComponentsServiceIntegrationTest$SchemaWithOneOf$OneOf" : {
"type" : "string",
"examples" : [ "<ImplementationOne><firstOne>string</firstOne><secondOne>string</secondOne></ImplementationOne>" ],
"examples" : [ "<OneOf><firstOne>string</firstOne><secondOne>string</secondOne></OneOf>" ],
"oneOf" : [ {
"$ref" : "#/components/schemas/io.github.springwolf.core.asyncapi.components.DefaultXmlComponentsServiceIntegrationTest$SchemaWithOneOf$ImplementationOne"
}, {
Expand All @@ -67,6 +67,6 @@
"$ref" : "#/components/schemas/io.github.springwolf.core.asyncapi.components.DefaultXmlComponentsServiceIntegrationTest$SchemaWithOneOf$OneOf"
}
},
"examples" : [ "<SchemaAnnotationFoo><AllOf><firstOne>string</firstOne><firstTwo>0</firstTwo><secondOne>string</secondOne><secondTwo>true</secondTwo></AllOf><AnyOf><firstOne>string</firstOne><secondOne>string</secondOne></AnyOf><field>string</field><ImplementationOne><firstOne>string</firstOne><secondOne>string</secondOne></ImplementationOne></SchemaAnnotationFoo>" ]
"examples" : [ "<SchemaAnnotationFoo><allOf><firstOne>string</firstOne><firstTwo>0</firstTwo><secondOne>string</secondOne><secondTwo>true</secondTwo></allOf><anyOf><firstOne>string</firstOne><secondOne>string</secondOne></anyOf><field>string</field><oneOf><firstOne>string</firstOne><secondOne>string</secondOne></oneOf></SchemaAnnotationFoo>" ]
}
}

0 comments on commit d3f7d0e

Please sign in to comment.