Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Codegen : Custom decode method broken into subMethods #507

Merged
merged 5 commits into from
Aug 17, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import com.linkedin.avroutil1.model.SchemaOrRef;
import com.linkedin.avroutil1.writer.avsc.AvscSchemaWriter;
import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.ArrayTypeName;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.FieldSpec;
Expand Down Expand Up @@ -517,7 +518,7 @@ protected JavaFileObject generateSpecificRecord(AvroRecordSchema recordSchema, S
.addParameter(SpecificRecordGeneratorUtil.CLASSNAME_RESOLVING_DECODER, "in")
.addException(IOException.class)
.addModifiers(Modifier.PUBLIC);
addCustomDecodeMethod(customDecodeBuilder, recordSchema, config);
addCustomDecodeMethod(customDecodeBuilder, recordSchema, config, classBuilder);
classBuilder.addMethod(customDecodeBuilder.build());
}

Expand Down Expand Up @@ -959,41 +960,78 @@ private String getMethodNameForFieldWithPrefix(String prefix, String fieldName)
}

private void addCustomDecodeMethod(MethodSpec.Builder customDecodeBuilder, AvroRecordSchema recordSchema,
SpecificRecordGenerationConfig config) {
SpecificRecordGenerationConfig config, TypeSpec.Builder classBuilder) {
int blockSize = 25, fieldCounter = 0, chunkCounter = 0;
// reset var counter
sizeValCounter = -1;
customDecodeBuilder.addStatement(
"org.apache.avro.Schema.Field[] fieldOrder = (com.linkedin.avroutil1.compatibility.AvroCompatibilityHelper.areFieldsReordered(getSchema())) ? in.readFieldOrder() : null")
.beginControlFlow("if (fieldOrder == null)");
for(AvroSchemaField field : recordSchema.getFields()) {
String escapedFieldName = getFieldNameWithSuffix(field);
customDecodeBuilder.addStatement(getSerializedCustomDecodeBlock(config, field.getSchemaOrRef().getSchema(),
field.getSchemaOrRef().getSchema().type(), "this." + replaceSingleDollarSignWithDouble(escapedFieldName),
"this." + replaceSingleDollarSignWithDouble(escapedFieldName), StringUtils.EMPTY_STRING));

while (fieldCounter < recordSchema.getFields().size()) {
String chunkMethodName = "customDecodeIfChunk" + chunkCounter;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit - why call the method "customDecodeIfChunk0()" ?
as oposed to customDecodeChunk0() ? what does the "if" stand for?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Screenshot 2023-08-16 at 4 35 08 PM

The generated method has if and else chunks.

// add call to new method.
customDecodeBuilder.addStatement(chunkMethodName + "(in)");
// create new method
MethodSpec.Builder customDecodeChunkMethod = MethodSpec.methodBuilder(chunkMethodName)
.addParameter(SpecificRecordGeneratorUtil.CLASSNAME_RESOLVING_DECODER, "in")
.addException(IOException.class)
.addModifiers(Modifier.PUBLIC);
for (; fieldCounter < Math.min(blockSize * chunkCounter + blockSize, recordSchema.getFields().size());
fieldCounter++) {
AvroSchemaField field = recordSchema.getField(fieldCounter);
String escapedFieldName = getFieldNameWithSuffix(field);
customDecodeChunkMethod.addStatement(getSerializedCustomDecodeBlock(config, field.getSchemaOrRef().getSchema(),
field.getSchemaOrRef().getSchema().type(), "this." + replaceSingleDollarSignWithDouble(escapedFieldName),
"this." + replaceSingleDollarSignWithDouble(escapedFieldName), StringUtils.EMPTY_STRING));
}
chunkCounter++;
classBuilder.addMethod(customDecodeChunkMethod.build());
}

// reset var counter
sizeValCounter = -1;
int fieldIndex = 0;
fieldCounter = 0;
chunkCounter = 0;
customDecodeBuilder.endControlFlow()
.beginControlFlow("else")
.beginControlFlow("for( int i = 0; i< $L; i++)", recordSchema.getFields().size())
.beginControlFlow("switch(fieldOrder[i].pos())");
for(AvroSchemaField field : recordSchema.getFields()) {
String escapedFieldName = getFieldNameWithSuffix(field);
customDecodeBuilder
.addStatement(String.format("case %s: ",fieldIndex++)+ getSerializedCustomDecodeBlock(config,
field.getSchemaOrRef().getSchema(), field.getSchemaOrRef().getSchema().type(),
"this." + replaceSingleDollarSignWithDouble(escapedFieldName),
"this." + replaceSingleDollarSignWithDouble(escapedFieldName), StringUtils.EMPTY_STRING))
.addStatement("break");
.beginControlFlow("else");

while (fieldCounter < recordSchema.getFields().size()) {
String chunkMethodName = "customDecodeElseChunk" + chunkCounter;
// add call to new method.
customDecodeBuilder.addStatement(chunkMethodName + "(in, fieldOrder)");
// create new method
MethodSpec.Builder customDecodeChunkMethod = MethodSpec.methodBuilder(chunkMethodName)
.addParameter(SpecificRecordGeneratorUtil.CLASSNAME_RESOLVING_DECODER, "in")
.addParameter(ArrayTypeName.of(SpecificRecordGeneratorUtil.CLASSNAME_SCHEMA_FIELD), "fieldOrder")
.addException(IOException.class)
.addModifiers(Modifier.PUBLIC);

customDecodeChunkMethod.beginControlFlow("for( int i = $L; i< $L; i++)", fieldCounter, Math.min(blockSize * chunkCounter + blockSize, recordSchema.getFields().size()))
.beginControlFlow("switch(fieldOrder[i].pos())");

for (; fieldCounter < Math.min(blockSize * chunkCounter + blockSize, recordSchema.getFields().size());
fieldCounter++) {
AvroSchemaField field = recordSchema.getField(fieldCounter);
String escapedFieldName = getFieldNameWithSuffix(field);
customDecodeChunkMethod.addStatement(String.format("case %s: ",fieldIndex++)+ getSerializedCustomDecodeBlock(config,
field.getSchemaOrRef().getSchema(), field.getSchemaOrRef().getSchema().type(),
"this." + replaceSingleDollarSignWithDouble(escapedFieldName),
"this." + replaceSingleDollarSignWithDouble(escapedFieldName), StringUtils.EMPTY_STRING))
.addStatement("break");
}
customDecodeChunkMethod
//switch
.endControlFlow()
//for
.endControlFlow();

chunkCounter++;
classBuilder.addMethod(customDecodeChunkMethod.build());
}
customDecodeBuilder
//switch
.endControlFlow()
//for
.endControlFlow()
//else
.endControlFlow();
customDecodeBuilder.endControlFlow();

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import java.util.Queue;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.apache.avro.Schema;
import org.apache.avro.reflect.Nullable;
import org.apache.avro.util.Utf8;

Expand All @@ -52,6 +53,7 @@ public class SpecificRecordGeneratorUtil {
public static final String AVRO_GEN_COMMENT = "GENERATED CODE by avro-util";

public static final ClassName CLASSNAME_SCHEMA = ClassName.get("org.apache.avro", "Schema");
public static final ClassName CLASSNAME_SCHEMA_FIELD = ClassName.get(Schema.Field.class);
public static final ClassName CLASSNAME_SPECIFIC_DATA = ClassName.get("org.apache.avro.specific", "SpecificData");
public static final ClassName CLASSNAME_SPECIFIC_RECORD = ClassName.get("org.apache.avro.specific", "SpecificRecord");
public static final ClassName CLASSNAME_SPECIFIC_RECORD_BASE = ClassName.get("org.apache.avro.specific", "SpecificRecordBase");
Expand Down
Loading