Skip to content

Commit 4f26809

Browse files
karthikrgKarthik Ramgopal
andauthored
Support for selectively demoting long to int in avro 1.9 to 1.11 (#593)
* Support for selectively demoting long to int in avro 1.9 to 1.11 * fix javadoc * fix javadoc * Fix array/map * Fix avro 1.9 * Fix 1.4 to 1.8 * Fix checkstyle * java8 --------- Co-authored-by: Karthik Ramgopal <[email protected]>
1 parent b32bae2 commit 4f26809

File tree

73 files changed

+3878
-138
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

73 files changed

+3878
-138
lines changed

avro-builder/tests/tests-allavro/src/test/java/com/linkedin/avroutil1/builder/SpecificRecordTest.java

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,14 @@
77
package com.linkedin.avroutil1.builder;
88

99
import com.linkedin.avroutil1.compatibility.AvroCodecUtil;
10+
import com.linkedin.avroutil1.compatibility.AvroCompatibilityHelper;
1011
import com.linkedin.avroutil1.compatibility.AvroRecordUtil;
12+
import com.linkedin.avroutil1.compatibility.CustomDecoder;
1113
import com.linkedin.avroutil1.compatibility.RandomRecordGenerator;
1214
import com.linkedin.avroutil1.compatibility.RecordGenerationConfig;
1315
import com.linkedin.avroutil1.compatibility.StringConverterUtil;
16+
17+
import java.io.ByteArrayOutputStream;
1418
import java.io.FileOutputStream;
1519
import java.io.IOException;
1620
import java.io.ObjectOutputStream;
@@ -29,9 +33,13 @@
2933
import java.util.Map;
3034
import java.util.Set;
3135
import java.util.stream.Collectors;
36+
37+
import com.linkedin.avroutil1.compatibility.backports.SpecificRecordBaseExt;
3238
import noutf8.TestCollections;
3339
import org.apache.avro.AvroRuntimeException;
3440
import org.apache.avro.generic.IndexedRecord;
41+
import org.apache.avro.io.Decoder;
42+
import org.apache.avro.io.Encoder;
3543
import org.apache.avro.util.Utf8;
3644
import org.testng.Assert;
3745
import org.testng.annotations.BeforeClass;
@@ -2040,6 +2048,36 @@ public void testNoUtf8Encoding() throws IOException {
20402048
Assert.assertTrue(instance.arOfMap.get(0).containsValue(strValue));
20412049
}
20422050

2051+
@DataProvider
2052+
private Object[][] customDecodeDataProvider() {
2053+
return new Object[][]{
2054+
{vs19.MoneyRange.class},
2055+
{vs110.MoneyRange.class},
2056+
{vs111.MoneyRange.class}
2057+
};
2058+
}
2059+
2060+
@Test(dataProvider = "customDecodeDataProvider")
2061+
public void testCustomDecode(Class<? extends SpecificRecordBaseExt> specificRecordClass) throws Exception {
2062+
RandomRecordGenerator generator = new RandomRecordGenerator();
2063+
SpecificRecordBaseExt instance = generator.randomSpecific(specificRecordClass);
2064+
2065+
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
2066+
Encoder encoder = AvroCompatibilityHelper.newBinaryEncoder(outputStream);
2067+
Method customEncodeMethod = instance.getClass().getMethod("customEncode", Encoder.class);
2068+
customEncodeMethod.invoke(instance, encoder);
2069+
encoder.flush();
2070+
2071+
byte[] data = outputStream.toByteArray();
2072+
Decoder binaryDecoder = AvroCompatibilityHelper.newBinaryDecoder(data);
2073+
CustomDecoder decoder =
2074+
(CustomDecoder) AvroCompatibilityHelper.newCachedResolvingDecoder(
2075+
instance.getSchema(), instance.getSchema(), binaryDecoder);
2076+
SpecificRecordBaseExt decodedInstance = specificRecordClass.getDeclaredConstructor().newInstance();
2077+
decodedInstance.customDecode(decoder);
2078+
Assert.assertEquals(instance, decodedInstance);
2079+
}
2080+
20432081
@BeforeClass
20442082
public void setup() {
20452083
System.setProperty("org.apache.avro.specific.use_custom_coders", "true");

avro-codegen/src/main/java/com/linkedin/avroutil1/codegen/SpecificRecordClassGenerator.java

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,7 @@ protected JavaFile generateSpecificRecord(AvroRecordSchema recordSchema, Specifi
356356
classBuilder.addSuperinterface(SpecificRecordGeneratorUtil.CLASSNAME_SPECIFIC_RECORD);
357357

358358
// extends
359-
classBuilder.superclass(SpecificRecordGeneratorUtil.CLASSNAME_SPECIFIC_RECORD_BASE);
359+
classBuilder.superclass(SpecificRecordGeneratorUtil.CLASSNAME_SPECIFIC_RECORD_BASE_EXT);
360360

361361
//add class-level doc from schema doc
362362
//file-level (top of file) comment is added to the file object later
@@ -519,9 +519,27 @@ protected JavaFile generateSpecificRecord(AvroRecordSchema recordSchema, Specifi
519519
.addParameter(SpecificRecordGeneratorUtil.CLASSNAME_RESOLVING_DECODER, "in")
520520
.addException(IOException.class)
521521
.addModifiers(Modifier.PUBLIC);
522-
addCustomDecodeMethod(customDecodeBuilder, recordSchema, config, classBuilder, sizeValCounter);
522+
addCustomDecodeMethod(customDecodeBuilder, recordSchema, config, classBuilder, sizeValCounter, false);
523523
classBuilder.addMethod(customDecodeBuilder.build());
524524

525+
//customDecode with CustomDecoder
526+
MethodSpec.Builder methodBuilder = MethodSpec
527+
.methodBuilder("customDecode")
528+
.addParameter(SpecificRecordGeneratorUtil.CLASSNAME_CUSTOM_DECODER, "in")
529+
.addException(IOException.class)
530+
.addModifiers(Modifier.PUBLIC)
531+
.addAnnotation(Override.class);
532+
addCustomDecodeMethod(methodBuilder, recordSchema, config, classBuilder, sizeValCounter, true);
533+
classBuilder.addMethod(methodBuilder.build());
534+
535+
MethodSpec.Builder isCustomDecodingEnabledMethod = MethodSpec
536+
.methodBuilder("isCustomDecodingEnabled")
537+
.addModifiers(Modifier.PUBLIC)
538+
.returns(TypeName.BOOLEAN)
539+
.addAnnotation(Override.class)
540+
.addCode("return hasCustomCoders();");
541+
classBuilder.addMethod(isCustomDecodingEnabledMethod.build());
542+
525543
// Builder
526544
TypeSpec.Builder recordBuilder = TypeSpec.classBuilder("Builder");
527545
recordBuilder.addModifiers(Modifier.PUBLIC, Modifier.STATIC);
@@ -945,8 +963,13 @@ private String getMethodNameForFieldWithPrefix(String prefix, String fieldName)
945963
}
946964

947965
private void addCustomDecodeMethod(MethodSpec.Builder customDecodeBuilder, AvroRecordSchema recordSchema,
948-
SpecificRecordGenerationConfig config, TypeSpec.Builder classBuilder, Counter sizeValCounter) {
966+
SpecificRecordGenerationConfig config, TypeSpec.Builder classBuilder, Counter sizeValCounter, boolean isCustomDecoder) {
949967
int blockSize = 25, fieldCounter = 0, chunkCounter = 0;
968+
969+
// Decoder class name.
970+
ClassName decoderClassName = isCustomDecoder ? SpecificRecordGeneratorUtil.CLASSNAME_CUSTOM_DECODER :
971+
SpecificRecordGeneratorUtil.CLASSNAME_RESOLVING_DECODER;
972+
950973
// reset var counter
951974
sizeValCounter.reset();
952975
customDecodeBuilder.addStatement(
@@ -959,7 +982,7 @@ private void addCustomDecodeMethod(MethodSpec.Builder customDecodeBuilder, AvroR
959982
customDecodeBuilder.addStatement(chunkMethodName + "(in)");
960983
// create new method
961984
MethodSpec.Builder customDecodeChunkMethod = MethodSpec.methodBuilder(chunkMethodName)
962-
.addParameter(SpecificRecordGeneratorUtil.CLASSNAME_RESOLVING_DECODER, "in")
985+
.addParameter(decoderClassName, "in")
963986
.addException(IOException.class)
964987
.addModifiers(Modifier.PUBLIC);
965988
for (; fieldCounter < Math.min(blockSize * chunkCounter + blockSize, recordSchema.getFields().size());
@@ -989,7 +1012,7 @@ private void addCustomDecodeMethod(MethodSpec.Builder customDecodeBuilder, AvroR
9891012
customDecodeBuilder.addStatement(chunkMethodName + "(in, fieldOrder)");
9901013
// create new method
9911014
MethodSpec.Builder customDecodeChunkMethod = MethodSpec.methodBuilder(chunkMethodName)
992-
.addParameter(SpecificRecordGeneratorUtil.CLASSNAME_RESOLVING_DECODER, "in")
1015+
.addParameter(decoderClassName, "in")
9931016
.addParameter(ArrayTypeName.of(SpecificRecordGeneratorUtil.CLASSNAME_SCHEMA_FIELD), "fieldOrder")
9941017
.addException(IOException.class)
9951018
.addModifiers(Modifier.PUBLIC);

avro-codegen/src/main/java/com/linkedin/avroutil1/codegen/SpecificRecordGeneratorUtil.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,11 @@ public class SpecificRecordGeneratorUtil {
5151
public static final ClassName CLASSNAME_SPECIFIC_DATA = ClassName.get("org.apache.avro.specific", "SpecificData");
5252
public static final ClassName CLASSNAME_SPECIFIC_RECORD = ClassName.get("org.apache.avro.specific", "SpecificRecord");
5353
public static final ClassName CLASSNAME_SPECIFIC_RECORD_BASE = ClassName.get("org.apache.avro.specific", "SpecificRecordBase");
54+
public static final ClassName CLASSNAME_SPECIFIC_RECORD_BASE_EXT = ClassName.get("com.linkedin.avroutil1.compatibility.backports", "SpecificRecordBaseExt");
5455
public static final ClassName CLASSNAME_SPECIFIC_DATUM_READER = ClassName.get("org.apache.avro.specific", "SpecificDatumReader");
5556
public static final ClassName CLASSNAME_SPECIFIC_DATUM_WRITER = ClassName.get("org.apache.avro.specific", "SpecificDatumWriter");
5657
public static final ClassName CLASSNAME_ENCODER = ClassName.get("org.apache.avro.io", "Encoder");
58+
public static final ClassName CLASSNAME_CUSTOM_DECODER = ClassName.get("com.linkedin.avroutil1.compatibility", "CustomDecoder");
5759
public static final ClassName CLASSNAME_RESOLVING_DECODER = ClassName.get("org.apache.avro.io", "ResolvingDecoder");
5860
public static final ClassName CLASSNAME_DATUM_READER = ClassName.get("org.apache.avro.io", "DatumReader");
5961
public static final ClassName CLASSNAME_DATUM_WRITER = ClassName.get("org.apache.avro.io", "DatumWriter");

0 commit comments

Comments
 (0)