/// <summary> /// Add an entry to the class cache. /// </summary> /// <param name="objType">Type of the C# class</param> /// <param name="s">Schema</param> public void LoadClassCache(Type objType, Schema s) { switch (s) { case RecordSchema rs: if (!objType.IsClass) { throw new AvroException($"Cant map scalar type {objType.Name} to record {rs.Fullname}"); } if (typeof(byte[]).IsAssignableFrom(objType) || typeof(string).IsAssignableFrom(objType) || typeof(IEnumerable).IsAssignableFrom(objType) || typeof(IDictionary).IsAssignableFrom(objType)) { throw new AvroException($"Cant map type {objType.Name} to record {rs.Fullname}"); } AddClassNameMapItem(rs, objType); var c = GetClass(rs); foreach (var f in rs.Fields) { /* * //.StackOverflowException * var t = c.GetPropertyType(f); * LoadClassCache(t, f.Schema); */ if (_previousFields.TryAdd(f.Name, f.Schema)) { var t = c.GetPropertyType(f); LoadClassCache(t, f.Schema); } } break; case ArraySchema ars: if (!typeof(IEnumerable).IsAssignableFrom(objType)) { throw new AvroException($"Cant map type {objType.Name} to array {ars.Name}"); } if (!objType.IsGenericType) { throw new AvroException($"{objType.Name} needs to be a generic type"); } LoadClassCache(objType.GenericTypeArguments[0], ars.ItemSchema); break; case MapSchema ms: if (!typeof(IDictionary).IsAssignableFrom(objType)) { throw new AvroException($"Cant map type {objType.Name} to map {ms.Name}"); } if (!objType.IsGenericType) { throw new AvroException($"Cant map non-generic type {objType.Name} to map {ms.Name}"); } if (!typeof(string).IsAssignableFrom(objType.GenericTypeArguments[0])) { throw new AvroException($"First type parameter of {objType.Name} must be assignable to string"); } LoadClassCache(objType.GenericTypeArguments[1], ms.ValueSchema); break; case NamedSchema ns: EnumCache.AddEnumNameMapItem(ns, objType); break; case UnionSchema us: if (us.Schemas.Count == 2 && (us.Schemas[0].Tag == Schema.Type.Null || us.Schemas[1].Tag == Schema.Type.Null) && objType.IsClass) { // in this case objType will match the non null type in the union foreach (var o in us.Schemas) { if (o.Tag != Schema.Type.Null) { LoadClassCache(objType, o); } } } else { // check the schema types are registered foreach (var o in us.Schemas) { if (o.Tag == Schema.Type.Record && GetClass(o as RecordSchema) == null) { throw new AvroException($"Class for union record type {o.Fullname} is not registered. Create a ClassCache object and call LoadClassCache"); } } } break; } }
/// <summary> /// Add an entry to the class cache. /// </summary> /// <param name="objType">Type of the C# class</param> /// <param name="s">Schema</param> public void LoadClassCache(Type objType, Schema s) { switch (s) { case RecordSchema rs: if (!objType.IsClass) { throw new AvroException($"Cant map scalar type {objType.Name} to record {rs.Fullname}"); } if (typeof(byte[]).IsAssignableFrom(objType) || typeof(string).IsAssignableFrom(objType) || typeof(IEnumerable).IsAssignableFrom(objType) || typeof(IDictionary).IsAssignableFrom(objType)) { throw new AvroException($"Cant map type {objType.Name} to record {rs.Fullname}"); } AddClassNameMapItem(rs, objType); var c = GetClass(rs); foreach (var f in rs.Fields) { var t = c.GetPropertyType(f); LoadClassCache(t, f.Schema); } break; case ArraySchema ars: if (!typeof(IEnumerable).IsAssignableFrom(objType)) { throw new AvroException($"Cant map type {objType.Name} to array {ars.Name}"); } if (!objType.IsGenericType) { throw new AvroException($"{objType.Name} needs to be a generic type"); } LoadClassCache(objType.GenericTypeArguments[0], ars.ItemSchema); break; case MapSchema ms: if (!typeof(IDictionary).IsAssignableFrom(objType)) { throw new AvroException($"Cant map type {objType.Name} to map {ms.Name}"); } if (!objType.IsGenericType) { throw new AvroException($"Cant map non-generic type {objType.Name} to map {ms.Name}"); } if (!typeof(string).IsAssignableFrom(objType.GenericTypeArguments[0])) { throw new AvroException($"First type parameter of {objType.Name} must be assignable to string"); } LoadClassCache(objType.GenericTypeArguments[1], ms.ValueSchema); break; case NamedSchema ns: EnumCache.AddEnumNameMapItem(ns, objType); break; } }