From 39d884c1577470f31a2b27d6f0ccbebd86d7b2bd Mon Sep 17 00:00:00 2001 From: Karthik Ramgopal Date: Thu, 11 Jan 2024 14:38:30 -0800 Subject: [PATCH] Remove some concurrency and performance bottlenecks in SpecificRecordGenerator (#531) * Make java file write wait by using reduce instead of count * Remove unused pool * Cleanup unused imports * Make some shared global objects thread safe for concurrent access/modification * Remove some concurrency and performance bottlenecks in SpecificRecordGenerator --------- Co-authored-by: Karthik Ramgopal --- .../codegen/own/AvroUtilCodeGenOp.java | 2 +- .../codegen/SpecificRecordClassGenerator.java | 168 ++++++++---------- .../codegen/SpecificRecordGeneratorUtil.java | 39 +--- 3 files changed, 75 insertions(+), 134 deletions(-) diff --git a/avro-builder/builder/src/main/java/com/linkedin/avroutil1/builder/operations/codegen/own/AvroUtilCodeGenOp.java b/avro-builder/builder/src/main/java/com/linkedin/avroutil1/builder/operations/codegen/own/AvroUtilCodeGenOp.java index f2aec087a..001b14833 100644 --- a/avro-builder/builder/src/main/java/com/linkedin/avroutil1/builder/operations/codegen/own/AvroUtilCodeGenOp.java +++ b/avro-builder/builder/src/main/java/com/linkedin/avroutil1/builder/operations/codegen/own/AvroUtilCodeGenOp.java @@ -250,9 +250,9 @@ public void run(OperationContext opContext) throws Exception { throw new IllegalStateException("unable to create output folder " + outputFolder); } final Path outputDirectoryPath = outputFolder.toPath(); + final SpecificRecordClassGenerator generator = new SpecificRecordClassGenerator(); int totalGeneratedClasses = allNamedSchemaList.parallelStream().map(allNamedSchemas -> { - SpecificRecordClassGenerator generator = new SpecificRecordClassGenerator(); HashSet alreadyGeneratedSchemaNames = new HashSet<>(); List generatedSpecificClasses = new ArrayList<>(allNamedSchemas.size()); for (AvroNamedSchema namedSchema : allNamedSchemas) { diff --git a/avro-codegen/src/main/java/com/linkedin/avroutil1/codegen/SpecificRecordClassGenerator.java b/avro-codegen/src/main/java/com/linkedin/avroutil1/codegen/SpecificRecordClassGenerator.java index 528989b28..ac7b7f64d 100644 --- a/avro-codegen/src/main/java/com/linkedin/avroutil1/codegen/SpecificRecordClassGenerator.java +++ b/avro-codegen/src/main/java/com/linkedin/avroutil1/codegen/SpecificRecordClassGenerator.java @@ -63,7 +63,22 @@ public class SpecificRecordClassGenerator { private static final Logger LOGGER = LoggerFactory.getLogger(SpecificRecordClassGenerator.class); - private int sizeValCounter = -1; + private static class Counter { + + private int _counter = -1; + + void increment() { + _counter++; + } + + int get() { + return _counter; + } + + void reset() { + _counter = -1; + } + } /*** * Generates Java class for top level schema. @@ -332,6 +347,8 @@ private void addCommonClassComponents(SpecificRecordGenerationConfig config, Typ protected JavaFile generateSpecificRecord(AvroRecordSchema recordSchema, SpecificRecordGenerationConfig config) throws ClassNotFoundException { + Counter sizeValCounter = new Counter(); + // Default to broad compatibility config if null if(config == null) { config = SpecificRecordGenerationConfig.BROAD_COMPATIBILITY; @@ -469,9 +486,6 @@ protected JavaFile generateSpecificRecord(AvroRecordSchema recordSchema, Specifi } classBuilder.addField(fieldBuilder.build()); - //if declared schema, use fully qualified class (no import) - addFullyQualified(field, config.getDefaultFieldStringRepresentation()); - //getters classBuilder.addMethod(getGetterMethodSpec(field, config)); @@ -506,7 +520,7 @@ protected JavaFile generateSpecificRecord(AvroRecordSchema recordSchema, Specifi .addParameter(SpecificRecordGeneratorUtil.CLASSNAME_ENCODER, "out") .addException(IOException.class) .addModifiers(Modifier.PUBLIC); - addCustomEncodeMethod(customEncodeBuilder, recordSchema, config); + addCustomEncodeMethod(customEncodeBuilder, recordSchema, config, sizeValCounter); classBuilder.addMethod(customEncodeBuilder.build()); //customDecode @@ -515,7 +529,7 @@ protected JavaFile generateSpecificRecord(AvroRecordSchema recordSchema, Specifi .addParameter(SpecificRecordGeneratorUtil.CLASSNAME_RESOLVING_DECODER, "in") .addException(IOException.class) .addModifiers(Modifier.PUBLIC); - addCustomDecodeMethod(customDecodeBuilder, recordSchema, config, classBuilder); + addCustomDecodeMethod(customDecodeBuilder, recordSchema, config, classBuilder, sizeValCounter); classBuilder.addMethod(customDecodeBuilder.build()); } @@ -531,8 +545,6 @@ protected JavaFile generateSpecificRecord(AvroRecordSchema recordSchema, Specifi throw new ClassNotFoundException("Exception while creating Builder: %s", e); } - addDefaultFullyQualifiedClassesForSpecificRecord(classBuilder, recordSchema); - //create file object TypeSpec classSpec = classBuilder.build(); return JavaFile.builder(recordSchema.getNamespace(), classSpec) @@ -548,7 +560,6 @@ private void addAllArgsConstructor(AvroRecordSchema recordSchema, for (AvroSchemaField field : recordSchema.getFields()) { //if declared schema, use fully qualified class (no import) String escapedFieldName = getFieldNameWithSuffix(field); - addFullyQualified(field, defaultFieldStringRepresentation); allArgsConstructorBuilder.addParameter(getParameterSpecForField(field, defaultMethodStringRepresentation, true)); if(SpecificRecordGeneratorUtil.isNullUnionOf(AvroType.STRING, field.getSchema())) { allArgsConstructorBuilder.addStatement( @@ -954,10 +965,10 @@ private String getMethodNameForFieldWithPrefix(String prefix, String fieldName) } private void addCustomDecodeMethod(MethodSpec.Builder customDecodeBuilder, AvroRecordSchema recordSchema, - SpecificRecordGenerationConfig config, TypeSpec.Builder classBuilder) { + SpecificRecordGenerationConfig config, TypeSpec.Builder classBuilder, Counter sizeValCounter) { int blockSize = 25, fieldCounter = 0, chunkCounter = 0; // reset var counter - sizeValCounter = -1; + sizeValCounter.reset(); customDecodeBuilder.addStatement( "org.apache.avro.Schema.Field[] fieldOrder = (com.linkedin.avroutil1.compatibility.AvroCompatibilityHelper.areFieldsReordered(getSchema())) ? in.readFieldOrder() : null") .beginControlFlow("if (fieldOrder == null)"); @@ -977,14 +988,15 @@ private void addCustomDecodeMethod(MethodSpec.Builder customDecodeBuilder, AvroR String escapedFieldName = getFieldNameWithSuffix(field); customDecodeChunkMethod.addStatement(getSerializedCustomDecodeBlock(config, field.getSchemaOrRef().getSchema(), field.getSchemaOrRef().getSchema().type(), "this." + replaceSingleDollarSignWithDouble(escapedFieldName), - "this." + replaceSingleDollarSignWithDouble(escapedFieldName), StringUtils.EMPTY_STRING)); + "this." + replaceSingleDollarSignWithDouble(escapedFieldName), StringUtils.EMPTY_STRING, + sizeValCounter)); } chunkCounter++; classBuilder.addMethod(customDecodeChunkMethod.build()); } // reset var counter - sizeValCounter = -1; + sizeValCounter.reset(); int fieldIndex = 0; fieldCounter = 0; chunkCounter = 0; @@ -1012,7 +1024,8 @@ private void addCustomDecodeMethod(MethodSpec.Builder customDecodeBuilder, AvroR 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)) + "this." + replaceSingleDollarSignWithDouble(escapedFieldName), StringUtils.EMPTY_STRING, + sizeValCounter)) .addStatement("break"); } customDecodeChunkMethod @@ -1031,7 +1044,8 @@ private void addCustomDecodeMethod(MethodSpec.Builder customDecodeBuilder, AvroR private String getSerializedCustomDecodeBlock(SpecificRecordGenerationConfig config, - AvroSchema fieldSchema, AvroType fieldType, String fieldName, String schemaFieldName, String arrayOption) { + AvroSchema fieldSchema, AvroType fieldType, String fieldName, String schemaFieldName, String arrayOption, + Counter sizeValCounter) { String serializedCodeBlock = ""; CodeBlock.Builder codeBlockBuilder = CodeBlock.builder(); switch (fieldType) { @@ -1080,12 +1094,12 @@ private String getSerializedCustomDecodeBlock(SpecificRecordGenerationConfig con serializedCodeBlock = codeBlockBuilder.build().toString(); break; case ARRAY: - sizeValCounter++; + sizeValCounter.increment(); - String arrayVarName = getArrayVarName(); - String gArrayVarName = getGArrayVarName(); - String arraySizeVarName = getSizeVarName(); - String arrayElementVarName = getElementVarName(); + String arrayVarName = getArrayVarName(sizeValCounter.get()); + String gArrayVarName = getGArrayVarName(sizeValCounter.get()); + String arraySizeVarName = getSizeVarName(sizeValCounter.get()); + String arrayElementVarName = getElementVarName(sizeValCounter.get()); AvroSchema arrayItemSchema = ((AvroArraySchema) fieldSchema).getValueSchema(); Class arrayItemClass = SpecificRecordGeneratorUtil.getJavaClassForAvroTypeIfApplicable(arrayItemSchema.type(), @@ -1117,7 +1131,8 @@ private String getSerializedCustomDecodeBlock(SpecificRecordGenerationConfig con codeBlockBuilder.addStatement( getSerializedCustomDecodeBlock(config, arrayItemSchema, arrayItemSchema.type(), arrayElementVarName, - schemaFieldName, arrayOption + SpecificRecordGeneratorUtil.ARRAY_GET_ELEMENT_TYPE)); + schemaFieldName, arrayOption + SpecificRecordGeneratorUtil.ARRAY_GET_ELEMENT_TYPE, + sizeValCounter)); codeBlockBuilder.addStatement("$L.add($L)", arrayVarName, arrayElementVarName) .endControlFlow() .endControlFlow() @@ -1128,11 +1143,11 @@ private String getSerializedCustomDecodeBlock(SpecificRecordGenerationConfig con break; case MAP: - sizeValCounter++; - String mapVarName = getMapVarName(); - String mapKeyVarName = getKeyVarName(); - String mapSizeVarName = getSizeVarName(); - String mapValueVarName = getValueVarName(); + sizeValCounter.increment(); + String mapVarName = getMapVarName(sizeValCounter.get()); + String mapKeyVarName = getKeyVarName(sizeValCounter.get()); + String mapSizeVarName = getSizeVarName(sizeValCounter.get()); + String mapValueVarName = getValueVarName(sizeValCounter.get()); AvroType mapItemAvroType = ((AvroMapSchema) fieldSchema).getValueSchema().type(); Class mapItemClass = SpecificRecordGeneratorUtil.getJavaClassForAvroTypeIfApplicable(mapItemAvroType, config.getDefaultFieldStringRepresentation(), true); @@ -1159,11 +1174,13 @@ private String getSerializedCustomDecodeBlock(SpecificRecordGenerationConfig con .addStatement("$T $L = null", CharSequence.class, mapKeyVarName) .addStatement( getSerializedCustomDecodeBlock(config, ((AvroMapSchema) fieldSchema).getValueSchema(), AvroType.STRING, - mapKeyVarName, schemaFieldName, arrayOption + SpecificRecordGeneratorUtil.MAP_GET_VALUE_TYPE)) + mapKeyVarName, schemaFieldName, arrayOption + SpecificRecordGeneratorUtil.MAP_GET_VALUE_TYPE, + sizeValCounter)) .addStatement("$T $L = null", ((mapItemClass != null) ? mapItemClass : mapItemClassName), mapValueVarName) .addStatement(getSerializedCustomDecodeBlock(config, ((AvroMapSchema) fieldSchema).getValueSchema(), ((AvroMapSchema) fieldSchema).getValueSchema().type(), mapValueVarName, schemaFieldName, - arrayOption + SpecificRecordGeneratorUtil.MAP_GET_VALUE_TYPE)); + arrayOption + SpecificRecordGeneratorUtil.MAP_GET_VALUE_TYPE, + sizeValCounter)); codeBlockBuilder.addStatement("$L.put($L,$L)", mapVarName, mapKeyVarName, mapValueVarName) .endControlFlow() @@ -1184,7 +1201,8 @@ private String getSerializedCustomDecodeBlock(SpecificRecordGenerationConfig con codeBlockBuilder.addStatement("case $L: ", i); codeBlockBuilder.addStatement( getSerializedCustomDecodeBlock(config, unionMember.getSchema(), unionMember.getSchema().type(), - fieldName, schemaFieldName, arrayOption + ".getTypes().get(" + i + ")")); + fieldName, schemaFieldName, arrayOption + ".getTypes().get(" + i + ")", + sizeValCounter)); if (unionMember.getSchema().type().equals(AvroType.NULL)) { codeBlockBuilder.addStatement("$L = null", fieldName); } @@ -1221,16 +1239,17 @@ private boolean hasCustomCoders(AvroRecordSchema recordSchema) { } private void addCustomEncodeMethod(MethodSpec.Builder customEncodeBuilder, AvroRecordSchema recordSchema, - SpecificRecordGenerationConfig config) { + SpecificRecordGenerationConfig config, Counter sizeValCounter) { for(AvroSchemaField field : recordSchema.getFields()) { String escapedFieldName = getFieldNameWithSuffix(field); customEncodeBuilder.addStatement(getSerializedCustomEncodeBlock(config, field.getSchemaOrRef().getSchema(), - field.getSchemaOrRef().getSchema().type(), "this."+replaceSingleDollarSignWithDouble(escapedFieldName))); + field.getSchemaOrRef().getSchema().type(), "this."+replaceSingleDollarSignWithDouble(escapedFieldName), + sizeValCounter)); } } private String getSerializedCustomEncodeBlock(SpecificRecordGenerationConfig config, - AvroSchema fieldSchema, AvroType fieldType, String fieldName) { + AvroSchema fieldSchema, AvroType fieldType, String fieldName, Counter sizeValCounter) { String serializedCodeBlock = ""; CodeBlock.Builder codeBlockBuilder = CodeBlock.builder(); switch (fieldType) { @@ -1282,31 +1301,25 @@ private String getSerializedCustomEncodeBlock(SpecificRecordGenerationConfig con .toString(); break; case ARRAY: - sizeValCounter++; - String lengthVarName = getSizeVarName(); - String actualSizeVarName = getActualSizeVarName(); + sizeValCounter.increment(); + String lengthVarName = getSizeVarName(sizeValCounter.get()); + String actualSizeVarName = getActualSizeVarName(sizeValCounter.get()); AvroType arrayItemAvroType = ((AvroArraySchema) fieldSchema).getValueSchema().type(); Class arrayItemClass = SpecificRecordGeneratorUtil.getJavaClassForAvroTypeIfApplicable(arrayItemAvroType, config.getDefaultFieldStringRepresentation(), true); TypeName arrayItemTypeName = SpecificRecordGeneratorUtil.getTypeName(((AvroArraySchema) fieldSchema).getValueSchema(), arrayItemAvroType, true, config.getDefaultFieldStringRepresentation()); - if(arrayItemClass != null) { - SpecificRecordGeneratorUtil.fullyQualifiedClassesInRecord.add(arrayItemClass.getName()); - } else { - SpecificRecordGeneratorUtil.fullyQualifiedClassesInRecord.add(arrayItemTypeName.toString()); - } - codeBlockBuilder.addStatement("long $L = ((java.util.List)$L).size()", lengthVarName, fieldName) .addStatement("out.writeArrayStart()") .addStatement("out.setItemCount($L)", lengthVarName) .addStatement("long $L = 0", actualSizeVarName) .beginControlFlow("for ($1T $2L: (java.util.List<$1T>)$3L)", arrayItemClass != null ? arrayItemClass : arrayItemTypeName, - getElementVarName(), fieldName) + getElementVarName(sizeValCounter.get()), fieldName) .addStatement("$L++", actualSizeVarName) .addStatement("out.startItem()") .addStatement(getSerializedCustomEncodeBlock(config, ((AvroArraySchema) fieldSchema).getValueSchema(), - arrayItemAvroType, getElementVarName())) + arrayItemAvroType, getElementVarName(sizeValCounter.get()), sizeValCounter)) .endControlFlow(); codeBlockBuilder @@ -1319,11 +1332,11 @@ arrayItemAvroType, getElementVarName())) serializedCodeBlock = codeBlockBuilder.build().toString(); break; case MAP: - sizeValCounter++; - lengthVarName = getSizeVarName(); - actualSizeVarName = getActualSizeVarName(); - String elementVarName = getElementVarName(); - String valueVarName = getValueVarName(); + sizeValCounter.increment(); + lengthVarName = getSizeVarName(sizeValCounter.get()); + actualSizeVarName = getActualSizeVarName(sizeValCounter.get()); + String elementVarName = getElementVarName(sizeValCounter.get()); + String valueVarName = getValueVarName(sizeValCounter.get()); codeBlockBuilder .addStatement("long $L = ((Map)$L).size()", lengthVarName, fieldName) @@ -1351,7 +1364,7 @@ arrayItemAvroType, getElementVarName())) codeBlockBuilder.addStatement( getSerializedCustomEncodeBlock(config, ((AvroMapSchema) fieldSchema).getValueSchema(), mapItemAvroType, - valueVarName)) + valueVarName, sizeValCounter)) .endControlFlow() .addStatement("out.writeMapEnd()") .beginControlFlow("if ($L != $L)", actualSizeVarName, lengthVarName) @@ -1391,7 +1404,8 @@ arrayItemAvroType, getElementVarName())) } codeBlockBuilder.addStatement("out.writeIndex($L)", i) .addStatement( - getSerializedCustomEncodeBlock(config, unionMemberSchema, unionMemberSchema.type(), fieldName)); + getSerializedCustomEncodeBlock(config, unionMemberSchema, unionMemberSchema.type(), fieldName, + sizeValCounter)); } codeBlockBuilder.endControlFlow() .beginControlFlow("else") @@ -1411,39 +1425,35 @@ arrayItemAvroType, getElementVarName())) return SpecificRecordGeneratorUtil.SINGLE_DOLLAR_SIGN_REGEX.matcher(serializedCodeBlock).replaceAll("\\$\\$"); } - private String getKeyVarName() { + private String getKeyVarName(int sizeValCounter) { return "k" + sizeValCounter; } - private String getValueVarName() { + private String getValueVarName(int sizeValCounter) { return "v" + sizeValCounter; } - private String getElementVarName() { + private String getElementVarName(int sizeValCounter) { return "e" + sizeValCounter; } - private String getElementVarNameForCounter(int counter) { - return "e" + counter; - } - - private String getSizeVarName() { + private String getSizeVarName(int sizeValCounter) { return "size" + sizeValCounter; } - private String getActualSizeVarName() { + private String getActualSizeVarName(int sizeValCounter) { return "actualSize" + sizeValCounter; } - private String getArrayVarName() { + private String getArrayVarName(int sizeValCounter) { return "a" + sizeValCounter; } - private String getGArrayVarName() { + private String getGArrayVarName(int sizeValCounter) { return "ga" + sizeValCounter; } - private String getMapVarName() { + private String getMapVarName(int sizeValCounter) { return "m" + sizeValCounter; } @@ -1645,40 +1655,6 @@ private void addGetByIndexMethod(TypeSpec.Builder classBuilder, AvroRecordSchema classBuilder.addMethod(methodSpecBuilder.addCode(switchBuilder.build()).build()); } - private void addDefaultFullyQualifiedClassesForSpecificRecord(TypeSpec.Builder classBuilder, - AvroRecordSchema recordSchema) { - - List fieldNamesInRecord = - recordSchema.getFields().stream().map(AvroSchemaField::getName).collect(Collectors.toList()); - - for(String classToQualify: SpecificRecordGeneratorUtil.fullyQualifiedClassesInRecord) { - String[] splitClassName = classToQualify.split("\\."); - if(!fieldNamesInRecord.contains(splitClassName[0])){ - classBuilder.alwaysQualify(splitClassName[splitClassName.length-1]); - } - } - - for(TypeName classNameToQualify: SpecificRecordGeneratorUtil.fullyQualifiedClassNamesInRecord) { - - if(!fieldNamesInRecord.contains(classNameToQualify.toString().split("\\.")[0])){ - String[] fullyQualifiedNameArray = classNameToQualify.toString().split("\\."); - classBuilder.alwaysQualify(fullyQualifiedNameArray[fullyQualifiedNameArray.length-1]); - } - } - } - - private void addFullyQualified(AvroSchemaField field, AvroJavaStringRepresentation defaultStringRep) { - if(field.getSchemaOrRef().getSchema() != null) { - Class fieldClass = SpecificRecordGeneratorUtil.getJavaClassForAvroTypeIfApplicable(field.getSchemaOrRef().getSchema().type(), defaultStringRep, false); - if (fieldClass != null) { - SpecificRecordGeneratorUtil.fullyQualifiedClassesInRecord.add(fieldClass.getName()); - } else { - SpecificRecordGeneratorUtil.fullyQualifiedClassNamesInRecord.add( - SpecificRecordGeneratorUtil.getTypeName(field.getSchemaOrRef().getSchema(), field.getSchemaOrRef().getSchema().type(), true, defaultStringRep)); - } - } - } - private MethodSpec getOverloadedSetterSpecIfStringField(AvroSchemaField field, SpecificRecordGenerationConfig config) { MethodSpec.Builder stringSetter = null; diff --git a/avro-codegen/src/main/java/com/linkedin/avroutil1/codegen/SpecificRecordGeneratorUtil.java b/avro-codegen/src/main/java/com/linkedin/avroutil1/codegen/SpecificRecordGeneratorUtil.java index b6040203e..be5a975b1 100644 --- a/avro-codegen/src/main/java/com/linkedin/avroutil1/codegen/SpecificRecordGeneratorUtil.java +++ b/avro-codegen/src/main/java/com/linkedin/avroutil1/codegen/SpecificRecordGeneratorUtil.java @@ -6,7 +6,6 @@ package com.linkedin.avroutil1.codegen; -import com.linkedin.avroutil1.compatibility.CompatibleSpecificRecordBuilderBase; import com.linkedin.avroutil1.model.AvroArraySchema; import com.linkedin.avroutil1.model.AvroEnumSchema; import com.linkedin.avroutil1.model.AvroFixedSchema; @@ -23,14 +22,8 @@ import com.squareup.javapoet.ClassName; import com.squareup.javapoet.ParameterizedTypeName; import com.squareup.javapoet.TypeName; -import java.io.IOException; -import java.io.ObjectInput; -import java.io.ObjectOutput; import java.nio.ByteBuffer; import java.util.ArrayList; -import java.util.Arrays; -import java.util.ConcurrentModificationException; -import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; @@ -66,34 +59,8 @@ public class SpecificRecordGeneratorUtil { public static final ClassName CLASSNAME_FIXED_SIZE = ClassName.get("org.apache.avro.specific", "FixedSize"); public static final ClassName CLASSNAME_SPECIFIC_FIXED = ClassName.get("org.apache.avro.specific", "SpecificFixed"); - - public static String ARRAY_GET_ELEMENT_TYPE = ".getElementType()"; - public static String MAP_GET_VALUE_TYPE = ".getValueType()"; - - public static HashSet fullyQualifiedClassNamesInRecord = new HashSet<>(); - - public static HashSet fullyQualifiedClassesInRecord = new HashSet<>(Arrays.asList( - CLASSNAME_DATUM_READER.canonicalName(), - CLASSNAME_DATUM_WRITER.canonicalName(), - CLASSNAME_ENCODER.canonicalName(), - CLASSNAME_RESOLVING_DECODER.canonicalName(), - CLASSNAME_SPECIFIC_DATA.canonicalName(), - CLASSNAME_SPECIFIC_DATUM_READER.canonicalName(), - CLASSNAME_SPECIFIC_DATUM_WRITER.canonicalName(), - CLASSNAME_SPECIFIC_RECORD.canonicalName(), - CLASSNAME_SPECIFIC_RECORD_BASE.canonicalName(), - IOException.class.getName(), - Exception.class.getName(), - ObjectInput.class.getName(), - ObjectOutput.class.getName(), - String.class.getName(), - Object.class.getName(), - ConcurrentModificationException.class.getName(), - IllegalArgumentException.class.getName(), - IndexOutOfBoundsException.class.getName(), - HashMap.class.getName(), - CompatibleSpecificRecordBuilderBase.class.getName() - )); + public static final String ARRAY_GET_ELEMENT_TYPE = ".getElementType()"; + public static final String MAP_GET_VALUE_TYPE = ".getValueType()"; private SpecificRecordGeneratorUtil(){} @@ -204,7 +171,6 @@ public static TypeName getTypeName(AvroSchema fieldSchema, AvroType avroType, bo if (valueClass == null) { TypeName parameterTypeName = getTypeName(arraySchema.getValueSchema(), arraySchema.getValueSchema().type(), true, defaultStringRepresentation); - fullyQualifiedClassesInRecord.add(parameterTypeName.toString()); className = ParameterizedTypeName.get(ClassName.get(List.class), parameterTypeName); } else { className = ParameterizedTypeName.get(List.class, valueClass); @@ -218,7 +184,6 @@ public static TypeName getTypeName(AvroSchema fieldSchema, AvroType avroType, bo //complex map is allowed if (mapValueClass == null) { TypeName mapValueTypeName = getTypeName(mapSchema.getValueSchema(), mapSchema.getValueSchema().type(), true, defaultStringRepresentation); - fullyQualifiedClassesInRecord.add(mapValueTypeName.toString()); className = ParameterizedTypeName.get(ClassName.get(Map.class), TypeName.get(mapKeyClass), mapValueTypeName); } else {