Skip to content

Commit 02f4b1e

Browse files
committed
wip on deserialization
1 parent 27e0ac4 commit 02f4b1e

File tree

3 files changed

+66
-21
lines changed

3 files changed

+66
-21
lines changed

src/DynamicObj/DynamicObj.fs

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ type DynamicObj() =
1818
#if !FABLE_COMPILER
1919
inherit DynamicObject()
2020
#endif
21-
21+
2222
let mutable properties = new Dictionary<string, obj>()
2323

2424
/// <summary>
@@ -272,13 +272,40 @@ type DynamicObj() =
272272
/// Important to return both so JSON serialization with Json.NET works.
273273
override this.GetDynamicMemberNames() = this.GetPropertyNames(true)
274274

275-
//// potential deserialization support
276-
//[<JsonExtensionData>]
277-
//member private this._additionalData : IDictionary<string, JToken> = new Dictionary<string, JToken>()
275+
// potential deserialization support
276+
[<JsonExtensionData(WriteData = false)>]
277+
member private this.AdditionalProperties : IDictionary<string, JToken> = new Dictionary<string, JToken>()
278+
279+
[<OnDeserialized>]
280+
member private this.OnDeserialized(context:StreamingContext) =
281+
let rec processToken (token: JToken) : obj =
282+
match token.Type with
283+
| JTokenType.Object ->
284+
let dict = DynamicObj()
285+
let jobject = token :?> JObject
286+
for property in jobject.Properties() do
287+
dict.SetProperty(property.Name, processToken(property.Value))
288+
box dict
289+
| JTokenType.Array ->
290+
let array = token :?> JArray
291+
let res =
292+
array
293+
|> Seq.cast<JToken>
294+
|> Seq.toArray
295+
|> Array.map processToken
296+
box res
297+
| JTokenType.Integer -> box (token.ToObject<int>())
298+
| JTokenType.Float -> box (token.ToObject<float>())
299+
| JTokenType.String -> box (token.ToObject<string>())
300+
| JTokenType.Boolean -> box (token.ToObject<bool>())
301+
| JTokenType.Date -> box (token.ToObject<System.DateTime>())
302+
| JTokenType.Null -> null
303+
| _ -> failwith "Unsupported JToken type"
278304

279-
//[<OnDeserialized>]
280-
//member private this.OnDeserialized(context:StreamingContext) = ()
281-
// map over key value pairs in additional data, box the token values and set dynamic properties via SetProperty.
305+
for kv in this.AdditionalProperties do
306+
let propertyName = kv.Key
307+
let propertValue = kv.Value
308+
this.SetProperty(propertyName, processToken propertValue)
282309

283310
#endif
284311

src/DynamicObj/DynamicObj.fsproj

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,12 @@
3333
<Compile Include="DynamicObj.fs" />
3434
<Compile Include="DynObj.fs" />
3535
<None Include="Playground.fsx" />
36-
<None Include="..\..\README.md" Pack="true" PackagePath="\"/>
36+
<None Include="..\..\README.md" Pack="true" PackagePath="\" />
3737
</ItemGroup>
3838

3939
<ItemGroup>
4040
<PackageReference Include="Fable.Core" Version="4.3.0" />
4141
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
4242
</ItemGroup>
43-
44-
<ItemGroup>
45-
<Content Include="*.fsproj; **\*.fs; **\*.fsi" PackagePath="fable\" />
46-
</ItemGroup>
4743

4844
</Project>

tests/DynamicObject.Tests/Serialization.fs

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ let test_dynobj =
2525
)
2626
obj
2727

28+
let test_dyn_obj_json = """{"dynamic_string":"yes","dynamic_number":69,"dynamic_boolean":true,"dynamic_array":["First","Second"],"dynamic_object":{"inner":"yup"}}"""
29+
2830
type DerivedClass1(staticProp: string) =
2931
inherit DynamicObj()
3032
member this.StaticProp = staticProp
@@ -47,6 +49,8 @@ let test_derived_1 =
4749
let obj = DerivedClass1("lol")
4850
obj.SetProperty("dynamicProp", 42)
4951
obj
52+
53+
let test_derived_1_json = """{"StaticProp":"lol","dynamicProp":42}"""
5054

5155
let test_derived_2 =
5256
let obj = DerivedClass2(
@@ -68,19 +72,37 @@ let test_derived_2 =
6872
)
6973
obj
7074

75+
let test_derived_2_json = """{"StaticString":"lol","StaticNumber":42.0,"StaticBoolean":true,"StaticArray":["First","Second"],"StaticObject":{"StaticProp":"lol","dynamicProp":42},"dynamic_string":"yes","dynamic_number":69,"dynamic_boolean":true,"dynamic_array":["First","Second"],"dynamic_object":{"inner":"yup"}}"""
76+
7177
#if !FABLE_COMPILER
7278
let tests_newtonsoft = testList "Newtonsoft (.NET)" [
73-
testCase "Serialize DynamicObj" <| fun _ ->
74-
let actual = JsonConvert.SerializeObject(test_dynobj)
75-
Expect.equal actual """{"dynamic_string":"yes","dynamic_number":69,"dynamic_boolean":true,"dynamic_array":["First","Second"],"dynamic_object":{"inner":"yup"}}""" ""
79+
testList "Serialization" [
80+
testCase "Serialize DynamicObj" <| fun _ ->
81+
let actual = JsonConvert.SerializeObject(test_dynobj)
82+
Expect.equal actual test_dyn_obj_json ""
83+
84+
testCase "Serialize simple derived class from DynamicObj" <| fun _ ->
85+
let actual = JsonConvert.SerializeObject(test_derived_1)
86+
Expect.equal actual test_derived_1_json ""
87+
88+
testCase "Serialize complex derived class from DynamicObj" <| fun _ ->
89+
let actual = JsonConvert.SerializeObject(test_derived_2)
90+
Expect.equal actual test_derived_2_json ""
91+
]
92+
ftestList "Deserialization" [
93+
testCase "Deserialize DynamicObj" <| fun _ ->
94+
let actual = JsonConvert.DeserializeObject<DynamicObj>(test_dyn_obj_json)
95+
96+
printfn "expected props:"
97+
for prop in test_dynobj.GetProperties(true) do
98+
printfn $"{prop.Key}, {prop.Value}, {prop.Value.GetType()}"
7699

77-
testCase "Serialize simplederived class from DynamicObj" <| fun _ ->
78-
let actual = JsonConvert.SerializeObject(test_derived_1)
79-
Expect.equal actual """{"StaticProp":"lol","dynamicProp":42}""" ""
100+
printfn "actual props:"
101+
for prop in actual.GetProperties(true) do
102+
printfn $"{prop.Key}, {prop.Value}, {prop.Value.GetType()}"
80103

81-
testCase "Serialize complex derived class from DynamicObj" <| fun _ ->
82-
let actual = JsonConvert.SerializeObject(test_derived_2)
83-
Expect.equal actual """{"StaticString":"lol","StaticNumber":42.0,"StaticBoolean":true,"StaticArray":["First","Second"],"StaticObject":{"StaticProp":"lol","dynamicProp":42},"dynamic_string":"yes","dynamic_number":69,"dynamic_boolean":true,"dynamic_array":["First","Second"],"dynamic_object":{"inner":"yup"}}""" ""
104+
Expect.equal (actual.GetHashCode()) (test_dynobj.GetHashCode()) ""
105+
]
84106
]
85107
#endif
86108

0 commit comments

Comments
 (0)