MartinCl2.Text.Json.Serialization 1.0.0

Just-in-time compiled JSON serialization utilizing System.Text.Json

Install-Package MartinCl2.Text.Json.Serialization -Version 1.0.0
dotnet add package MartinCl2.Text.Json.Serialization --version 1.0.0
<PackageReference Include="MartinCl2.Text.Json.Serialization" Version="1.0.0" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add MartinCl2.Text.Json.Serialization --version 1.0.0
The NuGet Team does not provide support for this client. Please contact its maintainers for support.

JSON Serializer JIT Compiler for .NET Core 3.0

Emit CIL/MSIL code at runtime for serializing JSON object, utilizing the System.Test.Json namespace provided since .NET Core 3.0.

Example usage

static string CompileAndSerialize<T>(T obj)
{
    JsonJitSerializer<T> serializer = JsonJitSerializer<T>.Compile(new JsonSerializerOptions()
    {
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase
    });

    return serializer.Serialize(obj);
}

static async Task CompileAndSerializeAsync<T>(Stream stream, T obj)
{
    JsonJitSerializer<T> serializer = JsonJitSerializer<T>.Compile(new JsonSerializerOptions()
    {
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase
    });

    using (Utf8JsonWriter writer = new Utf8JsonWriter(stream))
    {
        await serializer.SerializeAsync(writer, obj);
    }
}

High level design

The JIT compiler generates a dynamic class inside a dynamic assembly when JsonJitSerializer.Compile&lt;T&gt; is called. This dynamic class is a value type and implements ISerializerImplementation&lt;T&gt;. That interface defines two methods: Serialize and SerializeChunk. Serialize serializes an object in one shot. SerializeChunk is re-enterable which can be called with the same parameter until it returns false, so it can be used for asynchronized serialization. Both methods will be implemented by generated IL codes. Other than that, the dynamic class contains static fields used as constants, such as converters, names and serialization options.

The dynamic class contains a list of Object fields used as serialization stack. The type Object is actually used as void* (Note: value type will be boxed). However there is no runtime casting involved. Therefore the runtime memory consumption is linear to the depth of the payload object. One exception is IDictionary&lt;string, T&gt;, because a local variable is needed to store a KeyValuePair&lt;string, T&gt; for every dictionary. Since the dynamic class is a value type, the serialization stack will be allocated on the stack at runtime.

Supported feature

  • Just-in-time compiled JSON serialization with System.Text.Json.JsonSerializerOptions.
  • Custom JsonConverter attribute.
  • Custom JsonPropertyName attribute.
  • Both synchronized and asynchronized (re-enterable) serialization.
  • struct serialization.
  • Correctly deal with ref getter.
  • IEnumerable&lt;T&gt; and IDictionary&lt;string, T&gt; serialization.
  • Value type enumerator optimization.
  • O(depth of structure + number of dictionary) runtime memory consumption.

Benchmark

See: https://github.com/Martin1994/JsonJitSerializer

JSON Serializer JIT Compiler for .NET Core 3.0

Emit CIL/MSIL code at runtime for serializing JSON object, utilizing the System.Test.Json namespace provided since .NET Core 3.0.

Example usage

static string CompileAndSerialize<T>(T obj)
{
    JsonJitSerializer<T> serializer = JsonJitSerializer<T>.Compile(new JsonSerializerOptions()
    {
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase
    });

    return serializer.Serialize(obj);
}

static async Task CompileAndSerializeAsync<T>(Stream stream, T obj)
{
    JsonJitSerializer<T> serializer = JsonJitSerializer<T>.Compile(new JsonSerializerOptions()
    {
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase
    });

    using (Utf8JsonWriter writer = new Utf8JsonWriter(stream))
    {
        await serializer.SerializeAsync(writer, obj);
    }
}

High level design

The JIT compiler generates a dynamic class inside a dynamic assembly when JsonJitSerializer.Compile&lt;T&gt; is called. This dynamic class is a value type and implements ISerializerImplementation&lt;T&gt;. That interface defines two methods: Serialize and SerializeChunk. Serialize serializes an object in one shot. SerializeChunk is re-enterable which can be called with the same parameter until it returns false, so it can be used for asynchronized serialization. Both methods will be implemented by generated IL codes. Other than that, the dynamic class contains static fields used as constants, such as converters, names and serialization options.

The dynamic class contains a list of Object fields used as serialization stack. The type Object is actually used as void* (Note: value type will be boxed). However there is no runtime casting involved. Therefore the runtime memory consumption is linear to the depth of the payload object. One exception is IDictionary&lt;string, T&gt;, because a local variable is needed to store a KeyValuePair&lt;string, T&gt; for every dictionary. Since the dynamic class is a value type, the serialization stack will be allocated on the stack at runtime.

Supported feature

  • Just-in-time compiled JSON serialization with System.Text.Json.JsonSerializerOptions.
  • Custom JsonConverter attribute.
  • Custom JsonPropertyName attribute.
  • Both synchronized and asynchronized (re-enterable) serialization.
  • struct serialization.
  • Correctly deal with ref getter.
  • IEnumerable&lt;T&gt; and IDictionary&lt;string, T&gt; serialization.
  • Value type enumerator optimization.
  • O(depth of structure + number of dictionary) runtime memory consumption.

Benchmark

See: https://github.com/Martin1994/JsonJitSerializer

  • .NETCoreApp 3.0

    • No dependencies.

This package is not used by any popular GitHub repositories.

Version History

Version Downloads Last updated
1.0.0 92 9/13/2019