Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Sweet Jayson

5.00/5 (2 votes)
8 Jun 2015CPOL5 min read 9.5K  
Fast, reliable, easy to use, fully json.org compliant, thread safe C# JSON library for server side and desktop operations

Introduction

There are many .NET JSON libraries you can find on the internet. Some of them say they are small, some say they are fast. Mostly they are right, but what about reliability. When you get in deep, you see that according to your case, they miss something and you cannot succeed with that library or you need to write more and more extensions to manage your specific case. Forget all about these and try Sweet.Jayson.

Background

It is fast, reliable, easy to use, thread safe and fully json.org compliant. It is designed and coded from ground keeping all these in mind, not after a point in time.

What is Promised?

Sweet.Jayson JSON library supports:

C#
public class CustomBaseType
{
    public string Label { get; set; }
    public string Ref { get; set; }
    public string SHA { get; set; }
    public List<string> Items { get; set; } 
}

public class CustomType
{ 
    public string State;
    public CustomBaseType Base { get; set; }
}

public static class Program
{
    public static void Main(params string[] args)
    {
        var dto = new CustomType() { 
            { 
                State = "open" 
                Base = new CustomBaseType() 
                    {
                        Label = "technoweenie:master",
                        Ref = "master",
                        SHA = "53397635da83a2f4b5e862b5e59cc66f6c39f9c6",
                        Items = new List<object> { "Dev", "Test", "Prod" }
                    }
            };

        var jsonObj = 
            (Dictionary<string, object>)JaysonConverter.ToJsonObject(dto);
    }
}
  • .NET 3.5, 4.0, 4.5 & Mono
  • Any POCO type serialization/deserialization
  • Default .NET types (DateTime, DateTimeOffset, TimeSpan, Guid, ArrayList, Hashtable, HashSet …)
  • Default and custom Generic .NET types (List<T>, Dictionary<T,K>, Stack<T>, Queue<T> …)
  • Concurrent collection types (ConcurrentBag<T>, ConcurrentDictionary<T,K>,
    ConcurrentStack<T>, ConcurrentQueue<T>)
  • Any dictionary type that has key type different than typeof(string) with special key value pair ($k, $v) object (IDictionary<int,decimal>, IDictionary, Hashtable …)
  • DataTable, DataSet (also custom DataSets and DataTable relations in DataSets)
  • Nullable types (int?, DateTime? …)
  • Interfaces, both default .NET and also custom interfaces (IList, IList<T>, IMyCustomInterface…)
  • Array types (both class and value types) (int[], char[], string[] …)
  • Byte arrays (byte[]) as Base64String
  • Multidimensional arrays (int[,])
  • Jagged arrays (int[][])
  • Mixed arrays (int[][,] and int[,][])
  • dynamic Types
  • struct Types, both on serialization and deserialization
  • Types without default constructor (e.g. Tuple)
  • Embedding type information with "$type" notation for exact type deserialization
  • Embedding global type information with "$types" notation for exact type deserialization and compact output
  • Including or excluding "null" values into/from output (both in Properties or in Lists separately),
  • Serializing Guid as byte array (byte[])
  • Case sensitive/in-case sensitive property names
    JavaScript
    {
        "state": "open",
        "base": {
            "label": "technoweenie:master",
            "ref": "master",
            "sha": "53397635da83a2f4b5e862b5e59cc66f6c39f9c6"
        }
    }

    or:

    JavaScript
    {
        "State": "open",
        "Base": {
            "Label": "technoweenie:master",
            "Ref": "master",
            "SHA": "53397635da83a2f4b5e862b5e59cc66f6c39f9c6"
        }
    }
  • Enable/Disable Formatting and beautify output (Pretty print) without performance loss:
    JavaScript
    {"state"":"open","base"":{"label":"technoweenie:master",
    "ref"":"master","sha"":"53397635da83a2f4b5e862b5e59cc66f6c39f9c6"}}

    or:

    JavaScript
    {
        "state": "open",
        "base": {
            "label": "technoweenie:master",
            "ref": "master",
            "sha": "53397635da83a2f4b5e862b5e59cc66f6c39f9c6"
        }
    }
  • Changing types in deserialization using System.Runtime.Serialization.SerializationBinder,
  • Changing Property and Field names into any value without using custom Attribute classes by JaysonTypeOverride:
    C#
    var dto1 = TestClasses.GetTypedContainerDto();
    
    JaysonSerializationSettings jaysonSerializationSettings = 
        JaysonSerializationSettings.DefaultClone();
    jaysonSerializationSettings.TypeNames = JaysonTypeNameSerialization.All;
    jaysonSerializationSettings.
        AddTypeOverride(
            new JaysonTypeOverride<TextElementDto>().
                IgnoreMember("ElementType").
                SetMemberAlias("ElementId", "id"));
    
    JaysonDeserializationSettings jaysonDeserializationSettings = 
        JaysonDeserializationSettings.DefaultClone();
    jaysonDeserializationSettings.
        AddTypeOverride(
            new JaysonTypeOverride<TextElementDto, TextElementDto2>()).
        AddTypeOverride(new JaysonTypeOverride<TextElementDto2>().
            SetMemberAlias("ElementId", "id").
            IgnoreMember("ElementType"));
    
    string json = JaysonConverter.ToJsonString(dto1, jaysonSerializationSettings);
    var dto2 = JaysonConverter.ToObject<TypedContainerDto>(json, jaysonDeserializationSettings);
  • Changing types in serialization/deserialization using JaysonTypeOverride
  • Ignoring Field and Properties over JaysonTypeOverride
  • Including or excluding read-only members (Field & Properties) into/from serialization
  • AnonymousType serialization/deserialization (deserialization is only possible if the type already exists in the current process)
  • Custom Number (byte, short, int, long, float, double, decimal, sbyte, ushort, uint, ulong),
    DateTime, DateTimeOffset and TimeSpan formatting in serialization
  • Various DateTime serialization/deserialization formats over JaysonDateFormatType: Iso8601
    Local date: "1983-10-25T16:00:30.345+0300"
    UTC date: "1983-10-25T13:00:30.345Z"

    Microsoft

    Local date: "/Date(1224043200000+0300)/"
    UTC date: "/Date(1224043200000)/"

    JScript

    Local date: new Date(1224043200000+0300)
    UTC date: new Date(1224043200000)

    UnixEpoch

    Any long number: 1224043200000

    CustomDate

    Any date custom date format defined in serialization settings

    CustomUnixEpoch

    Any custom long number format defined in serialization settings
  • Converting Decimal values to Double or keep them in Decimal form

  • Enable/Disable AnonymousTypes, DynamicObject and ExpandoObject Types

  • Enable/Disable Unicode Character Escaping
    \u0357
  • Sorting Field and Property names descending
  • Ignoring Circular References or raise exception on Circular Reference
  • Use Enum Type names or numeric Enum values
  • Maximum Object Depth in deserialization
  • Option to work with default types such as Dictionary<string,object> or ExpandoObject,
    List<object>, ArrayList or Array instead of converting the object to a custom .NET type
    • Option to parse JSON arrays [] conversion between List<object>, ArrayList or Array
    • Option to parse JSON objects {} to Dictionary<string, object> or ExpandoObject
    JavaScript
    {
        "State": "open",
        "Base": {
            "Label": "technoweenie:master",
            "Ref": "master",
            "SHA": "53397635da83a2f4b5e862b5e59cc66f6c39f9c6",
            "Items": [
                "Dev",
                "Test",
                "Prod"
            ]
        }
    }

    will be parsed to:

    C#
    new Dictionary<string, object> { 
        { "State": "open" },
        { "Base": 
            {
                "Label": "technoweenie:master",
                "Ref": "master",
                "SHA": "53397635da83a2f4b5e862b5e59cc66f6c39f9c6",
                "Items": new List<object> { "Dev", "Test", "Prod" }
            }
        }
    };
  • Custom object creation outside the conversion process using JaysonObjectActivator
  • Converting any .NET object to Dictionary<string,object> and List<object> using
    JaysonConverter.ToJsonObject function
  • Object referencing with $id and $ref tags,
    JavaScript
    {
        "$type": "ObjectToDict.A, ObjectToDict",  
        "$id": 1,  
        "O2": {  
            "1": {  
                "$type": "System.Decimal, mscorlib",  
                "$value": 2  
            },  
            "$id": 2,  
            "a": "b",  
            "true": false,  
            "#self": {  
                "$ref": 2  
            },  
            "#list": {  
                "$type": "System.Collections.Generic.List`1[[System.Object, mscorlib]], mscorlib",  
                "$id": 3,  
                "$values": [  
                    {  
                        "$ref": 2  
                    }  
                ]  
            }  
        },  
        "O1": true,  
        "E1": "EnumB, EnumC",  
        "D2": 23456.78901,  
        "L2": {  
            "$id": 4,  
            "$values": [  
                1,  
                null,  
                2,  
                null  
            ]  
        },  
        "L1": {  
            "$type": "System.Int64, mscorlib",  
            "$value": 12345678909876544  
        },  
        "D4": {  
            "$ref": 2  
        },  
        "D1": {  
            "$type": "System.Decimal, mscorlib",  
            "$value": 12345.6789  
        },  
        "I1": 123456789  
    }
  • Enable or disable KV mode for Dictionary<?,object>
    JavaScript
    {  
        "$type": "Sweet.Jayson.Tests.A, Sweet.Jayson.Tests",  
        "D3": {  
            "$type": "System.Collections.Generic.Dictionary`2
            [[System.Object, mscorlib],[System.Object, mscorlib]], mscorlib",  
            "1": {  
                "$type": "System.Decimal, mscorlib",  
                "$value": 2  
            },  
            "a": "b",  
            "True": false  
        }  
    }

    or:

    JavaScript
    {  
        "$type": "Sweet.Jayson.Tests.A, Sweet.Jayson.Tests",  
        "D3": {  
            "$type": "System.Collections.Generic.Dictionary`2
            [[System.Object, mscorlib],[System.Object, mscorlib]], mscorlib",  
            "$kv": [  
                {  
                    "$k": 1,  
                    "$v": {  
                        "$type": "System.Decimal, mscorlib",  
                        "$value": 2  
                    }  
                },  
                {  
                    "$k": "a",  
                    "$v": "b"  
                },  
                {  
                    "$k": true,  
                    "$v": false  
                }  
            ]  
        }  
    }

Points of Interest

JSON is a simplified notation for transferring object states. It is simple and easy to use in dynamic languages such as JScript, Pyton, Ruby or any other, but when it comes to use it in statically compiled languages, it is a pain to map and bind to classes.

Do not assume that .NET libraries are supplying you the best of breed out there. Most of the time, they are designed to support generic cases and coded poorly. .NET is a great framework but in each specific case you need it falls short.

My opinion is, you need to try to write your own whenever you need performance and stability, or give a try to a third party library while testing. Also do not assume that every famous third party library is great. Most of the time, they are famous by chance or because they are this first in that area. So, you also need to test them well and accept that they are successful in many cases, but not all. But if you are also in such a case and will try to write your own library, don't forget to be ready for restless days and nights.

This library gets started after testing and testing many third party libraries and .NET's own on JSON serialization and deserialization. When they failed or needed too much effort to success for most of the specific needs, was bored and needed to write a new one which is the new kid in town and wanted to share and let the others not to taste those pain.

Please do not hesitate to get in contact whenever you need help about the library.

History

v1.0.0.0

  • 3 May 2015, Initial release

v1.0.0.1

  • 6 June 2015, Added support for special types; Stack, Queue and Concurrent lists

v1.0.0.2

  • 6 June 2015, Minor fix for list handling, when the last item is null or boolean

v1.0.0.3

  • 8 June 2015, Performance optimization on GUID serialization

v1.0.0.4

9 June 2015

  • Some refactoring
  • Sealed some classes
  • Error message class implemented
  • License header added to JaysonError file

v1.0.0.5

9 June 2015

  • Long number serialization fix
  • AsciiToLower & AsciiToUpper fix

v1.0.0.6

10 June 2015

  • New tests added
  • IDictionary<object, object> Key conversion fix
  • ConvertToPrimitive fix for enums

v1.0.0.7

11 June 2015

  • Performance improvements
  • JaysonOrderedDictionary implemented for member names
  • Detailed test cases

v1.0.0.8

17 June 2015

  • Object referencing support
  • Performance optimisation
  • Setting for enable/disable KV mode for Dictionary<?,object>
  • Detailed test cases

v1.0.0.9

14 July 2015

  • System.Runtime.Serialization.ISerializable interface support
  • System.Type System.Type serialization support
  • System.Reflection.ConstructorInfo, System.Reflection.MethodInfo, System.Reflection.PropertyInfo and System.Reflection.FieldInfo serialization support
  • System.Exception serialization support
  • Fix for .Net System.Type.GetType which works different than Mono version
  • Detailed test cases

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)