1. fixing infinite recursion with cyclic references (#2640)
2. using record names in unions to make possible to use several record 3. tests refactored Co-authored-by: iliax <ikuramshin@provectus.com>
This commit is contained in:
parent
049b35fc99
commit
97f1c639a3
2 changed files with 201 additions and 98 deletions
|
@ -4,7 +4,6 @@ import java.net.URI;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import org.apache.avro.Schema;
|
import org.apache.avro.Schema;
|
||||||
|
@ -22,7 +21,7 @@ public class AvroJsonSchemaConverter implements JsonSchemaConverter<Schema> {
|
||||||
builder.type(type);
|
builder.type(type);
|
||||||
|
|
||||||
Map<String, FieldSchema> definitions = new HashMap<>();
|
Map<String, FieldSchema> definitions = new HashMap<>();
|
||||||
final FieldSchema root = convertSchema("root", schema, definitions, false);
|
final FieldSchema root = convertSchema(schema, definitions, true);
|
||||||
builder.definitions(definitions);
|
builder.definitions(definitions);
|
||||||
|
|
||||||
if (type.getType().equals(JsonType.Type.OBJECT)) {
|
if (type.getType().equals(JsonType.Type.OBJECT)) {
|
||||||
|
@ -36,11 +35,11 @@ public class AvroJsonSchemaConverter implements JsonSchemaConverter<Schema> {
|
||||||
|
|
||||||
|
|
||||||
private FieldSchema convertField(Schema.Field field, Map<String, FieldSchema> definitions) {
|
private FieldSchema convertField(Schema.Field field, Map<String, FieldSchema> definitions) {
|
||||||
return convertSchema(field.name(), field.schema(), definitions, true);
|
return convertSchema(field.schema(), definitions, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private FieldSchema convertSchema(String name, Schema schema,
|
private FieldSchema convertSchema(Schema schema,
|
||||||
Map<String, FieldSchema> definitions, boolean ref) {
|
Map<String, FieldSchema> definitions, boolean isRoot) {
|
||||||
if (!schema.isUnion()) {
|
if (!schema.isUnion()) {
|
||||||
JsonType type = convertType(schema);
|
JsonType type = convertType(schema);
|
||||||
switch (type.getType()) {
|
switch (type.getType()) {
|
||||||
|
@ -53,12 +52,12 @@ public class AvroJsonSchemaConverter implements JsonSchemaConverter<Schema> {
|
||||||
return new SimpleFieldSchema(type);
|
return new SimpleFieldSchema(type);
|
||||||
case OBJECT:
|
case OBJECT:
|
||||||
if (schema.getType().equals(Schema.Type.MAP)) {
|
if (schema.getType().equals(Schema.Type.MAP)) {
|
||||||
return new MapFieldSchema(convertSchema(name, schema.getValueType(), definitions, ref));
|
return new MapFieldSchema(convertSchema(schema.getValueType(), definitions, isRoot));
|
||||||
} else {
|
} else {
|
||||||
return createObjectSchema(name, schema, definitions, ref);
|
return createObjectSchema(schema, definitions, isRoot);
|
||||||
}
|
}
|
||||||
case ARRAY:
|
case ARRAY:
|
||||||
return createArraySchema(name, schema, definitions);
|
return createArraySchema(schema, definitions);
|
||||||
default:
|
default:
|
||||||
throw new RuntimeException("Unknown type");
|
throw new RuntimeException("Unknown type");
|
||||||
}
|
}
|
||||||
|
@ -67,20 +66,26 @@ public class AvroJsonSchemaConverter implements JsonSchemaConverter<Schema> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private FieldSchema createUnionSchema(Schema schema, Map<String, FieldSchema> definitions) {
|
|
||||||
|
|
||||||
|
// this method formats json-schema field in a way
|
||||||
|
// to fit avro-> json encoding rules (https://avro.apache.org/docs/1.11.1/specification/_print/#json-encoding)
|
||||||
|
private FieldSchema createUnionSchema(Schema schema, Map<String, FieldSchema> definitions) {
|
||||||
final boolean nullable = schema.getTypes().stream()
|
final boolean nullable = schema.getTypes().stream()
|
||||||
.anyMatch(t -> t.getType().equals(Schema.Type.NULL));
|
.anyMatch(t -> t.getType().equals(Schema.Type.NULL));
|
||||||
|
|
||||||
final Map<String, FieldSchema> fields = schema.getTypes().stream()
|
final Map<String, FieldSchema> fields = schema.getTypes().stream()
|
||||||
.filter(t -> !t.getType().equals(Schema.Type.NULL))
|
.filter(t -> !t.getType().equals(Schema.Type.NULL))
|
||||||
.map(f -> Tuples.of(
|
.map(f -> {
|
||||||
f.getType().getName().toLowerCase(Locale.ROOT),
|
String oneOfFieldName;
|
||||||
convertSchema(
|
if (f.getType().equals(Schema.Type.RECORD)) {
|
||||||
f.getType().getName().toLowerCase(Locale.ROOT),
|
// for records using full record name
|
||||||
f, definitions, true
|
oneOfFieldName = f.getFullName();
|
||||||
)
|
} else {
|
||||||
)).collect(Collectors.toMap(
|
// for primitive types - using type name
|
||||||
|
oneOfFieldName = f.getType().getName().toLowerCase();
|
||||||
|
}
|
||||||
|
return Tuples.of(oneOfFieldName, convertSchema(f, definitions, false));
|
||||||
|
}).collect(Collectors.toMap(
|
||||||
Tuple2::getT1,
|
Tuple2::getT1,
|
||||||
Tuple2::getT2
|
Tuple2::getT2
|
||||||
));
|
));
|
||||||
|
@ -97,8 +102,16 @@ public class AvroJsonSchemaConverter implements JsonSchemaConverter<Schema> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private FieldSchema createObjectSchema(String name, Schema schema,
|
private FieldSchema createObjectSchema(Schema schema,
|
||||||
Map<String, FieldSchema> definitions, boolean ref) {
|
Map<String, FieldSchema> definitions,
|
||||||
|
boolean isRoot) {
|
||||||
|
var definitionName = schema.getFullName();
|
||||||
|
if (definitions.containsKey(definitionName)) {
|
||||||
|
return createRefField(definitionName);
|
||||||
|
}
|
||||||
|
// adding stub record, need to avoid infinite recursion
|
||||||
|
definitions.put(definitionName, new ObjectFieldSchema(Map.of(), List.of()));
|
||||||
|
|
||||||
final Map<String, FieldSchema> fields = schema.getFields().stream()
|
final Map<String, FieldSchema> fields = schema.getFields().stream()
|
||||||
.map(f -> Tuples.of(f.name(), convertField(f, definitions)))
|
.map(f -> Tuples.of(f.name(), convertField(f, definitions)))
|
||||||
.collect(Collectors.toMap(
|
.collect(Collectors.toMap(
|
||||||
|
@ -110,19 +123,26 @@ public class AvroJsonSchemaConverter implements JsonSchemaConverter<Schema> {
|
||||||
.filter(f -> !f.schema().isNullable())
|
.filter(f -> !f.schema().isNullable())
|
||||||
.map(Schema.Field::name).collect(Collectors.toList());
|
.map(Schema.Field::name).collect(Collectors.toList());
|
||||||
|
|
||||||
if (ref) {
|
var objectSchema = new ObjectFieldSchema(fields, required);
|
||||||
String definitionName = String.format("Record%s", schema.getName());
|
if (isRoot) {
|
||||||
definitions.put(definitionName, new ObjectFieldSchema(fields, required));
|
// replacing stub with self-reference (need for usage in json-schema's oneOf)
|
||||||
return new RefFieldSchema(String.format("#/definitions/%s", definitionName));
|
definitions.put(definitionName, new RefFieldSchema("#"));
|
||||||
|
return objectSchema;
|
||||||
} else {
|
} else {
|
||||||
return new ObjectFieldSchema(fields, required);
|
// replacing stub record with actual object structure
|
||||||
|
definitions.put(definitionName, objectSchema);
|
||||||
|
return createRefField(definitionName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ArrayFieldSchema createArraySchema(String name, Schema schema,
|
private RefFieldSchema createRefField(String definitionName) {
|
||||||
|
return new RefFieldSchema(String.format("#/definitions/%s", definitionName));
|
||||||
|
}
|
||||||
|
|
||||||
|
private ArrayFieldSchema createArraySchema(Schema schema,
|
||||||
Map<String, FieldSchema> definitions) {
|
Map<String, FieldSchema> definitions) {
|
||||||
return new ArrayFieldSchema(
|
return new ArrayFieldSchema(
|
||||||
convertSchema(name, schema.getElementType(), definitions, true)
|
convertSchema(schema.getElementType(), definitions, false)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,27 +1,29 @@
|
||||||
package com.provectus.kafka.ui.util.jsonschema;
|
package com.provectus.kafka.ui.util.jsonschema;
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.github.fge.jsonschema.core.exceptions.ProcessingException;
|
|
||||||
import com.github.fge.jsonschema.core.report.ProcessingReport;
|
|
||||||
import com.github.fge.jsonschema.main.JsonSchemaFactory;
|
|
||||||
import io.confluent.kafka.schemaregistry.avro.AvroSchemaUtils;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
import org.apache.avro.Schema;
|
import org.apache.avro.Schema;
|
||||||
import org.apache.avro.generic.GenericData;
|
|
||||||
import org.junit.jupiter.api.Assertions;
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
public class AvroJsonSchemaConverterTest {
|
class AvroJsonSchemaConverterTest {
|
||||||
@Test
|
|
||||||
public void avroConvertTest() throws URISyntaxException, JsonProcessingException {
|
|
||||||
final AvroJsonSchemaConverter converter = new AvroJsonSchemaConverter();
|
|
||||||
URI basePath = new URI("http://example.com/");
|
|
||||||
|
|
||||||
Schema recordSchema = (new Schema.Parser()).parse(
|
private AvroJsonSchemaConverter converter;
|
||||||
" {"
|
private URI basePath;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void init() throws URISyntaxException {
|
||||||
|
converter = new AvroJsonSchemaConverter();
|
||||||
|
basePath = new URI("http://example.com/");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void avroConvertTest() {
|
||||||
|
String avroSchema =
|
||||||
|
" {"
|
||||||
+ " \"type\": \"record\","
|
+ " \"type\": \"record\","
|
||||||
+ " \"name\": \"Message\","
|
+ " \"name\": \"Message\","
|
||||||
+ " \"namespace\": \"com.provectus.kafka\","
|
+ " \"namespace\": \"com.provectus.kafka\","
|
||||||
|
@ -76,45 +78,59 @@ public class AvroJsonSchemaConverterTest {
|
||||||
+ " }"
|
+ " }"
|
||||||
+ " }"
|
+ " }"
|
||||||
+ " ]"
|
+ " ]"
|
||||||
+ " }"
|
+ " }";
|
||||||
);
|
|
||||||
|
|
||||||
|
String expectedJsonSchema = "{ "
|
||||||
|
+ " \"$id\" : \"http://example.com/Message\", "
|
||||||
|
+ " \"$schema\" : \"https://json-schema.org/draft/2020-12/schema\", "
|
||||||
|
+ " \"type\" : \"object\", "
|
||||||
|
+ " \"properties\" : { "
|
||||||
|
+ " \"record\" : { \"$ref\" : \"#/definitions/com.provectus.kafka.InnerMessage\" } "
|
||||||
|
+ " }, "
|
||||||
|
+ " \"required\" : [ \"record\" ], "
|
||||||
|
+ " \"definitions\" : { "
|
||||||
|
+ " \"com.provectus.kafka.Message\" : { \"$ref\" : \"#\" }, "
|
||||||
|
+ " \"com.provectus.kafka.InnerMessage\" : { "
|
||||||
|
+ " \"type\" : \"object\", "
|
||||||
|
+ " \"properties\" : { "
|
||||||
|
+ " \"long_text\" : { "
|
||||||
|
+ " \"oneOf\" : [ { "
|
||||||
|
+ " \"type\" : \"null\" "
|
||||||
|
+ " }, { "
|
||||||
|
+ " \"type\" : \"object\", "
|
||||||
|
+ " \"properties\" : { "
|
||||||
|
+ " \"string\" : { "
|
||||||
|
+ " \"type\" : \"string\" "
|
||||||
|
+ " } "
|
||||||
|
+ " } "
|
||||||
|
+ " } ] "
|
||||||
|
+ " }, "
|
||||||
|
+ " \"array\" : { "
|
||||||
|
+ " \"type\" : \"array\", "
|
||||||
|
+ " \"items\" : { \"type\" : \"string\" } "
|
||||||
|
+ " }, "
|
||||||
|
+ " \"id\" : { \"type\" : \"integer\" }, "
|
||||||
|
+ " \"text\" : { \"type\" : \"string\" }, "
|
||||||
|
+ " \"map\" : { "
|
||||||
|
+ " \"type\" : \"object\", "
|
||||||
|
+ " \"additionalProperties\" : { \"type\" : \"integer\" } "
|
||||||
|
+ " }, "
|
||||||
|
+ " \"order\" : { "
|
||||||
|
+ " \"enum\" : [ \"SPADES\", \"HEARTS\", \"DIAMONDS\", \"CLUBS\" ], "
|
||||||
|
+ " \"type\" : \"string\" "
|
||||||
|
+ " } "
|
||||||
|
+ " }, "
|
||||||
|
+ " \"required\" : [ \"id\", \"text\", \"order\", \"array\", \"map\" ] "
|
||||||
|
+ " } "
|
||||||
|
+ " } "
|
||||||
|
+ "}";
|
||||||
|
|
||||||
String expected = "{\"$id\":\"http://example.com/Message\","
|
convertAndCompare(expectedJsonSchema, avroSchema);
|
||||||
+ "\"$schema\":\"https://json-schema.org/draft/2020-12/schema\","
|
|
||||||
+ "\"type\":\"object\",\"properties\":{\"record\":"
|
|
||||||
+ "{\"$ref\":\"#/definitions/RecordInnerMessage\"}},"
|
|
||||||
+ "\"required\":[\"record\"],\"definitions\":"
|
|
||||||
+ "{\"RecordInnerMessage\":{\"type\":\"object\",\""
|
|
||||||
+ "properties\":{\"long_text\":{\"oneOf\":[{\"type\":\"null\"},"
|
|
||||||
+ "{\"type\":\"object\",\"properties\":{\"string\":"
|
|
||||||
+ "{\"type\":\"string\"}}}]},\"array\":{\"type\":\"array\",\"items\":"
|
|
||||||
+ "{\"type\":\"string\"}},\"id\":{\"type\":\"integer\"},\"text\":"
|
|
||||||
+ "{\"type\":\"string\"},\"map\":{\"type\":\"object\","
|
|
||||||
+ "\"additionalProperties\":{\"type\":\"integer\"}},"
|
|
||||||
+ "\"order\":{\"enum\":[\"SPADES\",\"HEARTS\",\"DIAMONDS\",\"CLUBS\"],"
|
|
||||||
+ "\"type\":\"string\"}},"
|
|
||||||
+ "\"required\":[\"id\",\"text\",\"order\",\"array\",\"map\"]}}}";
|
|
||||||
|
|
||||||
final JsonSchema convertRecord = converter.convert(basePath, recordSchema);
|
|
||||||
|
|
||||||
ObjectMapper om = new ObjectMapper();
|
|
||||||
Assertions.assertEquals(
|
|
||||||
om.readTree(expected),
|
|
||||||
om.readTree(
|
|
||||||
convertRecord.toJson()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNullableUnions() throws URISyntaxException, IOException, ProcessingException {
|
void testNullableUnions() {
|
||||||
final AvroJsonSchemaConverter converter = new AvroJsonSchemaConverter();
|
String avroSchema =
|
||||||
URI basePath = new URI("http://example.com/");
|
|
||||||
final ObjectMapper objectMapper = new ObjectMapper();
|
|
||||||
|
|
||||||
Schema recordSchema = (new Schema.Parser()).parse(
|
|
||||||
" {"
|
" {"
|
||||||
+ " \"type\": \"record\","
|
+ " \"type\": \"record\","
|
||||||
+ " \"name\": \"Message\","
|
+ " \"name\": \"Message\","
|
||||||
|
@ -138,38 +154,105 @@ public class AvroJsonSchemaConverterTest {
|
||||||
+ " \"default\": null"
|
+ " \"default\": null"
|
||||||
+ " }"
|
+ " }"
|
||||||
+ " ]"
|
+ " ]"
|
||||||
+ " }"
|
+ " }";
|
||||||
);
|
|
||||||
|
|
||||||
final GenericData.Record record = new GenericData.Record(recordSchema);
|
String expectedJsonSchema =
|
||||||
record.put("text", "Hello world");
|
|
||||||
record.put("value", 100L);
|
|
||||||
byte[] jsonBytes = AvroSchemaUtils.toJson(record);
|
|
||||||
String serialized = new String(jsonBytes);
|
|
||||||
|
|
||||||
String expected =
|
|
||||||
"{\"$id\":\"http://example.com/Message\","
|
"{\"$id\":\"http://example.com/Message\","
|
||||||
+ "\"$schema\":\"https://json-schema.org/draft/2020-12/schema\","
|
+ "\"$schema\":\"https://json-schema.org/draft/2020-12/schema\","
|
||||||
+ "\"type\":\"object\",\"properties\":{\"text\":"
|
+ "\"type\":\"object\",\"properties\":{\"text\":"
|
||||||
+ "{\"oneOf\":[{\"type\":\"null\"},{\"type\":\"object\","
|
+ "{\"oneOf\":[{\"type\":\"null\"},{\"type\":\"object\","
|
||||||
+ "\"properties\":{\"string\":{\"type\":\"string\"}}}]},\"value\":"
|
+ "\"properties\":{\"string\":{\"type\":\"string\"}}}]},\"value\":"
|
||||||
+ "{\"oneOf\":[{\"type\":\"null\"},{\"type\":\"object\","
|
+ "{\"oneOf\":[{\"type\":\"null\"},{\"type\":\"object\","
|
||||||
+ "\"properties\":{\"string\":{\"type\":\"string\"},\"long\":{\"type\":\"integer\"}}}]}}}";
|
+ "\"properties\":{\"string\":{\"type\":\"string\"},\"long\":{\"type\":\"integer\"}}}]}},"
|
||||||
|
+ "\"definitions\" : { \"com.provectus.kafka.Message\" : { \"$ref\" : \"#\" }}}";
|
||||||
|
|
||||||
final JsonSchema convert = converter.convert(basePath, recordSchema);
|
convertAndCompare(expectedJsonSchema, avroSchema);
|
||||||
Assertions.assertEquals(
|
|
||||||
objectMapper.readTree(expected),
|
|
||||||
objectMapper.readTree(convert.toJson())
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
final ProcessingReport validate =
|
|
||||||
JsonSchemaFactory.byDefault().getJsonSchema(
|
|
||||||
objectMapper.readTree(expected)
|
|
||||||
).validate(
|
|
||||||
objectMapper.readTree(serialized)
|
|
||||||
);
|
|
||||||
|
|
||||||
Assertions.assertTrue(validate.isSuccess());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testRecordReferences() {
|
||||||
|
String avroSchema =
|
||||||
|
"{\n"
|
||||||
|
+ " \"type\": \"record\", "
|
||||||
|
+ " \"namespace\": \"n.s\", "
|
||||||
|
+ " \"name\": \"RootMsg\", "
|
||||||
|
+ " \"fields\":\n"
|
||||||
|
+ " [ "
|
||||||
|
+ " { "
|
||||||
|
+ " \"name\": \"inner1\", "
|
||||||
|
+ " \"type\": { "
|
||||||
|
+ " \"type\": \"record\", "
|
||||||
|
+ " \"name\": \"Inner\", "
|
||||||
|
+ " \"fields\": [ { \"name\": \"f1\", \"type\": \"double\" } ] "
|
||||||
|
+ " } "
|
||||||
|
+ " }, "
|
||||||
|
+ " { "
|
||||||
|
+ " \"name\": \"inner2\", "
|
||||||
|
+ " \"type\": { "
|
||||||
|
+ " \"type\": \"record\", "
|
||||||
|
+ " \"namespace\": \"n.s2\", "
|
||||||
|
+ " \"name\": \"Inner\", "
|
||||||
|
+ " \"fields\": "
|
||||||
|
+ " [ { \"name\": \"f1\", \"type\": \"double\" } ] "
|
||||||
|
+ " } "
|
||||||
|
+ " }, "
|
||||||
|
+ " { "
|
||||||
|
+ " \"name\": \"refField\", "
|
||||||
|
+ " \"type\": [ \"null\", \"Inner\", \"n.s2.Inner\", \"RootMsg\" ] "
|
||||||
|
+ " } "
|
||||||
|
+ " ] "
|
||||||
|
+ "}";
|
||||||
|
|
||||||
|
String expectedJsonSchema = "{ "
|
||||||
|
+ " \"$id\" : \"http://example.com/RootMsg\", "
|
||||||
|
+ " \"$schema\" : \"https://json-schema.org/draft/2020-12/schema\", "
|
||||||
|
+ " \"type\" : \"object\", "
|
||||||
|
+ " \"properties\" : { "
|
||||||
|
+ " \"inner1\" : { \"$ref\" : \"#/definitions/n.s.Inner\" }, "
|
||||||
|
+ " \"inner2\" : { \"$ref\" : \"#/definitions/n.s2.Inner\" }, "
|
||||||
|
+ " \"refField\" : { "
|
||||||
|
+ " \"oneOf\" : [ "
|
||||||
|
+ " { "
|
||||||
|
+ " \"type\" : \"null\" "
|
||||||
|
+ " }, "
|
||||||
|
+ " { "
|
||||||
|
+ " \"type\" : \"object\", "
|
||||||
|
+ " \"properties\" : { "
|
||||||
|
+ " \"n.s.RootMsg\" : { \"$ref\" : \"#/definitions/n.s.RootMsg\" }, "
|
||||||
|
+ " \"n.s2.Inner\" : { \"$ref\" : \"#/definitions/n.s2.Inner\" }, "
|
||||||
|
+ " \"n.s.Inner\" : { \"$ref\" : \"#/definitions/n.s.Inner\" } "
|
||||||
|
+ " } "
|
||||||
|
+ " } ] "
|
||||||
|
+ " } "
|
||||||
|
+ " }, "
|
||||||
|
+ " \"required\" : [ \"inner1\", \"inner2\" ], "
|
||||||
|
+ " \"definitions\" : { "
|
||||||
|
+ " \"n.s.RootMsg\" : { \"$ref\" : \"#\" }, "
|
||||||
|
+ " \"n.s2.Inner\" : { "
|
||||||
|
+ " \"type\" : \"object\", "
|
||||||
|
+ " \"properties\" : { \"f1\" : { \"type\" : \"number\" } }, "
|
||||||
|
+ " \"required\" : [ \"f1\" ] "
|
||||||
|
+ " }, "
|
||||||
|
+ " \"n.s.Inner\" : { "
|
||||||
|
+ " \"type\" : \"object\", "
|
||||||
|
+ " \"properties\" : { \"f1\" : { \"type\" : \"number\" } }, "
|
||||||
|
+ " \"required\" : [ \"f1\" ] "
|
||||||
|
+ " } "
|
||||||
|
+ " } "
|
||||||
|
+ "}";
|
||||||
|
|
||||||
|
convertAndCompare(expectedJsonSchema, avroSchema);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
private void convertAndCompare(String expectedJsonSchema, String sourceAvroSchema) {
|
||||||
|
var parseAvroSchema = new Schema.Parser().parse(sourceAvroSchema);
|
||||||
|
var converted = converter.convert(basePath, parseAvroSchema).toJson();
|
||||||
|
var objectMapper = new ObjectMapper();
|
||||||
|
Assertions.assertEquals(
|
||||||
|
objectMapper.readTree(expectedJsonSchema),
|
||||||
|
objectMapper.readTree(converted)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
Loading…
Add table
Reference in a new issue