@@ -2061,7 +2061,7 @@ record = datumReader.read(record, decoder);
20612061 }
20622062
20632063 @ Test
2064- public void testWriteNonNullableMap () throws Exception {
2064+ public void testWriteMap () throws Exception {
20652065
20662066 // Field definitions
20672067 FieldType intMapField = new FieldType (false , new ArrowType .Map (false ), null );
@@ -2135,7 +2135,7 @@ public void testWriteNonNullableMap() throws Exception {
21352135 dateWriter .endMap ();
21362136 }
21372137
2138- File dataFile = new File (TMP , "testWriteNonNullableMap .avro" );
2138+ File dataFile = new File (TMP , "testWriteMap .avro" );
21392139
21402140 // Write an AVRO block using the producer classes
21412141 try (FileOutputStream fos = new FileOutputStream (dataFile )) {
@@ -2170,8 +2170,132 @@ record = datumReader.read(record, decoder);
21702170 }
21712171 }
21722172
2173+ @ Test
2174+ public void testWriteNullableMap () throws Exception {
2175+
2176+ // Field definitions
2177+ FieldType nullMapType = new FieldType (true , new ArrowType .Map (false ), null );
2178+ FieldType nonNullMapType = new FieldType (false , new ArrowType .Map (false ), null );
2179+
2180+ Field keyField = new Field ("key" , FieldType .notNullable (new ArrowType .Utf8 ()), null );
2181+ Field nullFieldType = new Field ("value" , FieldType .nullable (new ArrowType .Int (32 , true )), null );
2182+ Field nonNullFieldType = new Field ("value" , FieldType .notNullable (new ArrowType .Int (32 , true )), null );
2183+ Field nullEntryField = new Field ("entries" , FieldType .notNullable (new ArrowType .Struct ()), Arrays .asList (keyField , nullFieldType ));
2184+ Field nonNullEntryField = new Field ("entries" , FieldType .notNullable (new ArrowType .Struct ()), Arrays .asList (keyField , nonNullFieldType ));
2185+
2186+ // Create empty vectors
2187+ BufferAllocator allocator = new RootAllocator ();
2188+ MapVector nullEntriesVector = new MapVector ("nullEntriesVector" , allocator , nonNullMapType , null );
2189+ MapVector nullMapVector = new MapVector ("nullMapVector" , allocator , nullMapType , null );
2190+ MapVector nullBothVector = new MapVector ("nullBothVector" , allocator , nullMapType , null );
2191+
2192+ nullEntriesVector .initializeChildrenFromFields (Arrays .asList (nullEntryField ));
2193+ nullMapVector .initializeChildrenFromFields (Arrays .asList (nonNullEntryField ));
2194+ nullBothVector .initializeChildrenFromFields (Arrays .asList (nullEntryField ));
2195+
2196+ // Set up VSR
2197+ List <FieldVector > vectors = Arrays .asList (nullEntriesVector , nullMapVector , nullBothVector );
2198+ int rowCount = 3 ;
2199+
2200+ try (VectorSchemaRoot root = new VectorSchemaRoot (vectors )) {
2201+
2202+ root .setRowCount (rowCount );
2203+ root .allocateNew ();
2204+
2205+ // Set test data for intList
2206+ BaseWriter .MapWriter writer = nullEntriesVector .getWriter ();
2207+ writer .startMap ();
2208+ writer .startEntry ();
2209+ writer .key ().varChar ().writeVarChar ("key0" );
2210+ writer .value ().integer ().writeNull ();
2211+ writer .endEntry ();
2212+ writer .endMap ();
2213+ writer .startMap ();
2214+ writer .startEntry ();
2215+ writer .key ().varChar ().writeVarChar ("key1" );
2216+ writer .value ().integer ().writeInt (0 );
2217+ writer .endEntry ();
2218+ writer .endMap ();
2219+ writer .startMap ();
2220+ writer .startEntry ();
2221+ writer .key ().varChar ().writeVarChar ("key2" );
2222+ writer .value ().integer ().writeInt (1 );
2223+ writer .endEntry ();
2224+ writer .endMap ();
2225+
2226+ // Set test data for stringList
2227+ BaseWriter .MapWriter nullMapWriter = nullMapVector .getWriter ();
2228+ nullMapWriter .writeNull ();
2229+ nullMapWriter .startMap ();
2230+ nullMapWriter .startEntry ();
2231+ nullMapWriter .key ().varChar ().writeVarChar ("key1" );
2232+ nullMapWriter .value ().integer ().writeInt (0 );
2233+ nullMapWriter .endEntry ();
2234+ nullMapWriter .endMap ();
2235+ nullMapWriter .startMap ();
2236+ nullMapWriter .startEntry ();
2237+ nullMapWriter .key ().varChar ().writeVarChar ("key2" );
2238+ nullMapWriter .value ().integer ().writeInt (1 );
2239+ nullMapWriter .endEntry ();
2240+ nullMapWriter .endMap ();
2241+
2242+ // Set test data for dateList
2243+ BaseWriter .MapWriter nullBothWriter = nullBothVector .getWriter ();
2244+ nullBothWriter .writeNull ();
2245+ nullBothWriter .startMap ();
2246+ nullBothWriter .startEntry ();
2247+ nullBothWriter .key ().varChar ().writeVarChar ("key1" );
2248+ nullBothWriter .value ().integer ().writeNull ();
2249+ nullBothWriter .endEntry ();
2250+ nullBothWriter .endMap ();
2251+ nullBothWriter .startMap ();
2252+ nullBothWriter .startEntry ();
2253+ nullBothWriter .key ().varChar ().writeVarChar ("key2" );
2254+ nullBothWriter .value ().integer ().writeInt (0 );
2255+ nullBothWriter .endEntry ();
2256+ nullBothWriter .endMap ();
2257+
2258+ File dataFile = new File (TMP , "testWriteNullableMap.avro" );
2259+
2260+ // Write an AVRO block using the producer classes
2261+ try (FileOutputStream fos = new FileOutputStream (dataFile )) {
2262+ BinaryEncoder encoder = new EncoderFactory ().directBinaryEncoder (fos , null );
2263+ CompositeAvroProducer producer = ArrowToAvroUtils .createCompositeProducer (vectors );
2264+ for (int row = 0 ; row < rowCount ; row ++) {
2265+ producer .produce (encoder );
2266+ }
2267+ encoder .flush ();
2268+ }
2269+
2270+ // Set up reading the AVRO block as a GenericRecord
2271+ Schema schema = ArrowToAvroUtils .createAvroSchema (root .getSchema ().getFields ());
2272+ GenericDatumReader <GenericRecord > datumReader = new GenericDatumReader <>(schema );
2273+
2274+ try (InputStream inputStream = new FileInputStream (dataFile )) {
2275+
2276+ BinaryDecoder decoder = DecoderFactory .get ().binaryDecoder (inputStream , null );
2277+ GenericRecord record = null ;
2278+
2279+ // Read and check values
2280+ for (int row = 0 ; row < rowCount ; row ++) {
2281+ record = datumReader .read (record , decoder );
2282+ Map <String , Object > intMap = convertMap (nullEntriesVector .getObject (row ));
2283+ Map <String , Object > stringMap = convertMap (nullMapVector .getObject (row ));
2284+ Map <String , Object > dateMap = convertMap (nullBothVector .getObject (row ));
2285+ compareMaps (intMap , (Map ) record .get ("nullEntriesVector" ));
2286+ compareMaps (stringMap , (Map ) record .get ("nullMapVector" ));
2287+ compareMaps (dateMap , (Map ) record .get ("nullBothVector" ));
2288+ }
2289+ }
2290+ }
2291+ }
2292+
21732293 private Map <String , Object > convertMap (List <?> entryList ) {
21742294
2295+ if (entryList == null ) {
2296+ return null ;
2297+ }
2298+
21752299 Map <String , Object > map = new HashMap <>();
21762300 JsonStringArrayList <?> structList = (JsonStringArrayList <?>) entryList ;
21772301 for (Object entry : structList ) {
@@ -2184,14 +2308,19 @@ private Map<String, Object> convertMap(List<?> entryList) {
21842308 }
21852309
21862310 private void compareMaps (Map <String , ?> expected , Map <?, ?> actual ) {
2187- assertEquals (expected .size (), actual .size ());
2188- for (Object key : actual .keySet ()) {
2189- assertTrue (expected .containsKey (key .toString ()));
2190- Object actualValue = actual .get (key );
2191- if (actualValue instanceof Utf8 ) {
2192- assertEquals (expected .get (key .toString ()).toString (), actualValue .toString ());
2193- } else {
2194- assertEquals (expected .get (key .toString ()), actual .get (key ));
2311+ if (expected == null ) {
2312+ assertNull (actual );
2313+ }
2314+ else {
2315+ assertEquals (expected .size (), actual .size ());
2316+ for (Object key : actual .keySet ()) {
2317+ assertTrue (expected .containsKey (key .toString ()));
2318+ Object actualValue = actual .get (key );
2319+ if (actualValue instanceof Utf8 ) {
2320+ assertEquals (expected .get (key .toString ()).toString (), actualValue .toString ());
2321+ } else {
2322+ assertEquals (expected .get (key .toString ()), actual .get (key ));
2323+ }
21952324 }
21962325 }
21972326 }
0 commit comments