diff --git a/avro-builder/tests/codegen-110/src/main/avro/vs110/TestCollections.avsc b/avro-builder/tests/codegen-110/src/main/avro/vs110/TestCollections.avsc index 6e3b6f58f..a47652f91 100644 --- a/avro-builder/tests/codegen-110/src/main/avro/vs110/TestCollections.avsc +++ b/avro-builder/tests/codegen-110/src/main/avro/vs110/TestCollections.avsc @@ -78,6 +78,16 @@ "type": "array", "items": "int" } + }, + { + "name": "unionOfIntMap", + "type": [ + "null", + { + "type": "map", + "values": "int" + } + ] } ], "type": "record" diff --git a/avro-builder/tests/codegen-111/src/main/avro/vs111/TestCollections.avsc b/avro-builder/tests/codegen-111/src/main/avro/vs111/TestCollections.avsc index ebbb6de31..31d8bf286 100644 --- a/avro-builder/tests/codegen-111/src/main/avro/vs111/TestCollections.avsc +++ b/avro-builder/tests/codegen-111/src/main/avro/vs111/TestCollections.avsc @@ -79,6 +79,16 @@ "type": "array", "items": "int" } + }, + { + "name": "unionOfIntMap", + "type": [ + "null", + { + "type": "map", + "values": "int" + } + ] } ], "type": "record" diff --git a/avro-builder/tests/codegen-14/src/main/avro/vs14/TestCollections.avsc b/avro-builder/tests/codegen-14/src/main/avro/vs14/TestCollections.avsc index c8cb8cbeb..bb529c94f 100644 --- a/avro-builder/tests/codegen-14/src/main/avro/vs14/TestCollections.avsc +++ b/avro-builder/tests/codegen-14/src/main/avro/vs14/TestCollections.avsc @@ -79,6 +79,16 @@ "type": "array", "items": "int" } + }, + { + "name": "unionOfIntMap", + "type": [ + "null", + { + "type": "map", + "values": "int" + } + ] } ], "type": "record" diff --git a/avro-builder/tests/codegen-15/src/main/avro/vs15/TestCollections.avsc b/avro-builder/tests/codegen-15/src/main/avro/vs15/TestCollections.avsc index e4d4fe3a9..5e79b2177 100644 --- a/avro-builder/tests/codegen-15/src/main/avro/vs15/TestCollections.avsc +++ b/avro-builder/tests/codegen-15/src/main/avro/vs15/TestCollections.avsc @@ -79,6 +79,16 @@ "type": "array", "items": "int" } + }, + { + "name": "unionOfIntMap", + "type": [ + "null", + { + "type": "map", + "values": "int" + } + ] } ], "type": "record" diff --git a/avro-builder/tests/codegen-16/src/main/avro/vs16/TestCollections.avsc b/avro-builder/tests/codegen-16/src/main/avro/vs16/TestCollections.avsc index 3e5832ad0..a79e1144a 100644 --- a/avro-builder/tests/codegen-16/src/main/avro/vs16/TestCollections.avsc +++ b/avro-builder/tests/codegen-16/src/main/avro/vs16/TestCollections.avsc @@ -79,6 +79,16 @@ "type": "array", "items": "int" } + }, + { + "name": "unionOfIntMap", + "type": [ + "null", + { + "type": "map", + "values": "int" + } + ] } ], "type": "record" diff --git a/avro-builder/tests/codegen-17/src/main/avro/vs17/TestCollections.avsc b/avro-builder/tests/codegen-17/src/main/avro/vs17/TestCollections.avsc index ac9430f16..717c97ddd 100644 --- a/avro-builder/tests/codegen-17/src/main/avro/vs17/TestCollections.avsc +++ b/avro-builder/tests/codegen-17/src/main/avro/vs17/TestCollections.avsc @@ -79,6 +79,16 @@ "type": "array", "items": "int" } + }, + { + "name": "unionOfIntMap", + "type": [ + "null", + { + "type": "map", + "values": "int" + } + ] } ], "type": "record" diff --git a/avro-builder/tests/codegen-18/src/main/avro/vs18/TestCollections.avsc b/avro-builder/tests/codegen-18/src/main/avro/vs18/TestCollections.avsc index 42fa056fd..3fbbd5832 100644 --- a/avro-builder/tests/codegen-18/src/main/avro/vs18/TestCollections.avsc +++ b/avro-builder/tests/codegen-18/src/main/avro/vs18/TestCollections.avsc @@ -79,6 +79,16 @@ "type": "array", "items": "int" } + }, + { + "name": "unionOfIntMap", + "type": [ + "null", + { + "type": "map", + "values": "int" + } + ] } ], "type": "record" diff --git a/avro-builder/tests/codegen-19/src/main/avro/vs19/TestCollections.avsc b/avro-builder/tests/codegen-19/src/main/avro/vs19/TestCollections.avsc index 2651f92e9..7c9f39d0f 100644 --- a/avro-builder/tests/codegen-19/src/main/avro/vs19/TestCollections.avsc +++ b/avro-builder/tests/codegen-19/src/main/avro/vs19/TestCollections.avsc @@ -79,6 +79,16 @@ "type": "array", "items": "int" } + }, + { + "name": "unionOfIntMap", + "type": [ + "null", + { + "type": "map", + "values": "int" + } + ] } ], "type": "record" diff --git a/avro-builder/tests/codegen-charseq-method/src/main/avro/charseqmethod/TestCollections.avsc b/avro-builder/tests/codegen-charseq-method/src/main/avro/charseqmethod/TestCollections.avsc index 9dcaac88d..81933b9e5 100644 --- a/avro-builder/tests/codegen-charseq-method/src/main/avro/charseqmethod/TestCollections.avsc +++ b/avro-builder/tests/codegen-charseq-method/src/main/avro/charseqmethod/TestCollections.avsc @@ -79,6 +79,16 @@ "type": "array", "items": "int" } + }, + { + "name": "unionOfIntMap", + "type": [ + "null", + { + "type": "map", + "values": "int" + } + ] } ], "type": "record" diff --git a/avro-builder/tests/codegen-no-utf8-in-putbyindex/src/main/avro/charseqmethod/TestCollections.avsc b/avro-builder/tests/codegen-no-utf8-in-putbyindex/src/main/avro/charseqmethod/TestCollections.avsc index e8b8e730d..9e9a56baa 100644 --- a/avro-builder/tests/codegen-no-utf8-in-putbyindex/src/main/avro/charseqmethod/TestCollections.avsc +++ b/avro-builder/tests/codegen-no-utf8-in-putbyindex/src/main/avro/charseqmethod/TestCollections.avsc @@ -79,6 +79,16 @@ "type": "array", "items": "int" } + }, + { + "name": "unionOfIntMap", + "type": [ + "null", + { + "type": "map", + "values": "int" + } + ] } ], "type": "record" diff --git a/avro-builder/tests/tests-allavro/src/test/java/com/linkedin/avroutil1/builder/SpecificRecordTest.java b/avro-builder/tests/tests-allavro/src/test/java/com/linkedin/avroutil1/builder/SpecificRecordTest.java index 302c7b40c..3e09a5107 100644 --- a/avro-builder/tests/tests-allavro/src/test/java/com/linkedin/avroutil1/builder/SpecificRecordTest.java +++ b/avro-builder/tests/tests-allavro/src/test/java/com/linkedin/avroutil1/builder/SpecificRecordTest.java @@ -111,10 +111,10 @@ private Object[][] TestRoundTripSerializationProvider() { {vs110.BuilderTester.class, vs110.BuilderTester.getClassSchema()}, {vs111.BuilderTester.class, vs111.BuilderTester.getClassSchema()}, - {charseqmethod.TestCollections.class, charseqmethod.TestCollections.getClassSchema()}, + {charseqmethod.TestCollections.class, charseqmethod.TestCollections.getClassSchema()} - {vs14.ThousandField.class, vs14.ThousandField.getClassSchema()}, - {vs19.ThousandField.class, vs19.ThousandField.getClassSchema()} +// {vs14.ThousandField.class, vs14.ThousandField.getClassSchema()}, +// {vs19.ThousandField.class, vs19.ThousandField.getClassSchema()} }; } @@ -1374,6 +1374,7 @@ private Object[][] testStringTypeParamsProvider() { put("arOfUnionOfStr", "java.util.List"); put("arOfMapOfUnionOfArray", "java.util.List>>"); put("intAr", "java.util.List"); + put("unionOfIntMap", "java.util.Map"); }}; Map vs14TestCollectionsCharSeqFieldToType = new LinkedHashMap() {{ @@ -1386,6 +1387,7 @@ private Object[][] testStringTypeParamsProvider() { put("arOfUnionOfStr", "java.util.List"); put("arOfMapOfUnionOfArray", "java.util.List>>"); put("intAr", "java.util.List"); + put("unionOfIntMap", "java.util.Map"); }}; return new Object[][]{ @@ -1489,6 +1491,11 @@ public void testRecordWithCharSeqStringTypeForMethods() throws Exception { put("key2", "value2"); }}; + Map mapInt = new HashMap() {{ + put("key1", 1); + put("key2", 2); + }}; + Map> mapOfList = new HashMap>() {{ put("key1", Arrays.asList("val1", "val2")); put("key2", Arrays.asList("val10", "val20")); @@ -1501,7 +1508,8 @@ public void testRecordWithCharSeqStringTypeForMethods() throws Exception { .setArOfMap(Arrays.asList(mapCharSeq)) .setUnionOfMap(mapCharSeq) .setArOfUnionOfStr(Arrays.asList(str)) - .setArOfMapOfUnionOfArray(Arrays.asList(mapOfList)).setIntAr(Arrays.asList(1, 2, 3)); + .setArOfMapOfUnionOfArray(Arrays.asList(mapOfList)).setIntAr(Arrays.asList(1, 2, 3)) + .setUnionOfIntMap(mapInt); charseqmethod.TestCollections testCollections = testCollectionsBuilder.build(); @@ -1573,6 +1581,8 @@ public void testRecordWithCharSeqStringTypeForMethods() throws Exception { Assert.assertTrue(((List) ((Map.Entry)entry).getValue()).get(0) instanceof CharSequence); Assert.assertTrue(((List) ((Map.Entry)entry).getValue()).get(0) instanceof Utf8); } + + Assert.assertEquals(testCollections.getUnionOfIntMap().size(), 2); } @DataProvider @@ -1840,7 +1850,8 @@ public void testNewBuilder() throws Exception { .setArOfMap(instance.getArOfMap()) .setUnionOfMap(instance.getUnionOfMap()) .setArOfUnionOfStr(instance.getArOfUnionOfStr()) - .setArOfMapOfUnionOfArray(instance.getArOfMapOfUnionOfArray()); + .setArOfMapOfUnionOfArray(instance.getArOfMapOfUnionOfArray()) + .setUnionOfIntMap(instance.getUnionOfIntMap()); TestCollections.newBuilder(builder); @@ -1851,7 +1862,7 @@ public void testNewBuilder() throws Exception { public void modifiablePrimitiveCollectionTest() { String tba = "NewElement"; RandomRecordGenerator generator = new RandomRecordGenerator(); - TestCollections instance = generator.randomSpecific(TestCollections.class, RecordGenerationConfig.newConfig().withAvoidNulls(true)); + vs18.TestCollections instance = generator.randomSpecific(vs18.TestCollections.class, RecordGenerationConfig.newConfig().withAvoidNulls(true)); // array of string instance.getStrAr().add(tba); @@ -1877,6 +1888,11 @@ public void modifiablePrimitiveCollectionTest() { instance.getIntAr().add(Integer.MAX_VALUE); Assert.assertEquals((int) instance.getIntAr().get(instance.getIntAr().size() - 1), Integer.MAX_VALUE); Assert.assertEquals((int) instance.intAr.get(instance.getIntAr().size() - 1), Integer.MAX_VALUE); + + // Union (null, Map) + instance.getUnionOfIntMap().put("key1", Integer.MAX_VALUE); + Assert.assertEquals(Integer.MAX_VALUE, (int) instance.getUnionOfIntMap().get("key1")); + Assert.assertEquals(Integer.MAX_VALUE, (int) instance.getUnionOfIntMap().get("key1")); } @Test @@ -1909,6 +1925,11 @@ public void modifiablePrimitiveCollectionTestForCharSeq() { instance.getIntAr().add(Integer.MAX_VALUE); Assert.assertEquals((int) instance.getIntAr().get(instance.getIntAr().size() - 1), Integer.MAX_VALUE); Assert.assertEquals((int) instance.intAr.get(instance.getIntAr().size() - 1), Integer.MAX_VALUE); + + // Union (null, Map) + instance.getUnionOfIntMap().put("key1", Integer.MAX_VALUE); + Assert.assertEquals(Integer.MAX_VALUE, (int) instance.getUnionOfIntMap().get("key1")); + Assert.assertEquals(Integer.MAX_VALUE, (int) instance.getUnionOfIntMap().get("key1")); } @Test @@ -1941,6 +1962,48 @@ public void testCharSeqAccessorForNoUtf8() { instance.getIntAr().add(Integer.MAX_VALUE); Assert.assertEquals((int) instance.getIntAr().get(instance.getIntAr().size() - 1), Integer.MAX_VALUE); Assert.assertEquals((int) instance.intAr.get(instance.getIntAr().size() - 1), Integer.MAX_VALUE); + + // Union (null, Map) + instance.getUnionOfIntMap().put("key1", Integer.MAX_VALUE); + Assert.assertEquals(Integer.MAX_VALUE, (int) instance.getUnionOfIntMap().get("key1")); + Assert.assertEquals(Integer.MAX_VALUE, (int) instance.getUnionOfIntMap().get("key1")); + } + + @Test + public void testCharSeqAccessorForCharseq() { + String tba = "NewElement"; + RandomRecordGenerator generator = new RandomRecordGenerator(); + charseqmethod.TestCollections instance = generator.randomSpecific(charseqmethod.TestCollections.class, RecordGenerationConfig.newConfig().withAvoidNulls(true)); + + // array of string + instance.getStrAr().add(tba); + Assert.assertTrue(instance.getStrAr().contains(tba)); + Assert.assertTrue(instance.strAr.contains(new Utf8(tba))); + + // union[null, List] + instance.getUnionOfArray().add(tba); + Assert.assertTrue(instance.getUnionOfArray().contains(tba)); + Assert.assertTrue(instance.unionOfArray.contains(new Utf8(tba))); + + // array (union[null, string]) + instance.getArOfUnionOfStr().add(tba); + Assert.assertTrue(instance.getArOfUnionOfStr().contains(tba)); + Assert.assertTrue(instance.arOfUnionOfStr.contains(new Utf8(tba))); + + + // Union (null, Map) + instance.getUnionOfMap().put("key1", tba); + Assert.assertEquals(tba, instance.getUnionOfMap().get("key1")); + Assert.assertEquals(new Utf8(tba), instance.unionOfMap.get(new Utf8("key1"))); + + instance.getIntAr().add(Integer.MAX_VALUE); + Assert.assertEquals((int) instance.getIntAr().get(instance.getIntAr().size() - 1), Integer.MAX_VALUE); + Assert.assertEquals((int) instance.intAr.get(instance.getIntAr().size() - 1), Integer.MAX_VALUE); + + // Union (null, Map) + instance.getUnionOfIntMap().put("key1", Integer.MAX_VALUE); + Assert.assertEquals(Integer.MAX_VALUE, (int) instance.getUnionOfIntMap().get("key1")); + Assert.assertEquals(Integer.MAX_VALUE, (int) instance.getUnionOfIntMap().get("key1")); } @BeforeClass diff --git a/avro-builder/tests/tests-allavro/src/test/java/com/linkedin/avroutil1/compatibility/collectiontransformer/CollectionViewTest.java b/avro-builder/tests/tests-allavro/src/test/java/com/linkedin/avroutil1/compatibility/collectiontransformer/CollectionViewTest.java index fde87bd20..f8085c166 100644 --- a/avro-builder/tests/tests-allavro/src/test/java/com/linkedin/avroutil1/compatibility/collectiontransformer/CollectionViewTest.java +++ b/avro-builder/tests/tests-allavro/src/test/java/com/linkedin/avroutil1/compatibility/collectiontransformer/CollectionViewTest.java @@ -151,7 +151,7 @@ public void testStringMapView() { } // utf8 map should contain the same 3 elements for (String key : keys) { - Assert.assertTrue(utf8Map.containsKey(new Utf8(key))); + Assert.assertTrue(utf8Map.containsKey(key)); } // remove from map @@ -220,7 +220,7 @@ public void testCharSequenceMapView() { } // utf8 map should contain the same 3 elements for (CharSequence key : keys) { - Assert.assertTrue(utf8Map.containsKey(new Utf8(String.valueOf(key)))); + Assert.assertTrue(utf8Map.containsKey(key)); } // remove from view diff --git a/helper/helper/src/main/java/com/linkedin/avroutil1/compatibility/collectiontransformer/CollectionTransformerUtil.java b/helper/helper/src/main/java/com/linkedin/avroutil1/compatibility/collectiontransformer/CollectionTransformerUtil.java index 39b022478..3787dc050 100644 --- a/helper/helper/src/main/java/com/linkedin/avroutil1/compatibility/collectiontransformer/CollectionTransformerUtil.java +++ b/helper/helper/src/main/java/com/linkedin/avroutil1/compatibility/collectiontransformer/CollectionTransformerUtil.java @@ -53,11 +53,18 @@ public static List createUtf8ListView(List utf8List) { * @param utf8Map map of {@link Utf8} objects * @return a {@link StringMapView} for the given map of {@link Utf8} objects */ - public static Map createStringMapView(Map utf8Map) { + public static Map createStringMapView(Map utf8Map) { if (utf8Map == null) { return null; } - return new StringMapView(utf8Map); + if (utf8Map.isEmpty()) { + return utf8Map; + } + Object val = utf8Map.values().iterator().next(); + if (val instanceof CharSequence) { + return new StringMapView(utf8Map); + } + return utf8Map; } /** @@ -65,7 +72,7 @@ public static Map createStringMapView(Map utf8Map) { * @param utf8Map map of {@link Utf8} objects * @return a {@link CharSequenceMapView} for the given map of {@link Utf8} objects */ - public static Map createUtf8MapView(Map utf8Map) { + public static Map createUtf8MapView(Map utf8Map) { return utf8Map; } @@ -74,10 +81,17 @@ public static Map createUtf8MapView(Map utf8Map) { * @param utf8Map map of {@link Utf8} objects * @return a {@link CharSequenceMapView} for the given map of {@link Utf8} objects */ - public static Map createCharSequenceMapView(Map utf8Map) { + public static Map createCharSequenceMapView(Map utf8Map) { if (utf8Map == null) { return null; } - return new CharSequenceMapView(utf8Map); + if (utf8Map.isEmpty()) { + return utf8Map; + } + Object val = utf8Map.values().iterator().next(); + if (val instanceof CharSequence) { + return new CharSequenceMapView(utf8Map); + } + return utf8Map; } } diff --git a/helper/helper/src/main/java/com/linkedin/avroutil1/compatibility/collectiontransformer/MapTransformer.java b/helper/helper/src/main/java/com/linkedin/avroutil1/compatibility/collectiontransformer/MapTransformer.java index ad732d1b7..78dc56dee 100644 --- a/helper/helper/src/main/java/com/linkedin/avroutil1/compatibility/collectiontransformer/MapTransformer.java +++ b/helper/helper/src/main/java/com/linkedin/avroutil1/compatibility/collectiontransformer/MapTransformer.java @@ -62,7 +62,7 @@ public static Map getUtf8Map(Object mapObj, boolean isPrimitiveCollection) { public static Map getStringMap(Object mapObj, boolean isPrimitiveCollection) { if(isPrimitiveCollection) { - return CollectionTransformerUtil.createStringMapView((Map) mapObj); + return CollectionTransformerUtil.createStringMapView((Map) mapObj); } if (mapObj == null) { return null;