hubFS: THE place for F#

. . . are you on The Hub?
Welcome to hubFS: THE place for F# Sign in | Join | Help
in Search

Deserializing JSON

Last post 06-25-2009, 2:43 by kinch. 5 replies.
Sort Posts: Previous Next
  •  06-24-2009, 8:17 11076

    Deserializing JSON

    I have had no problem serializing F# records using JSON.net.

    However, am having no joy deserializing back to F# records.

    http://json.codeplex.com/WorkItem/View.aspx?WorkItemId=12458

    claims that this is because F# records have poorly named (internal) parameter names.

    Does anybody have successful experience deserializing JSON into F# records? Naturally I'd prefer to just 'blat' stuff back in, rather than (say) Using FParsec's JSON parser to walk the AST and do it the hard way.

    If not with JSON.net, then any other libraries have solved this problem?

    As for why I'm doing this: I am forced to work with some text file parameter / data interchange between two systems and need to be able to be a bit flexible and loosely-coupled. Some parameters are optional, data-sets vary in length, and there is some degree of conceptual nesting. If I were doing this in Python, I'd likely be serializing and deserializing YAML (or maybe JSON). I don't want to use XML.

    Worst comes to the worst, I'll deserialize back into objects in a bit of C# and then interrogate this lot from F# code... but would prefer to do all in native F# if at all possible.
  •  06-24-2009, 22:45 11093 in reply to 11076

    Re: Deserializing JSON

    Yea, fine control over what IL F# emits can be annoying when dealing with certain libraries that make certain assumptions :). Most libraries just expect all code to be like C# would generate it (this gets really nasty with expression trees).

    When doing object interop with serialization frameworks, you might need to just use the F# OO types. With these, you can generate constructors or read/write properties as you see fit. I agree though, it sucks since record types are a lot nicer to deal with.

    If you really wanted to use records, you could use F# reflection and hack something up to generate a type that looks like whatever the framework expects. Pass that type in, then pop it out to a record automatically. Won't work for all APIs, but might work for this one.

    BTW, if you go the F# OO route (which is still easier than using C# and doing interop), here's how it'd look:



    type FooReadWrite() =
        let mutable field1 = ""
        member x.Field1 with get() = field1 and set(v) = field1 <- v
       
    type FooReadOnly(field1: string) =
        member x.Field1 = field1

     

  •  06-24-2009, 23:29 11095 in reply to 11076

    Re: Deserializing JSON

    I haven't tried it out, but do try

    http://msdn.microsoft.com/en-us/library/system.runtime.serialization.json.datacontractjsonserializer.aspx

    as I think perhaps the .Net 'DataContract' programming model does work with F# records, and there is a JSON serializer/deserializer for this programming model.

  •  06-25-2009, 0:11 11096 in reply to 11095

    Re: Deserializing JSON

    Wow I feel sheepish -- the WCF stuff does work :\. DataContract can use fields directly, and doesn't need a specific constructor. (But a lot of APIs do need a properties and often a parameterless constructor... right?)

    You'll need to add some attributes to make it work properly, as the fields have an @ prefix, and the properties aren't settable:



    open System
    open System.Runtime.Serialization

    [<DataContract>]
    type rectest = {
        [<field: DataMember(Name = "id")>]
        id   : int
        [<field: DataMember(Name = "name")>]
        name : string }

    let dcs = Json.DataContractJsonSerializer(typeof<rectest>)
    let ms = new IO.MemoryStream()
    dcs.WriteObject(ms, { id = 2; name = "foo" })
    printfn "%s" (ms.ToArray() |> Text.Encoding.UTF8.GetString)
    ms.Seek(0L, IO.SeekOrigin.Begin) |> ignore
    let r = dcs.ReadObject(ms) :?> rectest
    printfn "%A" r

    Awesome. We can probably stick this into a few other places and make certain frameworks (say, ASP.NET MVC) work properly too!

    Thanks Brian!

  •  06-25-2009, 1:39 11097 in reply to 11096

    Re: Deserializing JSON

    As a note to the F# team, it'd be nice if the F# compiler didn't create mangled names. Since F# record generated fields are assembly-access only, it shouldn't matter if they have a name matching the property name, should it? Or is there 3rd party code out there that messes up if it encounters such a type?

  •  06-25-2009, 2:43 11099 in reply to 11097

    Re: Deserializing JSON

    Guys, thanks for the helpful replies!

    I haven't had time to work through them yet, but will do so.

    One more piece of info I should add, though:

    The problem I reported occurred with September 2008 CTP. This morning I upgraded to May 2009 CTP and am getting good results with JSON.net for serialization/deserialization of nested records, where records contain simple scalar types and / or nested arrays or ResizeArrays (= System.Collections.Generic.List). JSON.net will serialize F# lists no problem, but cannot deserialise.

    Now, I just have to see if I can figure out how to marshal some kind of dictionary / map in and out. Guessing will have to go with the regular dot net Dictionary for this.

    Once again, thx for the responses!
View as RSS news feed in XML
Powered by Community Server, by Telligent Systems