Click here to Skip to main content
15,894,362 members
Articles / Programming Languages / C#
Alternative
Article

Apolyton FastJSON

Rate me:
Please Sign up or sign in to vote.
4.67/5 (5 votes)
26 Nov 2012CPOL13 min read 41.8K   1.2K   34  
This is an alternative for "fastJSON"
This is an old version of the currently published article.

Introduction 

This is an alternative version of Gholam's great JSON library which brings a new deserializer and some new features at acceptable performance cost. 

Background  

FastJson-as-is is already great -now doubt. However, after I installed it and I got infected by its performance I discovered that it serializes by default all public properties (and fields). This was a blocking issue; creating stubs from my existing objects just for FastJson would kill performance so it was decided to enhance the code with this feature.  

A-FastJSON is not aiming to be the fastest. But as fast as possible while being correct and being able to report meaningful errors. Overall performance characteristics are comparable to fastJSON on which is it based. 

Using the code  

Since A-FastJson is built on top of fastJSON, it's API has a huge overlap: 

Image 1

Serialize an object 

Apolyton.FastJson.Json.Current.ToJson(c);  

Deserialize an object 

In order to deserialize an object directly (with custom type support), your call should like the following:

string jsonText =  "{...}"; // your json string 
var myObject = (MyClass)Apolyton.FastJson.Json.Current.ReadObject(jsonText);

Note: there is also a generic version of that method. 

However, A-FastJson comes with another deserializer which returns a value store based in IJsonValue. This is a lost faster than the ReadObject method, but is not that strongly typed. Reading the json value can be accomplished by  

string jsonText =  "{...}"; // your json string 
JsonObject myObject = Apolyton.FastJson.Json.Current.ReadJsonValue(jsonText);    

This class allows you to sniff into the values before continuing the deserialization. This is for instance useful for protocol validation since it allows you to trash the json request before full deserialization has happened which saves time and increases potentially your i/o (ReadJsonValue is almost twice as fast than ReadObject).  

An instance of JsonObject van be used to populate an existing instance of your strongly typed objects. For that use the BuilUp method on the Json singleton: 

string jsonText =  "{...}"; // your json string 
var deserializedStore = (JsonObject)Apolyton.FastJson.Json.Current.ReadJsonValue(jsonText);
var target = new MyClass();

Apolyton.FastJson.Json.Current.BuildUp(target, deserializedStore);

For optimal performance you should pool your target objects; The BuildUp method is supposed to ensure that you can recycle your instances.   

Configuration 

By default, the Json instance uses a the default parameters for serialization and deserialization. Due to internal refactoring, these configuration objects are expensive in contrast to those in fastJSON. This is because all serialization information is attached to it in order to avoid data corruption and unexpected outcome (see Bug Fixes section). 

Image 2 

The parameter names should be self explicit and are explained briefly in code.

Inspecting the configuration 

For debugging or automated protocol checks, one may want to see the list of properties from the same point of view as the Json (de-)serializer. For that, you can use the GetSerializationMembers method.

// For the default parameter
Apolyton.FastJson.Json.Current.GetSerializationMembers(typeof(MyClass)); 
or  
// For any parameter object
new JsomParameter().GetSerializationMembers(typeof(MyClass);

Key Features

  • Event faster deserialization of a json string into generic values (IJsonValue)
  • Type extension support through the ReadObject (BuildUp doens't need it) and ToJson functions
  • Optionally checks for DataMember attribute.
  • Handles DataMember.Name representing the json field name
  • Handles IgnoreDataMember by ignoring properties decorated with it.   

  • (Most) built-in value types are supported. 
  • Non-abstract reference types are supported (including inheritance)
  • Custom type support. 
  • Enhanced debugging capabilities purposes see the GetSerializationMembers method
  • Committed to quality over performance. 

==> See fastJSON 2.0.9 feature list for more complete list of features.

Points of Interest 

  • Always reuse configuration (JsonParameter) objects. Performance drops dramatically, if you don't.
  • The IJsonValue concept is inspired from the JSON API in Silverlight done by Microsoft. I found it very useful to sniff into incoming requests and trash them when they are not following basic expectations (mandatory fields missing). Running a full deserialization in order to do that was appearing to me as a waste of resources. The performance characteristics are surprising (see Benchmarks).
  • The code is protected by unit tests (around 110) which should ensure high quality of each release.
  • Do no try to deserialize into an enumeration. Use strong types where possible, use generic types otherwise. 
  •  Byte enumeration is not supported . Use byte[] instead.    

Benchmarks  

Before crunching some numbers, some points should be enlightened since they are easily forgotten:

  • All benchmarks published by framework developers, like this or fastJSON are optimized results. Real life results can look very differently. This is not bad intention, but perfectly normal. Therefore:
  • All results published here just performance indicators. You should compare the framework your end-to-end scenario while considering that: 
  • Performance varies not only from run-to-run, but also from class-to-class and the data in it. 
  • All benchmarks are run against fastJSON 2.0.9 which was the reference at publish time.
  • When reading benchmark results ensure that input and output are the same (*1)  

(*1) For instance, the fastJSON benchmark compares with BinaryFormatter which takes a stream as input. fastJSON cannot process streams. This aspect is ignored, but it leads to a potentially wrong assumption that fastJSON is faster than BinaryFormatter.. 

Scenario 1: A-FastJSON vs fastJSON x86 (custom types)

 Image 3

  • A-FastJSON serialization is comparable to fastJSON. Often it is slower (about 10%).
  • A-FastJSON deserialization into object is often faster or equal to fastJSON. 
  • A-FastJSON deserialization to IJsonValue is faster than serialization. Twice as fast as fastJSON.
  • A-FastJSON deserialization to IJsonValue, then build up of into given class is almost 10% faster than fastJSON

Scenario 2: A-FastJSON vs fastJSON x86 (custom types & exotic types) 

 Image 4
  • A-FastJSON serialization is faster most of the time than fastJSON. 
  • A-FastJSON deserialization is always faster than fastJSON (about 10%). 
  • A-FastJSON deserialization to IJsonValue more than twice as fast as fastJSON. 
  • A-FastJSON deserialization to IJsonValue, then build up of into given class is almost 20% faster than fastJSON  

Scenario 3: A-FastJSON vs fastJSON x64 (custom types)Image 5

  • A-FastJSON serialization is comparable to fastJSON. Sometimes its faster. 
  • A-FastJSON deserialization is comparable to fastJSON.  
  • A-FastJSON deserialization to IJsonValue is almost twice as fast as fastJSON.  
  • A-FastJSON deserialization to IJsonValue, is comparable to fastJSON  

Scenario 4: A-FastJSON vs fastJSON x64 (custom types & exotic)

 Image 6  
  • A-FastJSON serialization is comparable to fastJSON. Sometimes its faster. 
  • A-FastJSON deserialization is most of the time 5% faster than fastJSON.  
  • A-FastJSON deserialization to IJsonValue is almost twice as fast as fastJSON.  
  • A-FastJSON deserialization to IJsonValue, is most of the time 10% faster to fastJSON 

Conclusions

  • Both, A-FastJson and fastJSON are reasonably fast.  
  • In 64 bit scenarios the advantage of A-FastJson is lower.
  • If one needs built in data set support, fastJSON is likely the better option. 
  • If one needs exotic type support (dictionaries, hash-sets etc), A-FastJson is likely the better option. 
  • The IJsonValue conversion is surprisingly fast and seems to be a very good option -especially, if one considers that the second step, converting the generic dictionary into a given type is optional. 

Known Issues  

  • UseLowerCase parameter is still not implemented, see however the DataMember.Name property
  • DataSet and DataTable are not supported by the BuildUp method (*2). Anyway, the value to convert from one generic type into another one should be quite low. Given enough interest, extension methods might be added on IJsonValue.

 (*2) DataTable and DataSet are two or three dimensional objects. Json is n-dimensional by design. Whatever implementation is done on framework side, it would be arbitrary and therefore not platform independent. Following the least surprise principle, the framework should not handle DataSet and DataTable differently from any other object (which is currently does).  

Bug Fixes  

v0.9 Fork from fastJSON 2.0.9 

Serialization 

  • DateTime to Utc is now respecting the kind of the date time (JsonSerializer_DateTimeUtc)
  • Byte array was not proper when a List of bytes was serialized (see JsonSerializer_ByteEnumeration)
  • Serialization of custom types implementing IList was not considered  
  • TimeSpan was wrongly serialized.  

Deserialization  

  • Deserialization of a number of bytes was failing
  • Wrong date time was returned when given string was in utc and parameter was set to avoid utc dates 
JsonParameter
  • Changing serialization/ deserialization values at runtime could lead to unexpected output.
  • Code was changing some properties on its own behalf. 

MyPropInfo  

  • CanWrite was always false for fields  
  • Fill was never false and unused. Removed. 
  • GenericTypes was always null except for dictionaries with the name 'Dictionary'.

Benchmark

  • Fixing time measure flaw in benchmark tool.    

History 

25 October 2012: Fork of FastJSON. Development started.

License

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


Written By
Germany Germany
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

Discussions on this specific version of this article. Add your comments on how to improve this article here. These comments will not be visible on the final published version of this article.