/// <summary> /// Initializes a new instance of the <see cref="FileHierarchyReflector"/> class. /// </summary> /// <param name="index">The <see cref="Index"/>.</param> /// <param name="fh">The <see cref="FileHierarchy"/>.</param> /// <param name="pi">The <see cref="PropertyInfo"/>.</param> /// <param name="ff">The <see cref="FileFormat"/>.</param> internal FileHierarchyReflector(int index, FileHierarchyAttribute fh, PropertyInfo pi, FileFormatBase ff) { Index = index; Order = fh.Order < 0 ? int.MaxValue : fh.Order; FileHierarchy = fh; PropertyInfo = pi; FileFormat = ff; // Where an intrinsic type then we have an issue. if (FileColumnReflector.GetTypeCode(PropertyInfo.PropertyType) != TypeCode.Object) { throw new ArgumentException($"Type '{PropertyInfo.DeclaringType.Name}' Property '{PropertyInfo.Name}' must be a class or collection (FileHierarchyAttribute).", nameof(pi)); } // Determine the collection type. _collTypeReflector = ComplexTypeReflector.Create(PropertyInfo); // Load/cache the corresponding property type. var frr = (_collTypeReflector.ComplexTypeCode == ComplexTypeCode.Object) ? FileFormat.GetFileRecordReflector(PropertyInfo.PropertyType) : FileFormat.GetFileRecordReflector(_collTypeReflector.ItemType); if (fh.ValidationType != null) { frr.SetValidatorType(fh.ValidationType); } }
/// <summary> /// Initializes a new instance of the <see cref="PropertyMapperCustomBase{TEntity, TProperty}"/> class. /// </summary> /// <param name="srcePropertyExpression">The <see cref="LambdaExpression"/> to reference the source entity property.</param> /// <param name="destPropertyName">The name of the destination property (defaults to <see cref="SrcePropertyName"/> where null).</param> /// <param name="operationTypes">The <see cref="Mapper.OperationTypes"/> selection to enable inclusion or exclusion of property (default to <see cref="OperationTypes.Any"/>).</param> protected PropertyMapperCustomBase(Expression <Func <TSrce, TSrceProperty> > srcePropertyExpression, string destPropertyName, OperationTypes operationTypes = OperationTypes.Any) { SrcePropertyExpression = PropertyExpression.Create(srcePropertyExpression ?? throw new ArgumentNullException(nameof(srcePropertyExpression))); SrcePropertyInfo = TypeReflector.GetPropertyInfo(typeof(TSrce), SrcePropertyName); DestPropertyName = string.IsNullOrEmpty(destPropertyName) ? SrcePropertyExpression.Name : destPropertyName; OperationTypes = operationTypes; if (SrcePropertyInfo.PropertyType.IsClass && SrcePropertyInfo.PropertyType != typeof(string)) { SrceComplexTypeReflector = ComplexTypeReflector.Create(SrcePropertyInfo); } }
/// <summary> /// Recursively find all types (definitions). /// </summary> private static void FindAllTypes(List <Type> types, Type type) { foreach (var pi in type.GetProperties()) { var pcsa = pi.GetCustomAttribute <PropertyCollectionSchemaAttribute>(); if (pcsa != null) { if (pi.PropertyType == typeof(List <string>)) { continue; } var t = ComplexTypeReflector.GetItemType(pi.PropertyType); if (types.Contains(t)) { continue; } types.Add(t); FindAllTypes(types, t); } } }
/// <summary> /// Writes the schema for the object. /// </summary> private static void WriteObject(ConfigType ct, Type type, XNamespace ns, XElement xe, bool isRoot) { var csa = type.GetCustomAttribute <ClassSchemaAttribute>(); if (csa == null) { throw new InvalidOperationException($"Type '{type.Name}' does not have a required ClassSchemaAttribute."); } if (!Enum.TryParse <ConfigurationEntity>(csa.Name, out var ce)) { ce = ConfigurationEntity.CodeGen; } var xml = new XElement(ns + "element"); xml.Add(new XAttribute("name", csa.Name)); if (!isRoot) { xml.Add(new XAttribute("minOccurs", "0")); xml.Add(new XAttribute("maxOccurs", "unbounded")); } xml.Add(new XElement(ns + "annotation", new XElement(ns + "documentation", csa.Title))); var xct = new XElement(ns + "complexType"); // Add sub-collections within xs:choice element. var hasSeq = false; var xs = new XElement(ns + "choice"); xs.Add(new XAttribute("maxOccurs", "unbounded")); foreach (var pi in type.GetProperties()) { var pcsa = pi.GetCustomAttribute <PropertyCollectionSchemaAttribute>(); if (pcsa == null) { continue; } // Properties with List<string> are not compatible with XML and should be picked up as comma separated strings. if (pi.PropertyType == typeof(List <string>)) { continue; } WriteObject(ct, ComplexTypeReflector.GetItemType(pi.PropertyType), ns, xs, false); hasSeq = true; } if (hasSeq) { xct.Add(xs); } // Add properties as xs:attribute's. foreach (var pi in type.GetProperties()) { var jpa = pi.GetCustomAttribute <JsonPropertyAttribute>(); if (jpa == null) { continue; } var name = jpa.PropertyName ?? StringConversion.ToCamelCase(pi.Name) !; var xmlName = XmlYamlTranslate.GetXmlName(ct, ce, name); var xmlOverride = XmlYamlTranslate.GetXmlPropertySchemaAttribute(ct, ce, xmlName); var psa = xmlOverride.Attribute ?? pi.GetCustomAttribute <PropertySchemaAttribute>(); if (psa == null) { // Properties with List<string> are not compatible with XML and should be picked up as comma separated strings. if (pi.PropertyType == typeof(List <string>)) { var pcsa = pi.GetCustomAttribute <PropertyCollectionSchemaAttribute>(); if (pcsa == null) { continue; } var xpx = new XElement(ns + "attribute", new XAttribute("name", xmlName), new XAttribute("use", pcsa.IsMandatory ? "required" : "optional")); xpx.Add(new XElement(ns + "annotation", new XElement(ns + "documentation", GetDocumentation(name, pcsa)))); xct.Add(xpx); } continue; } var xp = new XElement(ns + "attribute", new XAttribute("name", xmlName), new XAttribute("use", psa.IsMandatory ? "required" : "optional")); xp.Add(new XElement(ns + "annotation", new XElement(ns + "documentation", GetDocumentation(name, psa)))); if (psa.Options == null) { xp.Add(new XAttribute("type", GetXmlType(pi, xmlOverride.Type))); } else { var xr = new XElement(ns + "restriction", new XAttribute("base", GetXmlType(pi, xmlOverride.Type))); foreach (var opt in psa.Options) { xr.Add(new XElement(ns + "enumeration", new XAttribute("value", opt))); } xp.Add(new XElement(ns + "simpleType", xr)); } xct.Add(xp); } // Add this type into the overall document. xml.Add(xct); xe.Add(xml); }
/// <summary> /// Initializes a new instance of the <see cref="DictionaryRule{TEntity, TProperty}"/> class. /// </summary> public DictionaryRule() { var(kt, vt) = ComplexTypeReflector.GetDictionaryType(typeof(TProperty)); _keyType = kt !; _valueType = vt !; }
/// <summary> /// Writes the schema for the object. /// </summary> private static void WriteObject(Type type, XNamespace ns, XElement xe, bool isRoot) { var csa = type.GetCustomAttribute <ClassSchemaAttribute>(); if (csa == null) { throw new InvalidOperationException($"Type '{type.Name}' does not have a required ClassSchemaAttribute."); } if (!Enum.TryParse <ConfigurationEntity>(csa.Name, out var ce)) { ce = ConfigurationEntity.CodeGen; } var xml = new XElement(ns + "element"); xml.Add(new XAttribute("name", csa.Name)); if (!isRoot) { xml.Add(new XAttribute("minOccurs", "0")); xml.Add(new XAttribute("maxOccurs", "unbounded")); } xml.Add(new XElement(ns + "annotation", new XElement(ns + "documentation", csa.Title))); var xct = new XElement(ns + "complexType"); // Add sub-collections within xs:sequence element. var hasSeq = false; var xs = new XElement(ns + "sequence"); foreach (var pi in type.GetProperties()) { var pcsa = pi.GetCustomAttribute <PropertyCollectionSchemaAttribute>(); if (pcsa == null) { continue; } WriteObject(ComplexTypeReflector.GetItemType(pi.PropertyType), ns, xs, false); hasSeq = true; } if (hasSeq) { xct.Add(xs); } // Add properties as xs:attribute's. foreach (var pi in type.GetProperties()) { var jpa = pi.GetCustomAttribute <JsonPropertyAttribute>(); if (jpa == null) { continue; } var psa = pi.GetCustomAttribute <PropertySchemaAttribute>(); if (psa == null) { continue; } var name = jpa.PropertyName ?? Beef.CodeGen.CodeGenerator.ToCamelCase(pi.Name) !; var xp = new XElement(ns + "attribute", new XAttribute("name", XmlJsonRename.GetXmlName(ce, name)), new XAttribute("use", psa.IsMandatory ? "required" : "optional")); xp.Add(new XElement(ns + "annotation", new XElement(ns + "documentation", GetDocumentation(name, psa)))); if (psa.Options == null) { xp.Add(new XAttribute("type", GetXmlType(pi))); } else { var xr = new XElement(ns + "restriction", new XAttribute("base", GetXmlType(pi))); foreach (var opt in psa.Options) { xr.Add(new XElement(ns + "enumeration", new XAttribute("value", opt))); } xp.Add(new XElement(ns + "simpleType", xr)); } xct.Add(xp); } // Add this type into the overall document. xml.Add(xct); xe.Add(xml); }
/// <summary> /// Writes the object definition. /// </summary> private static void WriteDefinition(Type type, JsonTextWriter jtw) { var csa = type.GetCustomAttribute <ClassSchemaAttribute>(); if (csa == null) { throw new InvalidOperationException($"Type {type.Name} does not have required ClassSchemaAttribute defined."); } jtw.WritePropertyName(csa.Name); jtw.WriteStartObject(); jtw.WritePropertyName("type"); jtw.WriteValue("object"); jtw.WritePropertyName("title"); jtw.WriteValue(CleanString(csa.Title) ?? StringConversion.ToSentenceCase(csa.Name) !); if (csa.Description != null) { jtw.WritePropertyName("description"); jtw.WriteValue(CleanString(csa.Description)); } jtw.WritePropertyName("properties"); jtw.WriteStartObject(); var rqd = new List <string>(); foreach (var pi in type.GetProperties()) { var jpa = pi.GetCustomAttribute <JsonPropertyAttribute>(); if (jpa == null) { continue; } var name = jpa.PropertyName ?? StringConversion.ToCamelCase(pi.Name) !; jtw.WritePropertyName(name); jtw.WriteStartObject(); var psa = pi.GetCustomAttribute <PropertySchemaAttribute>(); if (psa != null) { jtw.WritePropertyName("type"); jtw.WriteValue(GetJsonType(pi)); jtw.WritePropertyName("title"); jtw.WriteValue(CleanString(psa.Title) ?? StringConversion.ToSentenceCase(name) !); if (psa.Description != null) { jtw.WritePropertyName("description"); jtw.WriteValue(CleanString(psa.Description)); } if (psa.IsMandatory) { rqd.Add(name); } if (psa.Options != null) { jtw.WritePropertyName("enum"); jtw.WriteStartArray(); foreach (var opt in psa.Options) { jtw.WriteValue(opt); } jtw.WriteEndArray(); } } else { var pcsa = pi.GetCustomAttribute <PropertyCollectionSchemaAttribute>(); if (pcsa == null) { throw new InvalidOperationException($"Type '{type.Name}' Property '{pi.Name}' does not have a required PropertySchemaAttribute or PropertyCollectionSchemaAttribute."); } jtw.WritePropertyName("type"); jtw.WriteValue("array"); jtw.WritePropertyName("title"); jtw.WriteValue(CleanString(pcsa.Title) ?? StringConversion.ToSentenceCase(name) !); if (pcsa.Description != null) { jtw.WritePropertyName("description"); jtw.WriteValue(CleanString(pcsa.Description)); } jtw.WritePropertyName("items"); if (pi.PropertyType == typeof(List <string>)) { jtw.WriteStartObject(); jtw.WritePropertyName("type"); jtw.WriteValue("string"); jtw.WriteEndObject(); } else { var t = ComplexTypeReflector.GetItemType(pi.PropertyType); jtw.WriteStartObject(); jtw.WritePropertyName("$ref"); jtw.WriteValue($"#/definitions/{t.GetCustomAttribute<ClassSchemaAttribute>()!.Name}"); jtw.WriteEndObject(); } } jtw.WriteEndObject(); } jtw.WriteEndObject(); if (rqd.Count > 0) { jtw.WritePropertyName("required"); jtw.WriteStartArray(); foreach (var name in rqd) { jtw.WriteValue(name); } jtw.WriteEndArray(); } jtw.WriteEndObject(); }
/// <summary> /// Initializes a new instance of the <see cref="CollectionRule{TEntity, TProperty}"/> class. /// </summary> public CollectionRule() { _itemType = ComplexTypeReflector.GetItemType(typeof(TProperty)); }
/// <summary> /// Writes the schema for the object. /// </summary> private static void WriteObject(Type type, JsonTextWriter jtw, Action?additional = null) { jtw.WriteStartObject(); additional?.Invoke(); jtw.WritePropertyName("type"); jtw.WriteValue("object"); jtw.WritePropertyName("properties"); jtw.WriteStartObject(); var rqd = new List <string>(); foreach (var pi in type.GetProperties()) { var jpa = pi.GetCustomAttribute <JsonPropertyAttribute>(); if (jpa == null) { continue; } var name = jpa.PropertyName ?? Beef.CodeGen.CodeGenerator.ToCamelCase(pi.Name) !; jtw.WritePropertyName(name); jtw.WriteStartObject(); var psa = pi.GetCustomAttribute <PropertySchemaAttribute>(); if (psa != null) { jtw.WritePropertyName("type"); jtw.WriteValue(GetJsonType(pi)); jtw.WritePropertyName("title"); jtw.WriteValue(psa.Title ?? Beef.CodeGen.CodeGenerator.ToSentenceCase(name) !); if (psa.Description != null) { jtw.WritePropertyName("description"); jtw.WriteValue(psa.Description); } if (psa.IsMandatory) { rqd.Add(name); } if (psa.Options != null) { jtw.WritePropertyName("enum"); jtw.WriteStartArray(); foreach (var opt in psa.Options) { jtw.WriteValue(opt); } jtw.WriteEndArray(); } } else { var pcsa = pi.GetCustomAttribute <PropertyCollectionSchemaAttribute>(); if (pcsa == null) { throw new InvalidOperationException($"Type '{type.Name}' Property '{pi.Name}' does not have a required PropertySchemaAttribute or PropertyCollectionSchemaAttribute."); } jtw.WritePropertyName("type"); jtw.WriteValue("array"); jtw.WritePropertyName("title"); jtw.WriteValue(pcsa.Title ?? Beef.CodeGen.CodeGenerator.ToSentenceCase(name) !); if (pcsa.Description != null) { jtw.WritePropertyName("description"); jtw.WriteValue(pcsa.Description); } jtw.WritePropertyName("items"); jtw.WriteStartArray(); WriteObject(ComplexTypeReflector.GetItemType(pi.PropertyType), jtw); jtw.WriteEndArray(); } jtw.WriteEndObject(); } jtw.WriteEndObject(); if (rqd.Count > 0) { jtw.WritePropertyName("required"); jtw.WriteStartArray(); foreach (var name in rqd) { jtw.WriteValue(name); } jtw.WriteEndArray(); } jtw.WriteEndObject(); }