JSON Serialization

JSON (JavaScript Object Notation) is a popular text-based serialization format. In contrast to other text-based formats that store tables, JSON can represent arbitrary objects.

The JSON functionality in Numerics.NET is built on the JSON.NET framework. Both stand-alone classes and classes that integrate with JSON.NET serialization are available.

The classes that implement the JSON functionality live in the Extreme.Data.Json namespace. Because of the dependency on JSON.NET, they were given their own assembly, Extreme.Data.Json.dll.

Data Access Library features

The JsonFile object, which is the File-like class for reading and writing JSON, has the same functionality as all other File-like clases. The data source can be provided either as a string or a stream. The string can be the path to a file on the local file system, or it may point to a web resource.

In addition, the Open method can take a NewtonSoft.Json.JsonReader, and the Append method can take a NewtonSoft.Json.JsonWriter as the data source.

All methods take an optional argument of type JsonOptions that gives some additional details on how to read or write the JSON.

In addition to the standard methods, there are also methods that can convert a data frame, matrix, or vector to a JSON string or vice versa. To convert an object to a JSON string, use one of the overloads of the ToJson method. To deserialize an object from a string in JSON format, use the ToVector<T>(String, JsonOptions), ToMatrix<T>(String, JsonOptions), or ToDataFrame<R, C>(String, JsonOptions) method.

These methods are defined as extension methods, so they can be called on the objects and strings directly. The example below constructs a data frame, serializes it to a string, and then immediately deserializes the string to end up with an identical data frame:

C#
var data = new Dictionary<string, object>() {
        { "state", new string[] { "Ohio", "Ohio", "Ohio", "Nevada", "Nevada" } },
        { "year", new int[] { 2000, 2001, 2002, 2001, 2002 } },
        { "pop", new double[] { 1.5, 1.7, 3.6, 2.4, 2.9 } }
    };
var df1 = DataFrame.FromColumns(data);
var jsonString = df1.ToJson();
var df2 = jsonString.ToDataFrame();

JSON.NET Serialization

The JSON.NET library provides a full framework for serializing and deserializing any kind of .NET object. This is done most commonly through the use of serialization attributes which are applied to classes and their members to specify the exact format of the serialization.

To avoid a direct dependency of our core assembly on the JSON.NET assembly, we use a different mechanism: converters. A converter class is a class that can convert between some types of objects and text in JSON format.

Two converters are available. The ComplexJsonConverter class converts complex numbers of any type. The DataObjectJsonConverter class can convert data frames, matrices, vectors, and indexes. These converters can be used as the argument of a JsonConverter attribute to specify that a field should be serialized and deserialized using this converter.

Below is a complete sample that defines an object, complete with JSON serialization attributes. We then create an instance, serialize it to a string, and then deserialize to get a copy of the original object:

C#
using System.IO;

using Extreme.Data.Json;
using Extreme.DataAnalysis;
using Extreme.Mathematics;

using Newtonsoft.Json;

[JsonObject]
public class Instrument
{
    public string Symbol { get; set; }
    [JsonConverter(typeof(DataObjectJsonConverter))]
    public Vector<double> History { get; set; }
}

class SerializationExample
{
    public static void Sample()
    {
        var instrument = new Instrument();
        instrument.Symbol = "APPL";
        instrument.History = Vector.Create(1.0, 2.0, 3.0, 4.0, 5.0);
        instrument.History.Index = Index.CreateDateRange(new DateTime(2016, 05, 1), 5, Recurrence.Daily);
        var s = new JsonSerializer();
        var sw = new StringWriter();
        s.Serialize(sw, instrument);
        var json = sw.ToString();
        Console.WriteLine(json);
        // Needed for deserialization:
        s.Converters.Add(new DataObjectJsonConverter());
        var sr = new StringReader(json);
        var instrument2 = s.Deserialize<Instrument>(new JsonTextReader(sr));
        Console.WriteLine(instrument2.Symbol);
        Console.WriteLine(instrument2.History);
    }
}