diff --git a/helper/impls/helper-impl-110/src/main/java/com/linkedin/avroutil1/compatibility/avro110/FieldBuilder110.java b/helper/impls/helper-impl-110/src/main/java/com/linkedin/avroutil1/compatibility/avro110/FieldBuilder110.java index 72752b32f..fe4fc5c23 100644 --- a/helper/impls/helper-impl-110/src/main/java/com/linkedin/avroutil1/compatibility/avro110/FieldBuilder110.java +++ b/helper/impls/helper-impl-110/src/main/java/com/linkedin/avroutil1/compatibility/avro110/FieldBuilder110.java @@ -10,7 +10,9 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.linkedin.avroutil1.compatibility.AvroSchemaUtil; import com.linkedin.avroutil1.compatibility.FieldBuilder; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import org.apache.avro.JsonProperties; import org.apache.avro.Schema; @@ -169,6 +171,15 @@ public Schema.Field build() { * @return a representation of the input that avro likes for use as a field default value */ private static Object avroFriendlyDefaultValue(Object mightNotBeFriendly) throws Exception { + // handle default values that are lists + if (mightNotBeFriendly instanceof List) { + List list = (List) mightNotBeFriendly; + List result = new ArrayList<>(list.size()); + for (Object element : list) { + result.add(avroFriendlyDefaultValue(element)); + } + return result; + } //generic enums we turn to strings if (mightNotBeFriendly instanceof GenericData.EnumSymbol) { diff --git a/helper/impls/helper-impl-111/src/main/java/com/linkedin/avroutil1/compatibility/avro111/FieldBuilder111.java b/helper/impls/helper-impl-111/src/main/java/com/linkedin/avroutil1/compatibility/avro111/FieldBuilder111.java index a5519632a..432f2d54d 100644 --- a/helper/impls/helper-impl-111/src/main/java/com/linkedin/avroutil1/compatibility/avro111/FieldBuilder111.java +++ b/helper/impls/helper-impl-111/src/main/java/com/linkedin/avroutil1/compatibility/avro111/FieldBuilder111.java @@ -10,7 +10,9 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.linkedin.avroutil1.compatibility.AvroSchemaUtil; import com.linkedin.avroutil1.compatibility.FieldBuilder; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import org.apache.avro.JsonProperties; import org.apache.avro.Schema; @@ -168,6 +170,15 @@ public FieldBuilder removeProp(String propName) { * @return a representation of the input that avro likes for use as a field default value */ private static Object avroFriendlyDefaultValue(Object mightNotBeFriendly) throws Exception { + // handle default values that are lists + if (mightNotBeFriendly instanceof List) { + List list = (List) mightNotBeFriendly; + List result = new ArrayList<>(list.size()); + for (Object element : list) { + result.add(avroFriendlyDefaultValue(element)); + } + return result; + } //generic enums we turn to strings if (mightNotBeFriendly instanceof GenericData.EnumSymbol) { diff --git a/helper/impls/helper-impl-19/src/main/java/com/linkedin/avroutil1/compatibility/avro19/FieldBuilder19.java b/helper/impls/helper-impl-19/src/main/java/com/linkedin/avroutil1/compatibility/avro19/FieldBuilder19.java index ea5f6548f..1bbfc68a7 100644 --- a/helper/impls/helper-impl-19/src/main/java/com/linkedin/avroutil1/compatibility/avro19/FieldBuilder19.java +++ b/helper/impls/helper-impl-19/src/main/java/com/linkedin/avroutil1/compatibility/avro19/FieldBuilder19.java @@ -10,12 +10,13 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.linkedin.avroutil1.compatibility.AvroSchemaUtil; import com.linkedin.avroutil1.compatibility.FieldBuilder; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; +import java.util.Map; import org.apache.avro.JsonProperties; import org.apache.avro.Schema; import org.apache.avro.Schema.Field.Order; - -import java.util.Map; import org.apache.avro.generic.GenericData; import org.apache.avro.generic.GenericFixed; import org.apache.avro.generic.IndexedRecord; @@ -170,6 +171,15 @@ public FieldBuilder removeProp(String propName) { * @return a representation of the input that avro likes for use as a field default value */ private static Object avroFriendlyDefaultValue(Object mightNotBeFriendly) throws Exception { + // handle default values that are lists + if (mightNotBeFriendly instanceof List) { + List list = (List) mightNotBeFriendly; + List result = new ArrayList<>(list.size()); + for (Object element : list) { + result.add(avroFriendlyDefaultValue(element)); + } + return result; + } //generic enums we turn to strings if (mightNotBeFriendly instanceof GenericData.EnumSymbol) { diff --git a/helper/tests/helper-tests-110/src/test/java/com/linkedin/avroutil1/compatibility/avro110/Avro110FieldBuilderTest.java b/helper/tests/helper-tests-110/src/test/java/com/linkedin/avroutil1/compatibility/avro110/Avro110FieldBuilderTest.java index 4966f84ca..abe1fe409 100644 --- a/helper/tests/helper-tests-110/src/test/java/com/linkedin/avroutil1/compatibility/avro110/Avro110FieldBuilderTest.java +++ b/helper/tests/helper-tests-110/src/test/java/com/linkedin/avroutil1/compatibility/avro110/Avro110FieldBuilderTest.java @@ -10,6 +10,7 @@ import com.linkedin.avroutil1.compatibility.AvroCompatibilityHelper; import com.linkedin.avroutil1.compatibility.FieldBuilder; import com.linkedin.avroutil1.testcommon.TestUtil; +import java.io.IOException; import java.util.HashMap; import java.util.Map; import org.apache.avro.AvroRuntimeException; @@ -159,6 +160,19 @@ public void testNullDefaultForBoolField() throws Exception { } } + @Test + public void testArrayOfEnumDefaultValue() throws IOException { + Schema schema = Schema.parse(TestUtil.load("FieldWithArrayOfEnumDefaultValue.avsc")); + Schema.Field field = schema.getField("arrayOfEnum"); + Object defaultValue = AvroCompatibilityHelper.getGenericDefaultValue(field); + FieldBuilder builder = AvroCompatibilityHelper.newField(field); + builder.setDefault(defaultValue); + + // Test that .build() should not throw an exception. + Schema.Field resField = builder.build(); + Assert.assertNotNull(resField.defaultVal()); + } + @Test public void testAddPropsFields() { // default (no order specified). diff --git a/helper/tests/helper-tests-111/src/test/java/com/linkedin/avroutil1/compatibility/avro111/Avro111FieldBuilderTest.java b/helper/tests/helper-tests-111/src/test/java/com/linkedin/avroutil1/compatibility/avro111/Avro111FieldBuilderTest.java new file mode 100644 index 000000000..ca199889b --- /dev/null +++ b/helper/tests/helper-tests-111/src/test/java/com/linkedin/avroutil1/compatibility/avro111/Avro111FieldBuilderTest.java @@ -0,0 +1,31 @@ +/* + * Copyright 2023 LinkedIn Corp. + * Licensed under the BSD 2-Clause License (the "License"). + * See License in the project root for license information. + */ + +package com.linkedin.avroutil1.compatibility.avro111; + +import com.linkedin.avroutil1.compatibility.AvroCompatibilityHelper; +import com.linkedin.avroutil1.compatibility.FieldBuilder; +import com.linkedin.avroutil1.testcommon.TestUtil; +import java.io.IOException; +import org.apache.avro.Schema; +import org.testng.Assert; +import org.testng.annotations.Test; + + +public class Avro111FieldBuilderTest { + @Test + public void testArrayOfEnumDefaultValue() throws IOException { + Schema schema = Schema.parse(TestUtil.load("FieldWithArrayOfEnumDefaultValue.avsc")); + Schema.Field field = schema.getField("arrayOfEnum"); + Object defaultValue = AvroCompatibilityHelper.getGenericDefaultValue(field); + FieldBuilder builder = AvroCompatibilityHelper.newField(field); + builder.setDefault(defaultValue); + + // Test that .build() should not throw an exception. + Schema.Field resField = builder.build(); + Assert.assertNotNull(resField); + } +} diff --git a/helper/tests/helper-tests-19/src/test/java/com/linkedin/avroutil1/compatibility/avro19/Avro19FieldBuilderTest.java b/helper/tests/helper-tests-19/src/test/java/com/linkedin/avroutil1/compatibility/avro19/Avro19FieldBuilderTest.java index b53524a83..f79ce05ef 100644 --- a/helper/tests/helper-tests-19/src/test/java/com/linkedin/avroutil1/compatibility/avro19/Avro19FieldBuilderTest.java +++ b/helper/tests/helper-tests-19/src/test/java/com/linkedin/avroutil1/compatibility/avro19/Avro19FieldBuilderTest.java @@ -10,6 +10,7 @@ import com.linkedin.avroutil1.compatibility.AvroCompatibilityHelper; import com.linkedin.avroutil1.compatibility.FieldBuilder; import com.linkedin.avroutil1.testcommon.TestUtil; +import java.io.IOException; import java.util.HashMap; import java.util.Map; import org.apache.avro.AvroRuntimeException; @@ -159,6 +160,18 @@ public void testNullDefaultForBoolField() throws Exception { } } + @Test + public void testArrayOfEnumDefaultValue() throws IOException { + Schema schema = Schema.parse(TestUtil.load("FieldWithArrayOfEnumDefaultValue.avsc")); + Schema.Field field = schema.getField("arrayOfEnum"); + Object defaultValue = AvroCompatibilityHelper.getGenericDefaultValue(field); + FieldBuilder builder = AvroCompatibilityHelper.newField(field); + builder.setDefault(defaultValue); + + // Test that .build() should not throw an exception. + Schema.Field resField = builder.build(); + Assert.assertNotNull(resField.defaultVal()); + } @Test public void testAddPropsFields() { diff --git a/helper/tests/helper-tests-common/src/main/resources/FieldWithArrayOfEnumDefaultValue.avsc b/helper/tests/helper-tests-common/src/main/resources/FieldWithArrayOfEnumDefaultValue.avsc new file mode 100644 index 000000000..b0fbd2f16 --- /dev/null +++ b/helper/tests/helper-tests-common/src/main/resources/FieldWithArrayOfEnumDefaultValue.avsc @@ -0,0 +1,25 @@ +{ + "type": "record", + "name": "FieldWithArrayOfEnumDefaultValue", + "fields": [ + { + "name": "arrayOfEnum", + "type": { + "type": "array", + "items": { + "type": "enum", + "name": "EnumDefaultValue", + "symbols": [ + "A", + "B", + "C" + ] + } + }, + "default": [ + "A", + "B" + ] + } + ] +} \ No newline at end of file