c) {
- super(c);
+ this(SpecificData.get().getSchema(c));
}
public AliasAwareSpecificDatumReader(Schema schema) {
- super(schema);
+ this(schema, schema);
}
public AliasAwareSpecificDatumReader(Schema writer, Schema reader) {
diff --git a/helper/impls/helper-impl-14/src/main/java/com/linkedin/avroutil1/compatibility/avro14/codec/ResolvingDecoder.java b/helper/impls/helper-impl-14/src/main/java/com/linkedin/avroutil1/compatibility/avro14/codec/ResolvingDecoder.java
index 8b5b61a9a..e18e67ca7 100644
--- a/helper/impls/helper-impl-14/src/main/java/com/linkedin/avroutil1/compatibility/avro14/codec/ResolvingDecoder.java
+++ b/helper/impls/helper-impl-14/src/main/java/com/linkedin/avroutil1/compatibility/avro14/codec/ResolvingDecoder.java
@@ -24,6 +24,7 @@
package com.linkedin.avroutil1.compatibility.avro14.codec;
+import com.linkedin.avroutil1.compatibility.CustomDecoder;
import com.linkedin.avroutil1.compatibility.avro14.parsing.ResolvingGrammarGenerator;
import com.linkedin.avroutil1.compatibility.avro14.parsing.Symbol;
import java.io.IOException;
@@ -45,7 +46,7 @@
* See the parser documentation for
* information on how this works.
*/
-public class ResolvingDecoder extends ValidatingDecoder {
+public class ResolvingDecoder extends ValidatingDecoder implements CustomDecoder {
private Decoder backup;
@@ -153,7 +154,7 @@ public final void drain() throws IOException {
@Override
public int readInt() throws IOException {
- Symbol actual = parser.popSymbol();
+ Symbol actual = parser.advance(Symbol.INT);
if (actual == Symbol.INT) {
return in.readInt();
} else if (actual == Symbol.IntLongAdjustAction.INSTANCE) {
@@ -245,8 +246,7 @@ public Symbol doAction(Symbol input, Symbol top) throws IOException {
} else if (top == Symbol.DEFAULT_END_ACTION) {
in = backup;
} else if (top == Symbol.IntLongAdjustAction.INSTANCE) {
- parser.pushSymbol(Symbol.INT);
- return Symbol.INT;
+ return top;
} else {
throw new AvroTypeException("Unknown action: " + top);
}
diff --git a/helper/impls/helper-impl-15/src/main/java/com/linkedin/avroutil1/compatibility/avro15/backports/GenericDatumReaderExt.java b/helper/impls/helper-impl-15/src/main/java/com/linkedin/avroutil1/compatibility/avro15/backports/GenericDatumReaderExt.java
index bfb89434f..9b373996e 100644
--- a/helper/impls/helper-impl-15/src/main/java/com/linkedin/avroutil1/compatibility/avro15/backports/GenericDatumReaderExt.java
+++ b/helper/impls/helper-impl-15/src/main/java/com/linkedin/avroutil1/compatibility/avro15/backports/GenericDatumReaderExt.java
@@ -59,7 +59,7 @@ public void setSchema(Schema writer) {
@SuppressWarnings("unchecked")
@Override
public T read(T reuse, Decoder in) throws IOException {
- CachedResolvingDecoder resolver = new CachedResolvingDecoder(writer, reader, in);
+ CachedResolvingDecoder resolver = new CachedResolvingDecoder(Schema.applyAliases(writer, reader), reader, in);
resolver.init(in);
T result = (T) read(reuse, reader, resolver);
resolver.drain();
diff --git a/helper/impls/helper-impl-15/src/main/java/com/linkedin/avroutil1/compatibility/avro15/backports/SpecificDatumReaderExt.java b/helper/impls/helper-impl-15/src/main/java/com/linkedin/avroutil1/compatibility/avro15/backports/SpecificDatumReaderExt.java
index 1f487e4dc..5b01aba17 100644
--- a/helper/impls/helper-impl-15/src/main/java/com/linkedin/avroutil1/compatibility/avro15/backports/SpecificDatumReaderExt.java
+++ b/helper/impls/helper-impl-15/src/main/java/com/linkedin/avroutil1/compatibility/avro15/backports/SpecificDatumReaderExt.java
@@ -59,7 +59,7 @@ public void setSchema(Schema writer) {
@SuppressWarnings("unchecked")
@Override
public T read(T reuse, Decoder in) throws IOException {
- CachedResolvingDecoder resolver = new CachedResolvingDecoder(writer, reader, in);
+ CachedResolvingDecoder resolver = new CachedResolvingDecoder(Schema.applyAliases(writer, reader), reader, in);
resolver.init(in);
T result = (T) read(reuse, reader, resolver);
resolver.drain();
diff --git a/helper/impls/helper-impl-15/src/main/java/com/linkedin/avroutil1/compatibility/avro15/codec/AliasAwareSpecificDatumReader.java b/helper/impls/helper-impl-15/src/main/java/com/linkedin/avroutil1/compatibility/avro15/codec/AliasAwareSpecificDatumReader.java
index 4e4b6ddf2..fc5586a02 100644
--- a/helper/impls/helper-impl-15/src/main/java/com/linkedin/avroutil1/compatibility/avro15/codec/AliasAwareSpecificDatumReader.java
+++ b/helper/impls/helper-impl-15/src/main/java/com/linkedin/avroutil1/compatibility/avro15/codec/AliasAwareSpecificDatumReader.java
@@ -6,6 +6,7 @@
package com.linkedin.avroutil1.compatibility.avro15.codec;
+import com.linkedin.avroutil1.compatibility.avro15.backports.SpecificDatumReaderExt;
import org.apache.avro.Schema;
import org.apache.avro.specific.SpecificData;
import org.apache.avro.specific.SpecificDatumReader;
@@ -23,24 +24,25 @@
*
* @param
*/
-public class AliasAwareSpecificDatumReader extends SpecificDatumReader {
+public class AliasAwareSpecificDatumReader extends SpecificDatumReaderExt {
//same idea as the one in SpecificData
protected final static Map> CLASS_CACHE = new ConcurrentHashMap<>();
public AliasAwareSpecificDatumReader() {
+ this(null, null);
}
public AliasAwareSpecificDatumReader(Class c) {
- super(c);
+ this(SpecificData.get().getSchema(c));
}
public AliasAwareSpecificDatumReader(Schema schema) {
- super(schema);
+ this(schema, schema);
}
public AliasAwareSpecificDatumReader(Schema writer, Schema reader) {
- super(writer, reader);
+ super(writer, reader, SpecificData.get());
}
@Override
diff --git a/helper/impls/helper-impl-15/src/main/java/com/linkedin/avroutil1/compatibility/avro15/codec/ResolvingDecoder.java b/helper/impls/helper-impl-15/src/main/java/com/linkedin/avroutil1/compatibility/avro15/codec/ResolvingDecoder.java
index 0243b0ced..dde1ac8e4 100644
--- a/helper/impls/helper-impl-15/src/main/java/com/linkedin/avroutil1/compatibility/avro15/codec/ResolvingDecoder.java
+++ b/helper/impls/helper-impl-15/src/main/java/com/linkedin/avroutil1/compatibility/avro15/codec/ResolvingDecoder.java
@@ -24,6 +24,7 @@
package com.linkedin.avroutil1.compatibility.avro15.codec;
+import com.linkedin.avroutil1.compatibility.CustomDecoder;
import com.linkedin.avroutil1.compatibility.avro15.parsing.ResolvingGrammarGenerator;
import com.linkedin.avroutil1.compatibility.avro15.parsing.Symbol;
import java.io.IOException;
@@ -45,7 +46,7 @@
* See the parser documentation for
* information on how this works.
*/
-public class ResolvingDecoder extends ValidatingDecoder {
+public class ResolvingDecoder extends ValidatingDecoder implements CustomDecoder {
private Decoder backup;
@@ -158,7 +159,7 @@ public final void drain() throws IOException {
@Override
public int readInt() throws IOException {
- Symbol actual = parser.popSymbol();
+ Symbol actual = parser.advance(Symbol.INT);
if (actual == Symbol.INT) {
return in.readInt();
} else if (actual == Symbol.IntLongAdjustAction.INSTANCE) {
@@ -263,8 +264,7 @@ public Symbol doAction(Symbol input, Symbol top) throws IOException {
} else if (top == Symbol.DEFAULT_END_ACTION) {
in = backup;
} else if (top == Symbol.IntLongAdjustAction.INSTANCE) {
- parser.pushSymbol(Symbol.INT);
- return Symbol.INT;
+ return top;
} else {
throw new AvroTypeException("Unknown action: " + top);
}
diff --git a/helper/impls/helper-impl-16/src/main/java/com/linkedin/avroutil1/compatibility/avro16/backports/GenericDatumReaderExt.java b/helper/impls/helper-impl-16/src/main/java/com/linkedin/avroutil1/compatibility/avro16/backports/GenericDatumReaderExt.java
index 4f286e8cf..479d1080f 100644
--- a/helper/impls/helper-impl-16/src/main/java/com/linkedin/avroutil1/compatibility/avro16/backports/GenericDatumReaderExt.java
+++ b/helper/impls/helper-impl-16/src/main/java/com/linkedin/avroutil1/compatibility/avro16/backports/GenericDatumReaderExt.java
@@ -34,7 +34,8 @@ public GenericDatumReaderExt(Schema writer, Schema reader, GenericData genericDa
@Override
public T read(T reuse, Decoder in) throws IOException {
final Schema reader = getExpected();
- CachedResolvingDecoder resolver = new CachedResolvingDecoder(getSchema(), reader, in);
+ final Schema writer = getSchema();
+ CachedResolvingDecoder resolver = new CachedResolvingDecoder(Schema.applyAliases(writer, reader), reader, in);
resolver.configure(in);
T result = (T) read(reuse, reader, resolver);
resolver.drain();
diff --git a/helper/impls/helper-impl-16/src/main/java/com/linkedin/avroutil1/compatibility/avro16/backports/SpecificDatumReaderExt.java b/helper/impls/helper-impl-16/src/main/java/com/linkedin/avroutil1/compatibility/avro16/backports/SpecificDatumReaderExt.java
index 0f9be5e86..4db31af34 100644
--- a/helper/impls/helper-impl-16/src/main/java/com/linkedin/avroutil1/compatibility/avro16/backports/SpecificDatumReaderExt.java
+++ b/helper/impls/helper-impl-16/src/main/java/com/linkedin/avroutil1/compatibility/avro16/backports/SpecificDatumReaderExt.java
@@ -35,7 +35,8 @@ public SpecificDatumReaderExt(Schema writer, Schema reader, SpecificData specifi
@Override
public T read(T reuse, Decoder in) throws IOException {
final Schema reader = getExpected();
- CachedResolvingDecoder resolver = new CachedResolvingDecoder(getSchema(), reader, in);
+ final Schema writer = getSchema();
+ CachedResolvingDecoder resolver = new CachedResolvingDecoder(Schema.applyAliases(writer, reader), reader, in);
resolver.configure(in);
T result = (T) read(reuse, reader, resolver);
resolver.drain();
diff --git a/helper/impls/helper-impl-16/src/main/java/com/linkedin/avroutil1/compatibility/avro16/codec/AliasAwareSpecificDatumReader.java b/helper/impls/helper-impl-16/src/main/java/com/linkedin/avroutil1/compatibility/avro16/codec/AliasAwareSpecificDatumReader.java
index 9258fe819..7f52b63fd 100644
--- a/helper/impls/helper-impl-16/src/main/java/com/linkedin/avroutil1/compatibility/avro16/codec/AliasAwareSpecificDatumReader.java
+++ b/helper/impls/helper-impl-16/src/main/java/com/linkedin/avroutil1/compatibility/avro16/codec/AliasAwareSpecificDatumReader.java
@@ -6,6 +6,7 @@
package com.linkedin.avroutil1.compatibility.avro16.codec;
+import com.linkedin.avroutil1.compatibility.avro16.backports.SpecificDatumReaderExt;
import org.apache.avro.Schema;
import org.apache.avro.specific.SpecificData;
import org.apache.avro.specific.SpecificDatumReader;
@@ -23,7 +24,7 @@
*
* @param
*/
-public class AliasAwareSpecificDatumReader extends SpecificDatumReader {
+public class AliasAwareSpecificDatumReader extends SpecificDatumReaderExt {
//same idea as the one in SpecificData
protected final static Map> CLASS_CACHE = new ConcurrentHashMap<>();
@@ -45,6 +46,7 @@ public AliasAwareSpecificDatumReader(Schema writer, Schema reader) {
}
public AliasAwareSpecificDatumReader(Schema writer, Schema reader, SpecificData data) {
+ super(null, null, data);
throw new UnsupportedOperationException("providing custom SpecificData not supported (yet?)");
}
diff --git a/helper/impls/helper-impl-16/src/main/java/com/linkedin/avroutil1/compatibility/avro16/codec/ResolvingDecoder.java b/helper/impls/helper-impl-16/src/main/java/com/linkedin/avroutil1/compatibility/avro16/codec/ResolvingDecoder.java
index bd44d71a0..ee8b6871f 100644
--- a/helper/impls/helper-impl-16/src/main/java/com/linkedin/avroutil1/compatibility/avro16/codec/ResolvingDecoder.java
+++ b/helper/impls/helper-impl-16/src/main/java/com/linkedin/avroutil1/compatibility/avro16/codec/ResolvingDecoder.java
@@ -24,6 +24,7 @@
package com.linkedin.avroutil1.compatibility.avro16.codec;
+import com.linkedin.avroutil1.compatibility.CustomDecoder;
import com.linkedin.avroutil1.compatibility.avro16.parsing.ResolvingGrammarGenerator;
import com.linkedin.avroutil1.compatibility.avro16.parsing.Symbol;
import java.io.IOException;
@@ -34,7 +35,7 @@
import org.apache.avro.io.Decoder;
import org.apache.avro.io.DecoderFactory;
-public class ResolvingDecoder extends ValidatingDecoder {
+public class ResolvingDecoder extends ValidatingDecoder implements CustomDecoder {
private Decoder backup;
ResolvingDecoder(Schema writer, Schema reader, Decoder in) throws IOException {
@@ -66,7 +67,7 @@ public final void drain() throws IOException {
@Override
public int readInt() throws IOException {
- Symbol actual = parser.popSymbol();
+ Symbol actual = parser.advance(Symbol.INT);
if (actual == Symbol.INT) {
return in.readInt();
} else if (actual == Symbol.IntLongAdjustAction.INSTANCE) {
@@ -164,8 +165,7 @@ public Symbol doAction(Symbol input, Symbol top) throws IOException {
}
if (top == Symbol.IntLongAdjustAction.INSTANCE) {
- parser.pushSymbol(Symbol.INT);
- return Symbol.INT;
+ return top;
}
if (top instanceof Symbol.DefaultStartAction) {
diff --git a/helper/impls/helper-impl-17/src/main/java/com/linkedin/avroutil1/compatibility/avro17/backports/GenericDatumReaderExt.java b/helper/impls/helper-impl-17/src/main/java/com/linkedin/avroutil1/compatibility/avro17/backports/GenericDatumReaderExt.java
index a05ea957c..82025d73c 100644
--- a/helper/impls/helper-impl-17/src/main/java/com/linkedin/avroutil1/compatibility/avro17/backports/GenericDatumReaderExt.java
+++ b/helper/impls/helper-impl-17/src/main/java/com/linkedin/avroutil1/compatibility/avro17/backports/GenericDatumReaderExt.java
@@ -34,7 +34,8 @@ public GenericDatumReaderExt(Schema writer, Schema reader, GenericData genericDa
@Override
public T read(T reuse, Decoder in) throws IOException {
final Schema reader = getExpected();
- CachedResolvingDecoder resolver = new CachedResolvingDecoder(getSchema(), reader, in);
+ final Schema writer = getSchema();
+ CachedResolvingDecoder resolver = new CachedResolvingDecoder(Schema.applyAliases(writer, reader), reader, in);
resolver.configure(in);
T result = (T) read(reuse, reader, resolver);
resolver.drain();
diff --git a/helper/impls/helper-impl-17/src/main/java/com/linkedin/avroutil1/compatibility/avro17/backports/SpecificDatumReaderExt.java b/helper/impls/helper-impl-17/src/main/java/com/linkedin/avroutil1/compatibility/avro17/backports/SpecificDatumReaderExt.java
index 72a01910b..c8445451d 100644
--- a/helper/impls/helper-impl-17/src/main/java/com/linkedin/avroutil1/compatibility/avro17/backports/SpecificDatumReaderExt.java
+++ b/helper/impls/helper-impl-17/src/main/java/com/linkedin/avroutil1/compatibility/avro17/backports/SpecificDatumReaderExt.java
@@ -35,7 +35,8 @@ public SpecificDatumReaderExt(Schema writer, Schema reader, SpecificData specifi
@Override
public T read(T reuse, Decoder in) throws IOException {
final Schema reader = getExpected();
- CachedResolvingDecoder resolver = new CachedResolvingDecoder(getSchema(), reader, in);
+ final Schema writer = getSchema();
+ CachedResolvingDecoder resolver = new CachedResolvingDecoder(Schema.applyAliases(writer, reader), reader, in);
resolver.configure(in);
T result = (T) read(reuse, reader, resolver);
resolver.drain();
diff --git a/helper/impls/helper-impl-17/src/main/java/com/linkedin/avroutil1/compatibility/avro17/codec/AliasAwareSpecificDatumReader.java b/helper/impls/helper-impl-17/src/main/java/com/linkedin/avroutil1/compatibility/avro17/codec/AliasAwareSpecificDatumReader.java
index 5fbe2ba05..989b91001 100644
--- a/helper/impls/helper-impl-17/src/main/java/com/linkedin/avroutil1/compatibility/avro17/codec/AliasAwareSpecificDatumReader.java
+++ b/helper/impls/helper-impl-17/src/main/java/com/linkedin/avroutil1/compatibility/avro17/codec/AliasAwareSpecificDatumReader.java
@@ -6,6 +6,7 @@
package com.linkedin.avroutil1.compatibility.avro17.codec;
+import com.linkedin.avroutil1.compatibility.avro17.backports.SpecificDatumReaderExt;
import org.apache.avro.Schema;
import org.apache.avro.specific.SpecificData;
import org.apache.avro.specific.SpecificDatumReader;
@@ -24,7 +25,7 @@
*
* @param
*/
-public class AliasAwareSpecificDatumReader extends SpecificDatumReader {
+public class AliasAwareSpecificDatumReader extends SpecificDatumReaderExt {
//same idea as the one in SpecificData
protected final static Map> CLASS_CACHE = new ConcurrentHashMap<>();
@@ -47,10 +48,12 @@ public AliasAwareSpecificDatumReader(Schema writer, Schema reader) {
}
public AliasAwareSpecificDatumReader(Schema writer, Schema reader, SpecificData data) {
+ super(null, null, data);
throw new UnsupportedOperationException("providing custom SpecificData not supported (yet?)");
}
protected AliasAwareSpecificDatumReader(SpecificData data) {
+ super(null, null, data);
throw new UnsupportedOperationException("providing custom SpecificData not supported (yet?)");
}
diff --git a/helper/impls/helper-impl-17/src/main/java/com/linkedin/avroutil1/compatibility/avro17/codec/ResolvingDecoder.java b/helper/impls/helper-impl-17/src/main/java/com/linkedin/avroutil1/compatibility/avro17/codec/ResolvingDecoder.java
index ff656b811..5c9690061 100644
--- a/helper/impls/helper-impl-17/src/main/java/com/linkedin/avroutil1/compatibility/avro17/codec/ResolvingDecoder.java
+++ b/helper/impls/helper-impl-17/src/main/java/com/linkedin/avroutil1/compatibility/avro17/codec/ResolvingDecoder.java
@@ -24,6 +24,7 @@
package com.linkedin.avroutil1.compatibility.avro17.codec;
+import com.linkedin.avroutil1.compatibility.CustomDecoder;
import com.linkedin.avroutil1.compatibility.avro17.parsing.ResolvingGrammarGenerator;
import com.linkedin.avroutil1.compatibility.avro17.parsing.Symbol;
import java.io.IOException;
@@ -37,7 +38,7 @@
import org.apache.avro.io.DecoderFactory;
import org.apache.avro.util.Utf8;
-public class ResolvingDecoder extends ValidatingDecoder {
+public class ResolvingDecoder extends ValidatingDecoder implements CustomDecoder {
private Decoder backup;
private static final Charset UTF8 = Charset.forName("UTF-8");
@@ -70,7 +71,7 @@ public final void drain() throws IOException {
@Override
public int readInt() throws IOException {
- Symbol actual = parser.popSymbol();
+ Symbol actual = parser.advance(Symbol.INT);
if (actual == Symbol.INT) {
return in.readInt();
} else if (actual == Symbol.IntLongAdjustAction.INSTANCE) {
@@ -226,8 +227,7 @@ public Symbol doAction(Symbol input, Symbol top) throws IOException {
}
if (top == Symbol.IntLongAdjustAction.INSTANCE) {
- parser.pushSymbol(Symbol.INT);
- return Symbol.INT;
+ return top;
}
if (top instanceof Symbol.DefaultStartAction) {
diff --git a/helper/impls/helper-impl-18/src/main/java/com/linkedin/avroutil1/compatibility/avro18/backports/GenericDatumReaderExt.java b/helper/impls/helper-impl-18/src/main/java/com/linkedin/avroutil1/compatibility/avro18/backports/GenericDatumReaderExt.java
index df1c80b52..3a09719c3 100644
--- a/helper/impls/helper-impl-18/src/main/java/com/linkedin/avroutil1/compatibility/avro18/backports/GenericDatumReaderExt.java
+++ b/helper/impls/helper-impl-18/src/main/java/com/linkedin/avroutil1/compatibility/avro18/backports/GenericDatumReaderExt.java
@@ -38,7 +38,8 @@ public GenericDatumReaderExt(Schema writer, Schema reader, GenericData genericDa
@Override
public T read(T reuse, Decoder in) throws IOException {
final Schema reader = getExpected();
- CachedResolvingDecoder resolver = new CachedResolvingDecoder(getSchema(), reader, in);
+ final Schema writer = getSchema();
+ CachedResolvingDecoder resolver = new CachedResolvingDecoder(Schema.applyAliases(writer, reader), reader, in);
resolver.configure(in);
T result = (T) read(reuse, reader, resolver);
resolver.drain();
diff --git a/helper/impls/helper-impl-18/src/main/java/com/linkedin/avroutil1/compatibility/avro18/backports/SpecificDatumReaderExt.java b/helper/impls/helper-impl-18/src/main/java/com/linkedin/avroutil1/compatibility/avro18/backports/SpecificDatumReaderExt.java
index 67e3395b5..4b02fbd06 100644
--- a/helper/impls/helper-impl-18/src/main/java/com/linkedin/avroutil1/compatibility/avro18/backports/SpecificDatumReaderExt.java
+++ b/helper/impls/helper-impl-18/src/main/java/com/linkedin/avroutil1/compatibility/avro18/backports/SpecificDatumReaderExt.java
@@ -40,7 +40,8 @@ public SpecificDatumReaderExt(Schema writer, Schema reader, SpecificData specifi
@Override
public T read(T reuse, Decoder in) throws IOException {
final Schema reader = getExpected();
- CachedResolvingDecoder resolver = new CachedResolvingDecoder(getSchema(), reader, in);
+ final Schema writer = getSchema();
+ CachedResolvingDecoder resolver = new CachedResolvingDecoder(Schema.applyAliases(writer, reader), reader, in);
resolver.configure(in);
T result = (T) read(reuse, reader, resolver);
resolver.drain();
diff --git a/helper/impls/helper-impl-18/src/main/java/com/linkedin/avroutil1/compatibility/avro18/codec/AliasAwareSpecificDatumReader.java b/helper/impls/helper-impl-18/src/main/java/com/linkedin/avroutil1/compatibility/avro18/codec/AliasAwareSpecificDatumReader.java
index bae57cf7c..04956f057 100644
--- a/helper/impls/helper-impl-18/src/main/java/com/linkedin/avroutil1/compatibility/avro18/codec/AliasAwareSpecificDatumReader.java
+++ b/helper/impls/helper-impl-18/src/main/java/com/linkedin/avroutil1/compatibility/avro18/codec/AliasAwareSpecificDatumReader.java
@@ -6,6 +6,7 @@
package com.linkedin.avroutil1.compatibility.avro18.codec;
+import com.linkedin.avroutil1.compatibility.avro18.backports.SpecificDatumReaderExt;
import org.apache.avro.Schema;
import org.apache.avro.specific.SpecificData;
import org.apache.avro.specific.SpecificDatumReader;
@@ -20,7 +21,7 @@
*
* @param
*/
-public class AliasAwareSpecificDatumReader extends SpecificDatumReader {
+public class AliasAwareSpecificDatumReader extends SpecificDatumReaderExt {
public AliasAwareSpecificDatumReader() {
this(null, null);
@@ -40,10 +41,12 @@ public AliasAwareSpecificDatumReader(Schema writer, Schema reader) {
}
public AliasAwareSpecificDatumReader(Schema writer, Schema reader, SpecificData data) {
+ super(null, null, data);
throw new UnsupportedOperationException("providing custom SpecificData not supported (yet?)");
}
protected AliasAwareSpecificDatumReader(SpecificData data) {
+ super(null, null, data);
throw new UnsupportedOperationException("providing custom SpecificData not supported (yet?)");
}
}
diff --git a/helper/impls/helper-impl-18/src/main/java/com/linkedin/avroutil1/compatibility/avro18/codec/ResolvingDecoder.java b/helper/impls/helper-impl-18/src/main/java/com/linkedin/avroutil1/compatibility/avro18/codec/ResolvingDecoder.java
index 765447e94..bf60440ce 100644
--- a/helper/impls/helper-impl-18/src/main/java/com/linkedin/avroutil1/compatibility/avro18/codec/ResolvingDecoder.java
+++ b/helper/impls/helper-impl-18/src/main/java/com/linkedin/avroutil1/compatibility/avro18/codec/ResolvingDecoder.java
@@ -24,6 +24,7 @@
package com.linkedin.avroutil1.compatibility.avro18.codec;
+import com.linkedin.avroutil1.compatibility.CustomDecoder;
import com.linkedin.avroutil1.compatibility.avro18.parsing.ResolvingGrammarGenerator;
import com.linkedin.avroutil1.compatibility.avro18.parsing.Symbol;
import java.io.IOException;
@@ -37,7 +38,7 @@
import org.apache.avro.io.DecoderFactory;
import org.apache.avro.util.Utf8;
-public class ResolvingDecoder extends ValidatingDecoder {
+public class ResolvingDecoder extends ValidatingDecoder implements CustomDecoder {
private Decoder backup;
private static final Charset UTF8 = Charset.forName("UTF-8");
@@ -70,7 +71,7 @@ public final void drain() throws IOException {
@Override
public int readInt() throws IOException {
- Symbol actual = parser.popSymbol();
+ Symbol actual = parser.advance(Symbol.INT);
if (actual == Symbol.INT) {
return in.readInt();
} else if (actual == Symbol.IntLongAdjustAction.INSTANCE) {
@@ -226,8 +227,7 @@ public Symbol doAction(Symbol input, Symbol top) throws IOException {
}
if (top == Symbol.IntLongAdjustAction.INSTANCE) {
- parser.pushSymbol(Symbol.INT);
- return Symbol.INT;
+ return top;
}
if (top instanceof Symbol.DefaultStartAction) {
diff --git a/helper/impls/helper-impl-19/src/main/java/com/linkedin/avroutil1/compatibility/avro19/Avro19Adapter.java b/helper/impls/helper-impl-19/src/main/java/com/linkedin/avroutil1/compatibility/avro19/Avro19Adapter.java
index 0af84ff78..45b8bebca 100644
--- a/helper/impls/helper-impl-19/src/main/java/com/linkedin/avroutil1/compatibility/avro19/Avro19Adapter.java
+++ b/helper/impls/helper-impl-19/src/main/java/com/linkedin/avroutil1/compatibility/avro19/Avro19Adapter.java
@@ -24,6 +24,8 @@
import com.linkedin.avroutil1.compatibility.SkipDecoder;
import com.linkedin.avroutil1.compatibility.StringRepresentation;
import com.linkedin.avroutil1.compatibility.avro19.backports.Avro19DefaultValuesCache;
+import com.linkedin.avroutil1.compatibility.avro19.backports.GenericDatumReaderExt;
+import com.linkedin.avroutil1.compatibility.avro19.backports.SpecificDatumReaderExt;
import com.linkedin.avroutil1.compatibility.avro19.codec.AliasAwareSpecificDatumReader;
import com.linkedin.avroutil1.compatibility.avro19.codec.BoundedMemoryDecoder;
import com.linkedin.avroutil1.compatibility.avro19.codec.CachedResolvingDecoder;
@@ -38,7 +40,6 @@
import org.apache.avro.Schema;
import org.apache.avro.SchemaNormalization;
import org.apache.avro.generic.GenericData;
-import org.apache.avro.generic.GenericDatumReader;
import org.apache.avro.generic.GenericDatumWriter;
import org.apache.avro.io.Avro19BinaryDecoderAccessUtil;
import org.apache.avro.io.BinaryDecoder;
@@ -242,7 +243,7 @@ public DatumWriter> newGenericDatumWriter(Schema writer, GenericData genericDa
@Override
public DatumReader> newGenericDatumReader(Schema writer, Schema reader, GenericData genericData) {
- return new GenericDatumReader<>(writer, reader, genericData);
+ return new GenericDatumReaderExt<>(writer, reader, genericData);
}
@Override
@@ -252,7 +253,7 @@ public DatumWriter> newSpecificDatumWriter(Schema writer, SpecificData specifi
@Override
public DatumReader> newSpecificDatumReader(Schema writer, Schema reader, SpecificData specificData) {
- return new SpecificDatumReader<>(writer, reader, specificData);
+ return new SpecificDatumReaderExt<>(writer, reader, specificData);
}
@Override
diff --git a/helper/impls/helper-impl-19/src/main/java/com/linkedin/avroutil1/compatibility/avro19/backports/GenericDatumReaderExt.java b/helper/impls/helper-impl-19/src/main/java/com/linkedin/avroutil1/compatibility/avro19/backports/GenericDatumReaderExt.java
new file mode 100644
index 000000000..06d714f1c
--- /dev/null
+++ b/helper/impls/helper-impl-19/src/main/java/com/linkedin/avroutil1/compatibility/avro19/backports/GenericDatumReaderExt.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2025 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.avro19.backports;
+
+import com.linkedin.avroutil1.compatibility.avro19.codec.CachedResolvingDecoder;
+import org.apache.avro.AvroRuntimeException;
+import org.apache.avro.Conversion;
+import org.apache.avro.LogicalType;
+import org.apache.avro.Schema;
+import org.apache.avro.generic.Avro19GenericDataAccessUtil;
+import org.apache.avro.generic.GenericData;
+import org.apache.avro.generic.GenericDatumReader;
+import org.apache.avro.io.Decoder;
+
+import java.io.IOException;
+
+
+/**
+ * this class allows constructing a {@link GenericDatumReader} with
+ * a specified {@link GenericData} instance under avro 1.9
+ *
+ * @param
+ */
+public class GenericDatumReaderExt extends GenericDatumReader {
+
+ public GenericDatumReaderExt(Schema writer, Schema reader, GenericData genericData) {
+ super(writer, reader, genericData);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ public T read(T reuse, Decoder in) throws IOException {
+ final Schema reader = getExpected();
+ final Schema writer = getSchema();
+ CachedResolvingDecoder resolver = new CachedResolvingDecoder(Schema.applyAliases(writer, reader), reader, in);
+ resolver.configure(in);
+ T result = (T) read(reuse, reader, resolver);
+ resolver.drain();
+ return result;
+ }
+
+ private Object read(Object old, Schema expected,
+ CachedResolvingDecoder in) throws IOException {
+ Object datum = readWithoutConversion(old, expected, in);
+ LogicalType logicalType = expected.getLogicalType();
+ if (logicalType != null) {
+ Conversion> conversion = getData().getConversionFor(logicalType);
+ if (conversion != null) {
+ return convert(datum, expected, logicalType, conversion);
+ }
+ }
+ return datum;
+ }
+
+ private Object readWithoutConversion(Object old, Schema expected,
+ CachedResolvingDecoder in) throws IOException {
+ switch (expected.getType()) {
+ case RECORD:
+ return readRecord(old, expected, in);
+ case ENUM:
+ return readEnum(expected, in);
+ case ARRAY:
+ return readArray(old, expected, in);
+ case MAP:
+ return readMap(old, expected, in);
+ case UNION:
+ return read(old, expected.getTypes().get(in.readIndex()), in);
+ case FIXED:
+ return readFixed(old, expected, in);
+ case STRING:
+ return readString(old, expected, in);
+ case BYTES:
+ return readBytes(old, expected, in);
+ case INT:
+ return readInt(old, expected, in);
+ case LONG:
+ return in.readLong();
+ case FLOAT:
+ return in.readFloat();
+ case DOUBLE:
+ return in.readDouble();
+ case BOOLEAN:
+ return in.readBoolean();
+ case NULL:
+ in.readNull();
+ return null;
+ default:
+ throw new AvroRuntimeException("Unknown type: " + expected);
+ }
+ }
+
+ private Object readRecord(Object old, Schema expected,
+ CachedResolvingDecoder in) throws IOException {
+ final GenericData data = getData();
+ Object r = data.newRecord(old, expected);
+ Object state = Avro19GenericDataAccessUtil.getRecordState(data, r, expected);
+
+ for (Schema.Field f : in.readFieldOrder()) {
+ int pos = f.pos();
+ String name = f.name();
+ Object oldDatum = null;
+ if (old != null) {
+ oldDatum = Avro19GenericDataAccessUtil.getField(data, r, name, pos, state);
+ }
+ Avro19GenericDataAccessUtil.setField(getData(), r, f.name(), f.pos(), read(oldDatum, f.schema(), in), state);
+ }
+
+ return r;
+ }
+
+ private Object readArray(Object old, Schema expected,
+ CachedResolvingDecoder in) throws IOException {
+ Schema expectedType = expected.getElementType();
+ long l = in.readArrayStart();
+ long base = 0;
+ if (l > 0) {
+ Object array = newArray(old, (int) l, expected);
+ do {
+ for (long i = 0; i < l; i++) {
+ addToArray(array, base + i, read(peekArray(array), expectedType, in));
+ }
+ base += l;
+ } while ((l = in.arrayNext()) > 0);
+ return array;
+ } else {
+ return newArray(old, 0, expected);
+ }
+ }
+
+ private Object readMap(Object old, Schema expected,
+ CachedResolvingDecoder in) throws IOException {
+ Schema eValue = expected.getValueType();
+ long l = in.readMapStart();
+ Object map = newMap(old, (int) l);
+ if (l > 0) {
+ do {
+ for (int i = 0; i < l; i++) {
+ addToMap(map, readString(null, in), read(null, eValue, in));
+ }
+ } while ((l = in.mapNext()) > 0);
+ }
+ return map;
+ }
+}
diff --git a/helper/impls/helper-impl-19/src/main/java/com/linkedin/avroutil1/compatibility/avro19/backports/SpecificDatumReaderExt.java b/helper/impls/helper-impl-19/src/main/java/com/linkedin/avroutil1/compatibility/avro19/backports/SpecificDatumReaderExt.java
new file mode 100644
index 000000000..eee2f73f7
--- /dev/null
+++ b/helper/impls/helper-impl-19/src/main/java/com/linkedin/avroutil1/compatibility/avro19/backports/SpecificDatumReaderExt.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright 2025 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.avro19.backports;
+
+import com.linkedin.avroutil1.compatibility.avro19.codec.CachedResolvingDecoder;
+import com.linkedin.avroutil1.compatibility.backports.SpecificRecordBaseExt;
+import org.apache.avro.AvroRuntimeException;
+import org.apache.avro.Conversion;
+import org.apache.avro.LogicalType;
+import org.apache.avro.Schema;
+import org.apache.avro.generic.Avro19GenericDataAccessUtil;
+import org.apache.avro.generic.GenericData;
+import org.apache.avro.io.Decoder;
+import org.apache.avro.specific.SpecificData;
+import org.apache.avro.specific.SpecificDatumReader;
+import org.apache.avro.specific.SpecificRecordBase;
+
+import java.io.IOException;
+
+
+/**
+ * this class allows constructing a {@link SpecificDatumReader} with
+ * a specified {@link SpecificData} instance under avro 1.9.
+ *
+ * @param
+ */
+public class SpecificDatumReaderExt extends SpecificDatumReader {
+
+ public SpecificDatumReaderExt(Schema writer, Schema reader, SpecificData specificData) {
+ super(writer, reader, specificData);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ public T read(T reuse, Decoder in) throws IOException {
+ final Schema reader = getExpected();
+ final Schema writer = getSchema();
+ CachedResolvingDecoder resolver = new CachedResolvingDecoder(Schema.applyAliases(writer, reader), reader, in);
+ resolver.configure(in);
+ T result = (T) read(reuse, reader, resolver);
+ resolver.drain();
+ return result;
+ }
+
+ private Object read(Object old, Schema expected,
+ CachedResolvingDecoder in) throws IOException {
+ Object datum = readWithoutConversion(old, expected, in);
+ LogicalType logicalType = expected.getLogicalType();
+ if (logicalType != null) {
+ Conversion> conversion = getData().getConversionFor(logicalType);
+ if (conversion != null) {
+ return convert(datum, expected, logicalType, conversion);
+ }
+ }
+ return datum;
+ }
+
+ private Object readWithoutConversion(Object old, Schema expected,
+ CachedResolvingDecoder in) throws IOException {
+ switch (expected.getType()) {
+ case RECORD:
+ return readRecord(old, expected, in);
+ case ENUM:
+ return readEnum(expected, in);
+ case ARRAY:
+ return readArray(old, expected, in);
+ case MAP:
+ return readMap(old, expected, in);
+ case UNION:
+ return read(old, expected.getTypes().get(in.readIndex()), in);
+ case FIXED:
+ return readFixed(old, expected, in);
+ case STRING:
+ return readString(old, expected, in);
+ case BYTES:
+ return readBytes(old, expected, in);
+ case INT:
+ return readInt(old, expected, in);
+ case LONG:
+ return in.readLong();
+ case FLOAT:
+ return in.readFloat();
+ case DOUBLE:
+ return in.readDouble();
+ case BOOLEAN:
+ return in.readBoolean();
+ case NULL:
+ in.readNull();
+ return null;
+ default:
+ throw new AvroRuntimeException("Unknown type: " + expected);
+ }
+ }
+
+ private Object readRecord(Object old, Schema expected,
+ CachedResolvingDecoder in) throws IOException {
+ SpecificData specificData = getSpecificData();
+ if (specificData.useCustomCoders()) {
+ old = specificData.newRecord(old, expected);
+ if (old instanceof SpecificRecordBaseExt) {
+ SpecificRecordBaseExt d = (SpecificRecordBaseExt) old;
+ if (d.isCustomDecodingEnabled()) {
+ d.customDecode(in);
+ return d;
+ }
+ }
+ }
+
+ final GenericData data = getData();
+ Object r = data.newRecord(old, expected);
+ Object state = Avro19GenericDataAccessUtil.getRecordState(data, r, expected);
+
+ for (Schema.Field f : in.readFieldOrder()) {
+ int pos = f.pos();
+ String name = f.name();
+ Object oldDatum = null;
+ if (old != null) {
+ oldDatum = Avro19GenericDataAccessUtil.getField(data, r, name, pos, state);
+ }
+ readField(r, f, oldDatum, in, state);
+ }
+
+ return r;
+ }
+
+ private Object readArray(Object old, Schema expected,
+ CachedResolvingDecoder in) throws IOException {
+ Schema expectedType = expected.getElementType();
+ long l = in.readArrayStart();
+ long base = 0;
+ if (l > 0) {
+ Object array = newArray(old, (int) l, expected);
+ do {
+ for (long i = 0; i < l; i++) {
+ addToArray(array, base + i, read(peekArray(array), expectedType, in));
+ }
+ base += l;
+ } while ((l = in.arrayNext()) > 0);
+ return array;
+ } else {
+ return newArray(old, 0, expected);
+ }
+ }
+
+ private Object readMap(Object old, Schema expected,
+ CachedResolvingDecoder in) throws IOException {
+ Schema eValue = expected.getValueType();
+ long l = in.readMapStart();
+ Object map = newMap(old, (int) l);
+ if (l > 0) {
+ do {
+ for (int i = 0; i < l; i++) {
+ addToMap(map, readString(null, in), read(null, eValue, in));
+ }
+ } while ((l = in.mapNext()) > 0);
+ }
+ return map;
+ }
+
+ private void readField(Object r, Schema.Field f, Object oldDatum,
+ CachedResolvingDecoder in, Object state)
+ throws IOException {
+ if (r instanceof SpecificRecordBase) {
+ Conversion> conversion = ((SpecificRecordBase) r).getConversion(f.pos());
+
+ Object datum;
+ if (conversion != null) {
+ datum = readWithConversion(
+ oldDatum, f.schema(), f.schema().getLogicalType(), conversion, in);
+ } else {
+ datum = readWithoutConversion(oldDatum, f.schema(), in);
+ }
+
+ getData().setField(r, f.name(), f.pos(), datum);
+
+ } else {
+ Avro19GenericDataAccessUtil.setField(getData(), r, f.name(), f.pos(),
+ read(oldDatum, f.schema(), in), state);
+ }
+ }
+
+ private Object readWithConversion(Object old, Schema expected,
+ LogicalType logicalType,
+ Conversion> conversion,
+ CachedResolvingDecoder in) throws IOException {
+ return convert(readWithoutConversion(old, expected, in),
+ expected, logicalType, conversion);
+ }
+}
diff --git a/helper/impls/helper-impl-19/src/main/java/com/linkedin/avroutil1/compatibility/avro19/codec/AliasAwareSpecificDatumReader.java b/helper/impls/helper-impl-19/src/main/java/com/linkedin/avroutil1/compatibility/avro19/codec/AliasAwareSpecificDatumReader.java
index 35539178d..d7a7ff9a0 100644
--- a/helper/impls/helper-impl-19/src/main/java/com/linkedin/avroutil1/compatibility/avro19/codec/AliasAwareSpecificDatumReader.java
+++ b/helper/impls/helper-impl-19/src/main/java/com/linkedin/avroutil1/compatibility/avro19/codec/AliasAwareSpecificDatumReader.java
@@ -6,6 +6,7 @@
package com.linkedin.avroutil1.compatibility.avro19.codec;
+import com.linkedin.avroutil1.compatibility.avro19.backports.SpecificDatumReaderExt;
import org.apache.avro.Schema;
import org.apache.avro.specific.SpecificData;
import org.apache.avro.specific.SpecificDatumReader;
@@ -20,7 +21,7 @@
*
* @param
*/
-public class AliasAwareSpecificDatumReader extends SpecificDatumReader {
+public class AliasAwareSpecificDatumReader extends SpecificDatumReaderExt {
public AliasAwareSpecificDatumReader() {
this(null, null);
@@ -40,10 +41,12 @@ public AliasAwareSpecificDatumReader(Schema writer, Schema reader) {
}
public AliasAwareSpecificDatumReader(Schema writer, Schema reader, SpecificData data) {
+ super(null, null, data);
throw new UnsupportedOperationException("providing custom SpecificData not supported (yet?)");
}
protected AliasAwareSpecificDatumReader(SpecificData data) {
+ super(null, null, data);
throw new UnsupportedOperationException("providing custom SpecificData not supported (yet?)");
}
}
diff --git a/helper/impls/helper-impl-19/src/main/java/com/linkedin/avroutil1/compatibility/avro19/codec/CachedResolvingDecoder.java b/helper/impls/helper-impl-19/src/main/java/com/linkedin/avroutil1/compatibility/avro19/codec/CachedResolvingDecoder.java
index 7564fd3fc..2665a56af 100644
--- a/helper/impls/helper-impl-19/src/main/java/com/linkedin/avroutil1/compatibility/avro19/codec/CachedResolvingDecoder.java
+++ b/helper/impls/helper-impl-19/src/main/java/com/linkedin/avroutil1/compatibility/avro19/codec/CachedResolvingDecoder.java
@@ -10,6 +10,7 @@
import com.linkedin.avroutil1.compatibility.avro19.parsing.Symbol;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
+
import org.apache.avro.Schema;
import org.apache.avro.io.BinaryDecoder;
import org.apache.avro.io.Decoder;
diff --git a/helper/impls/helper-impl-19/src/main/java/com/linkedin/avroutil1/compatibility/avro19/codec/ResolvingDecoder.java b/helper/impls/helper-impl-19/src/main/java/com/linkedin/avroutil1/compatibility/avro19/codec/ResolvingDecoder.java
index 851cb2f48..0276a5bfa 100644
--- a/helper/impls/helper-impl-19/src/main/java/com/linkedin/avroutil1/compatibility/avro19/codec/ResolvingDecoder.java
+++ b/helper/impls/helper-impl-19/src/main/java/com/linkedin/avroutil1/compatibility/avro19/codec/ResolvingDecoder.java
@@ -29,13 +29,15 @@
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
+
+import com.linkedin.avroutil1.compatibility.CustomDecoder;
import org.apache.avro.AvroTypeException;
import org.apache.avro.Schema;
import org.apache.avro.io.Decoder;
import org.apache.avro.io.DecoderFactory;
import org.apache.avro.util.Utf8;
-public class ResolvingDecoder extends ValidatingDecoder {
+public class ResolvingDecoder extends ValidatingDecoder implements CustomDecoder {
private Decoder backup;
@@ -152,6 +154,23 @@ public final void drain() throws IOException {
parser.processImplicitActions();
}
+ @Override
+ public int readInt() throws IOException {
+ Symbol actual = parser.advance(Symbol.INT);
+ if (actual == Symbol.INT) {
+ return in.readInt();
+ } else if (actual == Symbol.IntLongAdjustAction.INSTANCE) {
+ long value = in.readLong();
+ if (value < Integer.MIN_VALUE || value > Integer.MAX_VALUE) {
+ throw new AvroTypeException(value + " cannot be represented as int");
+ }
+
+ return (int) value;
+ }
+
+ throw new AvroTypeException("Expected int but found " + actual);
+ }
+
@Override
public long readLong() throws IOException {
Symbol actual = parser.advance(Symbol.LONG);
@@ -307,6 +326,8 @@ public Symbol doAction(Symbol input, Symbol top) throws IOException {
in = DecoderFactory.get().binaryDecoder(dsa.contents, null);
} else if (top == Symbol.DEFAULT_END_ACTION) {
in = backup;
+ } else if (top == Symbol.IntLongAdjustAction.INSTANCE) {
+ return top;
} else {
throw new AvroTypeException("Unknown action: " + top);
}
diff --git a/helper/impls/helper-impl-19/src/main/java/com/linkedin/avroutil1/compatibility/avro19/parsing/ResolvingGrammarGenerator.java b/helper/impls/helper-impl-19/src/main/java/com/linkedin/avroutil1/compatibility/avro19/parsing/ResolvingGrammarGenerator.java
index 3d13aa075..efb37e6ef 100644
--- a/helper/impls/helper-impl-19/src/main/java/com/linkedin/avroutil1/compatibility/avro19/parsing/ResolvingGrammarGenerator.java
+++ b/helper/impls/helper-impl-19/src/main/java/com/linkedin/avroutil1/compatibility/avro19/parsing/ResolvingGrammarGenerator.java
@@ -82,6 +82,11 @@ private Symbol generate(Resolver.Action action, Map seen, boolea
return simpleGen(action.writer, seen, useFqcns);
} else if (action instanceof Resolver.ErrorAction) {
+ // We should be able to selectively demote long to int if it fits within the range of int.
+ if (isLongToIntDemotion((Resolver.ErrorAction) action, false)) {
+ return Symbol.IntLongAdjustAction.INSTANCE;
+ }
+
return Symbol.error(action.toString());
} else if (action instanceof Resolver.Skip) {
@@ -92,6 +97,16 @@ private Symbol generate(Resolver.Action action, Map seen, boolea
} else if (action instanceof Resolver.ReaderUnion) {
Resolver.ReaderUnion ru = (Resolver.ReaderUnion) action;
+
+ // Check if we need to handle selective long-to-int demotion within unions.
+ if (ru.actualAction instanceof Resolver.ErrorAction) {
+ if (isLongToIntDemotion((Resolver.ErrorAction) ru.actualAction, true)) {
+ return Symbol.seq(
+ Symbol.unionAdjustAction(ru.firstMatch, Symbol.IntLongAdjustAction.INSTANCE),
+ Symbol.UNION);
+ }
+ }
+
Symbol s = generate(ru.actualAction, seen, useFqcns);
return Symbol.seq(Symbol.unionAdjustAction(ru.firstMatch, s), Symbol.UNION);
@@ -107,17 +122,25 @@ private Symbol generate(Resolver.Action action, Map seen, boolea
if (((Resolver.WriterUnion) action).unionEquiv) {
return simpleGen(action.writer, seen, useFqcns);
}
- Resolver.Action[] branches = ((Resolver.WriterUnion) action).actions;
+ Resolver.WriterUnion wu = (Resolver.WriterUnion) action;
+ Resolver.Action[] branches = wu.actions;
Symbol[] symbols = new Symbol[branches.length];
String[] oldLabels = new String[branches.length];
String[] newLabels = new String[branches.length];
- int i = 0;
- for (Resolver.Action branch : branches) {
- symbols[i] = generate(branch, seen, useFqcns);
+
+ for (int i = 0; i < branches.length; i++) {
+ // Check if this branch needs long-to-int conversion
+ if (branches[i] instanceof Resolver.ErrorAction && isLongToIntDemotion((Resolver.ErrorAction) branches[i], true)) {
+ symbols[i] = Symbol.seq(
+ Symbol.unionAdjustAction(i, Symbol.IntLongAdjustAction.INSTANCE),
+ Symbol.UNION);
+ } else {
+ symbols[i] = generate(branches[i], seen, useFqcns);
+ }
+
Schema schema = action.writer.getTypes().get(i);
oldLabels[i] = schema.getName();
newLabels[i] = schema.getFullName();
- i++;
}
return Symbol.seq(Symbol.alt(symbols, oldLabels, newLabels, useFqcns), Symbol.WRITER_UNION_ACTION);
} else if (action instanceof Resolver.EnumAdjust) {
@@ -352,6 +375,39 @@ public static void encode(Encoder e, Schema s, JsonNode n) throws IOException {
}
}
+ private static boolean isLongToIntDemotion(Resolver.ErrorAction errorAction, boolean includeIntUnions) {
+ return isInt(errorAction.reader, includeIntUnions)
+ && errorAction.writer.getType() == Schema.Type.LONG
+ && isLongToIntDemotionError(errorAction, includeIntUnions);
+ }
+
+ private static boolean isLongToIntDemotionError(Resolver.ErrorAction errorAction, boolean includeIntUnions) {
+ if (errorAction.error == Resolver.ErrorAction.ErrorType.INCOMPATIBLE_SCHEMA_TYPES) {
+ return true;
+ }
+
+ return includeIntUnions && errorAction.error == Resolver.ErrorAction.ErrorType.NO_MATCHING_BRANCH;
+ }
+
+ private static boolean isInt(Schema schema, boolean includeIntUnions) {
+ if (schema.getType() == Schema.Type.INT) {
+ return true;
+ }
+
+ if (!includeIntUnions) {
+ return false;
+ }
+
+ if (schema.getType() != Schema.Type.UNION) {
+ return false;
+ }
+
+ List types = schema.getTypes();
+ return (types.size() == 2
+ && types.get(0).getType() == Schema.Type.NULL
+ && types.get(1).getType() == Schema.Type.INT);
+ }
+
/**
* Clever trick which differentiates items put into
* seen by {@link ValidatingGrammarGenerator validating()}
diff --git a/helper/impls/helper-impl-19/src/main/java/com/linkedin/avroutil1/compatibility/avro19/parsing/Symbol.java b/helper/impls/helper-impl-19/src/main/java/com/linkedin/avroutil1/compatibility/avro19/parsing/Symbol.java
index ff50d07d8..4b8bbd4c2 100644
--- a/helper/impls/helper-impl-19/src/main/java/com/linkedin/avroutil1/compatibility/avro19/parsing/Symbol.java
+++ b/helper/impls/helper-impl-19/src/main/java/com/linkedin/avroutil1/compatibility/avro19/parsing/Symbol.java
@@ -633,6 +633,10 @@ public FieldOrderAction(Schema.Field[] fields) {
}
}
+ public static class IntLongAdjustAction extends ImplicitAction {
+ public static final IntLongAdjustAction INSTANCE = new IntLongAdjustAction();
+ }
+
public static DefaultStartAction defaultStartAction(byte[] contents) {
return new DefaultStartAction(contents);
}
diff --git a/helper/impls/helper-impl-19/src/main/java/org/apache/avro/generic/Avro19GenericDataAccessUtil.java b/helper/impls/helper-impl-19/src/main/java/org/apache/avro/generic/Avro19GenericDataAccessUtil.java
new file mode 100644
index 000000000..9b486ecf8
--- /dev/null
+++ b/helper/impls/helper-impl-19/src/main/java/org/apache/avro/generic/Avro19GenericDataAccessUtil.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2025 LinkedIn Corp.
+ * Licensed under the BSD 2-Clause License (the "License").
+ * See License in the project root for license information.
+ */
+
+package org.apache.avro.generic;
+
+import org.apache.avro.Schema;
+
+/**
+ * this class exists to allow us access to package-private classes and methods on class {@link GenericData}
+ */
+public class Avro19GenericDataAccessUtil {
+ private Avro19GenericDataAccessUtil() {
+ }
+
+ public static Object getRecordState(GenericData data, Object record, Schema schema) {
+ return data.getRecordState(record, schema);
+ }
+
+ public static Object getField(GenericData data, Object record, String name, int pos, Object state) {
+ return data.getField(record, name, pos, state);
+ }
+
+ public static void setField(GenericData data, Object record, String name, int pos, Object value, Object state) {
+ data.setField(record, name, pos, value, state);
+ }
+}
diff --git a/helper/tests/codegen-110/src/main/raw-avro/by110/IntRecord.avsc b/helper/tests/codegen-110/src/main/raw-avro/by110/IntRecord.avsc
new file mode 100644
index 000000000..5bb9f233f
--- /dev/null
+++ b/helper/tests/codegen-110/src/main/raw-avro/by110/IntRecord.avsc
@@ -0,0 +1,57 @@
+{
+ "type": "record",
+ "namespace": "by110",
+ "name": "IntRecord",
+ "fields": [
+ {
+ "name": "unionField",
+ "type": [
+ "null",
+ "int"
+ ],
+ "default": null
+ },
+ {
+ "name": "field",
+ "type": "int"
+ },
+ {
+ "name": "arrayField",
+ "type": {
+ "type": "array",
+ "items": "int"
+ },
+ "default": []
+ },
+ {
+ "name": "mapField",
+ "type": {
+ "type": "map",
+ "values": "int"
+ },
+ "default": {}
+ },
+ {
+ "name": "unionArrayField",
+ "type": {
+ "type": "array",
+ "items": [
+ "null",
+ "int"
+ ]
+ },
+ "default": []
+ },
+ {
+ "name": "unionMapField",
+ "type": {
+ "type": "map",
+ "values": [
+ "null",
+ "int"
+ ]
+ },
+ "default": {}
+ }
+ ]
+}
\ No newline at end of file
diff --git a/helper/tests/codegen-110/src/main/raw-avro/by110/LongRecord.avsc b/helper/tests/codegen-110/src/main/raw-avro/by110/LongRecord.avsc
new file mode 100644
index 000000000..4a1681abf
--- /dev/null
+++ b/helper/tests/codegen-110/src/main/raw-avro/by110/LongRecord.avsc
@@ -0,0 +1,57 @@
+{
+ "type": "record",
+ "namespace": "by110",
+ "name": "LongRecord",
+ "fields": [
+ {
+ "name": "unionField",
+ "type": [
+ "null",
+ "long"
+ ],
+ "default": null
+ },
+ {
+ "name": "field",
+ "type": "long"
+ },
+ {
+ "name": "arrayField",
+ "type": {
+ "type": "array",
+ "items": "long"
+ },
+ "default": []
+ },
+ {
+ "name": "mapField",
+ "type": {
+ "type": "map",
+ "values": "long"
+ },
+ "default": {}
+ },
+ {
+ "name": "unionArrayField",
+ "type": {
+ "type": "array",
+ "items": [
+ "null",
+ "long"
+ ]
+ },
+ "default": []
+ },
+ {
+ "name": "unionMapField",
+ "type": {
+ "type": "map",
+ "values": [
+ "null",
+ "long"
+ ]
+ },
+ "default": {}
+ }
+ ]
+}
\ No newline at end of file
diff --git a/helper/tests/codegen-111/src/main/raw-avro/by111/IntRecord.avsc b/helper/tests/codegen-111/src/main/raw-avro/by111/IntRecord.avsc
new file mode 100644
index 000000000..245991a62
--- /dev/null
+++ b/helper/tests/codegen-111/src/main/raw-avro/by111/IntRecord.avsc
@@ -0,0 +1,57 @@
+{
+ "type": "record",
+ "namespace": "by111",
+ "name": "IntRecord",
+ "fields": [
+ {
+ "name": "unionField",
+ "type": [
+ "null",
+ "int"
+ ],
+ "default": null
+ },
+ {
+ "name": "field",
+ "type": "int"
+ },
+ {
+ "name": "arrayField",
+ "type": {
+ "type": "array",
+ "items": "int"
+ },
+ "default": []
+ },
+ {
+ "name": "mapField",
+ "type": {
+ "type": "map",
+ "values": "int"
+ },
+ "default": {}
+ },
+ {
+ "name": "unionArrayField",
+ "type": {
+ "type": "array",
+ "items": [
+ "null",
+ "int"
+ ]
+ },
+ "default": []
+ },
+ {
+ "name": "unionMapField",
+ "type": {
+ "type": "map",
+ "values": [
+ "null",
+ "int"
+ ]
+ },
+ "default": {}
+ }
+ ]
+}
\ No newline at end of file
diff --git a/helper/tests/codegen-111/src/main/raw-avro/by111/LongRecord.avsc b/helper/tests/codegen-111/src/main/raw-avro/by111/LongRecord.avsc
new file mode 100644
index 000000000..6e0d8c085
--- /dev/null
+++ b/helper/tests/codegen-111/src/main/raw-avro/by111/LongRecord.avsc
@@ -0,0 +1,57 @@
+{
+ "type": "record",
+ "namespace": "by111",
+ "name": "LongRecord",
+ "fields": [
+ {
+ "name": "unionField",
+ "type": [
+ "null",
+ "long"
+ ],
+ "default": null
+ },
+ {
+ "name": "field",
+ "type": "long"
+ },
+ {
+ "name": "arrayField",
+ "type": {
+ "type": "array",
+ "items": "long"
+ },
+ "default": []
+ },
+ {
+ "name": "mapField",
+ "type": {
+ "type": "map",
+ "values": "long"
+ },
+ "default": {}
+ },
+ {
+ "name": "unionArrayField",
+ "type": {
+ "type": "array",
+ "items": [
+ "null",
+ "long"
+ ]
+ },
+ "default": []
+ },
+ {
+ "name": "unionMapField",
+ "type": {
+ "type": "map",
+ "values": [
+ "null",
+ "long"
+ ]
+ },
+ "default": {}
+ }
+ ]
+}
\ No newline at end of file
diff --git a/helper/tests/codegen-14/src/main/raw-avro/by14/IntRecord.avsc b/helper/tests/codegen-14/src/main/raw-avro/by14/IntRecord.avsc
index ab2641547..fba71f0de 100644
--- a/helper/tests/codegen-14/src/main/raw-avro/by14/IntRecord.avsc
+++ b/helper/tests/codegen-14/src/main/raw-avro/by14/IntRecord.avsc
@@ -14,6 +14,44 @@
{
"name": "field",
"type": "int"
+ },
+ {
+ "name": "arrayField",
+ "type": {
+ "type": "array",
+ "items": "int"
+ },
+ "default": []
+ },
+ {
+ "name": "mapField",
+ "type": {
+ "type": "map",
+ "values": "int"
+ },
+ "default": {}
+ },
+ {
+ "name": "unionArrayField",
+ "type": {
+ "type": "array",
+ "items": [
+ "null",
+ "int"
+ ]
+ },
+ "default": []
+ },
+ {
+ "name": "unionMapField",
+ "type": {
+ "type": "map",
+ "values": [
+ "null",
+ "int"
+ ]
+ },
+ "default": {}
}
]
}
\ No newline at end of file
diff --git a/helper/tests/codegen-14/src/main/raw-avro/by14/LongRecord.avsc b/helper/tests/codegen-14/src/main/raw-avro/by14/LongRecord.avsc
index c357c9856..1c7cb5dd0 100644
--- a/helper/tests/codegen-14/src/main/raw-avro/by14/LongRecord.avsc
+++ b/helper/tests/codegen-14/src/main/raw-avro/by14/LongRecord.avsc
@@ -14,6 +14,44 @@
{
"name": "field",
"type": "long"
+ },
+ {
+ "name": "arrayField",
+ "type": {
+ "type": "array",
+ "items": "long"
+ },
+ "default": []
+ },
+ {
+ "name": "mapField",
+ "type": {
+ "type": "map",
+ "values": "long"
+ },
+ "default": {}
+ },
+ {
+ "name": "unionArrayField",
+ "type": {
+ "type": "array",
+ "items": [
+ "null",
+ "long"
+ ]
+ },
+ "default": []
+ },
+ {
+ "name": "unionMapField",
+ "type": {
+ "type": "map",
+ "values": [
+ "null",
+ "long"
+ ]
+ },
+ "default": {}
}
]
}
\ No newline at end of file
diff --git a/helper/tests/codegen-15/src/main/raw-avro/by15/IntRecord.avsc b/helper/tests/codegen-15/src/main/raw-avro/by15/IntRecord.avsc
index eafebd345..09a7cb0a8 100644
--- a/helper/tests/codegen-15/src/main/raw-avro/by15/IntRecord.avsc
+++ b/helper/tests/codegen-15/src/main/raw-avro/by15/IntRecord.avsc
@@ -14,6 +14,44 @@
{
"name": "field",
"type": "int"
+ },
+ {
+ "name": "arrayField",
+ "type": {
+ "type": "array",
+ "items": "int"
+ },
+ "default": []
+ },
+ {
+ "name": "mapField",
+ "type": {
+ "type": "map",
+ "values": "int"
+ },
+ "default": {}
+ },
+ {
+ "name": "unionArrayField",
+ "type": {
+ "type": "array",
+ "items": [
+ "null",
+ "int"
+ ]
+ },
+ "default": []
+ },
+ {
+ "name": "unionMapField",
+ "type": {
+ "type": "map",
+ "values": [
+ "null",
+ "int"
+ ]
+ },
+ "default": {}
}
]
}
\ No newline at end of file
diff --git a/helper/tests/codegen-15/src/main/raw-avro/by15/LongRecord.avsc b/helper/tests/codegen-15/src/main/raw-avro/by15/LongRecord.avsc
index c39ba7335..08ffe4057 100644
--- a/helper/tests/codegen-15/src/main/raw-avro/by15/LongRecord.avsc
+++ b/helper/tests/codegen-15/src/main/raw-avro/by15/LongRecord.avsc
@@ -14,6 +14,44 @@
{
"name": "field",
"type": "long"
+ },
+ {
+ "name": "arrayField",
+ "type": {
+ "type": "array",
+ "items": "long"
+ },
+ "default": []
+ },
+ {
+ "name": "mapField",
+ "type": {
+ "type": "map",
+ "values": "long"
+ },
+ "default": {}
+ },
+ {
+ "name": "unionArrayField",
+ "type": {
+ "type": "array",
+ "items": [
+ "null",
+ "long"
+ ]
+ },
+ "default": []
+ },
+ {
+ "name": "unionMapField",
+ "type": {
+ "type": "map",
+ "values": [
+ "null",
+ "long"
+ ]
+ },
+ "default": {}
}
]
}
\ No newline at end of file
diff --git a/helper/tests/codegen-16/src/main/raw-avro/by16/IntRecord.avsc b/helper/tests/codegen-16/src/main/raw-avro/by16/IntRecord.avsc
index f37656601..953aa6527 100644
--- a/helper/tests/codegen-16/src/main/raw-avro/by16/IntRecord.avsc
+++ b/helper/tests/codegen-16/src/main/raw-avro/by16/IntRecord.avsc
@@ -14,6 +14,44 @@
{
"name": "field",
"type": "int"
+ },
+ {
+ "name": "arrayField",
+ "type": {
+ "type": "array",
+ "items": "int"
+ },
+ "default": []
+ },
+ {
+ "name": "mapField",
+ "type": {
+ "type": "map",
+ "values": "int"
+ },
+ "default": {}
+ },
+ {
+ "name": "unionArrayField",
+ "type": {
+ "type": "array",
+ "items": [
+ "null",
+ "int"
+ ]
+ },
+ "default": []
+ },
+ {
+ "name": "unionMapField",
+ "type": {
+ "type": "map",
+ "values": [
+ "null",
+ "int"
+ ]
+ },
+ "default": {}
}
]
}
\ No newline at end of file
diff --git a/helper/tests/codegen-16/src/main/raw-avro/by16/LongRecord.avsc b/helper/tests/codegen-16/src/main/raw-avro/by16/LongRecord.avsc
index 818b83c90..040a93ee2 100644
--- a/helper/tests/codegen-16/src/main/raw-avro/by16/LongRecord.avsc
+++ b/helper/tests/codegen-16/src/main/raw-avro/by16/LongRecord.avsc
@@ -14,6 +14,44 @@
{
"name": "field",
"type": "long"
+ },
+ {
+ "name": "arrayField",
+ "type": {
+ "type": "array",
+ "items": "long"
+ },
+ "default": []
+ },
+ {
+ "name": "mapField",
+ "type": {
+ "type": "map",
+ "values": "long"
+ },
+ "default": {}
+ },
+ {
+ "name": "unionArrayField",
+ "type": {
+ "type": "array",
+ "items": [
+ "null",
+ "long"
+ ]
+ },
+ "default": []
+ },
+ {
+ "name": "unionMapField",
+ "type": {
+ "type": "map",
+ "values": [
+ "null",
+ "long"
+ ]
+ },
+ "default": {}
}
]
}
\ No newline at end of file
diff --git a/helper/tests/codegen-17/src/main/raw-avro/by17/IntRecord.avsc b/helper/tests/codegen-17/src/main/raw-avro/by17/IntRecord.avsc
index d5b5c80a3..7e2d16166 100644
--- a/helper/tests/codegen-17/src/main/raw-avro/by17/IntRecord.avsc
+++ b/helper/tests/codegen-17/src/main/raw-avro/by17/IntRecord.avsc
@@ -14,6 +14,44 @@
{
"name": "field",
"type": "int"
+ },
+ {
+ "name": "arrayField",
+ "type": {
+ "type": "array",
+ "items": "int"
+ },
+ "default": []
+ },
+ {
+ "name": "mapField",
+ "type": {
+ "type": "map",
+ "values": "int"
+ },
+ "default": {}
+ },
+ {
+ "name": "unionArrayField",
+ "type": {
+ "type": "array",
+ "items": [
+ "null",
+ "int"
+ ]
+ },
+ "default": []
+ },
+ {
+ "name": "unionMapField",
+ "type": {
+ "type": "map",
+ "values": [
+ "null",
+ "int"
+ ]
+ },
+ "default": {}
}
]
}
\ No newline at end of file
diff --git a/helper/tests/codegen-17/src/main/raw-avro/by17/LongRecord.avsc b/helper/tests/codegen-17/src/main/raw-avro/by17/LongRecord.avsc
index 12e8b8623..a3e518484 100644
--- a/helper/tests/codegen-17/src/main/raw-avro/by17/LongRecord.avsc
+++ b/helper/tests/codegen-17/src/main/raw-avro/by17/LongRecord.avsc
@@ -14,6 +14,44 @@
{
"name": "field",
"type": "long"
+ },
+ {
+ "name": "arrayField",
+ "type": {
+ "type": "array",
+ "items": "long"
+ },
+ "default": []
+ },
+ {
+ "name": "mapField",
+ "type": {
+ "type": "map",
+ "values": "long"
+ },
+ "default": {}
+ },
+ {
+ "name": "unionArrayField",
+ "type": {
+ "type": "array",
+ "items": [
+ "null",
+ "long"
+ ]
+ },
+ "default": []
+ },
+ {
+ "name": "unionMapField",
+ "type": {
+ "type": "map",
+ "values": [
+ "null",
+ "long"
+ ]
+ },
+ "default": {}
}
]
}
\ No newline at end of file
diff --git a/helper/tests/codegen-18/src/main/raw-avro/by18/IntRecord.avsc b/helper/tests/codegen-18/src/main/raw-avro/by18/IntRecord.avsc
index 40397758b..2f3da2788 100644
--- a/helper/tests/codegen-18/src/main/raw-avro/by18/IntRecord.avsc
+++ b/helper/tests/codegen-18/src/main/raw-avro/by18/IntRecord.avsc
@@ -14,6 +14,44 @@
{
"name": "field",
"type": "int"
+ },
+ {
+ "name": "arrayField",
+ "type": {
+ "type": "array",
+ "items": "int"
+ },
+ "default": []
+ },
+ {
+ "name": "mapField",
+ "type": {
+ "type": "map",
+ "values": "int"
+ },
+ "default": {}
+ },
+ {
+ "name": "unionArrayField",
+ "type": {
+ "type": "array",
+ "items": [
+ "null",
+ "int"
+ ]
+ },
+ "default": []
+ },
+ {
+ "name": "unionMapField",
+ "type": {
+ "type": "map",
+ "values": [
+ "null",
+ "int"
+ ]
+ },
+ "default": {}
}
]
}
\ No newline at end of file
diff --git a/helper/tests/codegen-18/src/main/raw-avro/by18/LongRecord.avsc b/helper/tests/codegen-18/src/main/raw-avro/by18/LongRecord.avsc
index 8f78a8b0d..c832d6eae 100644
--- a/helper/tests/codegen-18/src/main/raw-avro/by18/LongRecord.avsc
+++ b/helper/tests/codegen-18/src/main/raw-avro/by18/LongRecord.avsc
@@ -14,6 +14,44 @@
{
"name": "field",
"type": "long"
+ },
+ {
+ "name": "arrayField",
+ "type": {
+ "type": "array",
+ "items": "long"
+ },
+ "default": []
+ },
+ {
+ "name": "mapField",
+ "type": {
+ "type": "map",
+ "values": "long"
+ },
+ "default": {}
+ },
+ {
+ "name": "unionArrayField",
+ "type": {
+ "type": "array",
+ "items": [
+ "null",
+ "long"
+ ]
+ },
+ "default": []
+ },
+ {
+ "name": "unionMapField",
+ "type": {
+ "type": "map",
+ "values": [
+ "null",
+ "long"
+ ]
+ },
+ "default": {}
}
]
}
\ No newline at end of file
diff --git a/helper/tests/codegen-19/src/main/raw-avro/by19/IntRecord.avsc b/helper/tests/codegen-19/src/main/raw-avro/by19/IntRecord.avsc
new file mode 100644
index 000000000..26eed2528
--- /dev/null
+++ b/helper/tests/codegen-19/src/main/raw-avro/by19/IntRecord.avsc
@@ -0,0 +1,57 @@
+{
+ "type": "record",
+ "namespace": "by19",
+ "name": "IntRecord",
+ "fields": [
+ {
+ "name": "unionField",
+ "type": [
+ "null",
+ "int"
+ ],
+ "default": null
+ },
+ {
+ "name": "field",
+ "type": "int"
+ },
+ {
+ "name": "arrayField",
+ "type": {
+ "type": "array",
+ "items": "int"
+ },
+ "default": []
+ },
+ {
+ "name": "mapField",
+ "type": {
+ "type": "map",
+ "values": "int"
+ },
+ "default": {}
+ },
+ {
+ "name": "unionArrayField",
+ "type": {
+ "type": "array",
+ "items": [
+ "null",
+ "int"
+ ]
+ },
+ "default": []
+ },
+ {
+ "name": "unionMapField",
+ "type": {
+ "type": "map",
+ "values": [
+ "null",
+ "int"
+ ]
+ },
+ "default": {}
+ }
+ ]
+}
\ No newline at end of file
diff --git a/helper/tests/codegen-19/src/main/raw-avro/by19/LongRecord.avsc b/helper/tests/codegen-19/src/main/raw-avro/by19/LongRecord.avsc
new file mode 100644
index 000000000..d8c3c6f18
--- /dev/null
+++ b/helper/tests/codegen-19/src/main/raw-avro/by19/LongRecord.avsc
@@ -0,0 +1,57 @@
+{
+ "type": "record",
+ "namespace": "by19",
+ "name": "LongRecord",
+ "fields": [
+ {
+ "name": "unionField",
+ "type": [
+ "null",
+ "long"
+ ],
+ "default": null
+ },
+ {
+ "name": "field",
+ "type": "long"
+ },
+ {
+ "name": "arrayField",
+ "type": {
+ "type": "array",
+ "items": "long"
+ },
+ "default": []
+ },
+ {
+ "name": "mapField",
+ "type": {
+ "type": "map",
+ "values": "long"
+ },
+ "default": {}
+ },
+ {
+ "name": "unionArrayField",
+ "type": {
+ "type": "array",
+ "items": [
+ "null",
+ "long"
+ ]
+ },
+ "default": []
+ },
+ {
+ "name": "unionMapField",
+ "type": {
+ "type": "map",
+ "values": [
+ "null",
+ "long"
+ ]
+ },
+ "default": {}
+ }
+ ]
+}
\ No newline at end of file
diff --git a/helper/tests/helper-tests-110/src/test/java/com/linkedin/avroutil1/compatibility/avro110/AvroCompatibilityHelperAvro110Test.java b/helper/tests/helper-tests-110/src/test/java/com/linkedin/avroutil1/compatibility/avro110/AvroCompatibilityHelperAvro110Test.java
index b5226fb3a..7d4150a20 100644
--- a/helper/tests/helper-tests-110/src/test/java/com/linkedin/avroutil1/compatibility/avro110/AvroCompatibilityHelperAvro110Test.java
+++ b/helper/tests/helper-tests-110/src/test/java/com/linkedin/avroutil1/compatibility/avro110/AvroCompatibilityHelperAvro110Test.java
@@ -6,15 +6,33 @@
package com.linkedin.avroutil1.compatibility.avro110;
+import by110.IntRecord;
+import by110.LongRecord;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import com.linkedin.avroutil1.Pojo;
import com.linkedin.avroutil1.testcommon.TestUtil;
import com.linkedin.avroutil1.compatibility.AvroCompatibilityHelper;
import com.linkedin.avroutil1.compatibility.AvroVersion;
+
+import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.Map;
+
+import org.apache.avro.AvroTypeException;
import org.apache.avro.JsonProperties;
import org.apache.avro.Schema;
+import org.apache.avro.generic.GenericData;
+import org.apache.avro.generic.GenericDatumWriter;
+import org.apache.avro.generic.GenericRecord;
+import org.apache.avro.generic.IndexedRecord;
+import org.apache.avro.io.BinaryDecoder;
+import org.apache.avro.io.BinaryEncoder;
+import org.apache.avro.io.DatumReader;
+import org.apache.avro.specific.SpecificData;
+import org.apache.avro.specific.SpecificRecord;
+import org.apache.avro.util.Utf8;
import org.mockito.Mockito;
import org.testng.Assert;
import org.testng.annotations.Test;
@@ -74,4 +92,180 @@ public void testCreateSchemaFieldWithProvidedDefaultValue() throws IOException {
(List>) AvroCompatibilityHelper.createSchemaField("arrayOfArrayWithDefault", field.schema(), "", field.defaultVal()).defaultVal();
Assert.assertEquals(actualListValue.get(0).get(0), "dummyElement");
}
+
+ @Test
+ public void testIntRoundtrip() throws IOException {
+ IntRecord intRecord = new IntRecord();
+ intRecord.setField(42);
+ intRecord.setUnionField(55);
+ intRecord.setArrayField(ImmutableList.of(100, -200));
+ intRecord.setMapField(ImmutableMap.of("key1", 300, "key2", -400));
+ intRecord.setUnionArrayField(ImmutableList.of(99, -199));
+ intRecord.setUnionMapField(ImmutableMap.of("key1", 298, "key2", 355));
+ byte[] binary = toBinary(intRecord);
+
+ IntRecord roundtrip = toSpecificRecord(binary, IntRecord.SCHEMA$, IntRecord.SCHEMA$);
+ Assert.assertEquals(roundtrip.getField(), 42);
+ Assert.assertEquals(roundtrip.getUnionField().intValue(), 55);
+ Assert.assertEquals(roundtrip.getArrayField(), ImmutableList.of(100, -200));
+ Assert.assertEquals(roundtrip.getMapField(), ImmutableMap.of(new Utf8("key1"), 300, new Utf8("key2"), -400));
+ Assert.assertEquals(roundtrip.getUnionArrayField(), ImmutableList.of(99, -199));
+ Assert.assertEquals(roundtrip.getUnionMapField(), ImmutableMap.of(new Utf8("key1"), 298, new Utf8("key2"), 355));
+
+ GenericRecord genericRecord = toGenericRecord(binary, IntRecord.SCHEMA$, IntRecord.SCHEMA$);
+ Assert.assertEquals(genericRecord.get("field"), 42);
+ Assert.assertEquals(genericRecord.get("unionField"), 55);
+ Assert.assertEquals(genericRecord.get("arrayField"), ImmutableList.of(100, -200));
+ Assert.assertEquals(genericRecord.get("mapField"), ImmutableMap.of(new Utf8("key1"), 300, new Utf8("key2"), -400));
+ Assert.assertEquals(genericRecord.get("unionArrayField"), ImmutableList.of(99, -199));
+ Assert.assertEquals(genericRecord.get("unionMapField"), ImmutableMap.of(new Utf8("key1"), 298, new Utf8("key2"), 355));
+ }
+
+ @Test
+ public void testLongRoundtrip() throws IOException {
+ LongRecord longRecord = new LongRecord();
+ longRecord.setField(42L);
+ longRecord.setUnionField(55L);
+ longRecord.setArrayField(ImmutableList.of(100L, -200L));
+ longRecord.setMapField(ImmutableMap.of("key1", 300L, "key2", -400L));
+ longRecord.setUnionArrayField(ImmutableList.of(99L, -199L));
+ longRecord.setUnionMapField(ImmutableMap.of("key1", 298L, "key2", 355L));
+ byte[] binary = toBinary(longRecord);
+
+ LongRecord roundtrip = toSpecificRecord(binary, LongRecord.SCHEMA$, LongRecord.SCHEMA$);
+ Assert.assertEquals(roundtrip.getField(), 42L);
+ Assert.assertEquals(roundtrip.getUnionField().longValue(), 55L);
+ Assert.assertEquals(roundtrip.getArrayField(), ImmutableList.of(100L, -200L));
+ Assert.assertEquals(roundtrip.getMapField(), ImmutableMap.of(new Utf8("key1"), 300L, new Utf8("key2"), -400L));
+ Assert.assertEquals(roundtrip.getUnionArrayField(), ImmutableList.of(99L, -199L));
+ Assert.assertEquals(roundtrip.getUnionMapField(), ImmutableMap.of(new Utf8("key1"), 298L, new Utf8("key2"), 355L));
+
+ GenericRecord genericRecord = toGenericRecord(binary, LongRecord.SCHEMA$, LongRecord.SCHEMA$);
+ Assert.assertEquals(genericRecord.get("field"), 42L);
+ Assert.assertEquals(genericRecord.get("unionField"), 55L);
+ Assert.assertEquals(genericRecord.get("arrayField"), ImmutableList.of(100L, -200L));
+ Assert.assertEquals(genericRecord.get("mapField"), ImmutableMap.of(new Utf8("key1"), 300L, new Utf8("key2"), -400L));
+ Assert.assertEquals(genericRecord.get("unionArrayField"), ImmutableList.of(99L, -199L));
+ Assert.assertEquals(genericRecord.get("unionMapField"), ImmutableMap.of(new Utf8("key1"), 298L, new Utf8("key2"), 355L));
+ }
+
+ @Test
+ public void testIntToLongPromotion() throws IOException {
+ IntRecord intRecord = new IntRecord();
+ intRecord.setField(42);
+ intRecord.setUnionField(55);
+ intRecord.setArrayField(ImmutableList.of(100, -200));
+ intRecord.setMapField(ImmutableMap.of("key1", 300, "key2", -400));
+ intRecord.setUnionArrayField(ImmutableList.of(99, -199));
+ intRecord.setUnionMapField(ImmutableMap.of("key1", 298, "key2", 355));
+ byte[] binary = toBinary(intRecord);
+
+ LongRecord longRecord = toSpecificRecord(binary, IntRecord.SCHEMA$, LongRecord.SCHEMA$);
+ Assert.assertEquals(longRecord.getField(), 42L);
+ Assert.assertEquals(longRecord.getUnionField().longValue(), 55L);
+ Assert.assertEquals(longRecord.getArrayField(), ImmutableList.of(100L, -200L));
+ Assert.assertEquals(longRecord.getMapField(), ImmutableMap.of(new Utf8("key1"), 300L, new Utf8("key2"), -400L));
+ Assert.assertEquals(longRecord.getUnionArrayField(), ImmutableList.of(99L, -199L));
+ Assert.assertEquals(longRecord.getUnionMapField(), ImmutableMap.of(new Utf8("key1"), 298L, new Utf8("key2"), 355L));
+
+ GenericRecord genericRecord = toGenericRecord(binary, IntRecord.SCHEMA$, LongRecord.SCHEMA$);
+ Assert.assertEquals(genericRecord.get("field"), 42L);
+ Assert.assertEquals(genericRecord.get("unionField"), 55L);
+ Assert.assertEquals(genericRecord.get("arrayField"), ImmutableList.of(100L, -200L));
+ Assert.assertEquals(genericRecord.get("mapField"), ImmutableMap.of(new Utf8("key1"), 300L, new Utf8("key2"), -400L));
+ Assert.assertEquals(genericRecord.get("unionArrayField"), ImmutableList.of(99L, -199L));
+ Assert.assertEquals(genericRecord.get("unionMapField"), ImmutableMap.of(new Utf8("key1"), 298L, new Utf8("key2"), 355L));
+ }
+
+ @Test
+ public void testLongToIntDemotion() throws IOException {
+ LongRecord longRecord = new LongRecord();
+ longRecord.setField(42L);
+ longRecord.setUnionField(55L);
+ longRecord.setArrayField(ImmutableList.of(100L, -200L));
+ longRecord.setMapField(ImmutableMap.of("key1", 300L, "key2", -400L));
+ longRecord.setUnionArrayField(ImmutableList.of(99L, -199L));
+ longRecord.setUnionMapField(ImmutableMap.of("key1", 298L, "key2", 355L));
+ byte[] binary = toBinary(longRecord);
+
+ IntRecord intRecord = toSpecificRecord(binary, LongRecord.SCHEMA$, IntRecord.SCHEMA$);
+ Assert.assertEquals(intRecord.getField(), 42);
+ Assert.assertEquals(intRecord.getUnionField().intValue(), 55);
+ Assert.assertEquals(intRecord.getArrayField(), ImmutableList.of(100, -200));
+ Assert.assertEquals(intRecord.getMapField(), ImmutableMap.of(new Utf8("key1"), 300, new Utf8("key2"), -400));
+ Assert.assertEquals(intRecord.getUnionArrayField(), ImmutableList.of(99, -199));
+ Assert.assertEquals(intRecord.getUnionMapField(), ImmutableMap.of(new Utf8("key1"), 298, new Utf8("key2"), 355));
+
+ GenericRecord genericRecord = toGenericRecord(binary, LongRecord.SCHEMA$, IntRecord.SCHEMA$);
+ Assert.assertEquals(genericRecord.get("field"), 42);
+ Assert.assertEquals(genericRecord.get("unionField"), 55);
+ Assert.assertEquals(genericRecord.get("arrayField"), ImmutableList.of(100, -200));
+ Assert.assertEquals(genericRecord.get("mapField"), ImmutableMap.of(new Utf8("key1"), 300, new Utf8("key2"), -400));
+ Assert.assertEquals(genericRecord.get("unionArrayField"), ImmutableList.of(99, -199));
+ Assert.assertEquals(genericRecord.get("unionMapField"), ImmutableMap.of(new Utf8("key1"), 298, new Utf8("key2"), 355));
+ }
+
+ @Test
+ public void testLongToIntDemotionOutOfRange() throws IOException {
+ LongRecord longRecord = LongRecord.newBuilder().setField((long) Integer.MAX_VALUE + 1L).build();
+ byte[] binary = toBinary(longRecord);
+
+ LongRecord longRecord2 = LongRecord.newBuilder().setField(0L).setUnionField((long) Integer.MIN_VALUE - 1L).build();
+ byte[] binary2 = toBinary(longRecord2);
+
+ LongRecord longRecord3 = LongRecord.newBuilder().setField(0L).setArrayField(ImmutableList.of((long) Integer.MAX_VALUE + 1L)).build();
+ byte[] binary3 = toBinary(longRecord3);
+
+ LongRecord longRecord4 = LongRecord.newBuilder().setField(0L).setMapField(ImmutableMap.of("haha", (long) Integer.MIN_VALUE - 1L)).build();
+ byte[] binary4 = toBinary(longRecord4);
+
+ LongRecord longRecord5 = LongRecord.newBuilder().setField(0L).setUnionArrayField(ImmutableList.of((long) Integer.MAX_VALUE + 1L)).build();
+ byte[] binary5 = toBinary(longRecord5);
+
+ LongRecord longRecord6 = LongRecord.newBuilder().setField(0L).setUnionMapField(ImmutableMap.of("haha", (long) Integer.MIN_VALUE - 1L)).build();
+ byte[] binary6 = toBinary(longRecord6);
+
+ Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+ Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+
+ Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary2, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+ Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary2, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+
+ Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary3, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+ Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary3, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+
+ Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary4, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+ Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary4, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+
+ Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary5, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+ Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary5, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+
+ Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary6, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+ Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary6, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+ }
+
+ private byte[] toBinary(IndexedRecord record) throws IOException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ BinaryEncoder encoder = AvroCompatibilityHelper.newBinaryEncoder(baos);
+ GenericDatumWriter writer = new GenericDatumWriter<>(record.getSchema());
+ writer.write(record, encoder);
+ encoder.flush();
+ return baos.toByteArray();
+ }
+
+ private T toSpecificRecord(byte[] binary,
+ Schema writerSchema,
+ Schema readerSchema) throws IOException {
+ BinaryDecoder decoder = AvroCompatibilityHelper.newBinaryDecoder(binary);
+ DatumReader reader = AvroCompatibilityHelper.newSpecificDatumReader(writerSchema, readerSchema, SpecificData.get());
+ return reader.read(null, decoder);
+ }
+
+ private GenericRecord toGenericRecord(byte[] binary,
+ Schema writerSchema,
+ Schema readerSchema) throws IOException {
+ BinaryDecoder decoder = AvroCompatibilityHelper.newBinaryDecoder(binary);
+ DatumReader reader = AvroCompatibilityHelper.newGenericDatumReader(writerSchema, readerSchema, GenericData.get());
+ return reader.read(null, decoder);
+ }
}
diff --git a/helper/tests/helper-tests-111/src/test/java/com/linkedin/avroutil1/compatibility/avro111/AvroCompatibilityHelperAvro111Test.java b/helper/tests/helper-tests-111/src/test/java/com/linkedin/avroutil1/compatibility/avro111/AvroCompatibilityHelperAvro111Test.java
index e539da7ab..42b925547 100644
--- a/helper/tests/helper-tests-111/src/test/java/com/linkedin/avroutil1/compatibility/avro111/AvroCompatibilityHelperAvro111Test.java
+++ b/helper/tests/helper-tests-111/src/test/java/com/linkedin/avroutil1/compatibility/avro111/AvroCompatibilityHelperAvro111Test.java
@@ -6,11 +6,30 @@
package com.linkedin.avroutil1.compatibility.avro111;
+import by111.IntRecord;
+import by111.LongRecord;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import com.linkedin.avroutil1.compatibility.AvroCompatibilityHelper;
import com.linkedin.avroutil1.compatibility.AvroVersion;
+import org.apache.avro.AvroTypeException;
+import org.apache.avro.Schema;
+import org.apache.avro.generic.GenericData;
+import org.apache.avro.generic.GenericDatumWriter;
+import org.apache.avro.generic.GenericRecord;
+import org.apache.avro.generic.IndexedRecord;
+import org.apache.avro.io.BinaryDecoder;
+import org.apache.avro.io.BinaryEncoder;
+import org.apache.avro.io.DatumReader;
+import org.apache.avro.specific.SpecificData;
+import org.apache.avro.specific.SpecificRecord;
+import org.apache.avro.util.Utf8;
import org.testng.Assert;
import org.testng.annotations.Test;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
public class AvroCompatibilityHelperAvro111Test {
@@ -27,4 +46,180 @@ public void testAvroCompilerVersionDetection() {
AvroVersion detected = AvroCompatibilityHelper.getRuntimeAvroCompilerVersion();
Assert.assertEquals(detected, expected, "expected " + expected + ", got " + detected);
}
+
+ @Test
+ public void testIntRoundtrip() throws IOException {
+ IntRecord intRecord = new IntRecord();
+ intRecord.setField(42);
+ intRecord.setUnionField(55);
+ intRecord.setArrayField(ImmutableList.of(100, -200));
+ intRecord.setMapField(ImmutableMap.of("key1", 300, "key2", -400));
+ intRecord.setUnionArrayField(ImmutableList.of(99, -199));
+ intRecord.setUnionMapField(ImmutableMap.of("key1", 298, "key2", 355));
+ byte[] binary = toBinary(intRecord);
+
+ IntRecord roundtrip = toSpecificRecord(binary, IntRecord.SCHEMA$, IntRecord.SCHEMA$);
+ Assert.assertEquals(roundtrip.getField(), 42);
+ Assert.assertEquals(roundtrip.getUnionField().intValue(), 55);
+ Assert.assertEquals(roundtrip.getArrayField(), ImmutableList.of(100, -200));
+ Assert.assertEquals(roundtrip.getMapField(), ImmutableMap.of(new Utf8("key1"), 300, new Utf8("key2"), -400));
+ Assert.assertEquals(roundtrip.getUnionArrayField(), ImmutableList.of(99, -199));
+ Assert.assertEquals(roundtrip.getUnionMapField(), ImmutableMap.of(new Utf8("key1"), 298, new Utf8("key2"), 355));
+
+ GenericRecord genericRecord = toGenericRecord(binary, IntRecord.SCHEMA$, IntRecord.SCHEMA$);
+ Assert.assertEquals(genericRecord.get("field"), 42);
+ Assert.assertEquals(genericRecord.get("unionField"), 55);
+ Assert.assertEquals(genericRecord.get("arrayField"), ImmutableList.of(100, -200));
+ Assert.assertEquals(genericRecord.get("mapField"), ImmutableMap.of(new Utf8("key1"), 300, new Utf8("key2"), -400));
+ Assert.assertEquals(genericRecord.get("unionArrayField"), ImmutableList.of(99, -199));
+ Assert.assertEquals(genericRecord.get("unionMapField"), ImmutableMap.of(new Utf8("key1"), 298, new Utf8("key2"), 355));
+ }
+
+ @Test
+ public void testLongRoundtrip() throws IOException {
+ LongRecord longRecord = new LongRecord();
+ longRecord.setField(42L);
+ longRecord.setUnionField(55L);
+ longRecord.setArrayField(ImmutableList.of(100L, -200L));
+ longRecord.setMapField(ImmutableMap.of("key1", 300L, "key2", -400L));
+ longRecord.setUnionArrayField(ImmutableList.of(99L, -199L));
+ longRecord.setUnionMapField(ImmutableMap.of("key1", 298L, "key2", 355L));
+ byte[] binary = toBinary(longRecord);
+
+ LongRecord roundtrip = toSpecificRecord(binary, LongRecord.SCHEMA$, LongRecord.SCHEMA$);
+ Assert.assertEquals(roundtrip.getField(), 42L);
+ Assert.assertEquals(roundtrip.getUnionField().longValue(), 55L);
+ Assert.assertEquals(roundtrip.getArrayField(), ImmutableList.of(100L, -200L));
+ Assert.assertEquals(roundtrip.getMapField(), ImmutableMap.of(new Utf8("key1"), 300L, new Utf8("key2"), -400L));
+ Assert.assertEquals(roundtrip.getUnionArrayField(), ImmutableList.of(99L, -199L));
+ Assert.assertEquals(roundtrip.getUnionMapField(), ImmutableMap.of(new Utf8("key1"), 298L, new Utf8("key2"), 355L));
+
+ GenericRecord genericRecord = toGenericRecord(binary, LongRecord.SCHEMA$, LongRecord.SCHEMA$);
+ Assert.assertEquals(genericRecord.get("field"), 42L);
+ Assert.assertEquals(genericRecord.get("unionField"), 55L);
+ Assert.assertEquals(genericRecord.get("arrayField"), ImmutableList.of(100L, -200L));
+ Assert.assertEquals(genericRecord.get("mapField"), ImmutableMap.of(new Utf8("key1"), 300L, new Utf8("key2"), -400L));
+ Assert.assertEquals(genericRecord.get("unionArrayField"), ImmutableList.of(99L, -199L));
+ Assert.assertEquals(genericRecord.get("unionMapField"), ImmutableMap.of(new Utf8("key1"), 298L, new Utf8("key2"), 355L));
+ }
+
+ @Test
+ public void testIntToLongPromotion() throws IOException {
+ IntRecord intRecord = new IntRecord();
+ intRecord.setField(42);
+ intRecord.setUnionField(55);
+ intRecord.setArrayField(ImmutableList.of(100, -200));
+ intRecord.setMapField(ImmutableMap.of("key1", 300, "key2", -400));
+ intRecord.setUnionArrayField(ImmutableList.of(99, -199));
+ intRecord.setUnionMapField(ImmutableMap.of("key1", 298, "key2", 355));
+ byte[] binary = toBinary(intRecord);
+
+ LongRecord longRecord = toSpecificRecord(binary, IntRecord.SCHEMA$, LongRecord.SCHEMA$);
+ Assert.assertEquals(longRecord.getField(), 42L);
+ Assert.assertEquals(longRecord.getUnionField().longValue(), 55L);
+ Assert.assertEquals(longRecord.getArrayField(), ImmutableList.of(100L, -200L));
+ Assert.assertEquals(longRecord.getMapField(), ImmutableMap.of(new Utf8("key1"), 300L, new Utf8("key2"), -400L));
+ Assert.assertEquals(longRecord.getUnionArrayField(), ImmutableList.of(99L, -199L));
+ Assert.assertEquals(longRecord.getUnionMapField(), ImmutableMap.of(new Utf8("key1"), 298L, new Utf8("key2"), 355L));
+
+ GenericRecord genericRecord = toGenericRecord(binary, IntRecord.SCHEMA$, LongRecord.SCHEMA$);
+ Assert.assertEquals(genericRecord.get("field"), 42L);
+ Assert.assertEquals(genericRecord.get("unionField"), 55L);
+ Assert.assertEquals(genericRecord.get("arrayField"), ImmutableList.of(100L, -200L));
+ Assert.assertEquals(genericRecord.get("mapField"), ImmutableMap.of(new Utf8("key1"), 300L, new Utf8("key2"), -400L));
+ Assert.assertEquals(genericRecord.get("unionArrayField"), ImmutableList.of(99L, -199L));
+ Assert.assertEquals(genericRecord.get("unionMapField"), ImmutableMap.of(new Utf8("key1"), 298L, new Utf8("key2"), 355L));
+ }
+
+ @Test
+ public void testLongToIntDemotion() throws IOException {
+ LongRecord longRecord = new LongRecord();
+ longRecord.setField(42L);
+ longRecord.setUnionField(55L);
+ longRecord.setArrayField(ImmutableList.of(100L, -200L));
+ longRecord.setMapField(ImmutableMap.of("key1", 300L, "key2", -400L));
+ longRecord.setUnionArrayField(ImmutableList.of(99L, -199L));
+ longRecord.setUnionMapField(ImmutableMap.of("key1", 298L, "key2", 355L));
+ byte[] binary = toBinary(longRecord);
+
+ IntRecord intRecord = toSpecificRecord(binary, LongRecord.SCHEMA$, IntRecord.SCHEMA$);
+ Assert.assertEquals(intRecord.getField(), 42);
+ Assert.assertEquals(intRecord.getUnionField().intValue(), 55);
+ Assert.assertEquals(intRecord.getArrayField(), ImmutableList.of(100, -200));
+ Assert.assertEquals(intRecord.getMapField(), ImmutableMap.of(new Utf8("key1"), 300, new Utf8("key2"), -400));
+ Assert.assertEquals(intRecord.getUnionArrayField(), ImmutableList.of(99, -199));
+ Assert.assertEquals(intRecord.getUnionMapField(), ImmutableMap.of(new Utf8("key1"), 298, new Utf8("key2"), 355));
+
+ GenericRecord genericRecord = toGenericRecord(binary, LongRecord.SCHEMA$, IntRecord.SCHEMA$);
+ Assert.assertEquals(genericRecord.get("field"), 42);
+ Assert.assertEquals(genericRecord.get("unionField"), 55);
+ Assert.assertEquals(genericRecord.get("arrayField"), ImmutableList.of(100, -200));
+ Assert.assertEquals(genericRecord.get("mapField"), ImmutableMap.of(new Utf8("key1"), 300, new Utf8("key2"), -400));
+ Assert.assertEquals(genericRecord.get("unionArrayField"), ImmutableList.of(99, -199));
+ Assert.assertEquals(genericRecord.get("unionMapField"), ImmutableMap.of(new Utf8("key1"), 298, new Utf8("key2"), 355));
+ }
+
+ @Test
+ public void testLongToIntDemotionOutOfRange() throws IOException {
+ LongRecord longRecord = LongRecord.newBuilder().setField((long) Integer.MAX_VALUE + 1L).build();
+ byte[] binary = toBinary(longRecord);
+
+ LongRecord longRecord2 = LongRecord.newBuilder().setField(0L).setUnionField((long) Integer.MIN_VALUE - 1L).build();
+ byte[] binary2 = toBinary(longRecord2);
+
+ LongRecord longRecord3 = LongRecord.newBuilder().setField(0L).setArrayField(ImmutableList.of((long) Integer.MAX_VALUE + 1L)).build();
+ byte[] binary3 = toBinary(longRecord3);
+
+ LongRecord longRecord4 = LongRecord.newBuilder().setField(0L).setMapField(ImmutableMap.of("haha", (long) Integer.MIN_VALUE - 1L)).build();
+ byte[] binary4 = toBinary(longRecord4);
+
+ LongRecord longRecord5 = LongRecord.newBuilder().setField(0L).setUnionArrayField(ImmutableList.of((long) Integer.MAX_VALUE + 1L)).build();
+ byte[] binary5 = toBinary(longRecord5);
+
+ LongRecord longRecord6 = LongRecord.newBuilder().setField(0L).setUnionMapField(ImmutableMap.of("haha", (long) Integer.MIN_VALUE - 1L)).build();
+ byte[] binary6 = toBinary(longRecord6);
+
+ Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+ Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+
+ Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary2, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+ Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary2, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+
+ Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary3, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+ Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary3, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+
+ Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary4, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+ Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary4, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+
+ Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary5, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+ Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary5, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+
+ Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary6, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+ Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary6, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+ }
+
+ private byte[] toBinary(IndexedRecord record) throws IOException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ BinaryEncoder encoder = AvroCompatibilityHelper.newBinaryEncoder(baos);
+ GenericDatumWriter writer = new GenericDatumWriter<>(record.getSchema());
+ writer.write(record, encoder);
+ encoder.flush();
+ return baos.toByteArray();
+ }
+
+ private T toSpecificRecord(byte[] binary,
+ Schema writerSchema,
+ Schema readerSchema) throws IOException {
+ BinaryDecoder decoder = AvroCompatibilityHelper.newBinaryDecoder(binary);
+ DatumReader reader = AvroCompatibilityHelper.newSpecificDatumReader(writerSchema, readerSchema, SpecificData.get());
+ return reader.read(null, decoder);
+ }
+
+ private GenericRecord toGenericRecord(byte[] binary,
+ Schema writerSchema,
+ Schema readerSchema) throws IOException {
+ BinaryDecoder decoder = AvroCompatibilityHelper.newBinaryDecoder(binary);
+ DatumReader reader = AvroCompatibilityHelper.newGenericDatumReader(writerSchema, readerSchema, GenericData.get());
+ return reader.read(null, decoder);
+ }
}
diff --git a/helper/tests/helper-tests-111_0/src/test/java/com.linkedin.avroutil1.compatibility.avro111/AvroCompatibilityHelperAvro1110Test.java b/helper/tests/helper-tests-111_0/src/test/java/com.linkedin.avroutil1.compatibility.avro111/AvroCompatibilityHelperAvro1110Test.java
index 23addc6d6..4866a59f7 100644
--- a/helper/tests/helper-tests-111_0/src/test/java/com.linkedin.avroutil1.compatibility.avro111/AvroCompatibilityHelperAvro1110Test.java
+++ b/helper/tests/helper-tests-111_0/src/test/java/com.linkedin.avroutil1.compatibility.avro111/AvroCompatibilityHelperAvro1110Test.java
@@ -6,11 +6,30 @@
package com.linkedin.avroutil1.compatibility.avro111;
+import by111.IntRecord;
+import by111.LongRecord;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import com.linkedin.avroutil1.compatibility.AvroCompatibilityHelper;
import com.linkedin.avroutil1.compatibility.AvroVersion;
+import org.apache.avro.AvroTypeException;
+import org.apache.avro.Schema;
+import org.apache.avro.generic.GenericData;
+import org.apache.avro.generic.GenericDatumWriter;
+import org.apache.avro.generic.GenericRecord;
+import org.apache.avro.generic.IndexedRecord;
+import org.apache.avro.io.BinaryDecoder;
+import org.apache.avro.io.BinaryEncoder;
+import org.apache.avro.io.DatumReader;
+import org.apache.avro.specific.SpecificData;
+import org.apache.avro.specific.SpecificRecord;
+import org.apache.avro.util.Utf8;
import org.testng.Assert;
import org.testng.annotations.Test;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
// Tests version detection against Avro 1.11.0
public class AvroCompatibilityHelperAvro1110Test {
@@ -28,4 +47,180 @@ public void testAvroCompilerVersionDetection() {
AvroVersion detected = AvroCompatibilityHelper.getRuntimeAvroCompilerVersion();
Assert.assertEquals(detected, expected, "expected " + expected + ", got " + detected);
}
+
+ @Test
+ public void testIntRoundtrip() throws IOException {
+ IntRecord intRecord = new IntRecord();
+ intRecord.setField(42);
+ intRecord.setUnionField(55);
+ intRecord.setArrayField(ImmutableList.of(100, -200));
+ intRecord.setMapField(ImmutableMap.of("key1", 300, "key2", -400));
+ intRecord.setUnionArrayField(ImmutableList.of(99, -199));
+ intRecord.setUnionMapField(ImmutableMap.of("key1", 298, "key2", 355));
+ byte[] binary = toBinary(intRecord);
+
+ IntRecord roundtrip = toSpecificRecord(binary, IntRecord.SCHEMA$, IntRecord.SCHEMA$);
+ Assert.assertEquals(roundtrip.getField(), 42);
+ Assert.assertEquals(roundtrip.getUnionField().intValue(), 55);
+ Assert.assertEquals(roundtrip.getArrayField(), ImmutableList.of(100, -200));
+ Assert.assertEquals(roundtrip.getMapField(), ImmutableMap.of(new Utf8("key1"), 300, new Utf8("key2"), -400));
+ Assert.assertEquals(roundtrip.getUnionArrayField(), ImmutableList.of(99, -199));
+ Assert.assertEquals(roundtrip.getUnionMapField(), ImmutableMap.of(new Utf8("key1"), 298, new Utf8("key2"), 355));
+
+ GenericRecord genericRecord = toGenericRecord(binary, IntRecord.SCHEMA$, IntRecord.SCHEMA$);
+ Assert.assertEquals(genericRecord.get("field"), 42);
+ Assert.assertEquals(genericRecord.get("unionField"), 55);
+ Assert.assertEquals(genericRecord.get("arrayField"), ImmutableList.of(100, -200));
+ Assert.assertEquals(genericRecord.get("mapField"), ImmutableMap.of(new Utf8("key1"), 300, new Utf8("key2"), -400));
+ Assert.assertEquals(genericRecord.get("unionArrayField"), ImmutableList.of(99, -199));
+ Assert.assertEquals(genericRecord.get("unionMapField"), ImmutableMap.of(new Utf8("key1"), 298, new Utf8("key2"), 355));
+ }
+
+ @Test
+ public void testLongRoundtrip() throws IOException {
+ LongRecord longRecord = new LongRecord();
+ longRecord.setField(42L);
+ longRecord.setUnionField(55L);
+ longRecord.setArrayField(ImmutableList.of(100L, -200L));
+ longRecord.setMapField(ImmutableMap.of("key1", 300L, "key2", -400L));
+ longRecord.setUnionArrayField(ImmutableList.of(99L, -199L));
+ longRecord.setUnionMapField(ImmutableMap.of("key1", 298L, "key2", 355L));
+ byte[] binary = toBinary(longRecord);
+
+ LongRecord roundtrip = toSpecificRecord(binary, LongRecord.SCHEMA$, LongRecord.SCHEMA$);
+ Assert.assertEquals(roundtrip.getField(), 42L);
+ Assert.assertEquals(roundtrip.getUnionField().longValue(), 55L);
+ Assert.assertEquals(roundtrip.getArrayField(), ImmutableList.of(100L, -200L));
+ Assert.assertEquals(roundtrip.getMapField(), ImmutableMap.of(new Utf8("key1"), 300L, new Utf8("key2"), -400L));
+ Assert.assertEquals(roundtrip.getUnionArrayField(), ImmutableList.of(99L, -199L));
+ Assert.assertEquals(roundtrip.getUnionMapField(), ImmutableMap.of(new Utf8("key1"), 298L, new Utf8("key2"), 355L));
+
+ GenericRecord genericRecord = toGenericRecord(binary, LongRecord.SCHEMA$, LongRecord.SCHEMA$);
+ Assert.assertEquals(genericRecord.get("field"), 42L);
+ Assert.assertEquals(genericRecord.get("unionField"), 55L);
+ Assert.assertEquals(genericRecord.get("arrayField"), ImmutableList.of(100L, -200L));
+ Assert.assertEquals(genericRecord.get("mapField"), ImmutableMap.of(new Utf8("key1"), 300L, new Utf8("key2"), -400L));
+ Assert.assertEquals(genericRecord.get("unionArrayField"), ImmutableList.of(99L, -199L));
+ Assert.assertEquals(genericRecord.get("unionMapField"), ImmutableMap.of(new Utf8("key1"), 298L, new Utf8("key2"), 355L));
+ }
+
+ @Test
+ public void testIntToLongPromotion() throws IOException {
+ IntRecord intRecord = new IntRecord();
+ intRecord.setField(42);
+ intRecord.setUnionField(55);
+ intRecord.setArrayField(ImmutableList.of(100, -200));
+ intRecord.setMapField(ImmutableMap.of("key1", 300, "key2", -400));
+ intRecord.setUnionArrayField(ImmutableList.of(99, -199));
+ intRecord.setUnionMapField(ImmutableMap.of("key1", 298, "key2", 355));
+ byte[] binary = toBinary(intRecord);
+
+ LongRecord longRecord = toSpecificRecord(binary, IntRecord.SCHEMA$, LongRecord.SCHEMA$);
+ Assert.assertEquals(longRecord.getField(), 42L);
+ Assert.assertEquals(longRecord.getUnionField().longValue(), 55L);
+ Assert.assertEquals(longRecord.getArrayField(), ImmutableList.of(100L, -200L));
+ Assert.assertEquals(longRecord.getMapField(), ImmutableMap.of(new Utf8("key1"), 300L, new Utf8("key2"), -400L));
+ Assert.assertEquals(longRecord.getUnionArrayField(), ImmutableList.of(99L, -199L));
+ Assert.assertEquals(longRecord.getUnionMapField(), ImmutableMap.of(new Utf8("key1"), 298L, new Utf8("key2"), 355L));
+
+ GenericRecord genericRecord = toGenericRecord(binary, IntRecord.SCHEMA$, LongRecord.SCHEMA$);
+ Assert.assertEquals(genericRecord.get("field"), 42L);
+ Assert.assertEquals(genericRecord.get("unionField"), 55L);
+ Assert.assertEquals(genericRecord.get("arrayField"), ImmutableList.of(100L, -200L));
+ Assert.assertEquals(genericRecord.get("mapField"), ImmutableMap.of(new Utf8("key1"), 300L, new Utf8("key2"), -400L));
+ Assert.assertEquals(genericRecord.get("unionArrayField"), ImmutableList.of(99L, -199L));
+ Assert.assertEquals(genericRecord.get("unionMapField"), ImmutableMap.of(new Utf8("key1"), 298L, new Utf8("key2"), 355L));
+ }
+
+ @Test
+ public void testLongToIntDemotion() throws IOException {
+ LongRecord longRecord = new LongRecord();
+ longRecord.setField(42L);
+ longRecord.setUnionField(55L);
+ longRecord.setArrayField(ImmutableList.of(100L, -200L));
+ longRecord.setMapField(ImmutableMap.of("key1", 300L, "key2", -400L));
+ longRecord.setUnionArrayField(ImmutableList.of(99L, -199L));
+ longRecord.setUnionMapField(ImmutableMap.of("key1", 298L, "key2", 355L));
+ byte[] binary = toBinary(longRecord);
+
+ IntRecord intRecord = toSpecificRecord(binary, LongRecord.SCHEMA$, IntRecord.SCHEMA$);
+ Assert.assertEquals(intRecord.getField(), 42);
+ Assert.assertEquals(intRecord.getUnionField().intValue(), 55);
+ Assert.assertEquals(intRecord.getArrayField(), ImmutableList.of(100, -200));
+ Assert.assertEquals(intRecord.getMapField(), ImmutableMap.of(new Utf8("key1"), 300, new Utf8("key2"), -400));
+ Assert.assertEquals(intRecord.getUnionArrayField(), ImmutableList.of(99, -199));
+ Assert.assertEquals(intRecord.getUnionMapField(), ImmutableMap.of(new Utf8("key1"), 298, new Utf8("key2"), 355));
+
+ GenericRecord genericRecord = toGenericRecord(binary, LongRecord.SCHEMA$, IntRecord.SCHEMA$);
+ Assert.assertEquals(genericRecord.get("field"), 42);
+ Assert.assertEquals(genericRecord.get("unionField"), 55);
+ Assert.assertEquals(genericRecord.get("arrayField"), ImmutableList.of(100, -200));
+ Assert.assertEquals(genericRecord.get("mapField"), ImmutableMap.of(new Utf8("key1"), 300, new Utf8("key2"), -400));
+ Assert.assertEquals(genericRecord.get("unionArrayField"), ImmutableList.of(99, -199));
+ Assert.assertEquals(genericRecord.get("unionMapField"), ImmutableMap.of(new Utf8("key1"), 298, new Utf8("key2"), 355));
+ }
+
+ @Test
+ public void testLongToIntDemotionOutOfRange() throws IOException {
+ LongRecord longRecord = LongRecord.newBuilder().setField((long) Integer.MAX_VALUE + 1L).build();
+ byte[] binary = toBinary(longRecord);
+
+ LongRecord longRecord2 = LongRecord.newBuilder().setField(0L).setUnionField((long) Integer.MIN_VALUE - 1L).build();
+ byte[] binary2 = toBinary(longRecord2);
+
+ LongRecord longRecord3 = LongRecord.newBuilder().setField(0L).setArrayField(ImmutableList.of((long) Integer.MAX_VALUE + 1L)).build();
+ byte[] binary3 = toBinary(longRecord3);
+
+ LongRecord longRecord4 = LongRecord.newBuilder().setField(0L).setMapField(ImmutableMap.of("haha", (long) Integer.MIN_VALUE - 1L)).build();
+ byte[] binary4 = toBinary(longRecord4);
+
+ LongRecord longRecord5 = LongRecord.newBuilder().setField(0L).setUnionArrayField(ImmutableList.of((long) Integer.MAX_VALUE + 1L)).build();
+ byte[] binary5 = toBinary(longRecord5);
+
+ LongRecord longRecord6 = LongRecord.newBuilder().setField(0L).setUnionMapField(ImmutableMap.of("haha", (long) Integer.MIN_VALUE - 1L)).build();
+ byte[] binary6 = toBinary(longRecord6);
+
+ Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+ Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+
+ Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary2, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+ Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary2, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+
+ Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary3, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+ Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary3, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+
+ Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary4, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+ Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary4, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+
+ Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary5, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+ Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary5, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+
+ Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary6, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+ Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary6, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+ }
+
+ private byte[] toBinary(IndexedRecord record) throws IOException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ BinaryEncoder encoder = AvroCompatibilityHelper.newBinaryEncoder(baos);
+ GenericDatumWriter writer = new GenericDatumWriter<>(record.getSchema());
+ writer.write(record, encoder);
+ encoder.flush();
+ return baos.toByteArray();
+ }
+
+ private T toSpecificRecord(byte[] binary,
+ Schema writerSchema,
+ Schema readerSchema) throws IOException {
+ BinaryDecoder decoder = AvroCompatibilityHelper.newBinaryDecoder(binary);
+ DatumReader reader = AvroCompatibilityHelper.newSpecificDatumReader(writerSchema, readerSchema, SpecificData.get());
+ return reader.read(null, decoder);
+ }
+
+ private GenericRecord toGenericRecord(byte[] binary,
+ Schema writerSchema,
+ Schema readerSchema) throws IOException {
+ BinaryDecoder decoder = AvroCompatibilityHelper.newBinaryDecoder(binary);
+ DatumReader reader = AvroCompatibilityHelper.newGenericDatumReader(writerSchema, readerSchema, GenericData.get());
+ return reader.read(null, decoder);
+ }
}
\ No newline at end of file
diff --git a/helper/tests/helper-tests-14/src/test/java/com/linkedin/avroutil1/compatibility/avro14/AvroCompatibilityHelperAvro14Test.java b/helper/tests/helper-tests-14/src/test/java/com/linkedin/avroutil1/compatibility/avro14/AvroCompatibilityHelperAvro14Test.java
index c2a5e7134..41a6ffe2e 100644
--- a/helper/tests/helper-tests-14/src/test/java/com/linkedin/avroutil1/compatibility/avro14/AvroCompatibilityHelperAvro14Test.java
+++ b/helper/tests/helper-tests-14/src/test/java/com/linkedin/avroutil1/compatibility/avro14/AvroCompatibilityHelperAvro14Test.java
@@ -8,6 +8,8 @@
import by14.IntRecord;
import by14.LongRecord;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import com.linkedin.avroutil1.Pojo;
import com.linkedin.avroutil1.compatibility.AvroCompatibilityHelper;
import com.linkedin.avroutil1.compatibility.AvroVersion;
@@ -15,12 +17,14 @@
import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.apache.avro.AvroTypeException;
import org.apache.avro.Schema;
+import org.apache.avro.generic.GenericData;
import org.apache.avro.generic.GenericDatumWriter;
import org.apache.avro.generic.GenericRecord;
import org.apache.avro.generic.IndexedRecord;
@@ -28,6 +32,7 @@
import org.apache.avro.io.BinaryEncoder;
import org.apache.avro.io.DatumReader;
import org.apache.avro.specific.SpecificRecord;
+import org.apache.avro.util.Utf8;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.type.TypeReference;
@@ -98,15 +103,27 @@ public void testIntRoundtrip() throws IOException {
IntRecord intRecord = new IntRecord();
intRecord.field = 42;
intRecord.unionField = 55;
+ intRecord.arrayField = ImmutableList.of(100, -200);
+ intRecord.mapField = ImmutableMap.of("key1", 300, "key2", -400);
+ intRecord.unionArrayField = ImmutableList.of(99, -199);
+ intRecord.unionMapField = ImmutableMap.of("key1", 298, "key2", 355);
byte[] binary = toBinary(intRecord);
IntRecord roundtrip = toSpecificRecord(binary, IntRecord.SCHEMA$, IntRecord.SCHEMA$);
Assert.assertEquals(roundtrip.field, 42);
Assert.assertEquals(roundtrip.unionField.intValue(), 55);
+ Assert.assertEquals(roundtrip.arrayField, ImmutableList.of(100, -200));
+ Assert.assertEquals(roundtrip.mapField, ImmutableMap.of(new Utf8("key1"), 300, new Utf8("key2"), -400));
+ Assert.assertEquals(roundtrip.unionArrayField, ImmutableList.of(99, -199));
+ Assert.assertEquals(roundtrip.unionMapField, ImmutableMap.of(new Utf8("key1"), 298, new Utf8("key2"), 355));
GenericRecord genericRecord = toGenericRecord(binary, IntRecord.SCHEMA$, IntRecord.SCHEMA$);
Assert.assertEquals(genericRecord.get("field"), 42);
Assert.assertEquals(genericRecord.get("unionField"), 55);
+ Assert.assertEquals(new ArrayList<>((GenericData.Array) genericRecord.get("arrayField")), ImmutableList.of(100, -200));
+ Assert.assertEquals(genericRecord.get("mapField"), ImmutableMap.of(new Utf8("key1"), 300, new Utf8("key2"), -400));
+ Assert.assertEquals(new ArrayList<>((GenericData.Array) genericRecord.get("unionArrayField")), ImmutableList.of(99, -199));
+ Assert.assertEquals(genericRecord.get("unionMapField"), ImmutableMap.of(new Utf8("key1"), 298, new Utf8("key2"), 355));
}
@Test
@@ -114,15 +131,27 @@ public void testLongRoundtrip() throws IOException {
LongRecord longRecord = new LongRecord();
longRecord.field = 42L;
longRecord.unionField = 55L;
+ longRecord.arrayField = ImmutableList.of(100L, -200L);
+ longRecord.mapField = ImmutableMap.of("key1", 300L, "key2", -400L);
+ longRecord.unionArrayField = ImmutableList.of(99L, -199L);
+ longRecord.unionMapField = ImmutableMap.of("key1", 298L, "key2", 355L);
byte[] binary = toBinary(longRecord);
LongRecord roundtrip = toSpecificRecord(binary, LongRecord.SCHEMA$, LongRecord.SCHEMA$);
Assert.assertEquals(roundtrip.field, 42L);
Assert.assertEquals(roundtrip.unionField.longValue(), 55L);
+ Assert.assertEquals(roundtrip.arrayField, ImmutableList.of(100L, -200L));
+ Assert.assertEquals(roundtrip.mapField, ImmutableMap.of(new Utf8("key1"), 300L, new Utf8("key2"), -400L));
+ Assert.assertEquals(roundtrip.unionArrayField, ImmutableList.of(99L, -199L));
+ Assert.assertEquals(roundtrip.unionMapField, ImmutableMap.of(new Utf8("key1"), 298L, new Utf8("key2"), 355L));
GenericRecord genericRecord = toGenericRecord(binary, LongRecord.SCHEMA$, LongRecord.SCHEMA$);
Assert.assertEquals(genericRecord.get("field"), 42L);
Assert.assertEquals(genericRecord.get("unionField"), 55L);
+ Assert.assertEquals(new ArrayList<>((GenericData.Array) genericRecord.get("arrayField")), ImmutableList.of(100L, -200L));
+ Assert.assertEquals(genericRecord.get("mapField"), ImmutableMap.of(new Utf8("key1"), 300L, new Utf8("key2"), -400L));
+ Assert.assertEquals(new ArrayList<>((GenericData.Array) genericRecord.get("unionArrayField")), ImmutableList.of(99L, -199L));
+ Assert.assertEquals(genericRecord.get("unionMapField"), ImmutableMap.of(new Utf8("key1"), 298L, new Utf8("key2"), 355L));
}
@Test
@@ -130,15 +159,27 @@ public void testIntToLongPromotion() throws IOException {
IntRecord intRecord = new IntRecord();
intRecord.field = 42;
intRecord.unionField = 55;
+ intRecord.arrayField = ImmutableList.of(100, -200);
+ intRecord.mapField = ImmutableMap.of("key1", 300, "key2", -400);
+ intRecord.unionArrayField = ImmutableList.of(99, -199);
+ intRecord.unionMapField = ImmutableMap.of("key1", 298, "key2", 355);
byte[] binary = toBinary(intRecord);
LongRecord longRecord = toSpecificRecord(binary, IntRecord.SCHEMA$, LongRecord.SCHEMA$);
Assert.assertEquals(longRecord.field, 42L);
Assert.assertEquals(longRecord.unionField.longValue(), 55L);
+ Assert.assertEquals(longRecord.arrayField, ImmutableList.of(100L, -200L));
+ Assert.assertEquals(longRecord.mapField, ImmutableMap.of(new Utf8("key1"), 300L, new Utf8("key2"), -400L));
+ Assert.assertEquals(longRecord.unionArrayField, ImmutableList.of(99L, -199L));
+ Assert.assertEquals(longRecord.unionMapField, ImmutableMap.of(new Utf8("key1"), 298L, new Utf8("key2"), 355L));
GenericRecord genericRecord = toGenericRecord(binary, IntRecord.SCHEMA$, LongRecord.SCHEMA$);
Assert.assertEquals(genericRecord.get("field"), 42L);
Assert.assertEquals(genericRecord.get("unionField"), 55L);
+ Assert.assertEquals(new ArrayList<>((GenericData.Array) genericRecord.get("arrayField")), ImmutableList.of(100L, -200L));
+ Assert.assertEquals(genericRecord.get("mapField"), ImmutableMap.of(new Utf8("key1"), 300L, new Utf8("key2"), -400L));
+ Assert.assertEquals(new ArrayList<>((GenericData.Array) genericRecord.get("unionArrayField")), ImmutableList.of(99L, -199L));
+ Assert.assertEquals(genericRecord.get("unionMapField"), ImmutableMap.of(new Utf8("key1"), 298L, new Utf8("key2"), 355L));
}
@Test
@@ -146,32 +187,83 @@ public void testLongToIntDemotion() throws IOException {
LongRecord longRecord = new LongRecord();
longRecord.field = 42L;
longRecord.unionField = 55L;
+ longRecord.arrayField = ImmutableList.of(100L, -200L);
+ longRecord.mapField = ImmutableMap.of("key1", 300L, "key2", -400L);
+ longRecord.unionArrayField = ImmutableList.of(99L, -199L);
+ longRecord.unionMapField = ImmutableMap.of("key1", 298L, "key2", 355L);
byte[] binary = toBinary(longRecord);
IntRecord intRecord = toSpecificRecord(binary, LongRecord.SCHEMA$, IntRecord.SCHEMA$);
Assert.assertEquals(intRecord.field, 42);
Assert.assertEquals(intRecord.unionField.intValue(), 55);
+ Assert.assertEquals(intRecord.arrayField, ImmutableList.of(100, -200));
+ Assert.assertEquals(intRecord.mapField, ImmutableMap.of(new Utf8("key1"), 300, new Utf8("key2"), -400));
+ Assert.assertEquals(intRecord.unionArrayField, ImmutableList.of(99, -199));
+ Assert.assertEquals(intRecord.unionMapField, ImmutableMap.of(new Utf8("key1"), 298, new Utf8("key2"), 355));
GenericRecord genericRecord = toGenericRecord(binary, LongRecord.SCHEMA$, IntRecord.SCHEMA$);
Assert.assertEquals(genericRecord.get("field"), 42);
Assert.assertEquals(genericRecord.get("unionField"), 55);
+ Assert.assertEquals(new ArrayList<>((GenericData.Array) genericRecord.get("arrayField")), ImmutableList.of(100, -200));
+ Assert.assertEquals(genericRecord.get("mapField"), ImmutableMap.of(new Utf8("key1"), 300, new Utf8("key2"), -400));
+ Assert.assertEquals(new ArrayList<>((GenericData.Array) genericRecord.get("unionArrayField")), ImmutableList.of(99, -199));
+ Assert.assertEquals(genericRecord.get("unionMapField"), ImmutableMap.of(new Utf8("key1"), 298, new Utf8("key2"), 355));
}
@Test
public void testLongToIntDemotionOutOfRange() throws IOException {
- LongRecord longRecord = new LongRecord();
+ LongRecord longRecord = newLongRecord();
longRecord.field = (long) Integer.MAX_VALUE + 1L;
byte[] binary = toBinary(longRecord);
- LongRecord longRecord2 = new LongRecord();
+ LongRecord longRecord2 = newLongRecord();
longRecord2.unionField = (long) Integer.MIN_VALUE - 1L;
byte[] binary2 = toBinary(longRecord2);
+ LongRecord longRecord3 = newLongRecord();
+ longRecord3.arrayField = ImmutableList.of((long) Integer.MAX_VALUE + 1L);
+ byte[] binary3 = toBinary(longRecord3);
+
+ LongRecord longRecord4 = newLongRecord();
+ longRecord4.mapField = ImmutableMap.of("haha", (long) Integer.MIN_VALUE - 1L);
+ byte[] binary4 = toBinary(longRecord4);
+
+ LongRecord longRecord5 = newLongRecord();
+ longRecord5.unionArrayField = ImmutableList.of((long) Integer.MAX_VALUE + 1L);
+ byte[] binary5 = toBinary(longRecord5);
+
+ LongRecord longRecord6 = newLongRecord();
+ longRecord6.unionMapField = ImmutableMap.of("haha", (long) Integer.MIN_VALUE - 1L);
+ byte[] binary6 = toBinary(longRecord6);
+
Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary2, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary2, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+
+ Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary3, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+ Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary3, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+
+ Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary4, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+ Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary4, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+
+ Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary5, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+ Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary5, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+
+ Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary6, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+ Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary6, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+ }
+
+ private LongRecord newLongRecord() {
+ LongRecord longRecord = new LongRecord();
+ longRecord.field = 0L;
+ longRecord.unionField = 0L;
+ longRecord.arrayField = ImmutableList.of();
+ longRecord.mapField = ImmutableMap.of();
+ longRecord.unionArrayField = ImmutableList.of();
+ longRecord.unionMapField = ImmutableMap.of();
+ return longRecord;
}
private byte[] toBinary(IndexedRecord record) throws IOException {
diff --git a/helper/tests/helper-tests-15/src/test/java/com/linkedin/avroutil1/compatibility/avro15/AvroCompatibilityHelperAvro15Test.java b/helper/tests/helper-tests-15/src/test/java/com/linkedin/avroutil1/compatibility/avro15/AvroCompatibilityHelperAvro15Test.java
index f7e9e1e39..be3f0b395 100644
--- a/helper/tests/helper-tests-15/src/test/java/com/linkedin/avroutil1/compatibility/avro15/AvroCompatibilityHelperAvro15Test.java
+++ b/helper/tests/helper-tests-15/src/test/java/com/linkedin/avroutil1/compatibility/avro15/AvroCompatibilityHelperAvro15Test.java
@@ -8,6 +8,8 @@
import by15.IntRecord;
import by15.LongRecord;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import org.apache.avro.AvroTypeException;
import org.apache.avro.generic.GenericData;
import org.apache.avro.generic.GenericDatumWriter;
@@ -25,10 +27,12 @@
import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.apache.avro.Schema;
+import org.apache.avro.util.Utf8;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.type.TypeReference;
@@ -100,15 +104,27 @@ public void testIntRoundtrip() throws IOException {
IntRecord intRecord = new IntRecord();
intRecord.field = 42;
intRecord.unionField = 55;
+ intRecord.arrayField = ImmutableList.of(100, -200);
+ intRecord.mapField = ImmutableMap.of("key1", 300, "key2", -400);
+ intRecord.unionArrayField = ImmutableList.of(99, -199);
+ intRecord.unionMapField = ImmutableMap.of("key1", 298, "key2", 355);
byte[] binary = toBinary(intRecord);
IntRecord roundtrip = toSpecificRecord(binary, IntRecord.SCHEMA$, IntRecord.SCHEMA$);
Assert.assertEquals(roundtrip.field, 42);
Assert.assertEquals(roundtrip.unionField.intValue(), 55);
+ Assert.assertEquals(roundtrip.arrayField, ImmutableList.of(100, -200));
+ Assert.assertEquals(roundtrip.mapField, ImmutableMap.of(new Utf8("key1"), 300, new Utf8("key2"), -400));
+ Assert.assertEquals(roundtrip.unionArrayField, ImmutableList.of(99, -199));
+ Assert.assertEquals(roundtrip.unionMapField, ImmutableMap.of(new Utf8("key1"), 298, new Utf8("key2"), 355));
GenericRecord genericRecord = toGenericRecord(binary, IntRecord.SCHEMA$, IntRecord.SCHEMA$);
Assert.assertEquals(genericRecord.get("field"), 42);
Assert.assertEquals(genericRecord.get("unionField"), 55);
+ Assert.assertEquals(new ArrayList<>((GenericData.Array) genericRecord.get("arrayField")), ImmutableList.of(100, -200));
+ Assert.assertEquals(genericRecord.get("mapField"), ImmutableMap.of(new Utf8("key1"), 300, new Utf8("key2"), -400));
+ Assert.assertEquals(new ArrayList<>((GenericData.Array) genericRecord.get("unionArrayField")), ImmutableList.of(99, -199));
+ Assert.assertEquals(genericRecord.get("unionMapField"), ImmutableMap.of(new Utf8("key1"), 298, new Utf8("key2"), 355));
}
@Test
@@ -116,15 +132,27 @@ public void testLongRoundtrip() throws IOException {
LongRecord longRecord = new LongRecord();
longRecord.field = 42L;
longRecord.unionField = 55L;
+ longRecord.arrayField = ImmutableList.of(100L, -200L);
+ longRecord.mapField = ImmutableMap.of("key1", 300L, "key2", -400L);
+ longRecord.unionArrayField = ImmutableList.of(99L, -199L);
+ longRecord.unionMapField = ImmutableMap.of("key1", 298L, "key2", 355L);
byte[] binary = toBinary(longRecord);
LongRecord roundtrip = toSpecificRecord(binary, LongRecord.SCHEMA$, LongRecord.SCHEMA$);
Assert.assertEquals(roundtrip.field, 42L);
Assert.assertEquals(roundtrip.unionField.longValue(), 55L);
+ Assert.assertEquals(roundtrip.arrayField, ImmutableList.of(100L, -200L));
+ Assert.assertEquals(roundtrip.mapField, ImmutableMap.of(new Utf8("key1"), 300L, new Utf8("key2"), -400L));
+ Assert.assertEquals(roundtrip.unionArrayField, ImmutableList.of(99L, -199L));
+ Assert.assertEquals(roundtrip.unionMapField, ImmutableMap.of(new Utf8("key1"), 298L, new Utf8("key2"), 355L));
GenericRecord genericRecord = toGenericRecord(binary, LongRecord.SCHEMA$, LongRecord.SCHEMA$);
Assert.assertEquals(genericRecord.get("field"), 42L);
Assert.assertEquals(genericRecord.get("unionField"), 55L);
+ Assert.assertEquals(new ArrayList<>((GenericData.Array) genericRecord.get("arrayField")), ImmutableList.of(100L, -200L));
+ Assert.assertEquals(genericRecord.get("mapField"), ImmutableMap.of(new Utf8("key1"), 300L, new Utf8("key2"), -400L));
+ Assert.assertEquals(new ArrayList<>((GenericData.Array) genericRecord.get("unionArrayField")), ImmutableList.of(99L, -199L));
+ Assert.assertEquals(genericRecord.get("unionMapField"), ImmutableMap.of(new Utf8("key1"), 298L, new Utf8("key2"), 355L));
}
@Test
@@ -132,15 +160,27 @@ public void testIntToLongPromotion() throws IOException {
IntRecord intRecord = new IntRecord();
intRecord.field = 42;
intRecord.unionField = 55;
+ intRecord.arrayField = ImmutableList.of(100, -200);
+ intRecord.mapField = ImmutableMap.of("key1", 300, "key2", -400);
+ intRecord.unionArrayField = ImmutableList.of(99, -199);
+ intRecord.unionMapField = ImmutableMap.of("key1", 298, "key2", 355);
byte[] binary = toBinary(intRecord);
LongRecord longRecord = toSpecificRecord(binary, IntRecord.SCHEMA$, LongRecord.SCHEMA$);
Assert.assertEquals(longRecord.field, 42L);
Assert.assertEquals(longRecord.unionField.longValue(), 55L);
+ Assert.assertEquals(longRecord.arrayField, ImmutableList.of(100L, -200L));
+ Assert.assertEquals(longRecord.mapField, ImmutableMap.of(new Utf8("key1"), 300L, new Utf8("key2"), -400L));
+ Assert.assertEquals(longRecord.unionArrayField, ImmutableList.of(99L, -199L));
+ Assert.assertEquals(longRecord.unionMapField, ImmutableMap.of(new Utf8("key1"), 298L, new Utf8("key2"), 355L));
GenericRecord genericRecord = toGenericRecord(binary, IntRecord.SCHEMA$, LongRecord.SCHEMA$);
Assert.assertEquals(genericRecord.get("field"), 42L);
Assert.assertEquals(genericRecord.get("unionField"), 55L);
+ Assert.assertEquals(new ArrayList<>((GenericData.Array) genericRecord.get("arrayField")), ImmutableList.of(100L, -200L));
+ Assert.assertEquals(genericRecord.get("mapField"), ImmutableMap.of(new Utf8("key1"), 300L, new Utf8("key2"), -400L));
+ Assert.assertEquals(new ArrayList<>((GenericData.Array) genericRecord.get("unionArrayField")), ImmutableList.of(99L, -199L));
+ Assert.assertEquals(genericRecord.get("unionMapField"), ImmutableMap.of(new Utf8("key1"), 298L, new Utf8("key2"), 355L));
}
@Test
@@ -148,32 +188,83 @@ public void testLongToIntDemotion() throws IOException {
LongRecord longRecord = new LongRecord();
longRecord.field = 42L;
longRecord.unionField = 55L;
+ longRecord.arrayField = ImmutableList.of(100L, -200L);
+ longRecord.mapField = ImmutableMap.of("key1", 300L, "key2", -400L);
+ longRecord.unionArrayField = ImmutableList.of(99L, -199L);
+ longRecord.unionMapField = ImmutableMap.of("key1", 298L, "key2", 355L);
byte[] binary = toBinary(longRecord);
IntRecord intRecord = toSpecificRecord(binary, LongRecord.SCHEMA$, IntRecord.SCHEMA$);
Assert.assertEquals(intRecord.field, 42);
Assert.assertEquals(intRecord.unionField.intValue(), 55);
+ Assert.assertEquals(intRecord.arrayField, ImmutableList.of(100, -200));
+ Assert.assertEquals(intRecord.mapField, ImmutableMap.of(new Utf8("key1"), 300, new Utf8("key2"), -400));
+ Assert.assertEquals(intRecord.unionArrayField, ImmutableList.of(99, -199));
+ Assert.assertEquals(intRecord.unionMapField, ImmutableMap.of(new Utf8("key1"), 298, new Utf8("key2"), 355));
GenericRecord genericRecord = toGenericRecord(binary, LongRecord.SCHEMA$, IntRecord.SCHEMA$);
Assert.assertEquals(genericRecord.get("field"), 42);
Assert.assertEquals(genericRecord.get("unionField"), 55);
+ Assert.assertEquals(new ArrayList<>((GenericData.Array) genericRecord.get("arrayField")), ImmutableList.of(100, -200));
+ Assert.assertEquals(genericRecord.get("mapField"), ImmutableMap.of(new Utf8("key1"), 300, new Utf8("key2"), -400));
+ Assert.assertEquals(new ArrayList<>((GenericData.Array) genericRecord.get("unionArrayField")), ImmutableList.of(99, -199));
+ Assert.assertEquals(genericRecord.get("unionMapField"), ImmutableMap.of(new Utf8("key1"), 298, new Utf8("key2"), 355));
}
@Test
public void testLongToIntDemotionOutOfRange() throws IOException {
- LongRecord longRecord = new LongRecord();
+ LongRecord longRecord = newLongRecord();
longRecord.field = (long) Integer.MAX_VALUE + 1L;
byte[] binary = toBinary(longRecord);
- LongRecord longRecord2 = new LongRecord();
+ LongRecord longRecord2 = newLongRecord();
longRecord2.unionField = (long) Integer.MIN_VALUE - 1L;
byte[] binary2 = toBinary(longRecord2);
+ LongRecord longRecord3 = newLongRecord();
+ longRecord3.arrayField = ImmutableList.of((long) Integer.MAX_VALUE + 1L);
+ byte[] binary3 = toBinary(longRecord3);
+
+ LongRecord longRecord4 = newLongRecord();
+ longRecord4.mapField = ImmutableMap.of("haha", (long) Integer.MIN_VALUE - 1L);
+ byte[] binary4 = toBinary(longRecord4);
+
+ LongRecord longRecord5 = newLongRecord();
+ longRecord5.unionArrayField = ImmutableList.of((long) Integer.MAX_VALUE + 1L);
+ byte[] binary5 = toBinary(longRecord5);
+
+ LongRecord longRecord6 = newLongRecord();
+ longRecord6.unionMapField = ImmutableMap.of("haha", (long) Integer.MIN_VALUE - 1L);
+ byte[] binary6 = toBinary(longRecord6);
+
Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary2, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary2, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+
+ Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary3, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+ Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary3, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+
+ Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary4, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+ Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary4, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+
+ Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary5, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+ Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary5, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+
+ Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary6, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+ Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary6, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+ }
+
+ private LongRecord newLongRecord() {
+ LongRecord longRecord = new LongRecord();
+ longRecord.field = 0L;
+ longRecord.unionField = 0L;
+ longRecord.arrayField = ImmutableList.of();
+ longRecord.mapField = ImmutableMap.of();
+ longRecord.unionArrayField = ImmutableList.of();
+ longRecord.unionMapField = ImmutableMap.of();
+ return longRecord;
}
private byte[] toBinary(IndexedRecord record) throws IOException {
diff --git a/helper/tests/helper-tests-16/src/test/java/com/linkedin/avroutil1/compatibility/avro16/AvroCompatibilityHelperAvro16Test.java b/helper/tests/helper-tests-16/src/test/java/com/linkedin/avroutil1/compatibility/avro16/AvroCompatibilityHelperAvro16Test.java
index be0f49ae9..0925c70a8 100644
--- a/helper/tests/helper-tests-16/src/test/java/com/linkedin/avroutil1/compatibility/avro16/AvroCompatibilityHelperAvro16Test.java
+++ b/helper/tests/helper-tests-16/src/test/java/com/linkedin/avroutil1/compatibility/avro16/AvroCompatibilityHelperAvro16Test.java
@@ -8,6 +8,8 @@
import by16.IntRecord;
import by16.LongRecord;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import com.linkedin.avroutil1.Pojo;
import com.linkedin.avroutil1.testcommon.TestUtil;
import com.linkedin.avroutil1.compatibility.AvroCompatibilityHelper;
@@ -30,6 +32,7 @@
import org.apache.avro.io.DatumReader;
import org.apache.avro.specific.SpecificData;
import org.apache.avro.specific.SpecificRecord;
+import org.apache.avro.util.Utf8;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.type.TypeReference;
@@ -99,84 +102,154 @@ public void testCreateSchemaFieldWithProvidedDefaultValue() throws IOException {
@Test
public void testIntRoundtrip() throws IOException {
IntRecord intRecord = new IntRecord();
- intRecord.field = 42;
- intRecord.unionField = 55;
+ intRecord.setField(42);
+ intRecord.setUnionField(55);
+ intRecord.setArrayField(ImmutableList.of(100, -200));
+ intRecord.setMapField(ImmutableMap.of("key1", 300, "key2", -400));
+ intRecord.setUnionArrayField(ImmutableList.of(99, -199));
+ intRecord.setUnionMapField(ImmutableMap.of("key1", 298, "key2", 355));
byte[] binary = toBinary(intRecord);
IntRecord roundtrip = toSpecificRecord(binary, IntRecord.SCHEMA$, IntRecord.SCHEMA$);
- Assert.assertEquals(roundtrip.field, 42);
- Assert.assertEquals(roundtrip.unionField.intValue(), 55);
+ Assert.assertEquals((int) roundtrip.getField(), 42);
+ Assert.assertEquals(roundtrip.getUnionField().intValue(), 55);
+ Assert.assertEquals(roundtrip.getArrayField(), ImmutableList.of(100, -200));
+ Assert.assertEquals(roundtrip.getMapField(), ImmutableMap.of(new Utf8("key1"), 300, new Utf8("key2"), -400));
+ Assert.assertEquals(roundtrip.getUnionArrayField(), ImmutableList.of(99, -199));
+ Assert.assertEquals(roundtrip.getUnionMapField(), ImmutableMap.of(new Utf8("key1"), 298, new Utf8("key2"), 355));
GenericRecord genericRecord = toGenericRecord(binary, IntRecord.SCHEMA$, IntRecord.SCHEMA$);
Assert.assertEquals(genericRecord.get("field"), 42);
Assert.assertEquals(genericRecord.get("unionField"), 55);
+ Assert.assertEquals(genericRecord.get("arrayField"), ImmutableList.of(100, -200));
+ Assert.assertEquals(genericRecord.get("mapField"), ImmutableMap.of(new Utf8("key1"), 300, new Utf8("key2"), -400));
+ Assert.assertEquals(genericRecord.get("unionArrayField"), ImmutableList.of(99, -199));
+ Assert.assertEquals(genericRecord.get("unionMapField"), ImmutableMap.of(new Utf8("key1"), 298, new Utf8("key2"), 355));
}
@Test
public void testLongRoundtrip() throws IOException {
LongRecord longRecord = new LongRecord();
- longRecord.field = 42L;
- longRecord.unionField = 55L;
+ longRecord.setField(42L);
+ longRecord.setUnionField(55L);
+ longRecord.setArrayField(ImmutableList.of(100L, -200L));
+ longRecord.setMapField(ImmutableMap.of("key1", 300L, "key2", -400L));
+ longRecord.setUnionArrayField(ImmutableList.of(99L, -199L));
+ longRecord.setUnionMapField(ImmutableMap.of("key1", 298L, "key2", 355L));
byte[] binary = toBinary(longRecord);
LongRecord roundtrip = toSpecificRecord(binary, LongRecord.SCHEMA$, LongRecord.SCHEMA$);
- Assert.assertEquals(roundtrip.field, 42L);
- Assert.assertEquals(roundtrip.unionField.longValue(), 55L);
+ Assert.assertEquals((long) roundtrip.getField(), 42L);
+ Assert.assertEquals(roundtrip.getUnionField().longValue(), 55L);
+ Assert.assertEquals(roundtrip.getArrayField(), ImmutableList.of(100L, -200L));
+ Assert.assertEquals(roundtrip.getMapField(), ImmutableMap.of(new Utf8("key1"), 300L, new Utf8("key2"), -400L));
+ Assert.assertEquals(roundtrip.getUnionArrayField(), ImmutableList.of(99L, -199L));
+ Assert.assertEquals(roundtrip.getUnionMapField(), ImmutableMap.of(new Utf8("key1"), 298L, new Utf8("key2"), 355L));
GenericRecord genericRecord = toGenericRecord(binary, LongRecord.SCHEMA$, LongRecord.SCHEMA$);
Assert.assertEquals(genericRecord.get("field"), 42L);
Assert.assertEquals(genericRecord.get("unionField"), 55L);
+ Assert.assertEquals(genericRecord.get("arrayField"), ImmutableList.of(100L, -200L));
+ Assert.assertEquals(genericRecord.get("mapField"), ImmutableMap.of(new Utf8("key1"), 300L, new Utf8("key2"), -400L));
+ Assert.assertEquals(genericRecord.get("unionArrayField"), ImmutableList.of(99L, -199L));
+ Assert.assertEquals(genericRecord.get("unionMapField"), ImmutableMap.of(new Utf8("key1"), 298L, new Utf8("key2"), 355L));
}
@Test
public void testIntToLongPromotion() throws IOException {
IntRecord intRecord = new IntRecord();
- intRecord.field = 42;
- intRecord.unionField = 55;
+ intRecord.setField(42);
+ intRecord.setUnionField(55);
+ intRecord.setArrayField(ImmutableList.of(100, -200));
+ intRecord.setMapField(ImmutableMap.of("key1", 300, "key2", -400));
+ intRecord.setUnionArrayField(ImmutableList.of(99, -199));
+ intRecord.setUnionMapField(ImmutableMap.of("key1", 298, "key2", 355));
byte[] binary = toBinary(intRecord);
LongRecord longRecord = toSpecificRecord(binary, IntRecord.SCHEMA$, LongRecord.SCHEMA$);
- Assert.assertEquals(longRecord.field, 42L);
- Assert.assertEquals(longRecord.unionField.longValue(), 55L);
+ Assert.assertEquals((long) longRecord.getField(), 42L);
+ Assert.assertEquals(longRecord.getUnionField().longValue(), 55L);
+ Assert.assertEquals(longRecord.getArrayField(), ImmutableList.of(100L, -200L));
+ Assert.assertEquals(longRecord.getMapField(), ImmutableMap.of(new Utf8("key1"), 300L, new Utf8("key2"), -400L));
+ Assert.assertEquals(longRecord.getUnionArrayField(), ImmutableList.of(99L, -199L));
+ Assert.assertEquals(longRecord.getUnionMapField(), ImmutableMap.of(new Utf8("key1"), 298L, new Utf8("key2"), 355L));
GenericRecord genericRecord = toGenericRecord(binary, IntRecord.SCHEMA$, LongRecord.SCHEMA$);
Assert.assertEquals(genericRecord.get("field"), 42L);
Assert.assertEquals(genericRecord.get("unionField"), 55L);
+ Assert.assertEquals(genericRecord.get("arrayField"), ImmutableList.of(100L, -200L));
+ Assert.assertEquals(genericRecord.get("mapField"), ImmutableMap.of(new Utf8("key1"), 300L, new Utf8("key2"), -400L));
+ Assert.assertEquals(genericRecord.get("unionArrayField"), ImmutableList.of(99L, -199L));
+ Assert.assertEquals(genericRecord.get("unionMapField"), ImmutableMap.of(new Utf8("key1"), 298L, new Utf8("key2"), 355L));
}
@Test
public void testLongToIntDemotion() throws IOException {
LongRecord longRecord = new LongRecord();
- longRecord.field = 42L;
- longRecord.unionField = 55L;
+ longRecord.setField(42L);
+ longRecord.setUnionField(55L);
+ longRecord.setArrayField(ImmutableList.of(100L, -200L));
+ longRecord.setMapField(ImmutableMap.of("key1", 300L, "key2", -400L));
+ longRecord.setUnionArrayField(ImmutableList.of(99L, -199L));
+ longRecord.setUnionMapField(ImmutableMap.of("key1", 298L, "key2", 355L));
byte[] binary = toBinary(longRecord);
IntRecord intRecord = toSpecificRecord(binary, LongRecord.SCHEMA$, IntRecord.SCHEMA$);
- Assert.assertEquals(intRecord.field, 42);
- Assert.assertEquals(intRecord.unionField.intValue(), 55);
+ Assert.assertEquals((int) intRecord.getField(), 42);
+ Assert.assertEquals(intRecord.getUnionField().intValue(), 55);
+ Assert.assertEquals(intRecord.getArrayField(), ImmutableList.of(100, -200));
+ Assert.assertEquals(intRecord.getMapField(), ImmutableMap.of(new Utf8("key1"), 300, new Utf8("key2"), -400));
+ Assert.assertEquals(intRecord.getUnionArrayField(), ImmutableList.of(99, -199));
+ Assert.assertEquals(intRecord.getUnionMapField(), ImmutableMap.of(new Utf8("key1"), 298, new Utf8("key2"), 355));
GenericRecord genericRecord = toGenericRecord(binary, LongRecord.SCHEMA$, IntRecord.SCHEMA$);
Assert.assertEquals(genericRecord.get("field"), 42);
Assert.assertEquals(genericRecord.get("unionField"), 55);
+ Assert.assertEquals(genericRecord.get("arrayField"), ImmutableList.of(100, -200));
+ Assert.assertEquals(genericRecord.get("mapField"), ImmutableMap.of(new Utf8("key1"), 300, new Utf8("key2"), -400));
+ Assert.assertEquals(genericRecord.get("unionArrayField"), ImmutableList.of(99, -199));
+ Assert.assertEquals(genericRecord.get("unionMapField"), ImmutableMap.of(new Utf8("key1"), 298, new Utf8("key2"), 355));
}
@Test
public void testLongToIntDemotionOutOfRange() throws IOException {
- LongRecord longRecord = new LongRecord();
- longRecord.field = (long) Integer.MAX_VALUE + 1L;
+ LongRecord longRecord = LongRecord.newBuilder().setField((long) Integer.MAX_VALUE + 1L).build();
byte[] binary = toBinary(longRecord);
- LongRecord longRecord2 = new LongRecord();
- longRecord2.unionField = (long) Integer.MIN_VALUE - 1L;
+ LongRecord longRecord2 = LongRecord.newBuilder().setField(0L).setUnionField((long) Integer.MIN_VALUE - 1L).build();
byte[] binary2 = toBinary(longRecord2);
+ LongRecord longRecord3 = LongRecord.newBuilder().setField(0L).setArrayField(ImmutableList.of((long) Integer.MAX_VALUE + 1L)).build();
+ byte[] binary3 = toBinary(longRecord3);
+
+ LongRecord longRecord4 = LongRecord.newBuilder().setField(0L).setMapField(ImmutableMap.of("haha", (long) Integer.MIN_VALUE - 1L)).build();
+ byte[] binary4 = toBinary(longRecord4);
+
+ LongRecord longRecord5 = LongRecord.newBuilder().setField(0L).setUnionArrayField(ImmutableList.of((long) Integer.MAX_VALUE + 1L)).build();
+ byte[] binary5 = toBinary(longRecord5);
+
+ LongRecord longRecord6 = LongRecord.newBuilder().setField(0L).setUnionMapField(ImmutableMap.of("haha", (long) Integer.MIN_VALUE - 1L)).build();
+ byte[] binary6 = toBinary(longRecord6);
+
Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary2, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary2, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
- }
+ Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary3, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+ Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary3, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+
+ Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary4, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+ Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary4, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+
+ Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary5, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+ Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary5, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+
+ Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary6, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+ Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary6, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+ }
+
private byte[] toBinary(IndexedRecord record) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
BinaryEncoder encoder = AvroCompatibilityHelper.newBinaryEncoder(baos);
diff --git a/helper/tests/helper-tests-17/src/test/java/com/linkedin/avroutil1/compatibility/avro17/AvroCompatibilityHelperAvro17Test.java b/helper/tests/helper-tests-17/src/test/java/com/linkedin/avroutil1/compatibility/avro17/AvroCompatibilityHelperAvro17Test.java
index 66082f5b8..b8421155e 100644
--- a/helper/tests/helper-tests-17/src/test/java/com/linkedin/avroutil1/compatibility/avro17/AvroCompatibilityHelperAvro17Test.java
+++ b/helper/tests/helper-tests-17/src/test/java/com/linkedin/avroutil1/compatibility/avro17/AvroCompatibilityHelperAvro17Test.java
@@ -8,6 +8,8 @@
import by17.IntRecord;
import by17.LongRecord;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import com.linkedin.avroutil1.Pojo;
import com.linkedin.avroutil1.testcommon.TestUtil;
import com.linkedin.avroutil1.compatibility.AvroCompatibilityHelper;
@@ -30,6 +32,7 @@
import org.apache.avro.io.DatumReader;
import org.apache.avro.specific.SpecificData;
import org.apache.avro.specific.SpecificRecord;
+import org.apache.avro.util.Utf8;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.type.TypeReference;
@@ -116,82 +119,152 @@ public void testGetGenericDefaultValueCloningForEnums() throws IOException {
@Test
public void testIntRoundtrip() throws IOException {
IntRecord intRecord = new IntRecord();
- intRecord.field = 42;
- intRecord.unionField = 55;
+ intRecord.setField(42);
+ intRecord.setUnionField(55);
+ intRecord.setArrayField(ImmutableList.of(100, -200));
+ intRecord.setMapField(ImmutableMap.of("key1", 300, "key2", -400));
+ intRecord.setUnionArrayField(ImmutableList.of(99, -199));
+ intRecord.setUnionMapField(ImmutableMap.of("key1", 298, "key2", 355));
byte[] binary = toBinary(intRecord);
IntRecord roundtrip = toSpecificRecord(binary, IntRecord.SCHEMA$, IntRecord.SCHEMA$);
- Assert.assertEquals(roundtrip.field, 42);
- Assert.assertEquals(roundtrip.unionField.intValue(), 55);
+ Assert.assertEquals((int) roundtrip.getField(), 42);
+ Assert.assertEquals(roundtrip.getUnionField().intValue(), 55);
+ Assert.assertEquals(roundtrip.getArrayField(), ImmutableList.of(100, -200));
+ Assert.assertEquals(roundtrip.getMapField(), ImmutableMap.of(new Utf8("key1"), 300, new Utf8("key2"), -400));
+ Assert.assertEquals(roundtrip.getUnionArrayField(), ImmutableList.of(99, -199));
+ Assert.assertEquals(roundtrip.getUnionMapField(), ImmutableMap.of(new Utf8("key1"), 298, new Utf8("key2"), 355));
GenericRecord genericRecord = toGenericRecord(binary, IntRecord.SCHEMA$, IntRecord.SCHEMA$);
Assert.assertEquals(genericRecord.get("field"), 42);
Assert.assertEquals(genericRecord.get("unionField"), 55);
+ Assert.assertEquals(genericRecord.get("arrayField"), ImmutableList.of(100, -200));
+ Assert.assertEquals(genericRecord.get("mapField"), ImmutableMap.of(new Utf8("key1"), 300, new Utf8("key2"), -400));
+ Assert.assertEquals(genericRecord.get("unionArrayField"), ImmutableList.of(99, -199));
+ Assert.assertEquals(genericRecord.get("unionMapField"), ImmutableMap.of(new Utf8("key1"), 298, new Utf8("key2"), 355));
}
@Test
public void testLongRoundtrip() throws IOException {
LongRecord longRecord = new LongRecord();
- longRecord.field = 42L;
- longRecord.unionField = 55L;
+ longRecord.setField(42L);
+ longRecord.setUnionField(55L);
+ longRecord.setArrayField(ImmutableList.of(100L, -200L));
+ longRecord.setMapField(ImmutableMap.of("key1", 300L, "key2", -400L));
+ longRecord.setUnionArrayField(ImmutableList.of(99L, -199L));
+ longRecord.setUnionMapField(ImmutableMap.of("key1", 298L, "key2", 355L));
byte[] binary = toBinary(longRecord);
LongRecord roundtrip = toSpecificRecord(binary, LongRecord.SCHEMA$, LongRecord.SCHEMA$);
- Assert.assertEquals(roundtrip.field, 42L);
- Assert.assertEquals(roundtrip.unionField.longValue(), 55L);
+ Assert.assertEquals((long) roundtrip.getField(), 42L);
+ Assert.assertEquals(roundtrip.getUnionField().longValue(), 55L);
+ Assert.assertEquals(roundtrip.getArrayField(), ImmutableList.of(100L, -200L));
+ Assert.assertEquals(roundtrip.getMapField(), ImmutableMap.of(new Utf8("key1"), 300L, new Utf8("key2"), -400L));
+ Assert.assertEquals(roundtrip.getUnionArrayField(), ImmutableList.of(99L, -199L));
+ Assert.assertEquals(roundtrip.getUnionMapField(), ImmutableMap.of(new Utf8("key1"), 298L, new Utf8("key2"), 355L));
GenericRecord genericRecord = toGenericRecord(binary, LongRecord.SCHEMA$, LongRecord.SCHEMA$);
Assert.assertEquals(genericRecord.get("field"), 42L);
Assert.assertEquals(genericRecord.get("unionField"), 55L);
+ Assert.assertEquals(genericRecord.get("arrayField"), ImmutableList.of(100L, -200L));
+ Assert.assertEquals(genericRecord.get("mapField"), ImmutableMap.of(new Utf8("key1"), 300L, new Utf8("key2"), -400L));
+ Assert.assertEquals(genericRecord.get("unionArrayField"), ImmutableList.of(99L, -199L));
+ Assert.assertEquals(genericRecord.get("unionMapField"), ImmutableMap.of(new Utf8("key1"), 298L, new Utf8("key2"), 355L));
}
@Test
public void testIntToLongPromotion() throws IOException {
IntRecord intRecord = new IntRecord();
- intRecord.field = 42;
- intRecord.unionField = 55;
+ intRecord.setField(42);
+ intRecord.setUnionField(55);
+ intRecord.setArrayField(ImmutableList.of(100, -200));
+ intRecord.setMapField(ImmutableMap.of("key1", 300, "key2", -400));
+ intRecord.setUnionArrayField(ImmutableList.of(99, -199));
+ intRecord.setUnionMapField(ImmutableMap.of("key1", 298, "key2", 355));
byte[] binary = toBinary(intRecord);
LongRecord longRecord = toSpecificRecord(binary, IntRecord.SCHEMA$, LongRecord.SCHEMA$);
- Assert.assertEquals(longRecord.field, 42L);
- Assert.assertEquals(longRecord.unionField.longValue(), 55L);
+ Assert.assertEquals((long) longRecord.getField(), 42L);
+ Assert.assertEquals(longRecord.getUnionField().longValue(), 55L);
+ Assert.assertEquals(longRecord.getArrayField(), ImmutableList.of(100L, -200L));
+ Assert.assertEquals(longRecord.getMapField(), ImmutableMap.of(new Utf8("key1"), 300L, new Utf8("key2"), -400L));
+ Assert.assertEquals(longRecord.getUnionArrayField(), ImmutableList.of(99L, -199L));
+ Assert.assertEquals(longRecord.getUnionMapField(), ImmutableMap.of(new Utf8("key1"), 298L, new Utf8("key2"), 355L));
GenericRecord genericRecord = toGenericRecord(binary, IntRecord.SCHEMA$, LongRecord.SCHEMA$);
Assert.assertEquals(genericRecord.get("field"), 42L);
Assert.assertEquals(genericRecord.get("unionField"), 55L);
+ Assert.assertEquals(genericRecord.get("arrayField"), ImmutableList.of(100L, -200L));
+ Assert.assertEquals(genericRecord.get("mapField"), ImmutableMap.of(new Utf8("key1"), 300L, new Utf8("key2"), -400L));
+ Assert.assertEquals(genericRecord.get("unionArrayField"), ImmutableList.of(99L, -199L));
+ Assert.assertEquals(genericRecord.get("unionMapField"), ImmutableMap.of(new Utf8("key1"), 298L, new Utf8("key2"), 355L));
}
@Test
public void testLongToIntDemotion() throws IOException {
LongRecord longRecord = new LongRecord();
- longRecord.field = 42L;
- longRecord.unionField = 55L;
+ longRecord.setField(42L);
+ longRecord.setUnionField(55L);
+ longRecord.setArrayField(ImmutableList.of(100L, -200L));
+ longRecord.setMapField(ImmutableMap.of("key1", 300L, "key2", -400L));
+ longRecord.setUnionArrayField(ImmutableList.of(99L, -199L));
+ longRecord.setUnionMapField(ImmutableMap.of("key1", 298L, "key2", 355L));
byte[] binary = toBinary(longRecord);
IntRecord intRecord = toSpecificRecord(binary, LongRecord.SCHEMA$, IntRecord.SCHEMA$);
- Assert.assertEquals(intRecord.field, 42);
- Assert.assertEquals(intRecord.unionField.intValue(), 55);
+ Assert.assertEquals((int) intRecord.getField(), 42);
+ Assert.assertEquals(intRecord.getUnionField().intValue(), 55);
+ Assert.assertEquals(intRecord.getArrayField(), ImmutableList.of(100, -200));
+ Assert.assertEquals(intRecord.getMapField(), ImmutableMap.of(new Utf8("key1"), 300, new Utf8("key2"), -400));
+ Assert.assertEquals(intRecord.getUnionArrayField(), ImmutableList.of(99, -199));
+ Assert.assertEquals(intRecord.getUnionMapField(), ImmutableMap.of(new Utf8("key1"), 298, new Utf8("key2"), 355));
GenericRecord genericRecord = toGenericRecord(binary, LongRecord.SCHEMA$, IntRecord.SCHEMA$);
Assert.assertEquals(genericRecord.get("field"), 42);
Assert.assertEquals(genericRecord.get("unionField"), 55);
+ Assert.assertEquals(genericRecord.get("arrayField"), ImmutableList.of(100, -200));
+ Assert.assertEquals(genericRecord.get("mapField"), ImmutableMap.of(new Utf8("key1"), 300, new Utf8("key2"), -400));
+ Assert.assertEquals(genericRecord.get("unionArrayField"), ImmutableList.of(99, -199));
+ Assert.assertEquals(genericRecord.get("unionMapField"), ImmutableMap.of(new Utf8("key1"), 298, new Utf8("key2"), 355));
}
@Test
public void testLongToIntDemotionOutOfRange() throws IOException {
- LongRecord longRecord = new LongRecord();
- longRecord.field = (long) Integer.MAX_VALUE + 1L;
+ LongRecord longRecord = LongRecord.newBuilder().setField((long) Integer.MAX_VALUE + 1L).build();
byte[] binary = toBinary(longRecord);
- LongRecord longRecord2 = new LongRecord();
- longRecord2.unionField = (long) Integer.MIN_VALUE - 1L;
+ LongRecord longRecord2 = LongRecord.newBuilder().setField(0L).setUnionField((long) Integer.MIN_VALUE - 1L).build();
byte[] binary2 = toBinary(longRecord2);
+ LongRecord longRecord3 = LongRecord.newBuilder().setField(0L).setArrayField(ImmutableList.of((long) Integer.MAX_VALUE + 1L)).build();
+ byte[] binary3 = toBinary(longRecord3);
+
+ LongRecord longRecord4 = LongRecord.newBuilder().setField(0L).setMapField(ImmutableMap.of("haha", (long) Integer.MIN_VALUE - 1L)).build();
+ byte[] binary4 = toBinary(longRecord4);
+
+ LongRecord longRecord5 = LongRecord.newBuilder().setField(0L).setUnionArrayField(ImmutableList.of((long) Integer.MAX_VALUE + 1L)).build();
+ byte[] binary5 = toBinary(longRecord5);
+
+ LongRecord longRecord6 = LongRecord.newBuilder().setField(0L).setUnionMapField(ImmutableMap.of("haha", (long) Integer.MIN_VALUE - 1L)).build();
+ byte[] binary6 = toBinary(longRecord6);
+
Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary2, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary2, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+
+ Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary3, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+ Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary3, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+
+ Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary4, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+ Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary4, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+
+ Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary5, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+ Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary5, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+
+ Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary6, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+ Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary6, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
}
private byte[] toBinary(IndexedRecord record) throws IOException {
diff --git a/helper/tests/helper-tests-18/src/test/java/com/linkedin/avroutil1/compatibility/avro18/AvroCompatibilityHelperAvro18Test.java b/helper/tests/helper-tests-18/src/test/java/com/linkedin/avroutil1/compatibility/avro18/AvroCompatibilityHelperAvro18Test.java
index 0eda22b6a..b3b94ddf7 100644
--- a/helper/tests/helper-tests-18/src/test/java/com/linkedin/avroutil1/compatibility/avro18/AvroCompatibilityHelperAvro18Test.java
+++ b/helper/tests/helper-tests-18/src/test/java/com/linkedin/avroutil1/compatibility/avro18/AvroCompatibilityHelperAvro18Test.java
@@ -8,6 +8,8 @@
import by18.IntRecord;
import by18.LongRecord;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import com.linkedin.avroutil1.Pojo;
import com.linkedin.avroutil1.testcommon.TestUtil;
import com.linkedin.avroutil1.compatibility.AvroCompatibilityHelper;
@@ -30,6 +32,7 @@
import org.apache.avro.io.DatumReader;
import org.apache.avro.specific.SpecificData;
import org.apache.avro.specific.SpecificRecord;
+import org.apache.avro.util.Utf8;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.type.TypeReference;
@@ -99,82 +102,152 @@ public void testCreateSchemaFieldWithProvidedDefaultValue() throws IOException {
@Test
public void testIntRoundtrip() throws IOException {
IntRecord intRecord = new IntRecord();
- intRecord.field = 42;
- intRecord.unionField = 55;
+ intRecord.setField(42);
+ intRecord.setUnionField(55);
+ intRecord.setArrayField(ImmutableList.of(100, -200));
+ intRecord.setMapField(ImmutableMap.of("key1", 300, "key2", -400));
+ intRecord.setUnionArrayField(ImmutableList.of(99, -199));
+ intRecord.setUnionMapField(ImmutableMap.of("key1", 298, "key2", 355));
byte[] binary = toBinary(intRecord);
IntRecord roundtrip = toSpecificRecord(binary, IntRecord.SCHEMA$, IntRecord.SCHEMA$);
- Assert.assertEquals(roundtrip.field, 42);
- Assert.assertEquals(roundtrip.unionField.intValue(), 55);
+ Assert.assertEquals((int) roundtrip.getField(), 42);
+ Assert.assertEquals(roundtrip.getUnionField().intValue(), 55);
+ Assert.assertEquals(roundtrip.getArrayField(), ImmutableList.of(100, -200));
+ Assert.assertEquals(roundtrip.getMapField(), ImmutableMap.of(new Utf8("key1"), 300, new Utf8("key2"), -400));
+ Assert.assertEquals(roundtrip.getUnionArrayField(), ImmutableList.of(99, -199));
+ Assert.assertEquals(roundtrip.getUnionMapField(), ImmutableMap.of(new Utf8("key1"), 298, new Utf8("key2"), 355));
GenericRecord genericRecord = toGenericRecord(binary, IntRecord.SCHEMA$, IntRecord.SCHEMA$);
Assert.assertEquals(genericRecord.get("field"), 42);
Assert.assertEquals(genericRecord.get("unionField"), 55);
+ Assert.assertEquals(genericRecord.get("arrayField"), ImmutableList.of(100, -200));
+ Assert.assertEquals(genericRecord.get("mapField"), ImmutableMap.of(new Utf8("key1"), 300, new Utf8("key2"), -400));
+ Assert.assertEquals(genericRecord.get("unionArrayField"), ImmutableList.of(99, -199));
+ Assert.assertEquals(genericRecord.get("unionMapField"), ImmutableMap.of(new Utf8("key1"), 298, new Utf8("key2"), 355));
}
@Test
public void testLongRoundtrip() throws IOException {
LongRecord longRecord = new LongRecord();
- longRecord.field = 42L;
- longRecord.unionField = 55L;
+ longRecord.setField(42L);
+ longRecord.setUnionField(55L);
+ longRecord.setArrayField(ImmutableList.of(100L, -200L));
+ longRecord.setMapField(ImmutableMap.of("key1", 300L, "key2", -400L));
+ longRecord.setUnionArrayField(ImmutableList.of(99L, -199L));
+ longRecord.setUnionMapField(ImmutableMap.of("key1", 298L, "key2", 355L));
byte[] binary = toBinary(longRecord);
LongRecord roundtrip = toSpecificRecord(binary, LongRecord.SCHEMA$, LongRecord.SCHEMA$);
- Assert.assertEquals(roundtrip.field, 42L);
- Assert.assertEquals(roundtrip.unionField.longValue(), 55L);
+ Assert.assertEquals((long) roundtrip.getField(), 42L);
+ Assert.assertEquals(roundtrip.getUnionField().longValue(), 55L);
+ Assert.assertEquals(roundtrip.getArrayField(), ImmutableList.of(100L, -200L));
+ Assert.assertEquals(roundtrip.getMapField(), ImmutableMap.of(new Utf8("key1"), 300L, new Utf8("key2"), -400L));
+ Assert.assertEquals(roundtrip.getUnionArrayField(), ImmutableList.of(99L, -199L));
+ Assert.assertEquals(roundtrip.getUnionMapField(), ImmutableMap.of(new Utf8("key1"), 298L, new Utf8("key2"), 355L));
GenericRecord genericRecord = toGenericRecord(binary, LongRecord.SCHEMA$, LongRecord.SCHEMA$);
Assert.assertEquals(genericRecord.get("field"), 42L);
Assert.assertEquals(genericRecord.get("unionField"), 55L);
+ Assert.assertEquals(genericRecord.get("arrayField"), ImmutableList.of(100L, -200L));
+ Assert.assertEquals(genericRecord.get("mapField"), ImmutableMap.of(new Utf8("key1"), 300L, new Utf8("key2"), -400L));
+ Assert.assertEquals(genericRecord.get("unionArrayField"), ImmutableList.of(99L, -199L));
+ Assert.assertEquals(genericRecord.get("unionMapField"), ImmutableMap.of(new Utf8("key1"), 298L, new Utf8("key2"), 355L));
}
@Test
public void testIntToLongPromotion() throws IOException {
IntRecord intRecord = new IntRecord();
- intRecord.field = 42;
- intRecord.unionField = 55;
+ intRecord.setField(42);
+ intRecord.setUnionField(55);
+ intRecord.setArrayField(ImmutableList.of(100, -200));
+ intRecord.setMapField(ImmutableMap.of("key1", 300, "key2", -400));
+ intRecord.setUnionArrayField(ImmutableList.of(99, -199));
+ intRecord.setUnionMapField(ImmutableMap.of("key1", 298, "key2", 355));
byte[] binary = toBinary(intRecord);
LongRecord longRecord = toSpecificRecord(binary, IntRecord.SCHEMA$, LongRecord.SCHEMA$);
- Assert.assertEquals(longRecord.field, 42L);
- Assert.assertEquals(longRecord.unionField.longValue(), 55L);
+ Assert.assertEquals((long) longRecord.getField(), 42L);
+ Assert.assertEquals(longRecord.getUnionField().longValue(), 55L);
+ Assert.assertEquals(longRecord.getArrayField(), ImmutableList.of(100L, -200L));
+ Assert.assertEquals(longRecord.getMapField(), ImmutableMap.of(new Utf8("key1"), 300L, new Utf8("key2"), -400L));
+ Assert.assertEquals(longRecord.getUnionArrayField(), ImmutableList.of(99L, -199L));
+ Assert.assertEquals(longRecord.getUnionMapField(), ImmutableMap.of(new Utf8("key1"), 298L, new Utf8("key2"), 355L));
GenericRecord genericRecord = toGenericRecord(binary, IntRecord.SCHEMA$, LongRecord.SCHEMA$);
Assert.assertEquals(genericRecord.get("field"), 42L);
Assert.assertEquals(genericRecord.get("unionField"), 55L);
+ Assert.assertEquals(genericRecord.get("arrayField"), ImmutableList.of(100L, -200L));
+ Assert.assertEquals(genericRecord.get("mapField"), ImmutableMap.of(new Utf8("key1"), 300L, new Utf8("key2"), -400L));
+ Assert.assertEquals(genericRecord.get("unionArrayField"), ImmutableList.of(99L, -199L));
+ Assert.assertEquals(genericRecord.get("unionMapField"), ImmutableMap.of(new Utf8("key1"), 298L, new Utf8("key2"), 355L));
}
@Test
public void testLongToIntDemotion() throws IOException {
LongRecord longRecord = new LongRecord();
- longRecord.field = 42L;
- longRecord.unionField = 55L;
+ longRecord.setField(42L);
+ longRecord.setUnionField(55L);
+ longRecord.setArrayField(ImmutableList.of(100L, -200L));
+ longRecord.setMapField(ImmutableMap.of("key1", 300L, "key2", -400L));
+ longRecord.setUnionArrayField(ImmutableList.of(99L, -199L));
+ longRecord.setUnionMapField(ImmutableMap.of("key1", 298L, "key2", 355L));
byte[] binary = toBinary(longRecord);
IntRecord intRecord = toSpecificRecord(binary, LongRecord.SCHEMA$, IntRecord.SCHEMA$);
- Assert.assertEquals(intRecord.field, 42);
- Assert.assertEquals(intRecord.unionField.intValue(), 55);
+ Assert.assertEquals((int) intRecord.getField(), 42);
+ Assert.assertEquals(intRecord.getUnionField().intValue(), 55);
+ Assert.assertEquals(intRecord.getArrayField(), ImmutableList.of(100, -200));
+ Assert.assertEquals(intRecord.getMapField(), ImmutableMap.of(new Utf8("key1"), 300, new Utf8("key2"), -400));
+ Assert.assertEquals(intRecord.getUnionArrayField(), ImmutableList.of(99, -199));
+ Assert.assertEquals(intRecord.getUnionMapField(), ImmutableMap.of(new Utf8("key1"), 298, new Utf8("key2"), 355));
GenericRecord genericRecord = toGenericRecord(binary, LongRecord.SCHEMA$, IntRecord.SCHEMA$);
Assert.assertEquals(genericRecord.get("field"), 42);
Assert.assertEquals(genericRecord.get("unionField"), 55);
+ Assert.assertEquals(genericRecord.get("arrayField"), ImmutableList.of(100, -200));
+ Assert.assertEquals(genericRecord.get("mapField"), ImmutableMap.of(new Utf8("key1"), 300, new Utf8("key2"), -400));
+ Assert.assertEquals(genericRecord.get("unionArrayField"), ImmutableList.of(99, -199));
+ Assert.assertEquals(genericRecord.get("unionMapField"), ImmutableMap.of(new Utf8("key1"), 298, new Utf8("key2"), 355));
}
@Test
public void testLongToIntDemotionOutOfRange() throws IOException {
- LongRecord longRecord = new LongRecord();
- longRecord.field = (long) Integer.MAX_VALUE + 1L;
+ LongRecord longRecord = LongRecord.newBuilder().setField((long) Integer.MAX_VALUE + 1L).build();
byte[] binary = toBinary(longRecord);
- LongRecord longRecord2 = new LongRecord();
- longRecord2.unionField = (long) Integer.MIN_VALUE - 1L;
+ LongRecord longRecord2 = LongRecord.newBuilder().setField(0L).setUnionField((long) Integer.MIN_VALUE - 1L).build();
byte[] binary2 = toBinary(longRecord2);
+ LongRecord longRecord3 = LongRecord.newBuilder().setField(0L).setArrayField(ImmutableList.of((long) Integer.MAX_VALUE + 1L)).build();
+ byte[] binary3 = toBinary(longRecord3);
+
+ LongRecord longRecord4 = LongRecord.newBuilder().setField(0L).setMapField(ImmutableMap.of("haha", (long) Integer.MIN_VALUE - 1L)).build();
+ byte[] binary4 = toBinary(longRecord4);
+
+ LongRecord longRecord5 = LongRecord.newBuilder().setField(0L).setUnionArrayField(ImmutableList.of((long) Integer.MAX_VALUE + 1L)).build();
+ byte[] binary5 = toBinary(longRecord5);
+
+ LongRecord longRecord6 = LongRecord.newBuilder().setField(0L).setUnionMapField(ImmutableMap.of("haha", (long) Integer.MIN_VALUE - 1L)).build();
+ byte[] binary6 = toBinary(longRecord6);
+
Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary2, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary2, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+
+ Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary3, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+ Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary3, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+
+ Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary4, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+ Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary4, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+
+ Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary5, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+ Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary5, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+
+ Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary6, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+ Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary6, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
}
private byte[] toBinary(IndexedRecord record) throws IOException {
diff --git a/helper/tests/helper-tests-19/src/test/java/com/linkedin/avroutil1/compatibility/avro19/AvroCompatibilityHelperAvro19Test.java b/helper/tests/helper-tests-19/src/test/java/com/linkedin/avroutil1/compatibility/avro19/AvroCompatibilityHelperAvro19Test.java
index 10c9c70fd..67f9d3fd3 100644
--- a/helper/tests/helper-tests-19/src/test/java/com/linkedin/avroutil1/compatibility/avro19/AvroCompatibilityHelperAvro19Test.java
+++ b/helper/tests/helper-tests-19/src/test/java/com/linkedin/avroutil1/compatibility/avro19/AvroCompatibilityHelperAvro19Test.java
@@ -6,15 +6,33 @@
package com.linkedin.avroutil1.compatibility.avro19;
+import by19.IntRecord;
+import by19.LongRecord;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import com.linkedin.avroutil1.Pojo;
import com.linkedin.avroutil1.compatibility.AvroCompatibilityHelper;
import com.linkedin.avroutil1.compatibility.AvroVersion;
import com.linkedin.avroutil1.testcommon.TestUtil;
+
+import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.Map;
+
+import org.apache.avro.AvroTypeException;
import org.apache.avro.JsonProperties;
import org.apache.avro.Schema;
+import org.apache.avro.generic.GenericData;
+import org.apache.avro.generic.GenericDatumWriter;
+import org.apache.avro.generic.GenericRecord;
+import org.apache.avro.generic.IndexedRecord;
+import org.apache.avro.io.BinaryDecoder;
+import org.apache.avro.io.BinaryEncoder;
+import org.apache.avro.io.DatumReader;
+import org.apache.avro.specific.SpecificData;
+import org.apache.avro.specific.SpecificRecord;
+import org.apache.avro.util.Utf8;
import org.mockito.Mockito;
import org.testng.Assert;
import org.testng.annotations.Test;
@@ -75,4 +93,179 @@ public void testCreateSchemaFieldWithProvidedDefaultValue() throws IOException {
Assert.assertEquals(actualListValue.get(0).get(0), "dummyElement");
}
+ @Test
+ public void testIntRoundtrip() throws IOException {
+ IntRecord intRecord = new IntRecord();
+ intRecord.setField(42);
+ intRecord.setUnionField(55);
+ intRecord.setArrayField(ImmutableList.of(100, -200));
+ intRecord.setMapField(ImmutableMap.of("key1", 300, "key2", -400));
+ intRecord.setUnionArrayField(ImmutableList.of(99, -199));
+ intRecord.setUnionMapField(ImmutableMap.of("key1", 298, "key2", 355));
+ byte[] binary = toBinary(intRecord);
+
+ IntRecord roundtrip = toSpecificRecord(binary, IntRecord.SCHEMA$, IntRecord.SCHEMA$);
+ Assert.assertEquals(roundtrip.getField(), 42);
+ Assert.assertEquals(roundtrip.getUnionField().intValue(), 55);
+ Assert.assertEquals(roundtrip.getArrayField(), ImmutableList.of(100, -200));
+ Assert.assertEquals(roundtrip.getMapField(), ImmutableMap.of(new Utf8("key1"), 300, new Utf8("key2"), -400));
+ Assert.assertEquals(roundtrip.getUnionArrayField(), ImmutableList.of(99, -199));
+ Assert.assertEquals(roundtrip.getUnionMapField(), ImmutableMap.of(new Utf8("key1"), 298, new Utf8("key2"), 355));
+
+ GenericRecord genericRecord = toGenericRecord(binary, IntRecord.SCHEMA$, IntRecord.SCHEMA$);
+ Assert.assertEquals(genericRecord.get("field"), 42);
+ Assert.assertEquals(genericRecord.get("unionField"), 55);
+ Assert.assertEquals(genericRecord.get("arrayField"), ImmutableList.of(100, -200));
+ Assert.assertEquals(genericRecord.get("mapField"), ImmutableMap.of(new Utf8("key1"), 300, new Utf8("key2"), -400));
+ Assert.assertEquals(genericRecord.get("unionArrayField"), ImmutableList.of(99, -199));
+ Assert.assertEquals(genericRecord.get("unionMapField"), ImmutableMap.of(new Utf8("key1"), 298, new Utf8("key2"), 355));
+ }
+
+ @Test
+ public void testLongRoundtrip() throws IOException {
+ LongRecord longRecord = new LongRecord();
+ longRecord.setField(42L);
+ longRecord.setUnionField(55L);
+ longRecord.setArrayField(ImmutableList.of(100L, -200L));
+ longRecord.setMapField(ImmutableMap.of("key1", 300L, "key2", -400L));
+ longRecord.setUnionArrayField(ImmutableList.of(99L, -199L));
+ longRecord.setUnionMapField(ImmutableMap.of("key1", 298L, "key2", 355L));
+ byte[] binary = toBinary(longRecord);
+
+ LongRecord roundtrip = toSpecificRecord(binary, LongRecord.SCHEMA$, LongRecord.SCHEMA$);
+ Assert.assertEquals(roundtrip.getField(), 42L);
+ Assert.assertEquals(roundtrip.getUnionField().longValue(), 55L);
+ Assert.assertEquals(roundtrip.getArrayField(), ImmutableList.of(100L, -200L));
+ Assert.assertEquals(roundtrip.getMapField(), ImmutableMap.of(new Utf8("key1"), 300L, new Utf8("key2"), -400L));
+ Assert.assertEquals(roundtrip.getUnionArrayField(), ImmutableList.of(99L, -199L));
+ Assert.assertEquals(roundtrip.getUnionMapField(), ImmutableMap.of(new Utf8("key1"), 298L, new Utf8("key2"), 355L));
+
+ GenericRecord genericRecord = toGenericRecord(binary, LongRecord.SCHEMA$, LongRecord.SCHEMA$);
+ Assert.assertEquals(genericRecord.get("field"), 42L);
+ Assert.assertEquals(genericRecord.get("unionField"), 55L);
+ Assert.assertEquals(genericRecord.get("arrayField"), ImmutableList.of(100L, -200L));
+ Assert.assertEquals(genericRecord.get("mapField"), ImmutableMap.of(new Utf8("key1"), 300L, new Utf8("key2"), -400L));
+ Assert.assertEquals(genericRecord.get("unionArrayField"), ImmutableList.of(99L, -199L));
+ Assert.assertEquals(genericRecord.get("unionMapField"), ImmutableMap.of(new Utf8("key1"), 298L, new Utf8("key2"), 355L));
+ }
+
+ @Test
+ public void testIntToLongPromotion() throws IOException {
+ IntRecord intRecord = new IntRecord();
+ intRecord.setField(42);
+ intRecord.setUnionField(55);
+ intRecord.setArrayField(ImmutableList.of(100, -200));
+ intRecord.setMapField(ImmutableMap.of("key1", 300, "key2", -400));
+ intRecord.setUnionArrayField(ImmutableList.of(99, -199));
+ intRecord.setUnionMapField(ImmutableMap.of("key1", 298, "key2", 355));
+ byte[] binary = toBinary(intRecord);
+
+ LongRecord longRecord = toSpecificRecord(binary, IntRecord.SCHEMA$, LongRecord.SCHEMA$);
+ Assert.assertEquals(longRecord.getField(), 42L);
+ Assert.assertEquals(longRecord.getUnionField().longValue(), 55L);
+ Assert.assertEquals(longRecord.getArrayField(), ImmutableList.of(100L, -200L));
+ Assert.assertEquals(longRecord.getMapField(), ImmutableMap.of(new Utf8("key1"), 300L, new Utf8("key2"), -400L));
+ Assert.assertEquals(longRecord.getUnionArrayField(), ImmutableList.of(99L, -199L));
+ Assert.assertEquals(longRecord.getUnionMapField(), ImmutableMap.of(new Utf8("key1"), 298L, new Utf8("key2"), 355L));
+
+ GenericRecord genericRecord = toGenericRecord(binary, IntRecord.SCHEMA$, LongRecord.SCHEMA$);
+ Assert.assertEquals(genericRecord.get("field"), 42L);
+ Assert.assertEquals(genericRecord.get("unionField"), 55L);
+ Assert.assertEquals(genericRecord.get("arrayField"), ImmutableList.of(100L, -200L));
+ Assert.assertEquals(genericRecord.get("mapField"), ImmutableMap.of(new Utf8("key1"), 300L, new Utf8("key2"), -400L));
+ Assert.assertEquals(genericRecord.get("unionArrayField"), ImmutableList.of(99L, -199L));
+ Assert.assertEquals(genericRecord.get("unionMapField"), ImmutableMap.of(new Utf8("key1"), 298L, new Utf8("key2"), 355L));
+ }
+
+ @Test
+ public void testLongToIntDemotion() throws IOException {
+ LongRecord longRecord = new LongRecord();
+ longRecord.setField(42L);
+ longRecord.setUnionField(55L);
+ longRecord.setArrayField(ImmutableList.of(100L, -200L));
+ longRecord.setMapField(ImmutableMap.of("key1", 300L, "key2", -400L));
+ longRecord.setUnionArrayField(ImmutableList.of(99L, -199L));
+ longRecord.setUnionMapField(ImmutableMap.of("key1", 298L, "key2", 355L));
+ byte[] binary = toBinary(longRecord);
+
+ IntRecord intRecord = toSpecificRecord(binary, LongRecord.SCHEMA$, IntRecord.SCHEMA$);
+ Assert.assertEquals(intRecord.getField(), 42);
+ Assert.assertEquals(intRecord.getUnionField().intValue(), 55);
+ Assert.assertEquals(intRecord.getArrayField(), ImmutableList.of(100, -200));
+ Assert.assertEquals(intRecord.getMapField(), ImmutableMap.of(new Utf8("key1"), 300, new Utf8("key2"), -400));
+ Assert.assertEquals(intRecord.getUnionArrayField(), ImmutableList.of(99, -199));
+ Assert.assertEquals(intRecord.getUnionMapField(), ImmutableMap.of(new Utf8("key1"), 298, new Utf8("key2"), 355));
+
+ GenericRecord genericRecord = toGenericRecord(binary, LongRecord.SCHEMA$, IntRecord.SCHEMA$);
+ Assert.assertEquals(genericRecord.get("field"), 42);
+ Assert.assertEquals(genericRecord.get("unionField"), 55);
+ Assert.assertEquals(genericRecord.get("arrayField"), ImmutableList.of(100, -200));
+ Assert.assertEquals(genericRecord.get("mapField"), ImmutableMap.of(new Utf8("key1"), 300, new Utf8("key2"), -400));
+ Assert.assertEquals(genericRecord.get("unionArrayField"), ImmutableList.of(99, -199));
+ Assert.assertEquals(genericRecord.get("unionMapField"), ImmutableMap.of(new Utf8("key1"), 298, new Utf8("key2"), 355));
+ }
+
+ @Test
+ public void testLongToIntDemotionOutOfRange() throws IOException {
+ LongRecord longRecord = LongRecord.newBuilder().setField((long) Integer.MAX_VALUE + 1L).build();
+ byte[] binary = toBinary(longRecord);
+
+ LongRecord longRecord2 = LongRecord.newBuilder().setField(0L).setUnionField((long) Integer.MIN_VALUE - 1L).build();
+ byte[] binary2 = toBinary(longRecord2);
+
+ LongRecord longRecord3 = LongRecord.newBuilder().setField(0L).setArrayField(ImmutableList.of((long) Integer.MAX_VALUE + 1L)).build();
+ byte[] binary3 = toBinary(longRecord3);
+
+ LongRecord longRecord4 = LongRecord.newBuilder().setField(0L).setMapField(ImmutableMap.of("haha", (long) Integer.MIN_VALUE - 1L)).build();
+ byte[] binary4 = toBinary(longRecord4);
+
+ LongRecord longRecord5 = LongRecord.newBuilder().setField(0L).setUnionArrayField(ImmutableList.of((long) Integer.MAX_VALUE + 1L)).build();
+ byte[] binary5 = toBinary(longRecord5);
+
+ LongRecord longRecord6 = LongRecord.newBuilder().setField(0L).setUnionMapField(ImmutableMap.of("haha", (long) Integer.MIN_VALUE - 1L)).build();
+ byte[] binary6 = toBinary(longRecord6);
+
+ Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+ Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+
+ Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary2, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+ Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary2, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+
+ Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary3, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+ Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary3, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+
+ Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary4, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+ Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary4, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+
+ Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary5, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+ Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary5, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+
+ Assert.assertThrows(AvroTypeException.class, () -> toSpecificRecord(binary6, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+ Assert.assertThrows(AvroTypeException.class, () -> toGenericRecord(binary6, LongRecord.SCHEMA$, IntRecord.SCHEMA$));
+ }
+
+ private byte[] toBinary(IndexedRecord record) throws IOException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ BinaryEncoder encoder = AvroCompatibilityHelper.newBinaryEncoder(baos);
+ GenericDatumWriter writer = new GenericDatumWriter<>(record.getSchema());
+ writer.write(record, encoder);
+ encoder.flush();
+ return baos.toByteArray();
+ }
+
+ private T toSpecificRecord(byte[] binary,
+ Schema writerSchema,
+ Schema readerSchema) throws IOException {
+ BinaryDecoder decoder = AvroCompatibilityHelper.newBinaryDecoder(binary);
+ DatumReader reader = AvroCompatibilityHelper.newSpecificDatumReader(writerSchema, readerSchema, SpecificData.get());
+ return reader.read(null, decoder);
+ }
+
+ private GenericRecord toGenericRecord(byte[] binary,
+ Schema writerSchema,
+ Schema readerSchema) throws IOException {
+ BinaryDecoder decoder = AvroCompatibilityHelper.newBinaryDecoder(binary);
+ DatumReader reader = AvroCompatibilityHelper.newGenericDatumReader(writerSchema, readerSchema, GenericData.get());
+ return reader.read(null, decoder);
+ }
}