internal void EnsureUniqueNames(NetModel.NetModel model) { foreach (IGrouping <string, INetType> netTypes in model.NetTypes.GroupBy(c => c.Name)) { if (netTypes.Count() == 1) { continue; } foreach (var netClass in netTypes.OfType <NetClass>().ToList()) { foreach (var avroField in model.NetTypes.OfType <NetClass>().ToList() .SelectMany(c => c.Fields) .Where(f => (f.FieldType == netClass.Name || f.FieldType == netClass.Name + "[]" || f.FieldType == netClass.Name + "?") && f.Namespace == netClass.ClassNamespace)) { avroField.FieldType = avroField.Namespace + avroField.FieldType; } netClass.Name = netClass.ClassNamespace + netClass.Name; } } }
private void Resolve(object json, NetModel.NetModel model) { if (json is JObject parent) { foreach (var prop in parent) { if (prop.Key == "type" && prop.Value.ToString() == "record") { ResolveRecord(parent, model); } else if (prop.Key == "type" && prop.Value.ToString() == "enum") { _enumResolver.ResolveEnum(parent, model); } else if (prop.Value is JObject) { Resolve(prop.Value, model); } else if (prop.Value is JArray array) { foreach (var arrayItem in array) { switch (arrayItem) { case JObject jObject: Resolve(jObject, model); break; case JValue _: // This could be any item in an array - for example nullable break; default: throw new InvalidAvroObjectException($"Unhandled newtonsoft type {arrayItem.GetType().Name}"); } } } } } else if (json is JArray) { throw new InvalidAvroObjectException($"Unhandled array on root level"); } else { throw new InvalidAvroObjectException($"Unidentified newtonsoft object type {json.GetType().Name}"); } }
internal string FromAvroSchema(string schema) { Initialize(); JObject json = (JObject)JsonConvert.DeserializeObject(schema); NetModel.NetModel model = new NetModel.NetModel(); Resolve(json, model); _namespaceHelper.EnsureUniqueNames(model); StringBuilder sb = new StringBuilder(); foreach (INetType ac in model.NetTypes) { ac.Write(sb); } return(sb.ToString()); }
private void ResolveRecord(JObject parent, NetModel.NetModel model) { var shortName = parent["name"].ToString().Split('.').Last(); NetClass c = new NetClass() { Name = shortName, ClassNamespace = _namespaceHelper.ExtractNamespace(parent, parent["name"].ToString(), shortName) }; model.NetTypes.Add(c); // Get Fields foreach (var field in parent["fields"] as JArray) { if (field is JObject fieldObject) { // Get Field type NetClassField fieldType = new NetClassField(); bool isNullable = false; switch (field["type"]) { case JValue _: fieldType = ResolveField(fieldObject); break; case JObject fieldJObject: fieldType = ResolveField(fieldJObject); break; case JArray types: { if (types.Any(t => t.ToString() == "null")) { isNullable = true; } if (types.Count > 2) { throw new InvalidAvroObjectException( $"Unable to determine acceptable data type for {field["type"]}"); } // Is the field type an object that's defined in this spot JToken arrayFieldType = types.FirstOrDefault(x => x.ToString() != "null"); switch (arrayFieldType) { case JValue _: fieldObject["type"] = arrayFieldType; fieldType = ResolveField(fieldObject); break; case JObject arrayFieldJObject: fieldType = ResolveField(arrayFieldJObject); break; default: throw new InvalidAvroObjectException($"Unable to create array in array {arrayFieldType}"); } break; } default: throw new InvalidAvroObjectException($"Unable to process field type of {field["type"].GetType().Name}"); } if (isNullable) { fieldType.FieldType += "?"; } fieldType.Name = field["name"].ToString(); if (field["default"] is JValue) { fieldType.Default = field["default"].ToString(); } if (field["doc"] is JValue) { fieldType.Doc = field["doc"].ToString(); } c.Fields.Add(fieldType); } else { throw new InvalidAvroObjectException($"Field type {field.GetType().Name} not supported"); } } }