Beispiel #1
0
        /// <summary>
        /// PropertyType has to be (ComponentJson, Row or Type). Or PropertyType and PropertyValue type need to match. Applies also for list or dictionary.
        /// </summary>
        private void ValidatePropertyAndValueType(PropertyInfo propertyInfo, object propertyValue)
        {
            var property = new Property(propertyInfo, propertyValue);

            Type        propertyType      = property.PropertyType;
            ICollection propertyValueList = property.PropertyValueList;

            // Property type is of type ComponentJson or Row. For example property type object would throw exception.
            if (UtilFramework.IsSubclassOf(propertyType, typeof(ComponentJson)) || UtilFramework.IsSubclassOf(propertyType, typeof(Row)))
            {
                return;
            }
            // Property type is class Type. Property value typeof(int) is class RuntimeType (which derives from class Type)
            if (propertyType == typeof(Type))
            {
                return;
            }

            foreach (var item in propertyValueList)
            {
                if (item != null)
                {
                    // Property type is equal to value. No inheritance.
                    if (!(UtilFramework.TypeUnderlying(propertyType) == item.GetType()))
                    {
                        throw new Exception(string.Format("Combination property type and value type not supported! (PropertyName={0}.{1}; PropertyType={2}; ValueType={3}; Value={4};)", propertyInfo.DeclaringType.Name, propertyInfo.Name, propertyType.Name, item.GetType().Name, item));
                    }
                }
            }
        }
Beispiel #2
0
        /// <summary>
        /// Deserialize ComponentJson or Row objects.
        /// </summary>
        public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            // Deserialize Type object
            if (typeToConvert == typeof(Type))
            {
                var typeName = JsonSerializer.Deserialize <string>(ref reader);
                return((T)(object)Type.GetType(typeName));
            }

            // Deserialize ComponentJson or Row object
            var valueList = JsonSerializer.Deserialize <Dictionary <string, JsonElement> >(ref reader);

            // Deserialize Row
            if (UtilFramework.IsSubclassOf(typeToConvert, typeof(Row)))
            {
                var    typeRowName = valueList["$typeRow"].GetString();
                string rowJson     = valueList["$row"].GetRawText();
                Type   typeRow     = Type.GetType(typeRowName);
                var    resultRow   = JsonSerializer.Deserialize(rowJson, typeRow); // Native deserialization for data row.
                return((T)(object)resultRow);
            }

            // Read type information
            string typeText = valueList["$type"].GetString();
            Type   type     = Type.GetType(typeText);                        // TODO Cache on factory
            var    result   = (ComponentJson)Activator.CreateInstance(type); // TODO No parameterless constructor for ComponentJson

            // Loop through properties
            foreach (var propertyInfo in type.GetProperties())
            {
                if (valueList.ContainsKey(propertyInfo.Name))
                {
                    if (IsComponentJsonReference(propertyInfo))
                    {
                        // Deserialize ComponentJsonReference
                        var componentJsonReferenceValueList = JsonSerializer.Deserialize <Dictionary <string, JsonElement> >(valueList[propertyInfo.Name].GetRawText());
                        UtilFramework.Assert(componentJsonReferenceValueList["$type"].GetString() == "$componentJsonReference");
                        int id = componentJsonReferenceValueList["$id"].GetInt32();
                        Factory.ComponentJsonReferenceList.Add(new ComponentJsonReference {
                            PropertyInfo = propertyInfo, ComponentJson = result, Id = id
                        });
                        continue;
                    }

                    // Deserialize ComponentJson
                    var propertyValue = JsonSerializer.Deserialize(valueList[propertyInfo.Name].GetRawText(), propertyInfo.PropertyType, options);
                    propertyInfo.SetValue(result, propertyValue);
                }
            }

            // Add ComponentJson for ComponentJsonReference resolve
            Factory.ComponentJsonList.Add(result.Id, result);

            return((T)(object)result);
        }
Beispiel #3
0
        private bool IsComponentJsonReference(PropertyInfo propertyInfo)
        {
            bool     result              = false;
            Property property            = new Property(propertyInfo, null);
            bool     isComponentJsonList = propertyInfo.DeclaringType == typeof(ComponentJson) && propertyInfo.Name == nameof(ComponentJson.List);
            bool     isComponentJson     = UtilFramework.IsSubclassOf(property.PropertyType, typeof(ComponentJson));

            if (!isComponentJsonList && isComponentJson) // Is it a component reference?
            {
                if (property.PropertyEnum == PropertyEnum.List || property.PropertyEnum == PropertyEnum.Dictionary)
                {
                    throw new Exception("ComponentJson reference supported only for property! Not for list and dictionary!");
                }
                result = true;
            }
            return(result);
        }
Beispiel #4
0
        /// <summary>
        /// Serialize ComponentJson or Row objects.
        /// </summary>
        public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
        {
            // Serialize Type object
            if (typeof(T) == typeof(Type))
            {
                JsonSerializer.Serialize(writer, (value as Type).FullName);
                return;
            }

            // Serialize data row object
            if (UtilFramework.IsSubclassOf(typeof(T), typeof(Row)))
            {
                writer.WriteStartObject();
                writer.WritePropertyName("$typeRow");
                JsonSerializer.Serialize(writer, value.GetType().FullName);
                writer.WritePropertyName("$row");
                JsonSerializer.Serialize(writer, value, value.GetType()); // Native serialization of data row
                writer.WriteEndObject();
                return;
            }

            // ComponentJson or Row object start
            writer.WriteStartObject();

            // Type information
            writer.WritePropertyName("$type"); // Note: Type information could be omitted if property type is equal to property value type.
            JsonSerializer.Serialize(writer, value.GetType().FullName);

            // Loop through properties
            foreach (var propertyInfo in value.GetType().GetProperties())
            {
                var  propertyValue     = propertyInfo.GetValue(value);
                bool isIgnoreNullValue = false;
                if (propertyValue == null)
                {
                    isIgnoreNullValue = true;
                }
                if (propertyValue is ICollection list && list.Count == 0)
                {
                    isIgnoreNullValue = true;
                }
                if (!isIgnoreNullValue)
                {
                    ValidatePropertyAndValueType(propertyInfo, propertyValue);
                    writer.WritePropertyName(propertyInfo.Name);
                    if (IsComponentJsonReference(propertyInfo))
                    {
                        writer.WriteStartObject();
                        writer.WritePropertyName("$type");
                        JsonSerializer.Serialize(writer, "$componentJsonReference");
                        writer.WritePropertyName("$id");
                        var id = ((ComponentJson)propertyValue).Id;
                        JsonSerializer.Serialize <int>(writer, id);
                        writer.WriteEndObject();
                    }
                    else
                    {
                        // TODO Distinct serialize for client and for server.
                        // TODO Check ComponentJson reference is in same composition- graph.

                        // Serialize property value
                        JsonSerializer.Serialize(writer, propertyValue, propertyInfo.PropertyType, options);
                    }
                }
            }

            // ComponentJson or Row object end
            writer.WriteEndObject();
        }
Beispiel #5
0
 public override bool CanConvert(Type typeToConvert)
 {
     // Handle inheritance of ComponentJson and Row classes. Or handle Type object.
     return(UtilFramework.IsSubclassOf(typeToConvert, typeof(ComponentJson)) || UtilFramework.IsSubclassOf(typeToConvert, typeof(Row)) || typeToConvert == typeof(Type));
 }