Exemplo n.º 1
0
        private object ReadValue(
            ref Utf8JsonReader reader,
            IOpenApiType valueType,
            Type valueClrType,
            JsonSerializerOptions options)
        {
            // TODO: dictionary and enumerable handling
            if (!reader.Read())
            {
                throw new JsonException($"Unexpected end of stream.");
            }

            if (reader.TokenType == JsonTokenType.Null)
            {
                return(null);
            }

            if (valueClrType == typeof(string))
            {
                return(reader.GetString());
            }
            if (ReflectionHelper.ImplementsEnumerable(valueClrType, out var itemType))
            {
                var array = ReadArray(ref reader, _typeHandler.ResolveType(itemType), itemType, options);
                // TODO: convert to actual target type
                return(array);
            }
            else if (ReflectionHelper.ImplementsDictionary(valueClrType, out var dictKeyType, out var dictValueType))
            {
                // TODO: dictionarySupport
                return(null);
            }
Exemplo n.º 2
0
        public static object ReadObject(
            JsonElement obj,
            IOpenApiType itemType,
            Type itemClrType,
            IOpenApiTypeHandler typeHandler,
            bool objectAsDelta = false)
        {
            if (itemType == null)
            {
                throw new SerializationException("Cannot deserialize unknown type.");
            }

            var properties = obj.EnumerateObject().ToDictionary(p => p.Name, p => p.Value);

            if (properties.TryGetValue("@odata.type", out var type) && type.ValueKind == JsonValueKind.String)
            {
                var typeName   = type.GetString();
                var actualType = typeHandler.ResolveType(typeName);
                if (actualType == null)
                {
                    throw new SerializationException($"No type with identifier '{typeName}' found");
                }

                if (!itemClrType.IsAssignableFrom(actualType.ClrType))
                {
                    throw new SerializationException($"Type '{typeName}' is not assignable to '{itemType.JsonName}'");
                }

                itemType    = actualType;
                itemClrType = actualType.ClrType;
            }

            var instance = objectAsDelta
                ? Activator.CreateInstance(typeof(Delta <>).MakeGenericType(itemClrType))
                : Activator.CreateInstance(itemClrType);

            foreach (var member in properties)
            {
                if (itemType.TryGetProperty(member.Key, out var property))
                {
                    var propertyType = typeHandler.ResolveType(property.ClrProperty.PropertyType);

                    var value = ReadValue(member.Value,
                                          propertyType,
                                          property.ClrProperty.PropertyType,
                                          typeHandler,
                                          objectAsDelta);
                    // TODO: check for components in the model binding area which help us here
                    // many conversions (string -> enum,date,timespan) etc. do not work like this.
                    property.SetValue(instance, value);
                }
                else
                {
                    // TODO: how do we want to treat unknown props? fail or ignore?
                }
            }

            return(instance);
        }
Exemplo n.º 3
0
        public bool Equals(IOpenApiType other)
        {
            if (ReferenceEquals(null, other))
            {
                return(false);
            }

            if (ReferenceEquals(this, other))
            {
                return(true);
            }

            return(Equals(ClrType, other.ClrType));
        }
Exemplo n.º 4
0
        private object ReadArray(
            ref Utf8JsonReader reader,
            IOpenApiType itemType,
            Type itemClrType,
            JsonSerializerOptions options)
        {
            if (!reader.Read())
            {
                throw new JsonException($"Unexpected end of stream.");
            }

            switch (reader.TokenType)
            {
            case JsonTokenType.Null:
                return(null);

            case JsonTokenType.StartObject:
                return(ReadObjectArray(ref reader, itemType, itemClrType, options));

            case JsonTokenType.StartArray:
                if (itemClrType.IsArray)
                {
                    var elementType = itemClrType.GetElementType();
                    return(ReadArrayArray(ref reader,
                                          _typeHandler.ResolveType(elementType),
                                          elementType,
                                          options));
                }
                else
                {
                    throw new JsonException($"Unexpected JSON Token {reader.TokenType}.");
                }

            case JsonTokenType.String:
            case JsonTokenType.Number:
            case JsonTokenType.True:
            case JsonTokenType.False:
                // TODO: read array even though we already started it? we might need to do reading on our own
                // simple arrays
                return(JsonSerializer.Deserialize(ref reader, itemClrType.MakeArrayType(), options));

            case JsonTokenType.EndArray:
                return(Array.CreateInstance(itemClrType, 0));

            default:
                throw new JsonException($"Unexpected JSON Token {reader.TokenType}.");
            }
        }
Exemplo n.º 5
0
        public static void WriteArray(
            Utf8JsonWriter writer,
            IEnumerable resultItems,
            IOpenApiType itemType,
            SelectClause selectClause,
            IOpenApiTypeHandler typeHandler,
            JsonSerializerOptions options)
        {
            writer.WriteStartArray();

            foreach (var item in resultItems)
            {
                WriteValue(writer, itemType, item, selectClause, typeHandler, options);
            }

            writer.WriteEndArray();
        }
Exemplo n.º 6
0
        public static void WriteObject(
            Utf8JsonWriter writer,
            IOpenApiType itemType,
            object item,
            SelectClause selectClause,
            IOpenApiTypeHandler typeHandler,
            JsonSerializerOptions options)
        {
            if (item == null)
            {
                writer.WriteNullValue();
            }
            else
            {
                writer.WriteStartObject();

                var actualType = typeHandler.ResolveType(item.GetType());
                var needsType  = itemType == null || !itemType.Equals(actualType);
                if (needsType)
                {
                    writer.WriteString("@odata.type", actualType.JsonName);
                }

                foreach (var property in actualType.Properties)
                {
                    SelectClause subClause = null;
                    if (selectClause == null ||
                        selectClause.SelectClauses?.TryGetValue(property.ClrProperty, out subClause) == true ||
                        selectClause.IsStarSelect)
                    {
                        var key = options.PropertyNamingPolicy.ConvertName(property.JsonName);
                        writer.WritePropertyName(JsonEncodedText.Encode(key));

                        WriteValue(writer,
                                   typeHandler.ResolveType(property.ClrProperty.PropertyType),
                                   property.GetValue(item),
                                   subClause,
                                   typeHandler,
                                   options);
                    }
                }

                writer.WriteEndObject();
            }
        }
Exemplo n.º 7
0
        public static object ReadValue(
            JsonElement value,
            IOpenApiType valueType,
            Type valueClrType,
            IOpenApiTypeHandler typeHandler,
            bool objectsAsDelta = false)
        {
            switch (value.ValueKind)
            {
            case JsonValueKind.Object:
                if (valueType == null &&
                    ReflectionHelper.ImplementsDictionary(valueClrType, out var dictKeyType, out var dictValueType))
                {
                    var dictionary = Activator.CreateInstance(valueClrType);
                    var indexer    = valueClrType.GetProperties()
                                     .FirstOrDefault(p => IsDictionaryIndexer(p, dictKeyType, dictValueType));
                    if (indexer == null)
                    {
                        throw new SerializationException(
                                  "Could not find dictionary indexer for deserializing object");
                    }

                    var dictValueApiType = typeHandler.ResolveType(dictValueType);
                    foreach (var prop in value.EnumerateObject())
                    {
                        var dictValue = ReadValue(prop.Value,
                                                  dictValueApiType,
                                                  dictValueType,
                                                  typeHandler,
                                                  false);

                        indexer.SetValue(dictionary,
                                         dictValue,
                                         new object[]
                        {
                            prop.Name
                        });
                    }

                    return(dictionary);
                }
                else
                {
                    return(ReadObject(value, valueType, valueClrType, typeHandler, objectsAsDelta));
                }
        public Type GetType(IOpenApiObjectToTypeService objectService,
                            IObjectsProcessingKeyStore objectKeyStore,
                            IOpenApiType openApiType,
                            IDictionary <string, IOpenApiType> definitions,
                            string suggestedObjectName = null)
        {
            if (openApiType is OpenApiPrimitiveType)
            {
                return(_primitiveService.GetType((OpenApiPrimitiveType)openApiType,
                                                 nameIfEnum: suggestedObjectName));
            }

            if (openApiType.Matches <OpenApiReferencedType>())
            {
                return(_referenceService.GetType(objectService,
                                                 typeResolver: this,
                                                 objectKeyStore,
                                                 (OpenApiReferencedType)openApiType,
                                                 definitions));
            }

            if (openApiType.Matches <OpenApiObjectType>())
            {
                return(objectService.GetType((OpenApiObjectType)openApiType,
                                             definitions,
                                             suggestedObjectName,
                                             objectKeyStore));
            }

            if (openApiType.Matches <OpenApiArrayType>())
            {
                var memberType      = ((OpenApiArrayType)openApiType).Items;
                var arrayMemberType = GetType(objectService,
                                              objectKeyStore,
                                              memberType,
                                              definitions,
                                              suggestedObjectName + "Member");

                return(typeof(IEnumerable <>).MakeGenericType(arrayMemberType));
            }

            throw new NotSupportedException($"Unable to convert unsupported " +
                                            $"OpenApi Type {openApiType.GetType()}");
        }
Exemplo n.º 9
0
        private object ReadObject(
            ref Utf8JsonReader reader,
            IOpenApiType itemType,
            Type itemClrType,
            JsonSerializerOptions options)
        {
            if (itemType == null)
            {
                throw new JsonException($"Cannot deserialize unknown type.");
            }

            // TODO: better object creation, and polymorphism handling!
            var instance = Activator.CreateInstance(itemClrType);

            while (reader.Read())
            {
                if (reader.TokenType == JsonTokenType.EndObject)
                {
                    return(instance);
                }

                if (reader.TokenType != JsonTokenType.PropertyName)
                {
                    throw new JsonException($"Unexpected JSON Token {reader.TokenType}.");
                }

                var propertyName = reader.GetString();

                if (itemType.TryGetProperty(propertyName, out var property))
                {
                    var propertyType = _typeHandler.ResolveType(property.ClrProperty.PropertyType);
                    var value        = ReadValue(ref reader, propertyType, property.ClrProperty.PropertyType, options);
                    property.SetValue(instance, value);
                }
                else
                {
                    throw new JsonException($"Unexpected property {propertyName}.");
                }
            }

            throw new JsonException($"Unexpected end of stream.");
        }
Exemplo n.º 10
0
        private object ReadArrayArray(
            ref Utf8JsonReader reader,
            IOpenApiType itemType,
            Type itemClrType,
            JsonSerializerOptions options)
        {
            var resultItems = (IList)Activator.CreateInstance(typeof(List <>).MakeGenericType(itemClrType));

            do
            {
                if (reader.TokenType == JsonTokenType.EndArray)
                {
                    var array = Array.CreateInstance(itemClrType, resultItems.Count);
                    resultItems.CopyTo(array, 0);
                    return(array);
                }

                resultItems.Add(ReadArray(ref reader, itemType, itemClrType, options));
            } while (reader.Read());

            throw new JsonException($"Unexpected end of stream.");
        }
Exemplo n.º 11
0
        public static void WriteDictionary(
            Utf8JsonWriter writer,
            IDictionary value,
            IOpenApiType valueType,
            IOpenApiTypeHandler typeHandler,
            JsonSerializerOptions options)
        {
            writer.WriteStartObject();

            foreach (DictionaryEntry dictionaryEntry in value)
            {
                var key = options.DictionaryKeyPolicy != null
                    ? options.DictionaryKeyPolicy.ConvertName(dictionaryEntry.Key.ToString())
                    : dictionaryEntry.Key.ToString();

                writer.WritePropertyName(JsonEncodedText.Encode(key));

                WriteValue(writer, valueType, dictionaryEntry.Value, null, typeHandler, options);
            }

            writer.WriteEndObject();
        }
Exemplo n.º 12
0
        public static void WriteValue(
            Utf8JsonWriter writer,
            IOpenApiType itemType,
            object item,
            SelectClause subClause,
            IOpenApiTypeHandler typeHandler,
            JsonSerializerOptions options)
        {
            switch (item)
            {
            // we must handle dictionaries, enumerables etc on our own for proper nested object handling
            // maybe we find a better way to utilize the JsonSerializer.Serialize directly without loosing the proper type handling
            case string s:
                // string is an IEnumerable and needs to be handled special to avoid serialization as array
                writer.WriteStringValue(s);
                break;

            case Delta d:
                JsonSerializer.Serialize(writer, d, d.GetType(), options);
                break;

            case IDictionary c:
                if (ReflectionHelper.ImplementsDictionary(c.GetType(), out _, out var valueType))
                {
                    WriteDictionary(writer,
                                    c,
                                    typeHandler.ResolveType(valueType), // use static types for polymorphism
                                    typeHandler,
                                    options);
                }
                else
                {
                    WriteDictionary(writer, c, null, typeHandler, options);
                }

                break;

            case IEnumerable v:
                if (ReflectionHelper.ImplementsEnumerable(v.GetType(), out var enumerableItemType))
                {
                    WriteArray(writer,
                               v,
                               typeHandler.ResolveType(enumerableItemType),
                               subClause,
                               typeHandler,
                               options);
                }
                else
                {
                    WriteArray(writer, v, null, subClause, typeHandler, options);
                }

                break;

            default:
                if (itemType == null)
                {
                    // not handled by OpenApiQuery
                    JsonSerializer.Serialize(writer, item, options);
                }
                else
                {
                    WriteObject(writer, itemType, item, subClause, typeHandler, options);
                }

                break;
            }
        }