diff --git a/FSharp.Json.Tests/Collections.fs b/FSharp.Json.Tests/Collections.fs index e36bb85..1e770ff 100644 --- a/FSharp.Json.Tests/Collections.fs +++ b/FSharp.Json.Tests/Collections.fs @@ -18,6 +18,13 @@ module Collections = let actual = Json.serializeU value Assert.AreEqual(expected, actual) + [] + let ``ResizeArray serialization to JSON array`` () = + let expected = """["some","text"]""" + let value = [ "some"; "text" ] |> ResizeArray + let actual = Json.serializeU value + Assert.AreEqual(expected, actual) + [] let ``Array serialization/deserialization`` () = let expected = [|"some"; "text"|] @@ -32,6 +39,13 @@ module Collections = let actual = Json.deserialize json Assert.AreEqual(expected, actual) + [] + let ``ResizeArray serialization/deserialization`` () = + let expected = [ "some"; "text" ] |> ResizeArray + let json = Json.serialize (expected) + let actual = Json.deserialize> json + Assert.AreEqual(expected, actual) + [] let ``Array empty serialization/deserialization`` () = let expected = [||] @@ -45,3 +59,10 @@ module Collections = let json = Json.serialize(expected) let actual = Json.deserialize json Assert.AreEqual(expected, actual) + + [] + let ``ResizeArray empty serialization/deserialization`` () = + let expected = ResizeArray() + let json = Json.serialize (expected) + let actual = Json.deserialize> json + Assert.AreEqual(expected, actual) diff --git a/FSharp.Json/Core.fs b/FSharp.Json/Core.fs index 747fc17..28827fb 100644 --- a/FSharp.Json/Core.fs +++ b/FSharp.Json/Core.fs @@ -149,7 +149,7 @@ module internal Core = JsonValue.String ((value :?> Guid).ToString()) | t when t.IsEnum -> serializeEnum t jsonField value - | t when isTuple t || isList t || isArray t || isMap t || isRecord t || isUnion t -> + | t when isTuple t || isList t || isArray t || isMap t || isRecord t || isUnion t || isResizeArray t -> serialize config t value | _ -> failSerialization $"Unknown type: %s{t.Name}" | true -> @@ -265,6 +265,7 @@ module internal Core = | t when isList t -> serializeEnumerable (value :?> IEnumerable) | t when isTuple t -> serializeTupleItems (getTupleElements t) (FSharpValue.GetTupleFields value) | t when isUnion t -> serializeUnion t value + | t when isResizeArray t -> serializeEnumerable (value :?> IEnumerable) | t -> let msg = $"Failed to serialize, must be one of following types: record, map, array, list, tuple, union. Type is: %s{t.Name}." failSerialization msg @@ -374,7 +375,7 @@ module internal Core = JsonValueHelpers.getGuid path jValue :> obj | t when t.IsEnum -> deserializeEnum path t jsonField jValue - | t when isTuple t || isList t || isArray t || isMap t || isRecord t || isUnion t -> + | t when isTuple t || isList t || isArray t || isMap t || isRecord t || isUnion t || isResizeArray t -> deserialize config path t jValue | _ -> failDeserialization path $"Not supported type: %s{t.Name}" transformFromTargetType jsonField.Transform jValue @@ -431,6 +432,19 @@ module internal Core = arrayValues |> List.ofSeq |> createList itemType | _ -> failDeserialization path "Failed to parse list from JSON that is not array." + let deserializeResizeArray (path: JsonPath) (t: Type) (jvalue: JsonValue) : obj = + match jvalue with + | JsonValue.Array jvalues -> + let itemType = getResizeArrayItemType t + + let arrayValues = + deserializeArrayItems path itemType jvalues + + arrayValues + |> List.ofSeq + |> createResizeArray itemType + | _ -> failDeserialization path "Failed to parse resize array from JSON that is not array." + let deserializeArray (path: JsonPath) (t: Type) (jvalue: JsonValue): obj = match jvalue with | JsonValue.Array jvalues -> @@ -549,5 +563,6 @@ module internal Core = | t when isList t -> deserializeList path t jValue | t when isTuple t -> deserializeTuple path t jValue | t when isUnion t -> deserializeUnion path t jValue + | t when isResizeArray t -> deserializeResizeArray path t jValue | _ -> failDeserialization path $"Failed to serialize, must be one of following types: record, map, array, list, tuple, union. Type is: %s{t.Name}." - \ No newline at end of file + \ No newline at end of file diff --git a/FSharp.Json/Reflection.fs b/FSharp.Json/Reflection.fs index 9a6f789..1312545 100644 --- a/FSharp.Json/Reflection.fs +++ b/FSharp.Json/Reflection.fs @@ -35,6 +35,19 @@ module internal Reflection = let getListEmptyProperty_ (t: Type) = t.GetProperty("Empty") + let isResizeArray_ (t: Type) = + t.IsGenericType + && t.GetGenericTypeDefinition() = typedefof> + + let getResizeArrayType_ (itemType: Type) = + typedefof>.MakeGenericType ([| itemType |]) + + let getResizeArrayItemType_ (t: Type) = t.GetGenericArguments().[0] + + let getResizeArrayConstructor_ (t: Type) = t.GetConstructor([||]) + + let getResizeArrayAdd_ (t: Type) = t.GetMethod("Add") + let isMap_ (t: Type) = t.IsGenericType && t.GetGenericTypeDefinition() = typedefof> @@ -72,6 +85,13 @@ module internal Reflection = let getListConstructor: Type -> MethodInfo = getListConstructor_ |> cacheResult let getListEmptyProperty: Type -> PropertyInfo = getListEmptyProperty_ |> cacheResult + let isResizeArray : Type -> bool = isResizeArray_ |> cacheResult + let getResizeArrayType : Type -> Type = getResizeArrayType_ |> cacheResult + let getResizeArrayItemType : Type -> Type = getResizeArrayItemType_ |> cacheResult + let getResizeArrayAdd : Type -> MethodInfo = getResizeArrayAdd_ |> cacheResult + let getResizeArrayConstructor : Type -> ConstructorInfo = + getResizeArrayConstructor_ |> cacheResult + let isMap: Type -> bool = isMap_ |> cacheResult let getMapKeyType: Type -> Type = getMapKeyType_ |> cacheResult let getMapValueType: Type -> Type = getMapValueType_ |> cacheResult @@ -98,6 +118,22 @@ module internal Reflection = let theList = (getListEmptyProperty listType).GetValue(null) List.foldBack addItem items theList + let createResizeArray (itemType: Type) (items: obj list) = + let resizeArrayType = getResizeArrayType itemType + + let resizeArrayAdd resizeArray item = + (getResizeArrayAdd resizeArrayType) + .Invoke(resizeArray, [| item |]) + |> ignore + + resizeArray + + let newResizeArray = + (getResizeArrayConstructor resizeArrayType) + .Invoke([||]) + + List.fold resizeArrayAdd newResizeArray items + let KvpKey (value: obj): obj = let keyProperty = value.GetType().GetProperty("Key") keyProperty.GetValue(value, null) diff --git a/README.md b/README.md index df4b820..8bbfc19 100644 --- a/README.md +++ b/README.md @@ -168,7 +168,7 @@ option | option is not represented by itself
`None` value might be represente tuple | list record | object map | object -array
list | list +array
list
ResizeArray | list union | object with special structure
read more in [Unions](#unions) section obj | read [Untyped Data](#untyped-data) section