diff --git a/src/main/java/com/github/fge/avro/translators/RecordTranslator.java b/src/main/java/com/github/fge/avro/translators/RecordTranslator.java index 28f470c..ef69206 100644 --- a/src/main/java/com/github/fge/avro/translators/RecordTranslator.java +++ b/src/main/java/com/github/fge/avro/translators/RecordTranslator.java @@ -31,30 +31,27 @@ import org.codehaus.jackson.map.ObjectMapper; import java.io.IOException; +import java.util.LinkedList; import java.util.List; final class RecordTranslator - extends NamedAvroTypeTranslator -{ + extends NamedAvroTypeTranslator { private static final ObjectMapper OLD_MAPPER = new ObjectMapper(); private static final AvroTranslator INSTANCE = new RecordTranslator(); - private RecordTranslator() - { + private RecordTranslator() { super(Schema.Type.RECORD); } - public static AvroTranslator getInstance() - { + public static AvroTranslator getInstance() { return INSTANCE; } @Override protected void doTranslate(final Schema avroSchema, - final MutableTree jsonSchema, final ProcessingReport report) - throws ProcessingException - { + final MutableTree jsonSchema, final ProcessingReport report) + throws ProcessingException { final List fields = avroSchema.getFields(); if (fields.isEmpty()) { @@ -66,14 +63,12 @@ protected void doTranslate(final Schema avroSchema, final JsonPointer pwd = jsonSchema.getPointer(); - if (avroSchema.getDoc() != null) + if (avroSchema.getDoc() != null) { jsonSchema.getCurrentNode().put("description", avroSchema.getDoc()); + } jsonSchema.setType(NodeType.OBJECT); - final ArrayNode required = FACTORY.arrayNode(); - jsonSchema.getCurrentNode().put("required", required); - jsonSchema.getCurrentNode().put("additionalProperties", false); final ObjectNode properties = FACTORY.objectNode(); @@ -91,12 +86,15 @@ protected void doTranslate(final Schema avroSchema, * FIXME: "default" and readers'/writers' schema? Here, even with a * default value, the record field is marked as required. */ - for (final Schema.Field field: fields) { + final List requiredFields = new LinkedList(); + for (final Schema.Field field : fields) { fieldName = field.name(); fieldSchema = field.schema(); fieldType = fieldSchema.getType(); translator = AvroTranslators.getTranslator(fieldType); - required.add(fieldName); + if (field.defaultValue() == null) { + requiredFields.add(fieldName); + } ptr = JsonPointer.of("properties", fieldName); propertyNode = FACTORY.objectNode(); properties.put(fieldName, propertyNode); @@ -105,14 +103,22 @@ protected void doTranslate(final Schema avroSchema, translator.translate(fieldSchema, jsonSchema, report); jsonSchema.setPointer(pwd); } + + if (requiredFields.size() > 0) { + final ArrayNode required = FACTORY.arrayNode(); + for (String requiredFieldName : requiredFields) { + required.add(requiredFieldName); + } + jsonSchema.getCurrentNode().put("required", required); + } } private static void injectDefault(final ObjectNode propertyNode, - final Schema.Field field) - { + final Schema.Field field) { final JsonNode value = field.defaultValue(); - if (value == null) + if (value == null) { return; + } /* * Write the value to a string using a 1.8 writer, and read it from that diff --git a/src/test/java/com/github/fge/avro/AvroTranslationsTest.java b/src/test/java/com/github/fge/avro/AvroTranslationsTest.java index 59d4656..1504b6e 100644 --- a/src/test/java/com/github/fge/avro/AvroTranslationsTest.java +++ b/src/test/java/com/github/fge/avro/AvroTranslationsTest.java @@ -37,6 +37,7 @@ import java.io.IOException; import java.util.Iterator; import java.util.List; +import java.util.Map; import static org.testng.Assert.*; @@ -79,20 +80,17 @@ public final Iterator testData() } @Test( - dataProvider = "testData", - invocationCount = 10, - threadPoolSize = 4 + dataProvider = "testData" ) public final void conversionIsCorrectlyPerformed(final JsonNode avroSchema, final JsonNode jsonSchema) throws ProcessingException { - final ValueHolder input - = ValueHolder.hold(new SimpleJsonTree(avroSchema)); - + JsonTree tree = new SimpleJsonTree(avroSchema); + final ValueHolder input = ValueHolder.hold(tree); final ValueHolder output = PROCESSOR.process(report, input); - assertTrue(output.getValue().getBaseNode().equals(jsonSchema)); assertTrue(VALIDATOR.schemaIsValid(jsonSchema)); + assertTrue(output.getValue().getBaseNode().equals(jsonSchema)); } } diff --git a/src/test/resources/avro/fromSource.json b/src/test/resources/avro/fromSource.json index 2624cce..8196319 100644 --- a/src/test/resources/avro/fromSource.json +++ b/src/test/resources/avro/fromSource.json @@ -72,7 +72,7 @@ }, "record:org.apache.avro.FooBarSpecificRecord": { "type": "object", - "required": [ "id", "relatedids", "typeEnum" ], + "required": [ "id", "relatedids" ], "additionalProperties": false, "properties": { "id": { @@ -428,7 +428,6 @@ "definitions": { "record:org.apache.avro.mapreduce.TextStats": { "type": "object", - "required": [ "name", "count" ], "additionalProperties": false, "properties": { "name": { diff --git a/src/test/resources/avro/record.json b/src/test/resources/avro/record.json index 591cf2f..923af6a 100644 --- a/src/test/resources/avro/record.json +++ b/src/test/resources/avro/record.json @@ -7,7 +7,8 @@ "fields": [ { "name": "value", - "type": "long" + "type": "long", + "default": 1 }, { "name": "next", @@ -21,12 +22,13 @@ "record:LongList": { "type": "object", "additionalProperties": false, - "required": [ "value", "next" ], + "required": [ "next" ], "properties": { "value": { "type": "integer", "minimum": -9223372036854775808, - "maximum": 9223372036854775807 + "maximum": 9223372036854775807, + "default": 1 }, "next": { "oneOf": [ @@ -57,7 +59,7 @@ "type": "record", "name": "bar", "fields": [ - { "name": "moo", "type": "int", "default": -1 } + { "name": "moo", "type": "int", "default": 1 } ] }, "jsonSchema": { @@ -65,14 +67,13 @@ "definitions": { "record:bar": { "type": "object", - "required": [ "moo" ], "additionalProperties": false, "properties": { "moo": { "type": "integer", "minimum": -2147483648, "maximum": 2147483647, - "default": -1 + "default": 1 } } }