| /** |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| using System; |
| using System.Collections.Generic; |
| using System.Linq; |
| using Avro; |
| using Avro.IO; |
| using Avro.Generic; |
| |
| namespace Avro.Specific |
| { |
| /// <summary> |
| /// Generic wrapper class for writing data from specific objects |
| /// </summary> |
| /// <typeparam name="T">type name of specific object</typeparam> |
| public class SpecificWriter<T> : GenericWriter<T> |
| { |
| public SpecificWriter(Schema schema) : base(new SpecificDefaultWriter(schema)) { } |
| public SpecificWriter(SpecificDefaultWriter writer) : base(writer) { } |
| } |
| |
| /// <summary> |
| /// Class for writing data from any specific objects |
| /// </summary> |
| public class SpecificDefaultWriter : DefaultWriter |
| { |
| /// <summary> |
| /// Constructor |
| /// </summary> |
| /// <param name="schema">schema of the object to be written</param> |
| public SpecificDefaultWriter(Schema schema) : base(schema) { } |
| |
| /// <summary> |
| /// Serialized a record using the given RecordSchema. It uses GetField method |
| /// to extract the field value from the given object. |
| /// </summary> |
| /// <param name="schema">The RecordSchema to use for serialization</param> |
| /// <param name="value">The value to be serialized</param> |
| /// <param name="encoder">The Encoder for serialization</param> |
| |
| protected override void WriteRecord(RecordSchema schema, object value, Encoder encoder) |
| { |
| var rec = value as ISpecificRecord; |
| if (rec == null) |
| throw new AvroTypeException("Record object is not derived from ISpecificRecord"); |
| |
| foreach (Field field in schema) |
| { |
| try |
| { |
| Write(field.Schema, rec.Get(field.Pos), encoder); |
| } |
| catch (Exception ex) |
| { |
| throw new AvroException(ex.Message + " in field " + field.Name); |
| } |
| } |
| } |
| |
| /// <summary> |
| /// Validates that the record is a fixed record object and that the schema in the object is the |
| /// same as the given writer schema. Writes the given fixed record into the given encoder |
| /// </summary> |
| /// <param name="schema">writer schema</param> |
| /// <param name="value">fixed object to write</param> |
| /// <param name="encoder">encoder to write to</param> |
| protected override void WriteFixed(FixedSchema schema, object value, Encoder encoder) |
| { |
| var fixedrec = value as SpecificFixed; |
| if (fixedrec == null) |
| throw new AvroTypeException("Fixed object is not derived from SpecificFixed"); |
| |
| encoder.WriteFixed(fixedrec.Value); |
| } |
| |
| /// <summary> |
| /// Writes the given enum value into the given encoder. |
| /// </summary> |
| /// <param name="schema">writer schema</param> |
| /// <param name="value">enum value</param> |
| /// <param name="encoder">encoder to write to</param> |
| protected override void WriteEnum(EnumSchema schema, object value, Encoder encoder) |
| { |
| if (value == null) |
| throw new AvroTypeException("value is null in SpecificDefaultWriter.WriteEnum"); |
| |
| encoder.WriteEnum(schema.Ordinal(value.ToString())); |
| } |
| |
| /// <summary> |
| /// Serialized an array. The default implementation calls EnsureArrayObject() to ascertain that the |
| /// given value is an array. It then calls GetArrayLength() and GetArrayElement() |
| /// to access the members of the array and then serialize them. |
| /// </summary> |
| /// <param name="schema">The ArraySchema for serialization</param> |
| /// <param name="value">The value being serialized</param> |
| /// <param name="encoder">The encoder for serialization</param> |
| protected override void WriteArray(ArraySchema schema, object value, Encoder encoder) |
| { |
| var arr = value as System.Collections.IList; |
| if (arr == null) |
| throw new AvroTypeException("Array does not implement non-generic IList"); |
| |
| long l = arr.Count; |
| encoder.WriteArrayStart(); |
| encoder.SetItemCount(l); |
| for (int i = 0; i < l; i++) |
| { |
| encoder.StartItem(); |
| Write(schema.ItemSchema, arr[i], encoder); |
| } |
| encoder.WriteArrayEnd(); |
| } |
| |
| /// <summary> |
| /// Writes the given map into the given encoder. |
| /// </summary> |
| /// <param name="schema">writer schema</param> |
| /// <param name="value">map to write</param> |
| /// <param name="encoder">encoder to write to</param> |
| protected override void WriteMap(MapSchema schema, object value, Encoder encoder) |
| { |
| var map = value as System.Collections.IDictionary; |
| if (map == null) |
| throw new AvroTypeException("Map does not implement non-generic IDictionary"); |
| |
| encoder.WriteArrayStart(); |
| encoder.SetItemCount(map.Count); |
| foreach (System.Collections.DictionaryEntry de in map) |
| { |
| encoder.StartItem(); |
| encoder.WriteString(de.Key as string); |
| Write(schema.ValueSchema, de.Value, encoder); |
| } |
| encoder.WriteMapEnd(); |
| } |
| |
| /// <summary> |
| /// Resolves the given value against the given UnionSchema and serializes the object against |
| /// the resolved schema member. The default implementation of this method uses |
| /// ResolveUnion to find the member schema within the UnionSchema. |
| /// </summary> |
| /// <param name="us">The UnionSchema to resolve against</param> |
| /// <param name="value">The value to be serialized</param> |
| /// <param name="encoder">The encoder for serialization</param> |
| protected override void WriteUnion(UnionSchema us, object value, Encoder encoder) |
| { |
| for (int i = 0; i < us.Count; i++) |
| { |
| if (Matches(us[i], value)) |
| { |
| encoder.WriteUnionIndex(i); |
| Write(us[i], value, encoder); |
| return; |
| } |
| } |
| throw new AvroException("Cannot find a match for " + value.GetType() + " in " + us); |
| } |
| |
| protected override bool Matches(Schema sc, object obj) |
| { |
| if (obj == null && sc.Tag != Avro.Schema.Type.Null) return false; |
| switch (sc.Tag) |
| { |
| case Schema.Type.Null: |
| return obj == null; |
| case Schema.Type.Boolean: |
| return obj is bool; |
| case Schema.Type.Int: |
| return obj is int; |
| case Schema.Type.Long: |
| return obj is long; |
| case Schema.Type.Float: |
| return obj is float; |
| case Schema.Type.Double: |
| return obj is double; |
| case Schema.Type.Bytes: |
| return obj is byte[]; |
| case Schema.Type.String: |
| return obj is string; |
| case Schema.Type.Record: |
| return obj is ISpecificRecord && |
| (((obj as ISpecificRecord).Schema) as RecordSchema).SchemaName.Equals((sc as RecordSchema).SchemaName); |
| case Schema.Type.Enumeration: |
| return obj.GetType().IsEnum && (sc as EnumSchema).Symbols.Contains(obj.ToString()); |
| case Schema.Type.Array: |
| return obj is System.Collections.IList; |
| case Schema.Type.Map: |
| return obj is System.Collections.IDictionary; |
| case Schema.Type.Union: |
| return false; // Union directly within another union not allowed! |
| case Schema.Type.Fixed: |
| return obj is SpecificFixed && |
| (((obj as SpecificFixed).Schema) as FixedSchema).SchemaName.Equals((sc as FixedSchema).SchemaName); |
| default: |
| throw new AvroException("Unknown schema type: " + sc.Tag); |
| } |
| } |
| } |
| } |