/Json

Yet Another JSON parser

Primary LanguageC#Apache License 2.0Apache-2.0

Yet Another JSON parser

Features

  • parse/write JSON

  • parse/write ECMAScript like content

    • Unquoted property names
    • Single / multi-line comments
    • Trailing comma allowed for objects and arrays
    • Single quoted strings
    • Multi-line strings (by escaping new line characters)
    • Unicode CodePoint escape
    • Hexadecimal/octal/binary numbers
    • Numbers with leading or trailing decimal point
    • Positive infinity, negative infinity, NaN
    • Explicit plus sign for numbers
  • Support for C#/.NET Tuples (using Tuple Element Names)

Automatic for tuples included in a object

[JsonObject]
private sealed class TupleHolder {
	[JsonProperty]
	public (bool a, int b) Value1 { get; set; }
}

json => { Value1: { a: true, b: 42 } }

Manual for top level tuples or when using generics

JsonWriter.Serialize(
    output,
    (true, 42),
    JsonWriter.DefaultSettings.With(s => s.JsonWriteMode = JsonWriteMode.ECMAScript),
    tupleNames: new string[] { "a", "b" });
=> { a: true, b: 42 }

Manual using TupleElementNamesAttribute

public class ClassContaingTupleMethod {
  public (string value1, bool value2) MethodReturningTuple() {
    return ("test", true);
  }
}

string json = JsonUtility.Serialize(
  new ClassContaingTupleMethod().MethodReturningTuple(),
  tupleNames: 
    typeof(ClassContaingTupleMethod).GetMethod("MethodReturningTuple", BindingFlags.Instance | BindingFlags.Public)
    .ReturnParameter.GetCustomAttribute<TupleElementNamesAttribute>().TransformNames.ToArray());
// json => {"value1":"test","value2":true}

Usage

Parsing json

parsing a json string synchronously

using (var reader = new StringReader(json)) {
  var value = JsonParser.Parse<ObjectType>(new JsonReader(reader));
}

or

var value = JsonUtility.Parse<ObjectType>(json);

parsing a json string asynchronously

using (var reader = new StringReader(json)) {
  var value = await JsonParser.ParseAsync<ObjectType>(new JsonReader(reader));
}

or

var value = await JsonUtility.ParseAsync<ObjectType>(json);

parsing a json stream synchronously

using (var reader = new StreamReader(stream)) {
  var value = JsonParser.Parse<ObjectType>(new JsonReader(reader));
}

or

var value = JsonUtility.Parse<ObjectType>(stream);

parsing a json stream asynchronously

using (var reader = new StreamReader(stream)) {
  var value = await JsonParser.ParseAsync<ObjectType>(new JsonReader(reader));
}

or

var value = await JsonUtility.ParseAsync<ObjectType>(stream);

Writing json

serializing a value as json string synchronously

var sb = new StringBuilder();
using (var writer = new StringWriter(sb)) {
  var value = JsonWriter.Serialize(writer, value);
}
var json = sb.ToString();

or

var json = JsonUtility.Serialize(value);

serializing a value as json string asynchronously

var sb = new StringBuilder();
using (var writer = new StringWriter(sb)) {
  var value = await JsonWriter.SerializeAsync(writer, value);
}
var json = sb.ToString();

or

var json = await JsonUtility.SerializeAsync(value);

serializing a value to a stream synchronously

using (var writer = new StreamWriter(stream)) {
  JsonWriter.Serialize(writer, value);
}

or

JsonUtility.Serialize(stream, value);

serializing a value to a stream asynchronously

using (var writer = new StreamWriter(stream)) {
  await JsonWriter.SerializeAsync(writer, value);
}

or

await JsonUtility.SerializeAsync(stream, value);

Annotation

Objects

use IonKiwi.Json.MetaData.JsonObjectAttribute & IonKiwi.Json.MetaData.JsonPropertyAttribute

[JsonObject]
public class Object1 {

	[JsonProperty]
	public string Property1 { get; set; }
}

Collections

use IonKiwi.Json.MetaData.JsonCollectionAttribute and implement IEnumerable<>

[JsonCollection]
public class Collection1<T> : IEnumerable<T> {
}

Dictionaries

use IonKiwi.Json.MetaData.JsonDictionaryAttribute and implement IDictionary<,>

[JsonDictionary]
public class Dictionary1<TKey, TValue> : IDictionary<TKey, TValue> {
}

External/existing annotation

use existing DataContract/DataMember attributes (System.Runtime.Serialization)

IonKiwi.Json.Utilities.DataContractSupport.Register();

use existing Newtonsoft attributes

IonKiwi.Json.Newtonsoft.NewtonsoftSupport.Register();

Custom constructors

use IonKiwi.Json.MetaData.JsonConstructorAttribute & IonKiwi.Json.MetaData.JsonParameterAttribute

[JsonObject]
private class Object2 {

	[JsonConstructor]
	public Object2([JsonParameter("property1")]bool parameter1, int property2) {
		Property1 = parameter1;
		Property2 = property2;
	}

	[JsonProperty(Name = "property1")]
	public bool Property1 { get; }

	[JsonProperty(Name = "property2", Required = false)]
	public int Property2 { get; }

	[JsonProperty]
	public int Property3 { get; }
}

For non required properties, the default value will be used. You can declare multiple [JsonConstructor] constructors, the one with the most available parameters will be called.