FSharp · Script
open System
open System.Linq
open System.Text
open System.Runtime.Serialization.Formatters
open System.IO
open System.Data
open System.ComponentModel.DataAnnotations
open System.Globalization
open System.Reflection
open Microsoft.FSharp.Reflection
open Newtonsoft.Json
open Newtonsoft.Json.Linq
open Newtonsoft.Json.Converters
open Newtonsoft.Json.Serialization
//https://stackoverflow.com/questions/73551490/how-to-define-singleorarrayconverter-to-handle-json-property-in-f-port-from-c
type SingleOrArrayConverter<'T>() =
inherit JsonConverter()
override this.CanConvert(objectType) = objectType = typeof<ResizeArray<'T>>
override this.ReadJson(reader, objectType, existingValue, serializer) = // Unlike in C# it's not necessary to declare the types of the arguments when there is no ambiguity
let token = JToken.Load (reader)
if token.Type = JTokenType.Array then
// Upcast to obj as upcasting is not automatic for returned value
// https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/casting-and-conversions#upcasting
(token.ToObject<ResizeArray<'T>> ()) :> obj
else
ResizeArray [|(token.ToObject<'T> ())|] :> obj // Convert array to List<T> then upcast to object
override this.CanWrite = false // Simplified syntax
override this.WriteJson(writer, value, serializer) = raise (new NotImplementedException())
type Locality = {
category: string
id: int
location: string
postcode: int
state: string
latitude: decimal
longitude: decimal
}
type Localities = {
[<JsonProperty("locality")>]
[<JsonConverter(typeof<SingleOrArrayConverter<Locality>>)>] // Fix syntax: typeof<'T> not typeof(T)
locality: ResizeArray<Locality> // Be sure whether you want System.Collections.Generic.List<'T> a.k.a ResizeArray<'T> or FSharp.Collections.List<'T>
}
type PostCodeLocality = {
localities : Localities
}
let json0 = """
{
"localities": {
"locality":
{
"category": "category",
"id": 101,
"location": "location",
"postcode": 22,
"state": "ZZ",
"latitude": 81.0,
"longitude": 202.0
}
}
}
"""
let p1 = JsonConvert.DeserializeObject<PostCodeLocality>(json0)
let p2 : PostCodeLocality = { localities = { locality = new ResizeArray<Locality>([|{category="category"; id=101; location="location"; postcode=22;state="ZZ"; latitude=81.0M; longitude=202M }|]) } }
let json1 = JsonConvert.SerializeObject(p1, Formatting.Indented)
let json2 = JsonConvert.SerializeObject(p2, Formatting.Indented)
if (json1 <> json2) then raise (Exception("json1 != json2"))
let p3 = JsonConvert.DeserializeObject<PostCodeLocality>(json2)
let json3 = JsonConvert.SerializeObject(p3, Formatting.Indented)
if (json1 <> json3) then raise (Exception("json1 != json3"))