ServiceStack.Swift Custom Serialization

Hello,

is it possible to have a custom serializer/deserializer for the Swift client? I have a DTO that returns an object containing a Dictionary< string, object > property. In AppHost.cs I configured a custom serialization process like so:

  JsConfig<Dictionary<string, object>>.OnSerializingFn = MySerialize;
  JsConfig<Dictionary<string, object>>.OnDeserializedFn = MyDeserialize;

The MySerialize method will produce the following Json for dictionaries:

{
    "MyDictionary": {
        "a2": {
            "__type": "ValueOfInt32",
            "value": 1
        },
        "d5": {
            "__type": "ValueOfDateTime",
            "value": "2015-11-02T12:58:00.7125634-05:00"
        }
    }
}

When deserializing, the MyDeserialize method looks at the __type property and convert the value to the correct type. For .Net clients I created a custom client that handles this format and I would like to do the same for Swift.

It only really allows for customizable serialization by swapping out the property getters/setters for each type, but the JsonServiceClient.swift is included as source code so you have an opportunity to modify it to suit your needs, it’s stand-alone and doesn’t require any other dependencies.

You’re going to have a hard time trying to support unknown object types in the serializer since it’s based on extension enhancements of known types. I heavily discourage the use of undefined object or interface properties which are also not supported by Swift.

If you must have a untyped collection of arbitrary types, you could create an explicit Type that holds the information, e.g:

class UnknownType
{
    public string Name { get; set; }
    public string Value { get; set; }
}

And have a Dictionary<string,UnknownType> containing that type, which you can then convert to an Any Dictionary with an generic extension method, e.g:

let anyMap = unknownMap.convertToAnyDictionary()

I’m posting the solution I used in case it can be of use to someone:

  • I excluded the problematic type in the client’s configuration (e.g.: ExcludeTypes: abc). This way the native type codegen will not try to generate the class.
  • I created a new Swift class that implements the StringSerializable protocol.
  • I simply had to implements the methods of StringSerializable with my custom logic to be able to serialize/deserialize my custom format

My use case was trying to deserialize a Dictionary<string, object> and my Swift class looks like this:

public class MyProblematicType : SequenceType, StringSerializable
{
    public typealias Generator = DictionaryGenerator<String, Any>
    public static var typeName: String { return "MyProblematicType" }
    public required init() {}

    public func generate() -> MyProblematicType.Generator { return internalDictionary.generate() }
    private var internalDictionary: Dictionary<String, Any> = Dictionary<String, Any>()

    subscript(key: String) -> Any?
    {
        get { return internalDictionary[key]
        set (newValue) { internalDictionary[key] = newValue }
    }

    from static func fromObject(any: AnyObject) -> MyProblematicType
    {
        if let map = any as? NSDictionary {
             let bag = MyProblematicType()
             for (mapKey, mapValue) in map
             {
                 bag[mapKey as! String] = <my custom deserialization logic>
             }
             return bag
        }
        return nil
    }

    public func toJson() -> String
    {
        let jb = JObject()
        from (key, value) in internalDictionary
        {
            jb.append(key, json: <my custom serialization logic>)
        }
        return jb.toJson()
    }

    public func toString() -> String { return toJson() }
    public static func fromString(string: String) -> MyProblematicType?
    {
        if (let map = parseJson(string) as? NSDictionary { return fromObject(map) }
        return nil
    }
}


1 Like