Skip to content

Commit

Permalink
AVRO-807. C#: Some improvements and bugfixes. Contributed by Dona Alv…
Browse files Browse the repository at this point in the history
…arez.

git-svn-id: https://svn.apache.org/repos/asf/avro/trunk@1095529 13f79535-47bb-0310-9956-ffa450edef68
  • Loading branch information
cutting committed Apr 20, 2011
1 parent a364235 commit 03933b3
Show file tree
Hide file tree
Showing 13 changed files with 182 additions and 146 deletions.
4 changes: 4 additions & 0 deletions CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ Avro 1.5.1 (unreleased)
AVRO-763. Java MapReduce API: add support for configure() and
close() methods to mappers and reducers. (Marshall Pierce via cutting)

AVRO-807. C#: Some improvements and bugfixes, including making AvroGen
extensible and changing ISpecificRecord to an interface.
(Dona Alvarez via cutting)

BUG FIXES

AVRO-786. Java: Fix equals() to work on objects containing maps. (cutting)
Expand Down
2 changes: 1 addition & 1 deletion lang/csharp/src/apache/codegen/Avro.codegen.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="AvroGen.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,10 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Avro.codegen;

namespace Avro.codegen
namespace Avro
{
class Program
class AvroGen
{
static void Main(string[] args)
{
Expand All @@ -45,7 +44,6 @@ static void Usage()
Console.WriteLine("Usage:\navrogen -p <protocolfile> <outputdir>\navrogen -s <schemafile> <outputdir>");
return;
}

static void GenProtocol(string infile, string outdir)
{
try
Expand All @@ -64,7 +62,6 @@ static void GenProtocol(string infile, string outdir)
Console.WriteLine("Exception occurred. " + ex.Message);
}
}

static void GenSchema(string infile, string outdir)
{
try
Expand All @@ -83,6 +80,5 @@ static void GenSchema(string infile, string outdir)
Console.WriteLine("Exception occurred. " + ex.Message);
}
}

}
}
2 changes: 1 addition & 1 deletion lang/csharp/src/apache/main/Avro.main.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@
<Compile Include="CodeGen\AvroRuntimeException.cs" />
<Compile Include="CodeGen\CodeGen.cs" />
<Compile Include="CodeGen\CodeGenException.cs" />
<Compile Include="CodeGen\CodeGenExt.cs" />
<Compile Include="CodeGen\CodeGenUtil.cs" />
<Compile Include="Generic\DatumReader.cs" />
<Compile Include="Generic\DatumWriter.cs" />
<Compile Include="Generic\GenericEnum.cs" />
Expand Down
102 changes: 58 additions & 44 deletions lang/csharp/src/apache/main/CodeGen/CodeGen.cs

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,19 @@ namespace Avro
/// <summary>
/// A singleton class containing data used by codegen
/// </summary>
public sealed class CodeGenExt
public sealed class CodeGenUtil
{
private static readonly CodeGenExt instance = new CodeGenExt();
public static CodeGenExt Instance { get { return instance; } }
private static readonly CodeGenUtil instance = new CodeGenUtil();
public static CodeGenUtil Instance { get { return instance; } }

public CodeNamespaceImport[] NamespaceImports { get; private set; }
public CodeCommentStatement FileComment { get; private set; }
public HashSet<string> ReservedKeywords { get; private set; }
private const char AT = '@';
private const char DOT = '.';
private const char At = '@';
private const char Dot = '.';
public const string Object = "System.Object";

private CodeGenExt()
private CodeGenUtil()
{
NamespaceImports = new CodeNamespaceImport[] {
new CodeNamespaceImport("System"),
Expand Down Expand Up @@ -75,13 +76,13 @@ is regenerated
public string Mangle(string name)
{
var builder = new StringBuilder();
string[] names = name.Split(DOT);
string[] names = name.Split(Dot);
for (int i = 0; i < names.Length; ++i)
{
if (ReservedKeywords.Contains(names[i]))
builder.Append(AT);
builder.Append(At);
builder.Append(names[i]);
builder.Append(DOT);
builder.Append(Dot);
}
builder.Remove(builder.Length - 1, 1);
return builder.ToString();
Expand All @@ -96,7 +97,7 @@ public string UnMangle(string name)
{
var builder = new StringBuilder(name.Length);
for (int i = 0; i < name.Length; ++i)
if (name[i] != AT)
if (name[i] != At)
builder.Append(name[i]);
return builder.ToString();
}
Expand Down
21 changes: 2 additions & 19 deletions lang/csharp/src/apache/main/Schema/NamedSchema.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,17 +62,6 @@ public string Fullname
/// </summary>
private readonly IList<SchemaName> aliases;

/*
/// <summary>
/// Returns the SchemaName object of the named schema
/// </summary>
/// <returns></returns>
public SchemaName GetName()
{
return schemaName;
}
*/

/// <summary>
/// Static function to return a new instance of the named schema
/// </summary>
Expand Down Expand Up @@ -112,14 +101,8 @@ protected NamedSchema(Type type, SchemaName name, IList<SchemaName> aliases, Pro
{
this.SchemaName = name;
this.aliases = aliases;
try
{
names.Add(name, this);
}
catch (Exception ex)
{
throw new AvroException("Could not add " + name.Fullname + ". " + ex.Message);
}
if (!names.Add(name, this))
throw new AvroException("Duplicate schema name " + name.Fullname);
}

/// <summary>
Expand Down
114 changes: 72 additions & 42 deletions lang/csharp/src/apache/main/Specific/ObjectCreator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public sealed class ObjectCreator
private readonly Type[] margs;
private readonly Type[] largs;

private delegate object CtorDelegate();
public delegate object CtorDelegate();
private Type ctorType = typeof(CtorDelegate);
Dictionary<NameCtorKey, CtorDelegate> ctors;

Expand Down Expand Up @@ -103,6 +103,74 @@ public override int GetHashCode()
}
}

/// <summary>
/// Gets the type of the specified type name
/// </summary>
/// <param name="name">name of the object to get type of</param>
/// <param name="schemaType">schema type for the object</param>
/// <returns>Type</returns>
public Type GetType(string name, Schema.Type schemaType)
{
Type type;
if (diffAssembly)
{
// entry assembly different from current assembly, try entry assembly first
type = entryAssembly.GetType(name);
if (type == null) // now try current assembly and mscorlib
type = Type.GetType(name);
}
else
type = Type.GetType(name);

if (type == null) // type is still not found, need to loop through all loaded assemblies
{
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (Assembly assembly in assemblies)
{
type = assembly.GetType(name);
if (type != null)
break;
}
}
if (type == null)
throw new AvroException("Unable to find type " + name + " in all loaded assemblies");

if (schemaType == Schema.Type.Map)
{
margs[1] = type;
type = GenericMapType.MakeGenericType(margs);
}
else if (schemaType == Schema.Type.Array)
{
largs[0] = type;
type = GenericListType.MakeGenericType(largs);
}

return type;
}

/// <summary>
/// Gets the default constructor for the specified type
/// </summary>
/// <param name="name">name of object for the type</param>
/// <param name="schemaType">schema type for the object</param>
/// <param name="type">type of the object</param>
/// <returns>Default constructor for the type</returns>
public CtorDelegate GetConstructor(string name, Schema.Type schemaType, Type type)
{
ConstructorInfo ctorInfo = type.GetConstructor(Type.EmptyTypes);
if (ctorInfo == null)
throw new AvroException("Class " + name + " has no default constructor");

DynamicMethod dynMethod = new DynamicMethod("DM$OBJ_FACTORY_" + name, typeof(object), null, type, true);
ILGenerator ilGen = dynMethod.GetILGenerator();
ilGen.Emit(OpCodes.Nop);
ilGen.Emit(OpCodes.Newobj, ctorInfo);
ilGen.Emit(OpCodes.Ret);

return (CtorDelegate)dynMethod.CreateDelegate(ctorType);
}

/// <summary>
/// Creates new instance of the given type
/// </summary>
Expand All @@ -112,51 +180,13 @@ public override int GetHashCode()
public object New(string name, Schema.Type schemaType)
{
NameCtorKey key = new NameCtorKey(name, schemaType);

CtorDelegate ctor;
if (!ctors.TryGetValue(key, out ctor))
{
Type type;
if (diffAssembly)
{
// entry assembly different from current assembly, try entry assembly first
type = entryAssembly.GetType(name);
if (type == null) // now try current assembly and mscorlib
type = Type.GetType(name);
}
else
type = Type.GetType(name);

if (type == null) // type is still not found, need to loop through all loaded assemblies
{
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (Assembly assembly in assemblies)
{
type = assembly.GetType(name);
if (type != null)
break;
}
}
if (type == null)
throw new AvroException("Unable to find type " + name + " in all loaded assemblies");

if (schemaType == Schema.Type.Map)
{
margs[1] = type;
type = GenericMapType.MakeGenericType(margs);
}
else if (schemaType == Schema.Type.Array)
{
largs[0] = type;
type = GenericListType.MakeGenericType(largs);
}

DynamicMethod dynMethod = new DynamicMethod("DM$OBJ_FACTORY_" + name, typeof(object), null, type, true);
ILGenerator ilGen = dynMethod.GetILGenerator();
ilGen.Emit(OpCodes.Nop);
ilGen.Emit(OpCodes.Newobj, type.GetConstructor(Type.EmptyTypes));
ilGen.Emit(OpCodes.Ret);
Type type = GetType(name, schemaType);
ctor = GetConstructor(name, schemaType, type);

ctor = (CtorDelegate)dynMethod.CreateDelegate(ctorType);
ctors.Add(key, ctor);
}
return ctor();
Expand Down
27 changes: 16 additions & 11 deletions lang/csharp/src/apache/main/Specific/SpecificReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,16 @@ public class SpecificReader<T> : DatumReader<T>
/// </summary>
private readonly SpecificDefaultReader reader;

/// <summary>
/// Schema for the writer class
/// </summary>
public Schema WriterSchema { get { return reader.WriterSchema; } }

/// <summary>
/// Schema for the reader class
/// </summary>
public Schema ReaderSchema { get { return reader.ReaderSchema; } }

/// <summary>
/// Constructs a generic reader for the given schemas using the DefaultReader. If the
/// reader's and writer's schemas are different this class performs the resolution.
Expand All @@ -48,15 +58,10 @@ public SpecificReader(Schema writerSchema, Schema readerSchema)
reader = new SpecificDefaultReader(writerSchema, readerSchema);
}

/// <summary>
/// Schema for the writer class
/// </summary>
public Schema WriterSchema { get { return reader.WriterSchema; } }

/// <summary>
/// Schema for the reader class
/// </summary>
public Schema ReaderSchema { get { return reader.ReaderSchema; } }
public SpecificReader(SpecificDefaultReader reader)
{
this.reader = reader;
}

/// <summary>
/// Generic read function
Expand Down Expand Up @@ -102,7 +107,7 @@ protected override object ReadRecord(object reuse, RecordSchema writerSchema, Sc
{
RecordSchema rs = (RecordSchema)readerSchema;

SpecificRecord rec = (reuse != null ? reuse : ObjectCreator.Instance.New(rs.Fullname, Schema.Type.Record)) as SpecificRecord;
ISpecificRecord rec = (reuse != null ? reuse : ObjectCreator.Instance.New(rs.Fullname, Schema.Type.Record)) as ISpecificRecord;
object obj;
foreach (Field wf in writerSchema)
{
Expand Down Expand Up @@ -252,7 +257,7 @@ protected override object ReadMap(object reuse, MapSchema writerSchema, Schema r
/// <param name="schema">schema containing the type to be determined</param>
/// <param name="nullible">used for union schema</param>
/// <returns></returns>
private string getTargetType(Schema schema)
protected virtual string getTargetType(Schema schema)
{
bool nEnum = false;
string type = Avro.CodeGen.getType(schema, false, ref nEnum);
Expand Down
10 changes: 5 additions & 5 deletions lang/csharp/src/apache/main/Specific/SpecificRecord.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@
namespace Avro.Specific
{
/// <summary>
/// Base class for generated classes
/// Interface class for generated classes
/// </summary>
public abstract class SpecificRecord
public interface ISpecificRecord
{
public abstract Schema Schema { get; }
public abstract object Get(int fieldPos);
public abstract void Put(int fieldPos, object fieldValue);
Schema Schema { get; }
object Get(int fieldPos);
void Put(int fieldPos, object fieldValue);
}
}
Loading

0 comments on commit 03933b3

Please sign in to comment.