19 using System.Collections.Generic;
21 using System.Reflection;
24 using System.CodeDom.Compiler;
25 using Microsoft.CSharp;
40 public IList<Schema>
Schemas {
get;
private set; }
45 public IList<Protocol>
Protocols {
get;
private set; }
50 protected Dictionary<string, CodeNamespace>
namespaceLookup =
new Dictionary<string, CodeNamespace>(StringComparer.Ordinal);
57 this.
Schemas =
new List<Schema>();
86 if (
string.IsNullOrEmpty(name))
87 throw new ArgumentNullException(
"name",
"name cannot be null.");
89 CodeNamespace ns =
null;
125 foreach (KeyValuePair<SchemaName, NamedSchema> sn
in names)
127 switch (sn.Value.Tag)
134 throw new CodeGenException(
"Names in schema should only be of type NamedSchema, type found " + sn.Value.Tag);
148 foreach (KeyValuePair<SchemaName, NamedSchema> sn
in names)
150 switch (sn.Value.Tag)
157 throw new CodeGenException(
"Names in protocol should only be of type NamedSchema, type found " + sn.Value.Tag);
221 foreach (
Field field
in rs.Fields)
227 addName(asc.ItemSchema, names);
232 addName(ms.ValueSchema, names);
237 foreach (
Schema usc
in us.Schemas)
254 if (
null == fixedSchema)
throw new CodeGenException(
"Unable to cast schema into a fixed");
256 CodeTypeDeclaration ctd =
new CodeTypeDeclaration();
259 ctd.IsPartial =
true;
260 ctd.Attributes = MemberAttributes.Public;
261 ctd.BaseTypes.Add(
"SpecificFixed");
267 string sizefname =
"fixedSize";
268 var ctrfield =
new CodeTypeReference(typeof(uint));
269 var codeField =
new CodeMemberField(ctrfield, sizefname);
270 codeField.Attributes = MemberAttributes.Private | MemberAttributes.Static;
271 codeField.InitExpression =
new CodePrimitiveExpression(fixedSchema.
Size);
272 ctd.Members.Add(codeField);
275 var fieldRef =
new CodeFieldReferenceExpression(
new CodeThisReferenceExpression(), sizefname);
276 var
property =
new CodeMemberProperty();
277 property.Attributes = MemberAttributes.Public | MemberAttributes.Static;
278 property.Name =
"FixedSize";
279 property.Type = ctrfield;
280 property.GetStatements.Add(
new CodeMethodReturnStatement(
new CodeTypeReferenceExpression(schema.
Name +
"." + sizefname)));
281 ctd.Members.Add(property);
284 CodeConstructor cc =
new CodeConstructor();
285 cc.Attributes = MemberAttributes.Public;
286 cc.BaseConstructorArgs.Add(
new CodeVariableReferenceExpression(sizefname));
290 if (
string.IsNullOrEmpty(nspace))
293 codens.Types.Add(ctd);
304 if (
null == enumschema)
throw new CodeGenException(
"Unable to cast schema into an enum");
308 ctd.Attributes = MemberAttributes.Public;
310 foreach (
string symbol
in enumschema.Symbols)
313 throw new CodeGenException(
"Enum symbol " + symbol +
" is a C# reserved keyword");
314 CodeMemberField field =
new CodeMemberField(typeof(
int), symbol);
315 ctd.Members.Add(field);
318 string nspace = enumschema.Namespace;
319 if (
string.IsNullOrEmpty(nspace))
320 throw new CodeGenException(
"Namespace required for enum schema " + enumschema.Name);
323 codens.Types.Add(ctd);
331 var ctd =
new CodeTypeDeclaration(protocolNameMangled);
332 ctd.TypeAttributes = TypeAttributes.Abstract | TypeAttributes.Public;
334 ctd.BaseTypes.Add(
"Avro.Specific.ISpecificProtocol");
336 AddProtocolDocumentation(protocol, ctd);
339 var protocolField =
new CodeMemberField();
340 protocolField.Attributes = MemberAttributes.Private | MemberAttributes.Static | MemberAttributes.Final;
341 protocolField.Name =
"protocol";
342 protocolField.Type =
new CodeTypeReference(
"readonly Avro.Protocol");
344 var cpe =
new CodePrimitiveExpression(protocol.
ToString());
345 var cmie =
new CodeMethodInvokeExpression(
346 new CodeMethodReferenceExpression(
new CodeTypeReferenceExpression(typeof(
Protocol)),
"Parse"),
347 new CodeExpression[] { cpe });
349 protocolField.InitExpression = cmie;
351 ctd.Members.Add(protocolField);
354 var
property =
new CodeMemberProperty();
355 property.Attributes = MemberAttributes.Public | MemberAttributes.Final;
356 property.Name =
"Protocol";
357 property.Type =
new CodeTypeReference(
"Avro.Protocol");
358 property.HasGet =
true;
361 property.GetStatements.Add(
new CodeTypeReferenceExpression(
"return protocol"));
362 ctd.Members.Add(property);
367 var requestMethod = CreateRequestMethod();
369 var builder =
new StringBuilder();
373 builder.Append(
"switch(messageName)\n\t\t\t{");
375 foreach (var a
in protocol.
Messages)
377 builder.Append(
"\n\t\t\t\tcase \"").Append(a.Key).Append(
"\":\n");
380 string type = getType(a.Value.Response,
false, ref unused);
382 builder.Append(
"\t\t\t\trequestor.Request<")
384 .Append(
">(messageName, args, callback);\n");
385 builder.Append(
"\t\t\t\tbreak;\n");
388 builder.Append(
"\t\t\t}");
390 var cseGet =
new CodeSnippetExpression(builder.ToString());
392 requestMethod.Statements.Add(cseGet);
393 ctd.Members.Add(requestMethod);
395 AddMethods(protocol,
false, ctd);
398 if (
string.IsNullOrEmpty(nspace))
402 codens.Types.Add(ctd);
405 ctd =
new CodeTypeDeclaration(protocolNameMangled +
"Callback");
406 ctd.TypeAttributes = TypeAttributes.Abstract | TypeAttributes.Public;
408 ctd.BaseTypes.Add(protocolNameMangled);
414 AddProtocolDocumentation(protocol, ctd);
416 AddMethods(protocol,
true, ctd);
418 codens.Types.Add(ctd);
421 private static CodeMemberMethod CreateRequestMethod()
423 var requestMethod =
new CodeMemberMethod();
424 requestMethod.Attributes = MemberAttributes.Public | MemberAttributes.Final;
425 requestMethod.Name =
"Request";
426 requestMethod.ReturnType =
new CodeTypeReference(typeof (
void));
430 requestMethod.Parameters.Add(requestor);
432 var messageName =
new CodeParameterDeclarationExpression(typeof (
string),
"messageName");
433 requestMethod.Parameters.Add(messageName);
435 var args =
new CodeParameterDeclarationExpression(typeof (
object[]),
"args");
436 requestMethod.Parameters.Add(args);
438 var callback =
new CodeParameterDeclarationExpression(typeof (
object),
"callback");
439 requestMethod.Parameters.Add(callback);
441 return requestMethod;
444 private static void AddMethods(Protocol protocol,
bool generateCallback, CodeTypeDeclaration ctd)
446 foreach (var e
in protocol.Messages)
449 var message = e.Value;
450 var response = message.Response;
452 if (generateCallback && message.Oneway.GetValueOrDefault())
455 var messageMember =
new CodeMemberMethod();
456 messageMember.Name = CodeGenUtil.Instance.Mangle(name);
457 messageMember.Attributes = MemberAttributes.Public | MemberAttributes.Abstract;
459 if (message.Doc!=
null && message.Doc.Trim() !=
string.Empty)
460 messageMember.Comments.Add(
new CodeCommentStatement(message.Doc));
462 if (message.Oneway.GetValueOrDefault() || generateCallback)
464 messageMember.ReturnType =
new CodeTypeReference(typeof (
void));
468 bool ignored =
false;
469 string type = getType(response,
false, ref ignored);
471 messageMember.ReturnType =
new CodeTypeReference(type);
474 foreach (Field field
in message.Request.Fields)
476 bool ignored =
false;
477 string type = getType(field.Schema,
false, ref ignored);
479 string fieldName = CodeGenUtil.Instance.Mangle(field.Name);
480 var parameter =
new CodeParameterDeclarationExpression(type, fieldName);
481 messageMember.Parameters.Add(parameter);
484 if (generateCallback)
487 var type = getType(response,
false, ref unused);
488 var parameter =
new CodeParameterDeclarationExpression(
"Avro.IO.ICallback<" + type +
">",
490 messageMember.Parameters.Add(parameter);
494 ctd.Members.Add(messageMember);
498 private void AddProtocolDocumentation(Protocol protocol, CodeTypeDeclaration ctd)
501 if (protocol.Doc !=
null && protocol.Doc.Trim() !=
string.Empty)
504 if (interfaceDoc !=
null)
505 ctd.Comments.Add(interfaceDoc);
518 if (
null == recordSchema)
throw new CodeGenException(
"Unable to cast schema into a record");
524 ctd.BaseTypes.Add(isError ?
"SpecificException" :
"ISpecificRecord");
526 ctd.Attributes = MemberAttributes.Public;
528 ctd.IsPartial =
true;
533 var cmmGet =
new CodeMemberMethod();
535 cmmGet.Attributes = MemberAttributes.Public;
536 cmmGet.ReturnType =
new CodeTypeReference(
"System.Object");
537 cmmGet.Parameters.Add(
new CodeParameterDeclarationExpression(typeof(
int),
"fieldPos"));
538 StringBuilder getFieldStmt =
new StringBuilder(
"switch (fieldPos)\n\t\t\t{\n");
541 var cmmPut =
new CodeMemberMethod();
543 cmmPut.Attributes = MemberAttributes.Public;
544 cmmPut.ReturnType =
new CodeTypeReference(typeof(
void));
545 cmmPut.Parameters.Add(
new CodeParameterDeclarationExpression(typeof(
int),
"fieldPos"));
546 cmmPut.Parameters.Add(
new CodeParameterDeclarationExpression(
"System.Object",
"fieldValue"));
547 var putFieldStmt =
new StringBuilder(
"switch (fieldPos)\n\t\t\t{\n");
551 cmmGet.Attributes |= MemberAttributes.Override;
552 cmmPut.Attributes |= MemberAttributes.Override;
555 foreach (
Field field
in recordSchema.Fields)
558 bool nullibleEnum =
false;
559 string baseType = getType(field.
Schema,
false, ref nullibleEnum);
560 var ctrfield =
new CodeTypeReference(baseType);
563 string privFieldName =
string.Concat(
"_", field.
Name);
564 var codeField =
new CodeMemberField(ctrfield, privFieldName);
565 codeField.Attributes = MemberAttributes.Private;
568 CodeCommentStatement propertyComment =
null;
572 if (
null != propertyComment)
573 codeField.Comments.Add(propertyComment);
577 ctd.Members.Add(codeField);
580 var fieldRef =
new CodeFieldReferenceExpression(
new CodeThisReferenceExpression(), privFieldName);
584 var
property =
new CodeMemberProperty();
585 property.Attributes = MemberAttributes.Public | MemberAttributes.Final;
586 property.Name = mangledName;
587 property.Type = ctrfield;
588 property.GetStatements.Add(
new CodeMethodReturnStatement(fieldRef));
589 property.SetStatements.Add(
new CodeAssignStatement(fieldRef,
new CodePropertySetValueReferenceExpression()));
590 if (
null != propertyComment)
591 property.Comments.Add(propertyComment);
594 ctd.Members.Add(property);
597 getFieldStmt.Append(
"\t\t\tcase ");
598 getFieldStmt.Append(field.
Pos);
599 getFieldStmt.Append(
": return this.");
600 getFieldStmt.Append(mangledName);
601 getFieldStmt.Append(
";\n");
604 putFieldStmt.Append(
"\t\t\tcase ");
605 putFieldStmt.Append(field.
Pos);
606 putFieldStmt.Append(
": this.");
607 putFieldStmt.Append(mangledName);
611 putFieldStmt.Append(
" = fieldValue == null ? (");
612 putFieldStmt.Append(baseType);
613 putFieldStmt.Append(
")null : (");
615 string type = baseType.Remove(0, 16);
616 type = type.Remove(type.Length - 1);
618 putFieldStmt.Append(type);
619 putFieldStmt.Append(
")fieldValue; break;\n");
623 putFieldStmt.Append(
" = (");
624 putFieldStmt.Append(baseType);
625 putFieldStmt.Append(
")fieldValue; break;\n");
630 getFieldStmt.Append(
"\t\t\tdefault: throw new AvroRuntimeException(\"Bad index \" + fieldPos + \" in Get()\");\n\t\t\t}");
631 var cseGet =
new CodeSnippetExpression(getFieldStmt.ToString());
632 cmmGet.Statements.Add(cseGet);
633 ctd.Members.Add(cmmGet);
636 putFieldStmt.Append(
"\t\t\tdefault: throw new AvroRuntimeException(\"Bad index \" + fieldPos + \" in Put()\");\n\t\t\t}");
637 var csePut =
new CodeSnippetExpression(putFieldStmt.ToString());
638 cmmPut.Statements.Add(csePut);
639 ctd.Members.Add(cmmPut);
641 string nspace = recordSchema.Namespace;
642 if (
string.IsNullOrEmpty(nspace))
643 throw new CodeGenException(
"Namespace required for record schema " + recordSchema.Name);
646 codens.Types.Add(ctd);
657 internal static string getType(
Schema schema,
bool nullible, ref
bool nullibleEnum)
662 return "System.Object";
664 if (nullible)
return "System.Nullable<bool>";
665 else return typeof(
bool).ToString();
667 if (nullible)
return "System.Nullable<int>";
668 else return typeof(
int).ToString();
670 if (nullible)
return "System.Nullable<long>";
671 else return typeof(
long).ToString();
673 if (nullible)
return "System.Nullable<float>";
674 else return typeof(
float).ToString();
676 if (nullible)
return "System.Nullable<double>";
677 else return typeof(
double).ToString();
680 return typeof(
byte[]).ToString();
682 return typeof(
string).ToString();
686 if (
null == namedSchema)
693 else return CodeGenUtil.Instance.Mangle(namedSchema.Fullname);
695 case Schema.Type.Fixed:
696 case Schema.Type.Record:
697 case Schema.Type.Error:
698 namedSchema = schema as NamedSchema;
699 if (
null == namedSchema)
700 throw new CodeGenException(
"Unable to cast schema into a named schema");
701 return CodeGenUtil.Instance.Mangle(namedSchema.Fullname);
703 case Schema.Type.Array:
704 var arraySchema = schema as ArraySchema;
705 if (
null == arraySchema)
706 throw new CodeGenException(
"Unable to cast schema into an array schema");
708 return "IList<" + getType(arraySchema.ItemSchema,
false, ref nullibleEnum) +
">";
710 case Schema.Type.Map:
711 var mapSchema = schema as MapSchema;
712 if (
null == mapSchema)
713 throw new CodeGenException(
"Unable to cast schema into a map schema");
714 return "IDictionary<string," + getType(mapSchema.ValueSchema,
false, ref nullibleEnum) +
">";
716 case Schema.Type.Union:
717 var unionSchema = schema as UnionSchema;
718 if (
null == unionSchema)
719 throw new CodeGenException(
"Unable to cast schema into a union schema");
721 if (
null == nullibleType)
722 return CodeGenUtil.Object;
724 return getType(nullibleType,
true, ref nullibleEnum);
726 throw new CodeGenException(
"Unable to generate CodeTypeReference for " + schema.
Name +
" type " + schema.
Tag);
737 if (schema.
Count == 2)
739 bool nullable =
false;
761 var ctrfield =
new CodeTypeReference(
"Schema");
762 string schemaFname =
"_SCHEMA";
763 var codeField =
new CodeMemberField(ctrfield, schemaFname);
764 codeField.Attributes = MemberAttributes.Public | MemberAttributes.Static;
766 var cpe =
new CodePrimitiveExpression(schema.
ToString());
767 var cmie =
new CodeMethodInvokeExpression(
768 new CodeMethodReferenceExpression(
new CodeTypeReferenceExpression(typeof(
Schema)),
"Parse"),
769 new CodeExpression[] { cpe });
770 codeField.InitExpression = cmie;
771 ctd.Members.Add(codeField);
774 var
property =
new CodeMemberProperty();
775 property.Attributes = MemberAttributes.Public;
776 if (overrideFlag)
property.Attributes |= MemberAttributes.Override;
777 property.Name =
"Schema";
778 property.Type = ctrfield;
780 property.GetStatements.Add(
new CodeMethodReturnStatement(
new CodeTypeReferenceExpression(ctd.Name +
"." + schemaFname)));
781 ctd.Members.Add(property);
791 string text =
string.Format(
"<summary>\r\n {0}\r\n </summary>", comment);
792 return new CodeCommentStatement(text,
true);
801 var cscp =
new CSharpCodeProvider();
803 var opts =
new CodeGeneratorOptions();
804 opts.BracingStyle =
"C";
805 opts.IndentString =
"\t";
806 opts.BlankLinesBetweenMembers =
false;
808 using (var outfile =
new StreamWriter(outputFile))
810 cscp.GenerateCodeFromCompileUnit(
CompileUnit, outfile, opts);
820 var cscp =
new CSharpCodeProvider();
822 var opts =
new CodeGeneratorOptions();
823 opts.BracingStyle =
"C";
824 opts.IndentString =
"\t";
825 opts.BlankLinesBetweenMembers =
false;
827 CodeNamespaceCollection nsc =
CompileUnit.Namespaces;
828 for (
int i = 0; i < nsc.Count; i++)
833 Directory.CreateDirectory(dir);
835 var new_ns =
new CodeNamespace(ns.Name);
838 new_ns.Imports.Add(nci);
840 var types = ns.Types;
841 for (
int j = 0; j < types.Count; j++)
845 using (var writer =
new StreamWriter(file,
false))
847 new_ns.Types.Add(ctd);
848 cscp.GenerateCodeFromNamespace(new_ns, writer, opts);
849 new_ns.Types.Remove(ctd);
virtual CodeNamespace addNamespace(string name)
Adds a namespace object for the given name into the dictionary if it doesn't exist yet
virtual SchemaNames generateNames(Protocol protocol)
Generate list of named schemas from given protocol
Schema Schema
Field type's schema
Class for fields defined in a record
virtual CodeCommentStatement createDocComment(string comment)
Creates an XML documentation for the given comment
Class for enum type schemas
virtual void createSchemaField(Schema schema, CodeTypeDeclaration ctd, bool overrideFlag)
Creates the static schema field for class types
IList< Schema > Types
List of schemas objects representing the different schemas defined under the 'types' attribute
CodeGen()
Default constructor
virtual CodeTypeDeclaration processRecord(Schema schema)
Creates a class declaration
virtual SchemaNames generateNames(Schema schema)
Generate list of named schemas from given schema
int Pos
Position of the field within its record.
Base class for all schema types
bool Contains(SchemaName name)
Checks if given name is in the map
string Name
Name of the protocol
CodeNamespaceImport [] NamespaceImports
override string Name
Name of the schema
readonly string Name
Name of the field.
IList< Schema > Schemas
List of schemas in the union
A singleton class containing data used by codegen
CodeCompileUnit CompileUnit
Object that contains all the generated types
IList< Protocol > Protocols
List of protocols to generate code for
virtual void processInterface(Protocol protocol)
Type
Enum for schema types
int Size
Fixed size for the bytes
Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.
CodeCommentStatement FileComment
override string ToString()
Returns the canonical JSON representation of this schema.
static Schema getNullableType(UnionSchema schema)
Gets the schema of a union with null
virtual void AddSchema(Schema schema)
Adds a schema object to generate code for
virtual void processFixed(Schema schema)
Creates a class declaration for fixed schema
string Namespace
Namespace of the schema
Class for array type schemas
A class that contains a list of named schemas.
string UnMangle(string name)
Remove all the @
virtual void processProtocols()
Generates code for the protocol objects
IList< Schema > Schemas
List of schemas to generate code for
override string ToString()
Writes Protocol in JSON format
virtual void addName(Schema schema, SchemaNames names)
Recursively search the given schema for named schemas and adds them to the given container
bool Add(SchemaName name, NamedSchema schema)
Adds a schema name to the map if it doesn't exist yet
Dictionary< string, CodeNamespace > namespaceLookup
List of generated namespaces
static CodeGenUtil Instance
abstract string Name
The name of this schema.
IDictionary< string, Message > Messages
List of message objects representing the different schemas defined under the 'messages' attribute
string Documentation
Documentation for the field, if any.
HashSet< string > ReservedKeywords
int Count
Count of schemas in the union
virtual CodeCompileUnit GenerateCode()
Generates code for the given protocol and schema objects
virtual void AddProtocol(Protocol protocol)
Adds a protocol object to generate code for
virtual void processEnum(Schema schema)
Creates an enum declaration
Type Tag
Schema type property
virtual void WriteCompileUnit(string outputFile)
Writes the generated compile unit into one file
string Mangle(string name)
Append @ to all reserved keywords that appear on the given name
string Namespace
Namespace of the protocol
virtual void WriteTypes(string outputdir)
Writes each types in each namespaces into individual files
Base class for all named schemas: fixed, enum, record
virtual void processSchemas()
Generates code for the schema objects
SchemaName SchemaName
Name of the schema, contains name, namespace and enclosing namespace