A high-performance JSON serializer and deserializer for the Beef programming language.
- RFC 8259 compliant
- RFC 6901 JSON Pointer support
- Attribute-based serialization with
[JsonObject] - Result-based error handling
- Pretty-print support
- Stream-based parsing and serialization
- Comment support (optional JSONC)
- Safe access methods (TryGet, GetOrDefault)
- Optimized performance
- Clone the repository or download the latest release from the Releases page
- Add BJSON to your workspace via IDE
⚠️ Be sure you have latest nightly of Beef IDE installed due to some syntax not working properly in older versions. This is now fixed in the compiler.
The easiest way to work with JSON is using the [JsonObject] attribute for automatic serialization:
using BJSON;
using BJSON.Attributes;
using System.Collections;
[JsonObject]
class Person
{
public String Name = new .() ~ delete _;
public int Age;
public bool IsActive;
[JsonPropertyName("email_address")] // Custom JSON property name
public String Email = new .() ~ delete _;
public List<String> Tags = new .() ~ DeleteContainerAndItems!(_);
[JsonIgnore(Condition = .Always)] // Exclude from serialization
public int InternalId;
}
// Serialize to JSON
let person = scope Person();
person.Name.Set("John Doe");
person.Age = 30;
let output = scope String();
Json.Serialize(person, output);
// Output: {"Name":"John Doe","Age":30,"IsActive":false,"email_address":"","Tags":[]}
// Deserialize from JSON (pre-allocated object)
let json = """{"Name":"Jane","Age":25}""";
let stream = scope StringStream(json, .Reference);
let restored = scope Person();
Json.Deserialize<Person>(stream, restored);
// Or use allocating API (caller must delete)
let stream2 = scope StringStream(json, .Reference);
if (Json.Deserialize<Person>(stream2) case .Ok(let newPerson))
{
defer delete newPerson;
// use newPerson...
}- Primitives:
bool,int,float,double, etc. String(must be pre-allocated withnew .() ~ delete _)- Enums (serialized as strings)
- Nullable types (
int?,float?) - treated as optional List<T>for any supported typeDictionary<String, T>(string keys only)- Sized arrays (
int[3],float[N]) - Nested objects with
[JsonObject]
[JsonObject]- Mark class/struct for serialization[JsonPropertyName("name")]- Custom JSON property name[JsonIgnore]- Exclude field from serialization[JsonInclude]- Include private fields
For dynamic JSON handling without predefined types:
let jsonString = "{\"name\":\"BJSON\",\"version\":1.0}";
var result = Json.Deserialize(jsonString);
defer result.Dispose();
if (result case .Ok(let jsonValue))
{
// we expect object
if (let root = jsonValue.AsObject())
{
if (StringView name = root.GetValue("name"))
Console.WriteLine(name);
}
}
else if (result case .Err(let error))
{
Console.WriteLine("Error: {}", error);
}
//Note: You can also use switch case statement as welllet json = JsonObject()
{
("firstName", "John"),
("lastName", "Smith"),
("isAlive", true),
("age", 27)
};
defer json.Dispose();
let output = scope String();
Json.Serialize(json, output);
Console.WriteLine(output);let json = JsonObject()
{
("firstName", "John"),
("lastName", "Smith"),
("isAlive", true),
("age", 27),
("phoneNumbers", JsonArray()
{
JsonObject()
{
("type", "home"),
("number", "212 555-1234")
},
JsonObject()
{
("type", "office"),
("number", "646 555-4567")
}
})
};
defer json.Dispose();
let output = scope String();
let options = JsonWriterOptions() { Indented = true };
Json.Serialize(json, output, options);
Console.WriteLine(output);Enable JSONC (JSON with Comments) parsing:
// JSONC (JSON with Comments)
var config = DeserializerConfig() { EnableComments = true };
var deserializer = scope Deserializer(config);
let jsonWithComments = """
{
// Single-line comment
"setting": "bing bong",
/* Multi-line comment */
"enabled": true
}
""";
var result = deserializer.Deserialize(jsonWithComments);
defer result.Dispose();
if (result case .Ok(let val))
{
/* YOLO Errors
StringView settings = val["setting"];
Console.WriteLine(scope $"Settings value: {settings}");
*/
// or safer way
if (let root = val.AsObject())
{
if (StringView test = root.GetValue("setting"))
{
Console.WriteLine(test);
}
}
}
else if (result case .Err(let err))
{
Console.WriteLine(err);
}Use TryGet and GetOrDefault to safely access values without crashes:
let json = JsonObject() { ("name", "test"), ("value", 42) };
defer json.Dispose();
// TryGet - returns Result, use pattern matching
if (let val = json.TryGet("name"))
Console.WriteLine(scope $"Name: {(StringView)val}");
// GetOrDefault - returns fallback value on failure
let missing = json.GetOrDefault("nonexistent", "default");
Console.WriteLine(scope $"Value: {(StringView)missing}");
// Works with arrays too
let arr = JsonArray() { 1, 2, 3 };
defer arr.Dispose();
if (let first = arr.TryGet(0))
Console.WriteLine(scope $"First: {(int)first}");
let outOfBounds = arr.GetOrDefault(99, JsonNumber(0)); // Returns 0Navigate nested JSON structures using path expressions:
let jsonString = "{\"store\":{\"name\":\"My Shop\",\"products\":[{\"name\":\"Apple\"},{\"name\":\"Banana\"}]}}";
var result = Json.Deserialize(jsonString);
defer result.Dispose();
if (result case .Ok(let json))
{
// Direct path access
if (let storeName = json.GetByPointer("/store/name"))
Console.WriteLine(scope $"Store: {(StringView)storeName}");
// Access array elements
if (let product = json.GetByPointer("/store/products/0/name"))
Console.WriteLine(scope $"First product: {(StringView)product}");
// GetByPointerOrDefault - returns fallback on failure
let missing = json.GetByPointerOrDefault("/store/address", "N/A");
}JSON Pointer escape sequences:
~0represents~~1represents/
Json- Static methods for serialization and deserializationDeserializer- Configurable JSON parserJsonWriter- Output serializationJsonReader- Stream-based input parsingJsonPointer- RFC 6901 path-based navigation
JsonNullJsonBoolJsonNumberJsonStringJsonArrayJsonObject
DeserializerConfig
EnableComments- Allow C-style comments (default: false)
JsonWriterOptions
Indented- Enable pretty-printing (default: false)IndentString- Indentation string (default: " ")
The library includes comprehensive test suites covering RFC compliance, edge cases, and error handling.
BeefBuild.exe -testOr build the test project via IDE.
Test suites include:
- JSON.org standard tests
- Native JSON benchmark roundtrips
- NST JSON test suite
- Big List of Naughty Strings
MIT License
