} // end AvroEncode /// <summary> /// Make a copy of an object as an Avro GenericRecord /// </summary> /// <param name="obj">Original object</param> /// <param name="ktype">An associated KineticaType object that /// describes the original object.</param> /// <returns>GenericRecord object which is a copy of the specified object</returns> private Avro.Generic.GenericRecord MakeGenericRecord(object obj, KineticaType ktype) { // Get the schema var schema = KineticaData.SchemaFromType(obj.GetType(), ktype); // Create a new GenericRecord for this schema var recordToSend = new Avro.Generic.GenericRecord(schema); // Copy each field from obj to recordToSend foreach (var field in schema.Fields) { var property = obj.GetType() .GetProperties() .FirstOrDefault(prop => prop.Name.ToLowerInvariant() == field.Name.ToLowerInvariant()); if (property == null) { continue; } recordToSend.Add(field.Name, property.GetValue(obj, null)); } // Return the newly created object return(recordToSend); }
} // lookupKineticaType() /// <summary> /// Encode specified object using Avro /// </summary> /// <param name="obj">Object to encode</param> /// <returns>Byte array of binary Avro-encoded data</returns> internal byte[] AvroEncode(object obj) { // Create a stream that will allow us to view the underlying memory using (var ms = new MemoryStream()) { // Write the object to the memory stream // If obj is an ISpecificRecord, this is more efficient if (obj is Avro.Specific.ISpecificRecord) { var schema = (obj as Avro.Specific.ISpecificRecord).Schema; Avro.Specific.SpecificDefaultWriter writer = new Avro.Specific.SpecificDefaultWriter(schema); writer.Write(schema, obj, new BinaryEncoder(ms)); } else // Not an ISpecificRecord - this way is less efficient { // Get the KineticaType associated with the object to be encoded Type obj_type = obj.GetType(); KineticaType ktype = lookupKineticaType(obj_type); if (ktype == null) { throw new KineticaException("No known KineticaType associated with the given object. " + "Need a known KineticaType to encode the object."); } // Make a copy of the object to send as a GenericRecord, then write that to the memory stream var schema = KineticaData.SchemaFromType(obj.GetType(), ktype); var recordToSend = MakeGenericRecord(obj, ktype); var writer = new Avro.Generic.DefaultWriter(schema); writer.Write(schema, recordToSend, new BinaryEncoder(ms)); } // Get the memory from the stream return(ms.ToArray()); } } // end AvroEncode
} // end AvroDecode<T> /// <summary> /// Decode binary Avro data from a stream into an object /// </summary> /// <typeparam name="T">Type of expected object</typeparam> /// <param name="stream">Stream to read for object data</param> /// <returns>New object</returns> private T AvroDecode <T>(Stream stream) where T : Avro.Specific.ISpecificRecord, new() { // T obj = new T(); // Activator.CreateInstance<T>(); var schema = KineticaData.SchemaFromType(typeof(T), null); var reader = new Avro.Specific.SpecificReader <T>(schema, schema); return(reader.Read(default(T), new BinaryDecoder(stream))); }
/// <summary> /// Decode binary Avro data into an object. /// </summary> /// <typeparam name="T">Type of expected object</typeparam> /// <param name="bytes">Binary Avro data</param> /// <param name="ktype">An optional KineticaType object to help in decoding the object.</param> /// <returns>New object</returns> private T AvroDecode <T>(byte[] bytes, KineticaType ktype = null) where T : new() { // Get the schema var schema = KineticaData.SchemaFromType(typeof(T), ktype); // Create a stream to read the binary data using (var ms = new MemoryStream(bytes)) { // Create a new object to return T obj = new T(); if (obj is Avro.Specific.ISpecificRecord) { var reader = new Avro.Specific.SpecificDefaultReader(schema, schema); reader.Read(obj, new BinaryDecoder(ms)); } else { // Not ISpecificRecord, so first read into a new GenericRecord var reader = new Avro.Generic.DefaultReader(schema, schema); Avro.Generic.GenericRecord recordToReceive = new Avro.Generic.GenericRecord(schema); reader.Read(recordToReceive, new BinaryDecoder(ms)); // Now, copy all the fields from the GenericRecord to obj foreach (var field in schema.Fields) { var property = obj.GetType() .GetProperties() .FirstOrDefault(prop => prop.Name.ToLowerInvariant() == field.Name.ToLowerInvariant()); if (property == null) { continue; } object val; // Try to get the property if (recordToReceive.TryGetValue(field.Name, out val)) { // If successful, write the property to obj property.SetValue(obj, val); } } // end foreach } // end if-else // Return the new object return(obj); } // end using } // end AvroDecode<T>