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:
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 = "{...}";
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 = "{...}";
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 = "{...}";
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).
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.
Apolyton.FastJson.Json.Current.GetSerializationMembers(typeof(MyClass));
or
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)
- 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)
- 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)
- 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)
- 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
propertyDataSet
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.
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.