From 1b08260d0b3b5b49f70f7396b7d55ab1cfaeba80 Mon Sep 17 00:00:00 2001 From: Fokko Driesprong Date: Mon, 12 Feb 2024 16:02:03 +0100 Subject: [PATCH] Add some tests --- .../avro/io/BlockingDirectBinaryEncoder.java | 6 +- .../io/TestBlockingDirectBinaryEncoder.java | 77 ++- .../specific/TestRecordWithMapsAndArrays.java | 532 ++++++++++++++---- .../TestRecordWithMapsAndArrays.avsc | 24 + 4 files changed, 525 insertions(+), 114 deletions(-) diff --git a/lang/java/avro/src/main/java/org/apache/avro/io/BlockingDirectBinaryEncoder.java b/lang/java/avro/src/main/java/org/apache/avro/io/BlockingDirectBinaryEncoder.java index bf6e5a63cdc..2ef2375e640 100644 --- a/lang/java/avro/src/main/java/org/apache/avro/io/BlockingDirectBinaryEncoder.java +++ b/lang/java/avro/src/main/java/org/apache/avro/io/BlockingDirectBinaryEncoder.java @@ -54,7 +54,7 @@ public class BlockingDirectBinaryEncoder extends DirectBinaryEncoder { private int depth = 0; - private long blockItemCount; + private final ArrayDeque blockItemCounts; /** * Create a writer that sends its output to the underlying stream @@ -66,6 +66,7 @@ public BlockingDirectBinaryEncoder(OutputStream out) { super(out); this.buffers = new ArrayList<>(); this.stashedBuffers = new ArrayDeque<>(); + this.blockItemCounts = new ArrayDeque<>(); } private void startBlock() { @@ -86,6 +87,7 @@ private void endBlock() { this.depth -= 1; out = stashedBuffers.pop(); BufferOutputStream buffer = this.buffers.get(depth); + long blockItemCount = blockItemCounts.pop(); if (blockItemCount > 0) { try { // Make it negative, so the reader knows that the number of bytes is coming @@ -100,7 +102,7 @@ private void endBlock() { @Override public void setItemCount(long itemCount) throws IOException { - blockItemCount = itemCount; + blockItemCounts.push(itemCount); } @Override diff --git a/lang/java/avro/src/test/java/org/apache/avro/io/TestBlockingDirectBinaryEncoder.java b/lang/java/avro/src/test/java/org/apache/avro/io/TestBlockingDirectBinaryEncoder.java index da2976d18ff..fee4c23e198 100644 --- a/lang/java/avro/src/test/java/org/apache/avro/io/TestBlockingDirectBinaryEncoder.java +++ b/lang/java/avro/src/test/java/org/apache/avro/io/TestBlockingDirectBinaryEncoder.java @@ -22,6 +22,7 @@ import org.apache.avro.generic.GenericDatumReader; import org.apache.avro.message.BinaryMessageDecoder; import org.apache.avro.specific.TestRecordWithMapsAndArrays; +import org.hamcrest.Matchers; import org.junit.jupiter.api.Test; import java.io.ByteArrayOutputStream; @@ -31,6 +32,7 @@ import java.util.Map; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.hasEntry; import static org.hamcrest.Matchers.is; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; @@ -38,6 +40,27 @@ public class TestBlockingDirectBinaryEncoder { + private void writeToArray(BinaryEncoder encoder, int[] numbers) throws IOException { + encoder.writeArrayStart(); + encoder.setItemCount(numbers.length); + for (int number : numbers) { + encoder.startItem(); + encoder.writeString(Integer.toString(number)); + } + encoder.writeArrayEnd(); + } + + private void writeToMap(BinaryEncoder encoder, long[] numbers) throws IOException { + encoder.writeMapStart(); + encoder.setItemCount(numbers.length); + for (long number : numbers) { + encoder.startItem(); + encoder.writeString(Long.toString(number)); + encoder.writeLong(number); + } + encoder.writeMapEnd(); + } + @Test void blockingDirectBinaryEncoder() throws IOException, NoSuchAlgorithmException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); @@ -49,35 +72,57 @@ void blockingDirectBinaryEncoder() throws IOException, NoSuchAlgorithmException encoder.writeFixed(new byte[] { (byte) 0xC3, (byte) 0x01 }); encoder.writeFixed(SchemaNormalization.parsingFingerprint("CRC-64-AVRO", TestRecordWithMapsAndArrays.SCHEMA$)); - int len = 5; + // Array + this.writeToArray(encoder, new int[] { 1, 2, 3, 4, 5 }); + + // Map + writeToMap(encoder, new long[] { 1L, 2L, 3L, 4L, 5L }); + + // Nested Array encoder.writeArrayStart(); - encoder.setItemCount(len); - for (int i = 0; i < len; i++) { - encoder.startItem(); - encoder.writeString(Integer.toString(i)); - } + encoder.setItemCount(2); + this.writeToArray(encoder, new int[] { 1, 2 }); + this.writeToArray(encoder, new int[] { 3, 4, 5 }); encoder.writeArrayEnd(); + // Nested Map + encoder.writeMapStart(); - encoder.setItemCount(len); - for (long i = 0; i < len; i++) { - encoder.startItem(); - encoder.writeString(Long.toString(i)); - encoder.writeLong(i); - } + encoder.setItemCount(2); + encoder.writeString("first"); + this.writeToMap(encoder, new long[] { 1L, 2L }); + encoder.writeString("second"); + this.writeToMap(encoder, new long[] { 3L, 4L, 5L }); encoder.writeMapEnd(); + + // Read + encoder.flush(); BinaryMessageDecoder decoder = TestRecordWithMapsAndArrays.getDecoder(); TestRecordWithMapsAndArrays r = decoder.decode(baos.toByteArray()); - assertThat(r.getArr(), is(Arrays.asList("0", "1", "2", "3", "4"))); + assertThat(r.getArr(), is(Arrays.asList("1", "2", "3", "4", "5"))); Map map = r.getMap(); assertThat(map.size(), is(5)); - for (long i = 0; i < len; i++) { + for (long i = 1; i <= 5; i++) { assertThat(map.get(Long.toString(i)), is(i)); } + + assertThat(r.getNestedArr(), is(Arrays.asList(Arrays.asList("1", "2"), Arrays.asList("3", "4", "5")))); + + Map> nestedMap = r.getNestedMap(); + assertThat(nestedMap.size(), is(2)); + + assertThat(nestedMap.get("first").size(), is(2)); + assertThat(nestedMap.get("first").get("1"), is(1L)); + assertThat(nestedMap.get("first").get("2"), is(2L)); + + assertThat(nestedMap.get("second").size(), is(3)); + assertThat(nestedMap.get("second").get("3"), is(3L)); + assertThat(nestedMap.get("second").get("4"), is(4L)); + assertThat(nestedMap.get("second").get("5"), is(5L)); } @Test @@ -93,8 +138,8 @@ void testSkippingUsingBlocks() throws IOException, NoSuchAlgorithmException { in.read(null, mockDecoder); } - verify(mockDecoder, times(1)).skipMap(); - verify(mockDecoder, times(1)).skipArray(); + verify(mockDecoder, times(2)).skipMap(); + verify(mockDecoder, times(2)).skipArray(); verify(mockDecoder, times(0)).readString(); verify(mockDecoder, times(0)).readLong(); } diff --git a/lang/java/avro/src/test/java/org/apache/avro/specific/TestRecordWithMapsAndArrays.java b/lang/java/avro/src/test/java/org/apache/avro/specific/TestRecordWithMapsAndArrays.java index 7150f500143..81572bc22c5 100644 --- a/lang/java/avro/src/test/java/org/apache/avro/specific/TestRecordWithMapsAndArrays.java +++ b/lang/java/avro/src/test/java/org/apache/avro/specific/TestRecordWithMapsAndArrays.java @@ -24,13 +24,12 @@ import org.apache.avro.message.BinaryMessageDecoder; import org.apache.avro.message.SchemaStore; -@org.apache.avro.specific.AvroGenerated -public class TestRecordWithMapsAndArrays extends org.apache.avro.specific.SpecificRecordBase - implements org.apache.avro.specific.SpecificRecord { - private static final long serialVersionUID = 3113266652594662627L; +@AvroGenerated +public class TestRecordWithMapsAndArrays extends SpecificRecordBase implements SpecificRecord { + private static final long serialVersionUID = -3823801533006425147L; public static final org.apache.avro.Schema SCHEMA$ = new org.apache.avro.Schema.Parser().parse( - "{\"type\":\"record\",\"name\":\"TestRecordWithMapsAndArrays\",\"namespace\":\"org.apache.avro.specific\",\"fields\":[{\"name\":\"arr\",\"type\":{\"type\":\"array\",\"items\":{\"type\":\"string\",\"avro.java.string\":\"String\"},\"default\":[]}},{\"name\":\"map\",\"type\":{\"type\":\"map\",\"values\":\"long\",\"avro.java.string\":\"String\",\"default\":{}}}]}"); + "{\"type\":\"record\",\"name\":\"TestRecordWithMapsAndArrays\",\"namespace\":\"org.apache.avro.specific\",\"fields\":[{\"name\":\"arr\",\"type\":{\"type\":\"array\",\"items\":{\"type\":\"string\",\"avro.java.string\":\"String\"},\"default\":[]}},{\"name\":\"map\",\"type\":{\"type\":\"map\",\"values\":\"long\",\"avro.java.string\":\"String\",\"default\":{}}},{\"name\":\"nested_arr\",\"type\":{\"type\":\"array\",\"items\":{\"type\":\"array\",\"items\":{\"type\":\"string\",\"avro.java.string\":\"String\"},\"default\":[]},\"default\":[]}},{\"name\":\"nested_map\",\"type\":{\"type\":\"map\",\"values\":{\"type\":\"map\",\"values\":\"long\",\"avro.java.string\":\"String\",\"default\":{}},\"avro.java.string\":\"String\",\"default\":{}}}]}"); public static org.apache.avro.Schema getClassSchema() { return SCHEMA$; @@ -46,7 +45,7 @@ public static org.apache.avro.Schema getClassSchema() { /** * Return the BinaryMessageEncoder instance used by this class. - * + * * @return the message encoder used by this class */ public static BinaryMessageEncoder getEncoder() { @@ -55,7 +54,7 @@ public static BinaryMessageEncoder getEncoder() { /** * Return the BinaryMessageDecoder instance used by this class. - * + * * @return the message decoder used by this class */ public static BinaryMessageDecoder getDecoder() { @@ -65,7 +64,7 @@ public static BinaryMessageDecoder getDecoder() { /** * Create a new BinaryMessageDecoder instance for this class that uses the * specified {@link SchemaStore}. - * + * * @param resolver a {@link SchemaStore} used to find schemas by fingerprint * @return a BinaryMessageDecoder instance for this class backed by the given * SchemaStore @@ -76,7 +75,7 @@ public static BinaryMessageDecoder createDecoder(Sc /** * Serializes this TestRecordWithMapsAndArrays to a ByteBuffer. - * + * * @return a buffer holding the serialized data for this instance * @throws java.io.IOException if this instance could not be serialized */ @@ -86,7 +85,7 @@ public java.nio.ByteBuffer toByteBuffer() throws java.io.IOException { /** * Deserializes a TestRecordWithMapsAndArrays from a ByteBuffer. - * + * * @param b a byte buffer holding serialized data for an instance of this class * @return a TestRecordWithMapsAndArrays instance decoded from the given buffer * @throws java.io.IOException if the given bytes could not be deserialized into @@ -96,8 +95,10 @@ public static TestRecordWithMapsAndArrays fromByteBuffer(java.nio.ByteBuffer b) return DECODER.decode(b); } - private java.util.List arr; - private java.util.Map map; + private java.util.List arr; + private java.util.Map map; + private java.util.List> nested_arr; + private java.util.Map> nested_map; /** * Default constructor. Note that this does not initialize fields to their @@ -109,18 +110,23 @@ public TestRecordWithMapsAndArrays() { /** * All-args constructor. - * - * @param arr The new value for arr - * @param map The new value for map + * + * @param arr The new value for arr + * @param map The new value for map + * @param nested_arr The new value for nested_arr + * @param nested_map The new value for nested_map */ - public TestRecordWithMapsAndArrays(java.util.List arr, - java.util.Map map) { + public TestRecordWithMapsAndArrays(java.util.List arr, java.util.Map map, + java.util.List> nested_arr, + java.util.Map> nested_map) { this.arr = arr; this.map = map; + this.nested_arr = nested_arr; + this.nested_map = nested_map; } @Override - public org.apache.avro.specific.SpecificData getSpecificData() { + public SpecificData getSpecificData() { return MODEL$; } @@ -131,12 +137,16 @@ public org.apache.avro.Schema getSchema() { // Used by DatumWriter. Applications should not call. @Override - public java.lang.Object get(int field$) { + public Object get(int field$) { switch (field$) { case 0: return arr; case 1: return map; + case 2: + return nested_arr; + case 3: + return nested_map; default: throw new IndexOutOfBoundsException("Invalid index: " + field$); } @@ -145,13 +155,19 @@ public java.lang.Object get(int field$) { // Used by DatumReader. Applications should not call. @Override @SuppressWarnings(value = "unchecked") - public void put(int field$, java.lang.Object value$) { + public void put(int field$, Object value$) { switch (field$) { case 0: - arr = (java.util.List) value$; + arr = (java.util.List) value$; break; case 1: - map = (java.util.Map) value$; + map = (java.util.Map) value$; + break; + case 2: + nested_arr = (java.util.List>) value$; + break; + case 3: + nested_map = (java.util.Map>) value$; break; default: throw new IndexOutOfBoundsException("Invalid index: " + field$); @@ -160,90 +176,126 @@ public void put(int field$, java.lang.Object value$) { /** * Gets the value of the 'arr' field. - * + * * @return The value of the 'arr' field. */ - public java.util.List getArr() { + public java.util.List getArr() { return arr; } /** * Sets the value of the 'arr' field. - * + * * @param value the value to set. */ - public void setArr(java.util.List value) { + public void setArr(java.util.List value) { this.arr = value; } /** * Gets the value of the 'map' field. - * + * * @return The value of the 'map' field. */ - public java.util.Map getMap() { + public java.util.Map getMap() { return map; } /** * Sets the value of the 'map' field. - * + * * @param value the value to set. */ - public void setMap(java.util.Map value) { + public void setMap(java.util.Map value) { this.map = value; } + /** + * Gets the value of the 'nested_arr' field. + * + * @return The value of the 'nested_arr' field. + */ + public java.util.List> getNestedArr() { + return nested_arr; + } + + /** + * Sets the value of the 'nested_arr' field. + * + * @param value the value to set. + */ + public void setNestedArr(java.util.List> value) { + this.nested_arr = value; + } + + /** + * Gets the value of the 'nested_map' field. + * + * @return The value of the 'nested_map' field. + */ + public java.util.Map> getNestedMap() { + return nested_map; + } + + /** + * Sets the value of the 'nested_map' field. + * + * @param value the value to set. + */ + public void setNestedMap(java.util.Map> value) { + this.nested_map = value; + } + /** * Creates a new TestRecordWithMapsAndArrays RecordBuilder. - * + * * @return A new TestRecordWithMapsAndArrays RecordBuilder */ - public static org.apache.avro.specific.TestRecordWithMapsAndArrays.Builder newBuilder() { - return new org.apache.avro.specific.TestRecordWithMapsAndArrays.Builder(); + public static Builder newBuilder() { + return new Builder(); } /** * Creates a new TestRecordWithMapsAndArrays RecordBuilder by copying an * existing Builder. - * + * * @param other The existing builder to copy. * @return A new TestRecordWithMapsAndArrays RecordBuilder */ - public static org.apache.avro.specific.TestRecordWithMapsAndArrays.Builder newBuilder( - org.apache.avro.specific.TestRecordWithMapsAndArrays.Builder other) { + public static Builder newBuilder(Builder other) { if (other == null) { - return new org.apache.avro.specific.TestRecordWithMapsAndArrays.Builder(); + return new Builder(); } else { - return new org.apache.avro.specific.TestRecordWithMapsAndArrays.Builder(other); + return new Builder(other); } } /** * Creates a new TestRecordWithMapsAndArrays RecordBuilder by copying an * existing TestRecordWithMapsAndArrays instance. - * + * * @param other The existing instance to copy. * @return A new TestRecordWithMapsAndArrays RecordBuilder */ - public static org.apache.avro.specific.TestRecordWithMapsAndArrays.Builder newBuilder( - org.apache.avro.specific.TestRecordWithMapsAndArrays other) { + public static Builder newBuilder(TestRecordWithMapsAndArrays other) { if (other == null) { - return new org.apache.avro.specific.TestRecordWithMapsAndArrays.Builder(); + return new Builder(); } else { - return new org.apache.avro.specific.TestRecordWithMapsAndArrays.Builder(other); + return new Builder(other); } } /** * RecordBuilder for TestRecordWithMapsAndArrays instances. */ - @org.apache.avro.specific.AvroGenerated - public static class Builder extends org.apache.avro.specific.SpecificRecordBuilderBase + @AvroGenerated + public static class Builder extends SpecificRecordBuilderBase implements org.apache.avro.data.RecordBuilder { - private java.util.List arr; - private java.util.Map map; + private java.util.List arr; + private java.util.Map map; + private java.util.List> nested_arr; + private java.util.Map> nested_map; /** Creates a new Builder */ private Builder() { @@ -252,10 +304,10 @@ private Builder() { /** * Creates a Builder by copying an existing Builder. - * + * * @param other The existing Builder to copy. */ - private Builder(org.apache.avro.specific.TestRecordWithMapsAndArrays.Builder other) { + private Builder(Builder other) { super(other); if (isValidValue(fields()[0], other.arr)) { this.arr = data().deepCopy(fields()[0].schema(), other.arr); @@ -265,14 +317,22 @@ private Builder(org.apache.avro.specific.TestRecordWithMapsAndArrays.Builder oth this.map = data().deepCopy(fields()[1].schema(), other.map); fieldSetFlags()[1] = other.fieldSetFlags()[1]; } + if (isValidValue(fields()[2], other.nested_arr)) { + this.nested_arr = data().deepCopy(fields()[2].schema(), other.nested_arr); + fieldSetFlags()[2] = other.fieldSetFlags()[2]; + } + if (isValidValue(fields()[3], other.nested_map)) { + this.nested_map = data().deepCopy(fields()[3].schema(), other.nested_map); + fieldSetFlags()[3] = other.fieldSetFlags()[3]; + } } /** * Creates a Builder by copying an existing TestRecordWithMapsAndArrays instance - * + * * @param other The existing instance to copy. */ - private Builder(org.apache.avro.specific.TestRecordWithMapsAndArrays other) { + private Builder(TestRecordWithMapsAndArrays other) { super(SCHEMA$, MODEL$); if (isValidValue(fields()[0], other.arr)) { this.arr = data().deepCopy(fields()[0].schema(), other.arr); @@ -282,24 +342,32 @@ private Builder(org.apache.avro.specific.TestRecordWithMapsAndArrays other) { this.map = data().deepCopy(fields()[1].schema(), other.map); fieldSetFlags()[1] = true; } + if (isValidValue(fields()[2], other.nested_arr)) { + this.nested_arr = data().deepCopy(fields()[2].schema(), other.nested_arr); + fieldSetFlags()[2] = true; + } + if (isValidValue(fields()[3], other.nested_map)) { + this.nested_map = data().deepCopy(fields()[3].schema(), other.nested_map); + fieldSetFlags()[3] = true; + } } /** * Gets the value of the 'arr' field. - * + * * @return The value. */ - public java.util.List getArr() { + public java.util.List getArr() { return arr; } /** * Sets the value of the 'arr' field. - * + * * @param value The value of 'arr'. * @return This builder. */ - public org.apache.avro.specific.TestRecordWithMapsAndArrays.Builder setArr(java.util.List value) { + public Builder setArr(java.util.List value) { validate(fields()[0], value); this.arr = value; fieldSetFlags()[0] = true; @@ -308,7 +376,7 @@ public org.apache.avro.specific.TestRecordWithMapsAndArrays.Builder setArr(java. /** * Checks whether the 'arr' field has been set. - * + * * @return True if the 'arr' field has been set, false otherwise. */ public boolean hasArr() { @@ -317,10 +385,10 @@ public boolean hasArr() { /** * Clears the value of the 'arr' field. - * + * * @return This builder. */ - public org.apache.avro.specific.TestRecordWithMapsAndArrays.Builder clearArr() { + public Builder clearArr() { arr = null; fieldSetFlags()[0] = false; return this; @@ -328,21 +396,20 @@ public org.apache.avro.specific.TestRecordWithMapsAndArrays.Builder clearArr() { /** * Gets the value of the 'map' field. - * + * * @return The value. */ - public java.util.Map getMap() { + public java.util.Map getMap() { return map; } /** * Sets the value of the 'map' field. - * + * * @param value The value of 'map'. * @return This builder. */ - public org.apache.avro.specific.TestRecordWithMapsAndArrays.Builder setMap( - java.util.Map value) { + public Builder setMap(java.util.Map value) { validate(fields()[1], value); this.map = value; fieldSetFlags()[1] = true; @@ -351,7 +418,7 @@ public org.apache.avro.specific.TestRecordWithMapsAndArrays.Builder setMap( /** * Checks whether the 'map' field has been set. - * + * * @return True if the 'map' field has been set, false otherwise. */ public boolean hasMap() { @@ -360,27 +427,114 @@ public boolean hasMap() { /** * Clears the value of the 'map' field. - * + * * @return This builder. */ - public org.apache.avro.specific.TestRecordWithMapsAndArrays.Builder clearMap() { + public Builder clearMap() { map = null; fieldSetFlags()[1] = false; return this; } + /** + * Gets the value of the 'nested_arr' field. + * + * @return The value. + */ + public java.util.List> getNestedArr() { + return nested_arr; + } + + /** + * Sets the value of the 'nested_arr' field. + * + * @param value The value of 'nested_arr'. + * @return This builder. + */ + public Builder setNestedArr(java.util.List> value) { + validate(fields()[2], value); + this.nested_arr = value; + fieldSetFlags()[2] = true; + return this; + } + + /** + * Checks whether the 'nested_arr' field has been set. + * + * @return True if the 'nested_arr' field has been set, false otherwise. + */ + public boolean hasNestedArr() { + return fieldSetFlags()[2]; + } + + /** + * Clears the value of the 'nested_arr' field. + * + * @return This builder. + */ + public Builder clearNestedArr() { + nested_arr = null; + fieldSetFlags()[2] = false; + return this; + } + + /** + * Gets the value of the 'nested_map' field. + * + * @return The value. + */ + public java.util.Map> getNestedMap() { + return nested_map; + } + + /** + * Sets the value of the 'nested_map' field. + * + * @param value The value of 'nested_map'. + * @return This builder. + */ + public Builder setNestedMap(java.util.Map> value) { + validate(fields()[3], value); + this.nested_map = value; + fieldSetFlags()[3] = true; + return this; + } + + /** + * Checks whether the 'nested_map' field has been set. + * + * @return True if the 'nested_map' field has been set, false otherwise. + */ + public boolean hasNestedMap() { + return fieldSetFlags()[3]; + } + + /** + * Clears the value of the 'nested_map' field. + * + * @return This builder. + */ + public Builder clearNestedMap() { + nested_map = null; + fieldSetFlags()[3] = false; + return this; + } + @Override @SuppressWarnings("unchecked") public TestRecordWithMapsAndArrays build() { try { TestRecordWithMapsAndArrays record = new TestRecordWithMapsAndArrays(); - record.arr = fieldSetFlags()[0] ? this.arr : (java.util.List) defaultValue(fields()[0]); - record.map = fieldSetFlags()[1] ? this.map - : (java.util.Map) defaultValue(fields()[1]); + record.arr = fieldSetFlags()[0] ? this.arr : (java.util.List) defaultValue(fields()[0]); + record.map = fieldSetFlags()[1] ? this.map : (java.util.Map) defaultValue(fields()[1]); + record.nested_arr = fieldSetFlags()[2] ? this.nested_arr + : (java.util.List>) defaultValue(fields()[2]); + record.nested_map = fieldSetFlags()[3] ? this.nested_map + : (java.util.Map>) defaultValue(fields()[3]); return record; } catch (org.apache.avro.AvroMissingFieldException e) { throw e; - } catch (java.lang.Exception e) { + } catch (Exception e) { throw new org.apache.avro.AvroRuntimeException(e); } } @@ -415,7 +569,7 @@ public void customEncode(org.apache.avro.io.Encoder out) throws java.io.IOExcept out.writeArrayStart(); out.setItemCount(size0); long actualSize0 = 0; - for (java.lang.String e0 : this.arr) { + for (String e0 : this.arr) { actualSize0++; out.startItem(); out.writeString(e0); @@ -429,11 +583,11 @@ public void customEncode(org.apache.avro.io.Encoder out) throws java.io.IOExcept out.writeMapStart(); out.setItemCount(size1); long actualSize1 = 0; - for (java.util.Map.Entry e1 : this.map.entrySet()) { + for (java.util.Map.Entry e1 : this.map.entrySet()) { actualSize1++; out.startItem(); out.writeString(e1.getKey()); - java.lang.Long v1 = e1.getValue(); + Long v1 = e1.getValue(); out.writeLong(v1); } out.writeMapEnd(); @@ -441,6 +595,62 @@ public void customEncode(org.apache.avro.io.Encoder out) throws java.io.IOExcept throw new java.util.ConcurrentModificationException( "Map-size written was " + size1 + ", but element count was " + actualSize1 + "."); + long size2 = this.nested_arr.size(); + out.writeArrayStart(); + out.setItemCount(size2); + long actualSize2 = 0; + for (java.util.List e2 : this.nested_arr) { + actualSize2++; + out.startItem(); + long size3 = e2.size(); + out.writeArrayStart(); + out.setItemCount(size3); + long actualSize3 = 0; + for (String e3 : e2) { + actualSize3++; + out.startItem(); + out.writeString(e3); + } + out.writeArrayEnd(); + if (actualSize3 != size3) + throw new java.util.ConcurrentModificationException( + "Array-size written was " + size3 + ", but element count was " + actualSize3 + "."); + } + out.writeArrayEnd(); + if (actualSize2 != size2) + throw new java.util.ConcurrentModificationException( + "Array-size written was " + size2 + ", but element count was " + actualSize2 + "."); + + long size4 = this.nested_map.size(); + out.writeMapStart(); + out.setItemCount(size4); + long actualSize4 = 0; + for (java.util.Map.Entry> e4 : this.nested_map.entrySet()) { + actualSize4++; + out.startItem(); + out.writeString(e4.getKey()); + java.util.Map v4 = e4.getValue(); + long size5 = v4.size(); + out.writeMapStart(); + out.setItemCount(size5); + long actualSize5 = 0; + for (java.util.Map.Entry e5 : v4.entrySet()) { + actualSize5++; + out.startItem(); + out.writeString(e5.getKey()); + Long v5 = e5.getValue(); + out.writeLong(v5); + } + out.writeMapEnd(); + if (actualSize5 != size5) + throw new java.util.ConcurrentModificationException( + "Map-size written was " + size5 + ", but element count was " + actualSize5 + "."); + } + out.writeMapEnd(); + if (actualSize4 != size4) + throw new java.util.ConcurrentModificationException( + "Map-size written was " + size4 + ", but element count was " + actualSize4 + "."); + } @Override @@ -448,58 +658,118 @@ public void customDecode(org.apache.avro.io.ResolvingDecoder in) throws java.io. org.apache.avro.Schema.Field[] fieldOrder = in.readFieldOrderIfDiff(); if (fieldOrder == null) { long size0 = in.readArrayStart(); - java.util.List a0 = this.arr; + java.util.List a0 = this.arr; if (a0 == null) { - a0 = new SpecificData.Array((int) size0, SCHEMA$.getField("arr").schema()); + a0 = new SpecificData.Array((int) size0, SCHEMA$.getField("arr").schema()); this.arr = a0; } else a0.clear(); - SpecificData.Array ga0 = (a0 instanceof SpecificData.Array - ? (SpecificData.Array) a0 - : null); + SpecificData.Array ga0 = (a0 instanceof SpecificData.Array ? (SpecificData.Array) a0 : null); for (; 0 < size0; size0 = in.arrayNext()) { for (; size0 != 0; size0--) { - java.lang.String e0 = (ga0 != null ? ga0.peek() : null); + String e0 = (ga0 != null ? ga0.peek() : null); e0 = in.readString(); a0.add(e0); } } long size1 = in.readMapStart(); - java.util.Map m1 = this.map; // Need fresh name due to limitation of macro - // system + java.util.Map m1 = this.map; // Need fresh name due to limitation of macro system if (m1 == null) { - m1 = new java.util.HashMap((int) size1); + m1 = new java.util.HashMap((int) size1); this.map = m1; } else m1.clear(); for (; 0 < size1; size1 = in.mapNext()) { for (; size1 != 0; size1--) { - java.lang.String k1 = null; + String k1 = null; k1 = in.readString(); - java.lang.Long v1 = null; + Long v1 = null; v1 = in.readLong(); m1.put(k1, v1); } } + long size2 = in.readArrayStart(); + java.util.List> a2 = this.nested_arr; + if (a2 == null) { + a2 = new SpecificData.Array>((int) size2, SCHEMA$.getField("nested_arr").schema()); + this.nested_arr = a2; + } else + a2.clear(); + SpecificData.Array> ga2 = (a2 instanceof SpecificData.Array + ? (SpecificData.Array>) a2 + : null); + for (; 0 < size2; size2 = in.arrayNext()) { + for (; size2 != 0; size2--) { + java.util.List e2 = (ga2 != null ? ga2.peek() : null); + long size3 = in.readArrayStart(); + java.util.List a3 = e2; + if (a3 == null) { + a3 = new SpecificData.Array((int) size3, SCHEMA$.getField("nested_arr").schema().getElementType()); + e2 = a3; + } else + a3.clear(); + SpecificData.Array ga3 = (a3 instanceof SpecificData.Array ? (SpecificData.Array) a3 : null); + for (; 0 < size3; size3 = in.arrayNext()) { + for (; size3 != 0; size3--) { + String e3 = (ga3 != null ? ga3.peek() : null); + e3 = in.readString(); + a3.add(e3); + } + } + a2.add(e2); + } + } + + long size4 = in.readMapStart(); + java.util.Map> m4 = this.nested_map; // Need fresh name due to limitation of + // macro system + if (m4 == null) { + m4 = new java.util.HashMap>((int) size4); + this.nested_map = m4; + } else + m4.clear(); + for (; 0 < size4; size4 = in.mapNext()) { + for (; size4 != 0; size4--) { + String k4 = null; + k4 = in.readString(); + java.util.Map v4 = null; + long size5 = in.readMapStart(); + java.util.Map m5 = v4; // Need fresh name due to limitation of macro system + if (m5 == null) { + m5 = new java.util.HashMap((int) size5); + v4 = m5; + } else + m5.clear(); + for (; 0 < size5; size5 = in.mapNext()) { + for (; size5 != 0; size5--) { + String k5 = null; + k5 = in.readString(); + Long v5 = null; + v5 = in.readLong(); + m5.put(k5, v5); + } + } + m4.put(k4, v4); + } + } + } else { - for (int i = 0; i < 2; i++) { + for (int i = 0; i < 4; i++) { switch (fieldOrder[i].pos()) { case 0: long size0 = in.readArrayStart(); - java.util.List a0 = this.arr; + java.util.List a0 = this.arr; if (a0 == null) { - a0 = new SpecificData.Array((int) size0, SCHEMA$.getField("arr").schema()); + a0 = new SpecificData.Array((int) size0, SCHEMA$.getField("arr").schema()); this.arr = a0; } else a0.clear(); - SpecificData.Array ga0 = (a0 instanceof SpecificData.Array - ? (SpecificData.Array) a0 - : null); + SpecificData.Array ga0 = (a0 instanceof SpecificData.Array ? (SpecificData.Array) a0 : null); for (; 0 < size0; size0 = in.arrayNext()) { for (; size0 != 0; size0--) { - java.lang.String e0 = (ga0 != null ? ga0.peek() : null); + String e0 = (ga0 != null ? ga0.peek() : null); e0 = in.readString(); a0.add(e0); } @@ -508,24 +778,94 @@ public void customDecode(org.apache.avro.io.ResolvingDecoder in) throws java.io. case 1: long size1 = in.readMapStart(); - java.util.Map m1 = this.map; // Need fresh name due to limitation of macro - // system + java.util.Map m1 = this.map; // Need fresh name due to limitation of macro system if (m1 == null) { - m1 = new java.util.HashMap((int) size1); + m1 = new java.util.HashMap((int) size1); this.map = m1; } else m1.clear(); for (; 0 < size1; size1 = in.mapNext()) { for (; size1 != 0; size1--) { - java.lang.String k1 = null; + String k1 = null; k1 = in.readString(); - java.lang.Long v1 = null; + Long v1 = null; v1 = in.readLong(); m1.put(k1, v1); } } break; + case 2: + long size2 = in.readArrayStart(); + java.util.List> a2 = this.nested_arr; + if (a2 == null) { + a2 = new SpecificData.Array>((int) size2, SCHEMA$.getField("nested_arr").schema()); + this.nested_arr = a2; + } else + a2.clear(); + SpecificData.Array> ga2 = (a2 instanceof SpecificData.Array + ? (SpecificData.Array>) a2 + : null); + for (; 0 < size2; size2 = in.arrayNext()) { + for (; size2 != 0; size2--) { + java.util.List e2 = (ga2 != null ? ga2.peek() : null); + long size3 = in.readArrayStart(); + java.util.List a3 = e2; + if (a3 == null) { + a3 = new SpecificData.Array((int) size3, + SCHEMA$.getField("nested_arr").schema().getElementType()); + e2 = a3; + } else + a3.clear(); + SpecificData.Array ga3 = (a3 instanceof SpecificData.Array ? (SpecificData.Array) a3 + : null); + for (; 0 < size3; size3 = in.arrayNext()) { + for (; size3 != 0; size3--) { + String e3 = (ga3 != null ? ga3.peek() : null); + e3 = in.readString(); + a3.add(e3); + } + } + a2.add(e2); + } + } + break; + + case 3: + long size4 = in.readMapStart(); + java.util.Map> m4 = this.nested_map; // Need fresh name due to limitation + // of macro system + if (m4 == null) { + m4 = new java.util.HashMap>((int) size4); + this.nested_map = m4; + } else + m4.clear(); + for (; 0 < size4; size4 = in.mapNext()) { + for (; size4 != 0; size4--) { + String k4 = null; + k4 = in.readString(); + java.util.Map v4 = null; + long size5 = in.readMapStart(); + java.util.Map m5 = v4; // Need fresh name due to limitation of macro system + if (m5 == null) { + m5 = new java.util.HashMap((int) size5); + v4 = m5; + } else + m5.clear(); + for (; 0 < size5; size5 = in.mapNext()) { + for (; size5 != 0; size5--) { + String k5 = null; + k5 = in.readString(); + Long v5 = null; + v5 = in.readLong(); + m5.put(k5, v5); + } + } + m4.put(k4, v4); + } + } + break; + default: throw new java.io.IOException("Corrupt ResolvingDecoder."); } diff --git a/lang/java/avro/src/test/resources/TestRecordWithMapsAndArrays.avsc b/lang/java/avro/src/test/resources/TestRecordWithMapsAndArrays.avsc index e2bc0382b04..d19c0d8dfb9 100644 --- a/lang/java/avro/src/test/resources/TestRecordWithMapsAndArrays.avsc +++ b/lang/java/avro/src/test/resources/TestRecordWithMapsAndArrays.avsc @@ -18,6 +18,30 @@ "values": "long", "default": {} } + }, + { + "name": "nested_arr", + "type": { + "type": "array", + "items": { + "type": "array", + "items": "string", + "default": [] + }, + "default": [] + } + }, + { + "name": "nested_map", + "type": { + "type": "map", + "values": { + "type": "map", + "values": "long", + "default": {} + }, + "default": {} + } } ] }