ISSUE-876 Fixed array types to oneof for js support (#880)

This commit is contained in:
German Osin 2021-09-15 14:02:06 +03:00 committed by GitHub
parent 3d537f2bf1
commit 3c05b60313
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 29 additions and 31 deletions

View file

@ -67,6 +67,10 @@ public class AvroJsonSchemaConverter implements JsonSchemaConverter<Schema> {
} }
private FieldSchema createUnionSchema(Schema schema, Map<String, FieldSchema> definitions) { private FieldSchema createUnionSchema(Schema schema, Map<String, FieldSchema> definitions) {
final boolean nullable = schema.getTypes().stream()
.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 -> Tuples.of(
@ -80,7 +84,16 @@ public class AvroJsonSchemaConverter implements JsonSchemaConverter<Schema> {
Tuple2::getT2 Tuple2::getT2
)); ));
return new ObjectFieldSchema(fields, Collections.emptyList(), true); if (nullable) {
return new OneOfFieldSchema(
List.of(
new SimpleFieldSchema(new SimpleJsonType(JsonType.Type.NULL)),
new ObjectFieldSchema(fields, Collections.emptyList())
)
);
} else {
return new ObjectFieldSchema(fields, Collections.emptyList());
}
} }
private FieldSchema createObjectSchema(String name, Schema schema, private FieldSchema createObjectSchema(String name, Schema schema,

View file

@ -15,18 +15,11 @@ import reactor.util.function.Tuples;
public class ObjectFieldSchema implements FieldSchema { public class ObjectFieldSchema implements FieldSchema {
private final Map<String, FieldSchema> properties; private final Map<String, FieldSchema> properties;
private final List<String> required; private final List<String> required;
private final boolean nullable;
public ObjectFieldSchema(Map<String, FieldSchema> properties, public ObjectFieldSchema(Map<String, FieldSchema> properties,
List<String> required) { List<String> required) {
this(properties, required, false);
}
public ObjectFieldSchema(Map<String, FieldSchema> properties,
List<String> required, boolean nullable) {
this.properties = properties; this.properties = properties;
this.required = required; this.required = required;
this.nullable = nullable;
} }
public Map<String, FieldSchema> getProperties() { public Map<String, FieldSchema> getProperties() {
@ -46,18 +39,9 @@ public class ObjectFieldSchema implements FieldSchema {
Tuple2::getT2 Tuple2::getT2
)); ));
final ObjectNode objectNode = mapper.createObjectNode(); final ObjectNode objectNode = mapper.createObjectNode();
if (this.nullable) {
objectNode.set(
"type",
mapper.createArrayNode()
.add(JsonType.Type.OBJECT.getName())
.add(JsonType.Type.NULL.getName())
);
} else {
objectNode.setAll( objectNode.setAll(
new SimpleJsonType(JsonType.Type.OBJECT).toJsonNode(mapper) new SimpleJsonType(JsonType.Type.OBJECT).toJsonNode(mapper)
); );
}
objectNode.set("properties", mapper.valueToTree(nodes)); objectNode.set("properties", mapper.valueToTree(nodes));
if (!required.isEmpty()) { if (!required.isEmpty()) {
objectNode.set("required", mapper.valueToTree(required)); objectNode.set("required", mapper.valueToTree(required));

View file

@ -87,13 +87,14 @@ public class AvroJsonSchemaConverterTest {
+ "{\"$ref\":\"#/definitions/RecordInnerMessage\"}}," + "{\"$ref\":\"#/definitions/RecordInnerMessage\"}},"
+ "\"required\":[\"record\"],\"definitions\":" + "\"required\":[\"record\"],\"definitions\":"
+ "{\"RecordInnerMessage\":{\"type\":\"object\",\"" + "{\"RecordInnerMessage\":{\"type\":\"object\",\""
+ "properties\":{\"long_text\":{\"type\":[\"object\", \"null\"]," + "properties\":{\"long_text\":{\"oneOf\":[{\"type\":\"null\"},"
+ "\"properties\":{\"string\":{\"type\":\"string\"}}}," + "{\"type\":\"object\",\"properties\":{\"string\":"
+ "\"array\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}}," + "{\"type\":\"string\"}}}]},\"array\":{\"type\":\"array\",\"items\":"
+ "\"id\":{\"type\":\"integer\"},\"text\":{\"type\":\"string\"}," + "{\"type\":\"string\"}},\"id\":{\"type\":\"integer\"},\"text\":"
+ "\"map\":{\"type\":\"object\",\"additionalProperties\":" + "{\"type\":\"string\"},\"map\":{\"type\":\"object\","
+ "{\"type\":\"integer\"}},\"order\":{\"type\":\"string\"," + "\"additionalProperties\":{\"type\":\"integer\"}},"
+ "\"enum\":[\"SPADES\",\"HEARTS\",\"DIAMONDS\",\"CLUBS\"]}}," + "\"order\":{\"enum\":[\"SPADES\",\"HEARTS\",\"DIAMONDS\",\"CLUBS\"],"
+ "\"type\":\"string\"}},"
+ "\"required\":[\"id\",\"text\",\"order\",\"array\",\"map\"]}}}"; + "\"required\":[\"id\",\"text\",\"order\",\"array\",\"map\"]}}}";
final JsonSchema convertRecord = converter.convert(basePath, recordSchema); final JsonSchema convertRecord = converter.convert(basePath, recordSchema);
@ -151,10 +152,10 @@ public class AvroJsonSchemaConverterTest {
"{\"$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\":"
+ "{\"type\":[\"object\", \"null\"],\"properties\":{\"string\":" + "{\"oneOf\":[{\"type\":\"null\"},{\"type\":\"object\","
+ "{\"type\":\"string\"}}},\"value\":{\"type\":[\"object\", \"null\"]," + "\"properties\":{\"string\":{\"type\":\"string\"}}}]},\"value\":"
+ "\"properties\":{\"string\":{\"type\":\"string\"}," + "{\"oneOf\":[{\"type\":\"null\"},{\"type\":\"object\","
+ "\"long\":{\"type\":\"integer\"}}}}}"; + "\"properties\":{\"string\":{\"type\":\"string\"},\"long\":{\"type\":\"integer\"}}}]}}}";
final JsonSchema convert = converter.convert(basePath, recordSchema); final JsonSchema convert = converter.convert(basePath, recordSchema);
Assertions.assertEquals( Assertions.assertEquals(