diff --git a/avrohugger-core/src/main/scala/format/specific/methods/GetsGenerator.scala b/avrohugger-core/src/main/scala/format/specific/methods/GetsGenerator.scala new file mode 100644 index 00000000..f6365596 --- /dev/null +++ b/avrohugger-core/src/main/scala/format/specific/methods/GetsGenerator.scala @@ -0,0 +1,63 @@ +package avrohugger +package format +package specific +package methods + +import converters.JavaConverter +import avrohugger.matchers.TypeMatcher +import treehugger.forest._ +import definitions._ +import treehugger.forest +import treehuggerDSL._ + +/** + * This generator is an alternative to GetGenerator. with these differences + * It is used for schemas with more than 254 fields which cannot have a constructor and have class members instead. + * A further issue with large numbers of fields is that the case class produced by GetGenerator.toDef + * can exceed the JVM limit of 65536 bytes resulting in a "Method too large" compilation error. + * This class generates a smaller get method by delegating to private methods + * Thus generator differs from GetGenerator in the following respects + * 1. It generates a list of function definitions + * 2. It generates a private method for each field that converts to an AnyRef + * 3. The match expression public def get(field$: Int): AnyRef delegates to the appropriate private method + */ +object GetsGenerator { + def toDefs( + indexedFields: List[IndexedField], + classSymbol: ClassSymbol, + typeMatcher: TypeMatcher, + targetScalaPartialVersion: String) :List[forest.DefDef]= { + + def fieldGetMethodName(field: IndexedField) = s"get${field.avroField.name}AnyRef" + def asGetMethod( + field: IndexedField, + classSymbol: ClassSymbol, + typeMatcher: TypeMatcher, + targetScalaPartialVersion: String) = { + + DEFINFER(fieldGetMethodName(field)).withType(AnyRefClass).withFlags(Flags.PRIVATE):= { + BLOCK(JavaConverter.convertToJava( + field.avroField.schema, + REF("getSchema").DOT("getFields").APPLY().DOT("get").APPLY(LIT(field.idx)).DOT("schema").APPLY(), + false, + REF(FieldRenamer.rename(field.avroField.name)), + classSymbol, + typeMatcher, + targetScalaPartialVersion)).AS(AnyRefClass) + } + } + + def asGetCase(field: IndexedField) = { + CASE (LIT(field.idx)) ==> REF(fieldGetMethodName(field)) + } + + val errorCase = CASE(WILDCARD) ==> NEW("org.apache.avro.AvroRuntimeException", LIT("Bad index")) + val casesGet = indexedFields.map(field => asGetCase(field)):+errorCase + val methodsDef: List[forest.DefDef] = indexedFields.map(field => asGetMethod(field, classSymbol, typeMatcher, targetScalaPartialVersion)) + + val getDef = DEF("get", AnyRefClass) withParams(PARAM("field$", IntClass)) := BLOCK( + REF("field$") withAnnots(ANNOT("switch")) MATCH(casesGet) + ) + getDef:: methodsDef + } +} diff --git a/avrohugger-core/src/main/scala/format/specific/trees/SpecificCaseClassTree.scala b/avrohugger-core/src/main/scala/format/specific/trees/SpecificCaseClassTree.scala index 246e3060..97a56dd4 100644 --- a/avrohugger-core/src/main/scala/format/specific/trees/SpecificCaseClassTree.scala +++ b/avrohugger-core/src/main/scala/format/specific/trees/SpecificCaseClassTree.scala @@ -16,6 +16,9 @@ import scala.jdk.CollectionConverters._ object SpecificCaseClassTree { + // The java platform does not allow parameter lists longer than 254 + val PLATFORM_MAX_PARAMS = 254 + def toCaseClassDef( classStore: ClassStore, namespace: Option[String], @@ -29,160 +32,172 @@ object SpecificCaseClassTree { val classSymbol = RootClass.newClass(schema.getName) val avroFields = schema.getFields().asScala.toList - val shouldGenerateSimpleClass = restrictedFields && avroFields.size > 22 - - // generate list of constructor parameters - val params: List[ValDef] = avroFields.map { f => - val fieldName = FieldRenamer.rename(f.name) - val fieldType = typeMatcher.toScalaType(classStore, namespace, f.schema) - val defaultValue = DefaultValueMatcher.getDefaultValue( + val tooManyParams = avroFields.length > PLATFORM_MAX_PARAMS + if(tooManyParams) { + SpecificClassPublicVarMembersTree.toTooManyFieldsForAConstructorClassDef( classStore, namespace, - f, + schema, typeMatcher, - fieldName == fieldType.safeToString) - VAR(fieldName, fieldType) := defaultValue - } + maybeBaseTrait, + maybeFlags, + targetScalaPartialVersion) + } else { - // extension - val baseClassName = "org.apache.avro.specific.SpecificRecordBase" - val baseClass = RootClass.newClass(baseClassName) + val shouldGenerateSimpleClass = restrictedFields && avroFields.size > 22 - // no-arg constructor: make arbitrary default if none is provided - val defaultParams: List[Tree] = avroFields.zip(params).map(f => { - val (avroField, defaultValue) = (f._1, f._2.rhs) - if (defaultValue == EmptyTree) - DefaultParamMatcher.asDefaultParam(classStore, avroField.schema, typeMatcher) - else - defaultValue - }) - val defThis = DEFTHIS.withParams(PARAM("")).tree := { - THIS APPLY(defaultParams) - } + // generate list of constructor parameters + val params: List[ValDef] = avroFields.map { f => + val fieldName = FieldRenamer.rename(f.name) + val fieldType = typeMatcher.toScalaType(classStore, namespace, f.schema) + val defaultValue = DefaultValueMatcher.getDefaultValue( + classStore, + namespace, + f, + typeMatcher, + fieldName == fieldType.safeToString) + VAR(fieldName, fieldType) := defaultValue + } - // methods - first add an index the the schema's fields - val indexedFields = avroFields.zipWithIndex.map(p => { - val avroField = p._1 - val index = p._2 - IndexedField(avroField, index) - }) - val defGetSchema = namespace.fold(GetSchemaGenerator(classSymbol).toDef)(ns => GetSchemaGenerator(RootClass.newClass(s"$ns.${classSymbol}")).toDef) - val defGet = GetGenerator.toDef(indexedFields, classSymbol, typeMatcher, targetScalaPartialVersion) - val defPut = PutGenerator.toDef( - classStore, - namespace, - indexedFields, - typeMatcher, - classSymbol, - targetScalaPartialVersion) + // extension + val baseClassName = "org.apache.avro.specific.SpecificRecordBase" + val baseClass = RootClass.newClass(baseClassName) - val maybeFlagsWithCaseClassFinal = - if (shouldGenerateSimpleClass) maybeFlags - else maybeFlags.map { flags => - if (flags.contains(Flags.FINAL)) flags - else flags :+ Flags.FINAL.toLong + // no-arg constructor: make arbitrary default if none is provided + val defaultParams: List[Tree] = avroFields.zip(params).map(f => { + val (avroField, defaultValue) = (f._1, f._2.rhs) + if (defaultValue == EmptyTree) + DefaultParamMatcher.asDefaultParam(classStore, avroField.schema, typeMatcher) + else + defaultValue + }) + val defThis = DEFTHIS.withParams(PARAM("")).tree := { + THIS APPLY (defaultParams) } + // methods - first add an index the the schema's fields + val indexedFields = avroFields.zipWithIndex.map(p => { + val avroField = p._1 + val index = p._2 + IndexedField(avroField, index) + }) + val defGetSchema = namespace.fold(GetSchemaGenerator(classSymbol).toDef)(ns => GetSchemaGenerator(RootClass.newClass(s"$ns.${classSymbol}")).toDef) + val defGet = GetGenerator.toDef(indexedFields, classSymbol, typeMatcher, targetScalaPartialVersion) + val defPut = PutGenerator.toDef( + classStore, + namespace, + indexedFields, + typeMatcher, + classSymbol, + targetScalaPartialVersion) - // define the class def with the members previously defined - // There could be base traits, flags, or both, and could have no fields - val caseClassDef = (maybeBaseTrait, maybeFlagsWithCaseClassFinal) match { - case (Some(baseTrait), Some(flags)) => - if (shouldGenerateSimpleClass) { - CLASSDEF(classSymbol) - .withFlags(flags:_*) - .withParams(params) - .withParents(baseClass) - .withParents(baseTrait) - } - else if (avroFields.nonEmpty) { - CASECLASSDEF(classSymbol) - .withFlags(flags:_*) - .withParams(params) - .withParents(baseClass) - .withParents(baseTrait) - } - else { // for "empty" records: empty params and no no-arg ctor - CASECLASSDEF(classSymbol) - .withFlags(flags:_*) - .withParams(PARAM("")) - .withParents(baseClass) - .withParents(baseTrait) - } - case (Some(baseTrait), None) => - if (!avroFields.isEmpty) { - CASECLASSDEF(classSymbol) - .withParams(params) - .withFlags(Flags.FINAL) - .withParents(baseClass) - .withParents(baseTrait) - } - else { // for "empty" records: empty params and no no-arg ctor - CASECLASSDEF(classSymbol) - .withParams(PARAM("")) - .withFlags(Flags.FINAL) - .withParents(baseClass) - .withParents(baseTrait) + val maybeFlagsWithCaseClassFinal = + if (shouldGenerateSimpleClass) maybeFlags + else maybeFlags.map { flags => + if (flags.contains(Flags.FINAL)) flags + else flags :+ Flags.FINAL.toLong } - case (None, Some(flags)) => - if (shouldGenerateSimpleClass) { - CLASSDEF(classSymbol) - .withFlags(flags:_*) - .withParams(params) - .withParents(baseClass) - .withParents("Serializable") - } - else if (avroFields.nonEmpty) { - CASECLASSDEF(classSymbol) - .withFlags(flags:_*) - .withParams(params) - .withParents(baseClass) - } - else { // for "empty" records: empty params and no no-arg ctor - CASECLASSDEF(classSymbol) - .withFlags(flags:_*) - .withParams(PARAM("")) - .withParents(baseClass) - } - case (None, None) => - if (shouldGenerateSimpleClass) { - CLASSDEF(classSymbol) - .withParams(params) - .withParents(baseClass) - .withParents("Serializable") - } - else if (!avroFields.isEmpty) { - CASECLASSDEF(classSymbol) - .withFlags(Flags.FINAL) - .withParams(params) - .withParents(baseClass) - } - else { // for "empty" records: empty params and no no-arg ctor - CASECLASSDEF(classSymbol) - .withParams(PARAM("")) - .withParents(baseClass) - } - } - val caseClassTree = { - // for "empty" records: empty params and no no-arg ctor - if (!avroFields.isEmpty) caseClassDef := BLOCK( - defThis, - defGet, - defPut, - defGetSchema) - else caseClassDef := BLOCK( - defGet, - defPut, - defGetSchema) - } - val treeWithScalaDoc = ScalaDocGenerator.docToScalaDoc( - Left(schema), - caseClassTree) + // define the class def with the members previously defined + // There could be base traits, flags, or both, and could have no fields + val caseClassDef = (maybeBaseTrait, maybeFlagsWithCaseClassFinal) match { + case (Some(baseTrait), Some(flags)) => + if (shouldGenerateSimpleClass) { + CLASSDEF(classSymbol) + .withFlags(flags: _*) + .withParams(params) + .withParents(baseClass) + .withParents(baseTrait) + } + else if (avroFields.nonEmpty) { + CASECLASSDEF(classSymbol) + .withFlags(flags: _*) + .withParams(params) + .withParents(baseClass) + .withParents(baseTrait) + } + else { // for "empty" records: empty params and no no-arg ctor + CASECLASSDEF(classSymbol) + .withFlags(flags: _*) + .withParams(PARAM("")) + .withParents(baseClass) + .withParents(baseTrait) + } + case (Some(baseTrait), None) => + if (!avroFields.isEmpty) { + CASECLASSDEF(classSymbol) + .withParams(params) + .withFlags(Flags.FINAL) + .withParents(baseClass) + .withParents(baseTrait) + } + else { // for "empty" records: empty params and no no-arg ctor + CASECLASSDEF(classSymbol) + .withParams(PARAM("")) + .withFlags(Flags.FINAL) + .withParents(baseClass) + .withParents(baseTrait) + } + case (None, Some(flags)) => + if (shouldGenerateSimpleClass) { + CLASSDEF(classSymbol) + .withFlags(flags: _*) + .withParams(params) + .withParents(baseClass) + .withParents("Serializable") + } + else if (avroFields.nonEmpty) { + CASECLASSDEF(classSymbol) + .withFlags(flags: _*) + .withParams(params) + .withParents(baseClass) + } + else { // for "empty" records: empty params and no no-arg ctor + CASECLASSDEF(classSymbol) + .withFlags(flags: _*) + .withParams(PARAM("")) + .withParents(baseClass) + } + case (None, None) => + if (shouldGenerateSimpleClass) { + CLASSDEF(classSymbol) + .withParams(params) + .withParents(baseClass) + .withParents("Serializable") + } + else if (!avroFields.isEmpty) { + CASECLASSDEF(classSymbol) + .withFlags(Flags.FINAL) + .withParams(params) + .withParents(baseClass) + } + else { // for "empty" records: empty params and no no-arg ctor + CASECLASSDEF(classSymbol) + .withParams(PARAM("")) + .withParents(baseClass) + } + } + + val caseClassTree = { + // for "empty" records: empty params and no no-arg ctor + if (!avroFields.isEmpty) caseClassDef := BLOCK( + defThis, + defGet, + defPut, + defGetSchema) + else caseClassDef := BLOCK( + defGet, + defPut, + defGetSchema) + } - treeWithScalaDoc + val treeWithScalaDoc = ScalaDocGenerator.docToScalaDoc( + Left(schema), + caseClassTree) + treeWithScalaDoc + } } diff --git a/avrohugger-core/src/main/scala/format/specific/trees/SpecificClassPublicVarMembersTree.scala b/avrohugger-core/src/main/scala/format/specific/trees/SpecificClassPublicVarMembersTree.scala new file mode 100644 index 00000000..8c342f55 --- /dev/null +++ b/avrohugger-core/src/main/scala/format/specific/trees/SpecificClassPublicVarMembersTree.scala @@ -0,0 +1,81 @@ +package avrohugger +package format +package specific +package trees + +import avrohugger.format.specific.methods._ +import avrohugger.matchers.{DefaultValueMatcher, TypeMatcher} +import avrohugger.stores._ +import treehugger.forest._ +import definitions._ +import org.apache.avro.Schema +import treehugger.forest +import treehuggerDSL._ + +import scala.jdk.CollectionConverters._ + +object SpecificClassPublicVarMembersTree { + + def toTooManyFieldsForAConstructorClassDef( + classStore: ClassStore, + namespace: Option[String], + schema: Schema, + typeMatcher: TypeMatcher, + maybeBaseTrait: Option[String], + maybeFlags: Option[List[Long]], + targetScalaPartialVersion: String): forest.ClassDef = { + + val classSymbol = RootClass.newClass(schema.getName) + val avroFields = schema.getFields().asScala.toList + + + // generate list of memberVars + val memberVars: List[ValDef] = avroFields.map { f => + val fieldName = FieldRenamer.rename(f.name) + val fieldType = typeMatcher.toScalaType(classStore, namespace, f.schema) + val defaultValue = DefaultValueMatcher.getDefaultValue( + classStore, + namespace, + f, + typeMatcher, + fieldName == fieldType.safeToString) + val rhs = if (defaultValue.isEmpty) WILDCARD else defaultValue + VAR(fieldName, fieldType) := rhs + } + + // extension + val baseClassName = "org.apache.avro.specific.SpecificRecordBase" + val baseClass = RootClass.newClass(baseClassName) + + // methods - first add an index the the schema's fields + val indexedFields = avroFields.zipWithIndex.map(p => { + val avroField = p._1 + val index = p._2 + IndexedField(avroField, index) + }) + val defGetSchema = namespace.fold(GetSchemaGenerator(classSymbol).toDef)(ns => GetSchemaGenerator(RootClass.newClass(s"$ns.${classSymbol}")).toDef) + val defGets = GetsGenerator.toDefs(indexedFields, classSymbol, typeMatcher, targetScalaPartialVersion) + val defPut = PutGenerator.toDef( + classStore, + namespace, + indexedFields, + typeMatcher, + classSymbol, + targetScalaPartialVersion) + + val flagsWithClassFinal: List[Long] = { + val flags = maybeFlags.toList.flatten + if (flags.contains(Flags.FINAL)) flags + else flags :+ Flags.FINAL.toLong + } + + val baseTrait = maybeBaseTrait.getOrElse("Serializable") + + val classDef = CLASSDEF(classSymbol) + .withFlags(flagsWithClassFinal: _*) + .withParents(baseClass) + .withParents(baseTrait) + classDef := BLOCK((memberVars ++ defGets ++ Seq(defPut, defGetSchema)):_*) + } + +} diff --git a/avrohugger-core/src/test/avro/MoreThan254Fields.avdl b/avrohugger-core/src/test/avro/MoreThan254Fields.avdl new file mode 100644 index 00000000..f77c2974 --- /dev/null +++ b/avrohugger-core/src/test/avro/MoreThan254Fields.avdl @@ -0,0 +1,270 @@ +@namespace("test.avdl") +protocol MoreThan254FieldsProtocol { + + enum SomeEnum { + yes, no, maybe + } + + /** Used to test Scala 2.10 support */ + record MoreThan254Fields { + string field01; + int field02; + double field03; + union {null, string} field04; + union {null, int} field05; + union {null, double} field06; + long field07; + string field08; + SomeEnum field09; + string field10; + string field11; + string field12; + string field13; + string field14; + int field15; + double field16; + string field17; + int field18; + double field19; + string fiel20; + int field21; + string field22; + string field23; + double field24; + string field25; + double field26; + string field27; + double field28; + string field29; + int field30; + int field31; + int field32; + int field33; + int field34; + int field35; + int field36; + int field37; + int field38; + int field39; + int field40; + int field41; + int field42; + int field43; + int field44; + int field45; + int field46; + int field47; + int field48; + int field49; + int field50; + int field51; + int field52; + int field53; + int field54; + int field55; + int field56; + int field57; + int field58; + int field59; + int field60; + int field61; + int field62; + int field63; + int field64; + int field65; + int field66; + int field67; + int field68; + int field69; + int field70; + int field71; + int field72; + int field73; + int field74; + int field75; + int field76; + int field77; + int field78; + int field79; + int field80; + int field81; + int field82; + int field83; + int field84; + int field85; + int field86; + int field87; + int field88; + int field89; + int field90; + int field91; + int field92; + int field93; + int field94; + int field95; + int field96; + int field97; + int field98; + int field99; + int field100; + int field101; + int field102; + int field103; + int field104; + int field105; + int field106; + int field107; + int field108; + int field109; + int field110; + int field111; + int field112; + int field113; + int field114; + int field115; + int field116; + int field117; + int field118; + int field119; + int field120; + int field121; + int field122; + int field123; + int field124; + int field125; + int field126; + int field127; + int field128; + int field129; + int field130; + int field131; + int field132; + int field133; + int field134; + int field135; + int field136; + int field137; + int field138; + int field139; + int field140; + int field141; + int field142; + int field143; + int field144; + int field145; + int field146; + int field147; + int field148; + int field149; + int field150; + int field151; + int field152; + int field153; + int field154; + int field155; + int field156; + int field157; + int field158; + int field159; + int field160; + int field161; + int field162; + int field163; + int field164; + int field165; + int field166; + int field167; + int field168; + int field169; + int field170; + int field171; + int field172; + int field173; + int field174; + int field175; + int field176; + int field177; + int field178; + int field179; + int field180; + int field181; + int field182; + int field183; + int field184; + int field185; + int field186; + int field187; + int field188; + int field189; + int field190; + int field191; + int field192; + int field193; + int field194; + int field195; + int field196; + int field197; + int field198; + int field199; + int field200; + int field201; + int field202; + int field203; + int field204; + int field205; + int field206; + int field207; + int field208; + int field209; + int field210; + int field211; + int field212; + int field213; + int field214; + int field215; + int field216; + int field217; + int field218; + int field219; + int field220; + int field221; + int field222; + int field223; + int field224; + int field225; + int field226; + int field227; + int field228; + int field229; + int field230; + int field231; + int field232; + int field233; + int field234; + int field235; + int field236; + int field237; + int field238; + int field239; + int field240; + int field241; + int field242; + int field243; + int field244; + int field245; + int field246; + int field247; + int field248; + int field249; + int field250; + int field251; + int field252; + int field253; + int field254; + int field255; + int field256; + int field257; + int field258; + int field259; + } +} diff --git a/avrohugger-core/src/test/avro/MoreThan254Fields.avsc b/avrohugger-core/src/test/avro/MoreThan254Fields.avsc new file mode 100644 index 00000000..39189268 --- /dev/null +++ b/avrohugger-core/src/test/avro/MoreThan254Fields.avsc @@ -0,0 +1,347 @@ +{ + "protocol" : "MoreThan254FieldsProtocol", + "namespace" : "test.avsc", + "type" : "record", + "name" : "MoreThan254Fields", + "doc" : "Used to test Scala 2.10 support", + "fields" : [ { + "name" : "field01", + "type" : "string" + }, { + "name":"field02", + "type":[ + "null", + { + "type":"fixed", + "name":"field02_fixed", + "size":16, + "logicalType":"decimal", + "precision":38, + "scale":0 + } + ], + "default":null + }, { + "name" : "field03", + "type" : "double" + }, { + "name" : "field04", + "type" : [ "null", "string" ] + }, { + "name" : "field05", + "type" : [ "null", "int" ] + }, { + "name" : "field06", + "type" : [ "null", "double" ] + }, { + "name" : "field07", + "type" : "long" + }, { + "name" : "field08", + "type":[ + "null", + "string" + ], + "doc":"", + "default":null + }, { + "name" : "field09", + "type" : { + "type" : "enum", + "name" : "SomeEnum", + "symbols" : [ "yes", "no", "maybe" ] + } + }, { + "name" : "field10", + "type" : "string" + }, { + "name" : "field11", + "type" : "string" + }, { + "name" : "field12", + "type" : "string" + }, { + "name" : "field13", + "type" : "string" + }, { + "name" : "field14", + "type" : "string" + }, { + "name" : "field15", + "type" : "int" + }, { + "name" : "field16", + "type" : "double" + }, { + "name" : "field17", + "type" : "string" + }, { + "name" : "field18", + "type" : "int" + }, { + "name" : "field19", + "type" : "double" + }, { + "name" : "fiel20", + "type" : "string" + }, { + "name" : "field21", + "type" : "int" + }, { + "name" : "field22", + "type" : "string" + }, { + "name" : "field23", + "type" : "string" + }, { + "name" : "field24", + "type" : "double" + }, { + "name" : "field25", + "type" : "string" + }, { + "name" : "field26", + "type" : "double" + }, { + "name" : "field27", + "type" : "string" + }, { + "name" : "field28", + "type" : "double" + }, { + "name" : "field29", + "type" : "string" + }, + {"name" : "field30", "type" : "int" }, + {"name" : "field31", "type" : "int" }, + {"name" : "field32", "type" : "int" }, + {"name" : "field33", "type" : "int" }, + {"name" : "field34", "type" : "int" }, + {"name" : "field35", "type" : "int" }, + {"name" : "field36", "type" : "int" }, + {"name" : "field37", "type" : "int" }, + {"name" : "field38", "type" : "int" }, + {"name" : "field39", "type" : "int" }, + {"name" : "field40", "type" : "int" }, + {"name" : "field41", "type" : "int" }, + {"name" : "field42", "type" : "int" }, + {"name" : "field43", "type" : "int" }, + {"name" : "field44", "type" : "int" }, + {"name" : "field45", "type" : "int" }, + {"name" : "field46", "type" : "int" }, + {"name" : "field47", "type" : "int" }, + {"name" : "field48", "type" : "int" }, + {"name" : "field49", "type" : "int" }, + {"name" : "field50", "type" : "int" }, + {"name" : "field51", "type" : "int" }, + {"name" : "field52", "type" : "int" }, + {"name" : "field53", "type" : "int" }, + {"name" : "field54", "type" : "int" }, + {"name" : "field55", "type" : "int" }, + {"name" : "field56", "type" : "int" }, + {"name" : "field57", "type" : "int" }, + {"name" : "field58", "type" : "int" }, + {"name" : "field59", "type" : "int" }, + {"name" : "field60", "type" : "int" }, + {"name" : "field61", "type" : "int" }, + {"name" : "field62", "type" : "int" }, + {"name" : "field63", "type" : "int" }, + {"name" : "field64", "type" : "int" }, + {"name" : "field65", "type" : "int" }, + {"name" : "field66", "type" : "int" }, + {"name" : "field67", "type" : "int" }, + {"name" : "field68", "type" : "int" }, + {"name" : "field69", "type" : "int" }, + {"name" : "field70", "type" : "int" }, + {"name" : "field71", "type" : "int" }, + {"name" : "field72", "type" : "int" }, + {"name" : "field73", "type" : "int" }, + {"name" : "field74", "type" : "int" }, + {"name" : "field75", "type" : "int" }, + {"name" : "field76", "type" : "int" }, + {"name" : "field77", "type" : "int" }, + {"name" : "field78", "type" : "int" }, + {"name" : "field79", "type" : "int" }, + {"name" : "field80", "type" : "int" }, + {"name" : "field81", "type" : "int" }, + {"name" : "field82", "type" : "int" }, + {"name" : "field83", "type" : "int" }, + {"name" : "field84", "type" : "int" }, + {"name" : "field85", "type" : "int" }, + {"name" : "field86", "type" : "int" }, + {"name" : "field87", "type" : "int" }, + {"name" : "field88", "type" : "int" }, + {"name" : "field89", "type" : "int" }, + {"name" : "field90", "type" : "int" }, + {"name" : "field91", "type" : "int" }, + {"name" : "field92", "type" : "int" }, + {"name" : "field93", "type" : "int" }, + {"name" : "field94", "type" : "int" }, + {"name" : "field95", "type" : "int" }, + {"name" : "field96", "type" : "int" }, + {"name" : "field97", "type" : "int" }, + {"name" : "field98", "type" : "int" }, + {"name" : "field99", "type" : "int" }, + {"name" : "field100", "type" : "int" }, + {"name" : "field101", "type" : "int" }, + {"name" : "field102", "type" : "int" }, + {"name" : "field103", "type" : "int" }, + {"name" : "field104", "type" : "int" }, + {"name" : "field105", "type" : "int" }, + {"name" : "field106", "type" : "int" }, + {"name" : "field107", "type" : "int" }, + {"name" : "field108", "type" : "int" }, + {"name" : "field109", "type" : "int" }, + {"name" : "field110", "type" : "int" }, + {"name" : "field111", "type" : "int" }, + {"name" : "field112", "type" : "int" }, + {"name" : "field113", "type" : "int" }, + {"name" : "field114", "type" : "int" }, + {"name" : "field115", "type" : "int" }, + {"name" : "field116", "type" : "int" }, + {"name" : "field117", "type" : "int" }, + {"name" : "field118", "type" : "int" }, + {"name" : "field119", "type" : "int" }, + {"name" : "field120", "type" : "int" }, + {"name" : "field121", "type" : "int" }, + {"name" : "field122", "type" : "int" }, + {"name" : "field123", "type" : "int" }, + {"name" : "field124", "type" : "int" }, + {"name" : "field125", "type" : "int" }, + {"name" : "field126", "type" : "int" }, + {"name" : "field127", "type" : "int" }, + {"name" : "field128", "type" : "int" }, + {"name" : "field129", "type" : "int" }, + {"name" : "field130", "type" : "int" }, + {"name" : "field131", "type" : "int" }, + {"name" : "field132", "type" : "int" }, + {"name" : "field133", "type" : "int" }, + {"name" : "field134", "type" : "int" }, + {"name" : "field135", "type" : "int" }, + {"name" : "field136", "type" : "int" }, + {"name" : "field137", "type" : "int" }, + {"name" : "field138", "type" : "int" }, + {"name" : "field139", "type" : "int" }, + {"name" : "field140", "type" : "int" }, + {"name" : "field141", "type" : "int" }, + {"name" : "field142", "type" : "int" }, + {"name" : "field143", "type" : "int" }, + {"name" : "field144", "type" : "int" }, + {"name" : "field145", "type" : "int" }, + {"name" : "field146", "type" : "int" }, + {"name" : "field147", "type" : "int" }, + {"name" : "field148", "type" : "int" }, + {"name" : "field149", "type" : "int" }, + {"name" : "field150", "type" : "int" }, + {"name" : "field151", "type" : "int" }, + {"name" : "field152", "type" : "int" }, + {"name" : "field153", "type" : "int" }, + {"name" : "field154", "type" : "int" }, + {"name" : "field155", "type" : "int" }, + {"name" : "field156", "type" : "int" }, + {"name" : "field157", "type" : "int" }, + {"name" : "field158", "type" : "int" }, + {"name" : "field159", "type" : "int" }, + {"name" : "field160", "type" : "int" }, + {"name" : "field161", "type" : "int" }, + {"name" : "field162", "type" : "int" }, + {"name" : "field163", "type" : "int" }, + {"name" : "field164", "type" : "int" }, + {"name" : "field165", "type" : "int" }, + {"name" : "field166", "type" : "int" }, + {"name" : "field167", "type" : "int" }, + {"name" : "field168", "type" : "int" }, + {"name" : "field169", "type" : "int" }, + {"name" : "field170", "type" : "int" }, + {"name" : "field171", "type" : "int" }, + {"name" : "field172", "type" : "int" }, + {"name" : "field173", "type" : "int" }, + {"name" : "field174", "type" : "int" }, + {"name" : "field175", "type" : "int" }, + {"name" : "field176", "type" : "int" }, + {"name" : "field177", "type" : "int" }, + {"name" : "field178", "type" : "int" }, + {"name" : "field179", "type" : "int" }, + {"name" : "field180", "type" : "int" }, + {"name" : "field181", "type" : "int" }, + {"name" : "field182", "type" : "int" }, + {"name" : "field183", "type" : "int" }, + {"name" : "field184", "type" : "int" }, + {"name" : "field185", "type" : "int" }, + {"name" : "field186", "type" : "int" }, + {"name" : "field187", "type" : "int" }, + {"name" : "field188", "type" : "int" }, + {"name" : "field189", "type" : "int" }, + {"name" : "field190", "type" : "int" }, + {"name" : "field191", "type" : "int" }, + {"name" : "field192", "type" : "int" }, + {"name" : "field193", "type" : "int" }, + {"name" : "field194", "type" : "int" }, + {"name" : "field195", "type" : "int" }, + {"name" : "field196", "type" : "int" }, + {"name" : "field197", "type" : "int" }, + {"name" : "field198", "type" : "int" }, + {"name" : "field199", "type" : "int" }, + {"name" : "field200", "type" : "int" }, + {"name" : "field201", "type" : "int" }, + {"name" : "field202", "type" : "int" }, + {"name" : "field203", "type" : "int" }, + {"name" : "field204", "type" : "int" }, + {"name" : "field205", "type" : "int" }, + {"name" : "field206", "type" : "int" }, + {"name" : "field207", "type" : "int" }, + {"name" : "field208", "type" : "int" }, + {"name" : "field209", "type" : "int" }, + {"name" : "field210", "type" : "int" }, + {"name" : "field211", "type" : "int" }, + {"name" : "field212", "type" : "int" }, + {"name" : "field213", "type" : "int" }, + {"name" : "field214", "type" : "int" }, + {"name" : "field215", "type" : "int" }, + {"name" : "field216", "type" : "int" }, + {"name" : "field217", "type" : "int" }, + {"name" : "field218", "type" : "int" }, + {"name" : "field219", "type" : "int" }, + {"name" : "field220", "type" : "int" }, + {"name" : "field221", "type" : "int" }, + {"name" : "field222", "type" : "int" }, + {"name" : "field223", "type" : "int" }, + {"name" : "field224", "type" : "int" }, + {"name" : "field225", "type" : "int" }, + {"name" : "field226", "type" : "int" }, + {"name" : "field227", "type" : "int" }, + {"name" : "field228", "type" : "int" }, + {"name" : "field229", "type" : "int" }, + {"name" : "field230", "type" : "int" }, + {"name" : "field231", "type" : "int" }, + {"name" : "field232", "type" : "int" }, + {"name" : "field233", "type" : "int" }, + {"name" : "field234", "type" : "int" }, + {"name" : "field235", "type" : "int" }, + {"name" : "field236", "type" : "int" }, + {"name" : "field237", "type" : "int" }, + {"name" : "field238", "type" : "int" }, + {"name" : "field239", "type" : "int" }, + {"name" : "field240", "type" : "int" }, + {"name" : "field241", "type" : "int" }, + {"name" : "field242", "type" : "int" }, + {"name" : "field243", "type" : "int" }, + {"name" : "field244", "type" : "int" }, + {"name" : "field245", "type" : "int" }, + {"name" : "field246", "type" : "int" }, + {"name" : "field247", "type" : "int" }, + {"name" : "field248", "type" : "int" }, + {"name" : "field249", "type" : "int" }, + {"name" : "field250", "type" : "int" }, + {"name" : "field251", "type" : "int" }, + {"name" : "field252", "type" : "int" }, + {"name" : "field253", "type" : "int" }, + {"name" : "field254", "type" : "int" }, + {"name" : "field255", "type" : "int" }, + {"name" : "field256", "type" : "int" }, + {"name" : "field257", "type" : "int" }, + {"name" : "field258", "type" : "int" }, + {"name" : "field259", "type" : "int" } + ], + "messages" : { } +} diff --git a/avrohugger-core/src/test/scala/specific/SpecificMoreThank254FieldsSpec.scala b/avrohugger-core/src/test/scala/specific/SpecificMoreThank254FieldsSpec.scala new file mode 100644 index 00000000..bc53ecd4 --- /dev/null +++ b/avrohugger-core/src/test/scala/specific/SpecificMoreThank254FieldsSpec.scala @@ -0,0 +1,57 @@ +package avrohugger +package test +package specific + +import avrohugger.format.SpecificRecord +import org.specs2._ + +import java.io.File + +/** + * Test generating classes when >254 fields. + */ +class SpecificMoreThank254FieldsSpec extends Specification { + + val avdlPath = "avrohugger-core/src/test/avro/MoreThan254Fields.avdl" + val avscPath = "avrohugger-core/src/test/avro/MoreThan254Fields.avsc" + + val generator = new Generator(SpecificRecord) + val outDirNonRestricted = generator.defaultOutputDir + "/specific/moreThan254" + + def is = + s2""" + A Specific Generator should + generate classes when there are more than 254 fields + with AVDLs $e1 + with AVSCs $e2 + with AVDL strings $e3 + with AVSC strings $e4 +""" + + def e1 = { + generator.fileToFile(new File(avdlPath), outDirNonRestricted) + val source = util.Util.readFile(s"$outDirNonRestricted/test/avdl/MoreThan254Fields.scala") + source must not contain("case class") + } + + def e2 = { + generator.fileToFile(new File(avscPath), outDirNonRestricted) + val source = util.Util.readFile(s"$outDirNonRestricted/test/avsc/MoreThan254Fields.scala") + source must not contain("case class") + } + + def e3 = { + val inputString = util.Util.readFile(avdlPath) + generator.stringToFile(inputString, outDirNonRestricted) + val source = util.Util.readFile(s"$outDirNonRestricted/test/avdl/MoreThan254Fields.scala") + source must not contain("case class") + } + + def e4 = { + val inputString = util.Util.readFile(avscPath) + generator.stringToFile(inputString, outDirNonRestricted) + val source = util.Util.readFile(s"$outDirNonRestricted/test/avsc/MoreThan254Fields.scala") + source must not contain("case class") + } + +}