/// <summary> /// Static function to return instance of the union schema /// </summary> /// <param name="jarr">JSON object for the union schema</param> /// <param name="names">list of named schemas already read</param> /// <param name="encspace">enclosing namespace of the schema</param> /// <returns>new UnionSchema object</returns> internal static UnionSchema NewInstance(JArray jarr, PropertyMap props, SchemaNames names, string encspace) { List <Schema> schemas = new List <Schema>(); IDictionary <string, string> uniqueSchemas = new Dictionary <string, string>(); foreach (JToken jvalue in jarr) { Schema unionType = ParseJson(jvalue, names, encspace); if (null == unionType) { throw new SchemaParseException("Invalid JSON in union" + jvalue); } string name = unionType.Name; if (uniqueSchemas.ContainsKey(name)) { throw new SchemaParseException("Duplicate type in union: " + name); } uniqueSchemas.Add(name, name); schemas.Add(unionType); } return(new UnionSchema(schemas, props)); }
/// <summary> /// Writes the Field class in JSON format /// </summary> /// <param name="writer">JSON writer</param> /// <param name="names">list of named schemas already written</param> /// <param name="encspace">enclosing namespace for the field</param> protected internal void WriteJson(JsonTextWriter writer, SchemaNames names, string encspace) { writer.WriteStartObject(); JsonHelper.WriteIfNotNullOrEmpty(writer, "name", Name); JsonHelper.WriteIfNotNullOrEmpty(writer, "doc", Documentation); if (null != DefaultValue) { writer.WritePropertyName("default"); DefaultValue.WriteTo(writer, null); } if (null != Schema) { writer.WritePropertyName("type"); Schema.WriteJson(writer, names, encspace); } if (null != Props) { Props.WriteJson(writer); } if (null != Aliases) { writer.WritePropertyName("aliases"); writer.WriteStartArray(); foreach (string name in Aliases) { writer.WriteValue(name); } writer.WriteEndArray(); } writer.WriteEndObject(); }
/// <summary> /// Creates a new field for the record /// </summary> /// <param name="jfield">JSON object for the field</param> /// <param name="pos">position number of the field</param> /// <param name="names">list of named schemas already read</param> /// <param name="encspace">enclosing namespace of the records schema</param> /// <returns>new Field object</returns> private static Field CreateField(JToken jfield, int pos, SchemaNames names, string encspace) { var name = JsonHelper.GetRequiredString(jfield, "name"); var doc = JsonHelper.GetOptionalString(jfield, "doc"); var jorder = JsonHelper.GetOptionalString(jfield, "order"); Field.SortOrder sortorder = Field.SortOrder.Ignore; if (null != jorder) { sortorder = (Field.SortOrder)Enum.Parse(typeof(Field.SortOrder), jorder, true); } var aliases = Field.GetAliases(jfield); var props = JsonHelper.GetProperties(jfield); var defaultValue = jfield["default"]; JToken jtype = jfield["type"]; if (null == jtype) { throw new SchemaParseException("'type' was not found for field: " + name); } var schema = ParseJson(jtype, names, encspace); return(new Field(schema, name, aliases, pos, doc, defaultValue, sortorder, props)); }
/// <summary> /// Writes schema object in JSON format /// </summary> /// <param name="writer">JSON writer</param> /// <param name="names">list of named schemas already written</param> /// <param name="encspace">enclosing namespace of the schema</param> protected internal virtual void WriteJson(JsonTextWriter writer, SchemaNames names, string encspace) { WriteStartObject(writer); WriteJsonFields(writer, names, encspace); if (null != Props) { Props.WriteJson(writer); } writer.WriteEndObject(); }
/// <summary> /// Writes union schema in JSON format /// </summary> /// <param name="writer">JSON writer</param> /// <param name="names">list of named schemas already written</param> /// <param name="encspace">enclosing namespace of the schema</param> protected internal override void WriteJson(JsonTextWriter writer, SchemaNames names, string encspace) { writer.WriteStartArray(); foreach (Schema schema in Schemas) { schema.WriteJson(writer, names, encspace); } writer.WriteEndArray(); }
/// <summary> /// Static class to return a new instance of ArraySchema /// </summary> /// <param name="token">JSON object for the array schema</param> /// <param name="props"></param> /// <param name="names">list of named schemas already parsed</param> /// <param name="encspace">enclosing namespace for the array schema</param> /// <returns></returns> internal static ArraySchema NewInstance(JToken token, PropertyMap props, SchemaNames names, string encspace) { JToken jitem = token["items"]; if (jitem == null) { throw new BaijiTypeException("Array does not have 'items'"); } return(new ArraySchema(ParseJson(jitem, names, encspace), props)); }
/// <summary> /// Static function to return new instance of map schema /// </summary> /// <param name="jtok">JSON object for the map schema</param> /// <param name="names">list of named schemas already read</param> /// <param name="encspace">enclosing namespace of the map schema</param> /// <returns></returns> internal static MapSchema NewInstance(JToken jtok, PropertyMap props, SchemaNames names, string encspace) { JToken jvalue = jtok["values"]; if (null == jvalue) { throw new BaijiTypeException("Map does not have 'values'"); } return(new MapSchema(ParseJson(jvalue, names, encspace), props)); }
/// <summary> /// Static function to return new instance of the record schema /// </summary> /// <param name="jtok">JSON object for the record schema</param> /// <param name="props"></param> /// <param name="names">list of named schema already read</param> /// <param name="encspace">enclosing namespace of the records schema</param> /// <returns>new RecordSchema object</returns> internal static RecordSchema NewInstance(JToken jtok, PropertyMap props, SchemaNames names, string encspace) { bool request = false; JToken jfields = jtok["fields"]; // normal record if (null == jfields) { jfields = jtok["request"]; // anonymous record from messages if (null != jfields) { request = true; } } if (null == jfields) { throw new SchemaParseException("'fields' cannot be null for record"); } if (jfields.Type != JTokenType.Array) { throw new SchemaParseException("'fields' not an array for record"); } var name = GetName(jtok, encspace); var aliases = GetAliases(jtok, name.Space, name.EncSpace); var doc = JsonHelper.GetOptionalString(jtok, "doc"); var fields = new List <Field>(); var fieldMap = new Dictionary <string, Field>(); var fieldAliasMap = new Dictionary <string, Field>(); var result = new RecordSchema(name, doc, aliases, props, fields, request, fieldMap, fieldAliasMap, names); int fieldPos = 0; foreach (JObject jfield in jfields) { string fieldName = JsonHelper.GetRequiredString(jfield, "name"); Field field = CreateField(jfield, fieldPos++, names, name.Namespace); // add record namespace for field look up fields.Add(field); AddToFieldMap(fieldMap, fieldName, field); AddToFieldMap(fieldAliasMap, fieldName, field); if (null != field.Aliases) // add aliases to field lookup map so reader function will find it when writer field name appears only as an alias on the reader field { foreach (string alias in field.Aliases) { AddToFieldMap(fieldAliasMap, alias, field); } } } return(result); }
/// <summary> /// Writes enum schema in JSON format /// </summary> /// <param name="writer">JSON writer</param> /// <param name="names">list of named schema already written</param> /// <param name="encspace">enclosing namespace of the enum schema</param> protected internal override void WriteJsonFields(JsonTextWriter writer, SchemaNames names, string encspace) { base.WriteJsonFields(writer, names, encspace); writer.WritePropertyName("symbols"); writer.WriteStartArray(); foreach (string s in Symbols) { writer.WriteValue(s); } writer.WriteEndArray(); }
/// <summary> /// Constructor for the record schema /// </summary> /// <param name="name">name of the record schema</param> /// <param name="doc"></param> /// <param name="aliases">list of aliases for the record name</param> /// <param name="props"></param> /// <param name="fields">list of fields for the record</param> /// <param name="request">true if this is an anonymous record with 'request' instead of 'fields'</param> /// <param name="fieldMap">map of field names and field objects</param> /// <param name="fieldAliasMap">map of field aliases and field objects</param> /// <param name="names">list of named schema already read</param> private RecordSchema(SchemaName name, string doc, IList <SchemaName> aliases, PropertyMap props, List <Field> fields, bool request, IDictionary <string, Field> fieldMap, IDictionary <string, Field> fieldAliasMap, SchemaNames names) : base(SchemaType.Record, name, doc, aliases, props, names) { if (!request && null == name.Name) { throw new SchemaParseException("name cannot be null for record schema."); } Fields = fields; this._request = request; _fieldLookup = fieldMap; _fieldAliasLookup = fieldAliasMap; }
/// <summary> /// Constructor for named schema class /// </summary> /// <param name="type">schema type</param> /// <param name="name">name</param> /// <param name="aliases"></param> /// <param name="doc"></param> /// <param name="props"></param> /// <param name="names">list of named schemas already read</param> protected NamedSchema(SchemaType type, SchemaName name, string doc, IList <SchemaName> aliases, PropertyMap props, SchemaNames names) : base(type, props) { SchemaName = name; Doc = doc; this.aliases = aliases; if (null != name.Name) // Added this check for anonymous records inside Message { if (!names.Add(name, this)) { throw new BaijiException("Duplicate schema name " + name.Fullname); } } }
/// <summary> /// Writes the schema name in JSON format /// </summary> /// <param name="writer">JSON writer</param> /// <param name="names">list of named schemas already written</param> /// <param name="encspace">enclosing namespace of the schema</param> internal void WriteJson(JsonTextWriter writer, SchemaNames names, string encspace) { if (null == Name) { return; } JsonHelper.WriteIfNotNullOrEmpty(writer, "name", Name); if (!string.IsNullOrEmpty(Space)) { JsonHelper.WriteIfNotNullOrEmpty(writer, "namespace", Space); } else if (!string.IsNullOrEmpty(EncSpace)) // need to put enclosing name space for code generated classes { JsonHelper.WriteIfNotNullOrEmpty(writer, "namespace", EncSpace); } }
/// <summary> /// Parses a JSON string to create a new schema object /// </summary> /// <param name="json">JSON string</param> /// <param name="names">list of named schemas already read</param> /// <param name="encspace">enclosing namespace of the schema</param> /// <returns>new Schema object</returns> internal static Schema Parse(string json, SchemaNames names, string encspace) { Schema sc = PrimitiveSchema.NewInstance(json); if (null != sc) { return(sc); } try { bool isArray = json.StartsWith("[") && json.EndsWith("]"); JContainer j = isArray ? (JContainer)JArray.Parse(json) : (JContainer)JObject.Parse(json); return(ParseJson(j, names, encspace)); } catch (JsonSerializationException ex) { throw new SchemaParseException("Could not parse. " + ex.Message + Environment.NewLine + json); } }
/// <summary> /// Static function to return a new instance of the named schema /// </summary> /// <param name="jo">JSON object of the named schema</param> /// <param name="props"></param> /// <param name="names">list of named schemas already read</param> /// <param name="encspace">enclosing namespace of the named schema</param> /// <returns></returns> internal static NamedSchema NewInstance(JObject jo, PropertyMap props, SchemaNames names, string encspace) { string type = JsonHelper.GetRequiredString(jo, "type"); switch (type) { case "enum": return(EnumSchema.NewInstance(jo, props, names, encspace)); case "record": return(RecordSchema.NewInstance(jo, props, names, encspace)); default: NamedSchema result; if (names.TryGetValue(type, null, encspace, out result)) { return(result); } return(null); } }
/// <summary> /// Writes named schema in JSON format /// </summary> /// <param name="writer">JSON writer</param> /// <param name="names">list of named schemas already written</param> /// <param name="encspace">enclosing namespace of the named schema</param> protected internal override void WriteJsonFields(JsonTextWriter writer, SchemaNames names, string encspace) { SchemaName.WriteJson(writer, names, encspace); if (string.IsNullOrEmpty(Doc)) { writer.WritePropertyName("doc"); writer.WriteValue(Doc); } if (null != aliases) { writer.WritePropertyName("aliases"); writer.WriteStartArray(); foreach (SchemaName name in aliases) { string fullname = (null != name.Space) ? name.Space + "." + name.Name : name.Name; writer.WriteValue(fullname); } writer.WriteEndArray(); } }
/// <summary> /// Writes named schema in JSON format /// </summary> /// <param name="writer">JSON writer</param> /// <param name="names">list of named schemas already written</param> /// <param name="encspace">enclosing namespace of the named schema</param> protected internal override void WriteJson(JsonTextWriter writer, SchemaNames names, string encspace) { if (!names.Add(this)) { // schema is already in the list, write name only SchemaName schemaName = SchemaName; string name; if (schemaName.Namespace != encspace) { name = schemaName.Namespace + "." + schemaName.Name; // we need to add the qualifying namespace of the target schema if it's not the same as current namespace } else { name = schemaName.Name; } writer.WriteValue(name); } else { // schema is not in the list, write full schema definition base.WriteJson(writer, names, encspace); } }
/// <summary> /// Writes the records schema in JSON format /// </summary> /// <param name="writer">JSON writer</param> /// <param name="names">list of named schemas already written</param> /// <param name="encspace">enclosing namespace of the record schema</param> protected internal override void WriteJsonFields(JsonTextWriter writer, SchemaNames names, string encspace) { base.WriteJsonFields(writer, names, encspace); // we allow reading for empty fields, so writing of records with empty fields are allowed as well if (_request) { writer.WritePropertyName("request"); } else { writer.WritePropertyName("fields"); } writer.WriteStartArray(); if (null != Fields && Fields.Count > 0) { foreach (Field field in this) { field.WriteJson(writer, names, Namespace); // use the namespace of the record for the fields } } writer.WriteEndArray(); }
/// <summary> /// Writes primitive schema in JSON format /// </summary> /// <param name="w"></param> /// <param name="names"></param> /// <param name="encspace"></param> protected internal override void WriteJson(JsonTextWriter w, SchemaNames names, string encspace) { w.WriteValue(Name); }
/// <summary> /// Writes map schema in JSON format /// </summary> /// <param name="writer">JSON writer</param> /// <param name="names">list of named schemas already written</param> /// <param name="encspace">enclosing namespace of the map schema</param> protected internal override void WriteJsonFields(JsonTextWriter writer, SchemaNames names, string encspace) { writer.WritePropertyName("values"); ValueSchema.WriteJson(writer, names, encspace); }
/// <summary> /// Default implementation for writing schema properties in JSON format /// </summary> /// <param name="writer">JSON writer</param> /// <param name="names">list of named schemas already written</param> /// <param name="encspace">enclosing namespace of the schema</param> protected internal virtual void WriteJsonFields(JsonTextWriter writer, SchemaNames names, string encspace) { }
/// <summary> /// Static method to return new instance of schema object /// </summary> /// <param name="jtok">JSON object</param> /// <param name="names">list of named schemas already read</param> /// <param name="encspace">enclosing namespace of the schema</param> /// <returns>new Schema object</returns> internal static Schema ParseJson(JToken jtok, SchemaNames names, string encspace) { if (null == jtok) { throw new ArgumentNullException("jtok", "jtok cannot be null."); } if (jtok.Type == JTokenType.String) // primitive schema with no 'type' property or primitive or named type of a record field { string value = (string)jtok; PrimitiveSchema ps = PrimitiveSchema.NewInstance(value); if (null != ps) { return(ps); } NamedSchema schema = null; if (names.TryGetValue(value, null, encspace, out schema)) { return(schema); } throw new SchemaParseException("Undefined name: " + value); } if (jtok is JArray) // union schema with no 'type' property or union type for a record field { return(UnionSchema.NewInstance(jtok as JArray, null, names, encspace)); } if (jtok is JObject) // JSON object with open/close parenthesis, it must have a 'type' property { JObject jo = jtok as JObject; JToken jtype = jo["type"]; if (null == jtype) { throw new SchemaParseException("Property type is required"); } var props = JsonHelper.GetProperties(jtok); if (jtype.Type == JTokenType.String) { string type = (string)jtype; if (type.Equals("array")) { return(ArraySchema.NewInstance(jtok, props, names, encspace)); } if (type.Equals("map")) { return(MapSchema.NewInstance(jtok, props, names, encspace)); } Schema schema = PrimitiveSchema.NewInstance((string)type, props); if (null != schema) { return(schema); } return(NamedSchema.NewInstance(jo, props, names, encspace)); } else if (jtype.Type == JTokenType.Array) { return(UnionSchema.NewInstance(jtype as JArray, props, names, encspace)); } } throw new BaijiTypeException("Invalid JSON for schema: " + jtok); }
/// <summary> /// Constructor for enum schema /// </summary> /// <param name="name">name of enum</param> /// <param name="doc"></param> /// <param name="aliases">list of aliases for the name</param> /// <param name="symbols">list of enum symbols</param> /// <param name="symbolMap">map of enum symbols and value</param> /// <param name="names">list of named schema already read</param> private EnumSchema(SchemaName name, string doc, IList <SchemaName> aliases, IList <string> symbols, IDictionary <string, int?[]> symbolMap, PropertyMap props, SchemaNames names) : base(SchemaType.Enumeration, name, doc, aliases, props, names) { if (null == name.Name) { throw new SchemaParseException("name cannot be null for enum schema."); } Symbols = symbols; this.symbolMap = symbolMap; }
/// <summary> /// Static function to return new instance of EnumSchema /// </summary> /// <param name="token">JSON object for enum schema</param> /// <param name="names">list of named schema already parsed in</param> /// <param name="encspace">enclosing namespace for the enum schema</param> /// <returns>new instance of enum schema</returns> internal static EnumSchema NewInstance(JToken token, PropertyMap props, SchemaNames names, string encspace) { SchemaName name = GetName(token, encspace); var aliases = GetAliases(token, name.Space, name.EncSpace); var doc = JsonHelper.GetOptionalString(token, "doc"); JArray jsymbols = token["symbols"] as JArray; if (null == jsymbols) { throw new SchemaParseException("Enum has no symbols: " + name); } var symbols = new List <string>(); IDictionary <string, int?[]> symbolMap = new Dictionary <string, int?[]>(); int lastValue = -1; foreach (JToken jsymbol in jsymbols) { int? explicitValue = null; int actualValue; string symbol; if (jsymbol is JValue) { symbol = (string)((JValue)jsymbol).Value; actualValue = ++lastValue; } else if (jsymbol is JObject) { var symbolObj = (JObject)jsymbol; symbol = symbolObj.Value <string>("name"); if (symbol == null) { throw new SchemaParseException("Missing symbol name: " + jsymbol); } JToken valueToken; if (symbolObj.TryGetValue("value", out valueToken)) { try { explicitValue = symbolObj.Value <int>("value"); } catch (System.Exception) { throw new SchemaParseException("Only integer value is allowed for an enum symbol: " + jsymbol); } } lastValue = actualValue = explicitValue.HasValue ? explicitValue.Value : lastValue + 1; } else { throw new SchemaParseException("Invalid symbol object: " + jsymbol); } if (symbolMap.ContainsKey(symbol)) { throw new SchemaParseException("Duplicate symbol: " + symbol); } symbolMap[symbol] = new [] { explicitValue, actualValue }; symbols.Add(symbol); } return(new EnumSchema(name, doc, aliases, symbols, symbolMap, props, names)); }