diff --git a/ReflectorNet.Tests/JsonConverterTests/JsonNodeConverterTests.cs b/ReflectorNet.Tests/JsonConverterTests/JsonNodeConverterTests.cs
new file mode 100644
index 0000000..129ea19
--- /dev/null
+++ b/ReflectorNet.Tests/JsonConverterTests/JsonNodeConverterTests.cs
@@ -0,0 +1,747 @@
+/*
+ * ReflectorNet
+ * Author: Ivan Murzak (https://github.com/IvanMurzak)
+ * Copyright (c) 2025 Ivan Murzak
+ * Licensed under the Apache License, Version 2.0. See LICENSE file in the project root for full license information.
+ */
+
+using System;
+using System.Text.Json;
+using System.Text.Json.Nodes;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace com.IvanMurzak.ReflectorNet.Tests.JsonConverterTests
+{
+ ///
+ /// Comprehensive tests for JsonElement, JsonObject, and JsonArray JSON converters.
+ /// Tests cover serialization, deserialization, null handling, schema generation, and edge cases.
+ ///
+ public class JsonNodeConverterTests : BaseTest
+ {
+ private readonly Reflector _reflector;
+
+ public JsonNodeConverterTests(ITestOutputHelper output) : base(output)
+ {
+ _reflector = new Reflector();
+ }
+
+ #region JsonElement Tests
+
+ [Fact]
+ public void JsonElementConverter_Serialize_SimpleObject_ShouldSucceed()
+ {
+ // Arrange
+ var jsonElement = JsonDocument.Parse("{\"name\":\"John\",\"age\":30}").RootElement;
+
+ // Act
+ var json = _reflector.JsonSerializer.Serialize(jsonElement);
+ _output.WriteLine($"Serialized JsonElement: {json}");
+
+ // Assert
+ Assert.NotNull(json);
+ Assert.Contains("name", json);
+ Assert.Contains("John", json);
+ Assert.Contains("age", json);
+ Assert.Contains("30", json);
+ }
+
+ [Fact]
+ public void JsonElementConverter_Serialize_Array_ShouldSucceed()
+ {
+ // Arrange
+ var jsonElement = JsonDocument.Parse("[1,2,3,4,5]").RootElement;
+
+ // Act
+ var json = _reflector.JsonSerializer.Serialize(jsonElement);
+ _output.WriteLine($"Serialized JsonElement array: {json}");
+
+ // Assert
+ Assert.NotNull(json);
+ Assert.Contains("1", json);
+ Assert.Contains("5", json);
+ }
+
+ [Fact]
+ public void JsonElementConverter_Serialize_String_ShouldSucceed()
+ {
+ // Arrange
+ var jsonElement = JsonDocument.Parse("\"hello world\"").RootElement;
+
+ // Act
+ var json = _reflector.JsonSerializer.Serialize(jsonElement);
+ _output.WriteLine($"Serialized JsonElement string: {json}");
+
+ // Assert
+ Assert.NotNull(json);
+ Assert.Contains("hello world", json);
+ }
+
+ [Fact]
+ public void JsonElementConverter_Serialize_Number_ShouldSucceed()
+ {
+ // Arrange
+ var jsonElement = JsonDocument.Parse("42").RootElement;
+
+ // Act
+ var json = _reflector.JsonSerializer.Serialize(jsonElement);
+ _output.WriteLine($"Serialized JsonElement number: {json}");
+
+ // Assert
+ Assert.NotNull(json);
+ Assert.Contains("42", json);
+ }
+
+ [Fact]
+ public void JsonElementConverter_Serialize_Boolean_ShouldSucceed()
+ {
+ // Arrange
+ var jsonElement = JsonDocument.Parse("true").RootElement;
+
+ // Act
+ var json = _reflector.JsonSerializer.Serialize(jsonElement);
+ _output.WriteLine($"Serialized JsonElement boolean: {json}");
+
+ // Assert
+ Assert.NotNull(json);
+ Assert.Contains("true", json);
+ }
+
+ [Fact]
+ public void JsonElementConverter_Serialize_Null_ShouldSucceed()
+ {
+ // Arrange
+ var jsonElement = JsonDocument.Parse("null").RootElement;
+
+ // Act
+ var json = _reflector.JsonSerializer.Serialize(jsonElement);
+ _output.WriteLine($"Serialized JsonElement null: {json}");
+
+ // Assert
+ Assert.NotNull(json);
+ Assert.Contains("null", json);
+ }
+
+ [Fact]
+ public void JsonElementConverter_Deserialize_SimpleObject_ShouldSucceed()
+ {
+ // Arrange
+ var json = "{\"name\":\"Jane\",\"age\":25}";
+
+ // Act
+ var jsonElement = _reflector.JsonSerializer.Deserialize(json);
+ _output.WriteLine($"Deserialized JsonElement: {jsonElement}");
+
+ // Assert
+ Assert.Equal(JsonValueKind.Object, jsonElement.ValueKind);
+ Assert.True(jsonElement.TryGetProperty("name", out var nameProperty));
+ Assert.Equal("Jane", nameProperty.GetString());
+ Assert.True(jsonElement.TryGetProperty("age", out var ageProperty));
+ Assert.Equal(25, ageProperty.GetInt32());
+ }
+
+ [Fact]
+ public void JsonElementConverter_Deserialize_NestedObject_ShouldSucceed()
+ {
+ // Arrange
+ var json = "{\"user\":{\"name\":\"Bob\",\"address\":{\"city\":\"NYC\"}}}";
+
+ // Act
+ var jsonElement = _reflector.JsonSerializer.Deserialize(json);
+ _output.WriteLine($"Deserialized nested JsonElement: {jsonElement}");
+
+ // Assert
+ Assert.Equal(JsonValueKind.Object, jsonElement.ValueKind);
+ Assert.True(jsonElement.TryGetProperty("user", out var userProperty));
+ Assert.True(userProperty.TryGetProperty("address", out var addressProperty));
+ Assert.True(addressProperty.TryGetProperty("city", out var cityProperty));
+ Assert.Equal("NYC", cityProperty.GetString());
+ }
+
+ [Fact]
+ public void JsonElementConverter_RoundTrip_ComplexObject_ShouldPreserveData()
+ {
+ // Arrange
+ var originalJson = "{\"string\":\"test\",\"number\":123,\"bool\":true,\"array\":[1,2,3],\"nested\":{\"key\":\"value\"}}";
+ var originalElement = JsonDocument.Parse(originalJson).RootElement;
+
+ // Act
+ var serialized = _reflector.JsonSerializer.Serialize(originalElement);
+ _output.WriteLine($"Serialized: {serialized}");
+
+ var deserialized = _reflector.JsonSerializer.Deserialize(serialized);
+ var reserialized = _reflector.JsonSerializer.Serialize(deserialized);
+ _output.WriteLine($"Reserialized: {reserialized}");
+
+ // Assert - Verify data integrity by comparing property values
+ Assert.True(deserialized.TryGetProperty("string", out var stringProp));
+ Assert.Equal("test", stringProp.GetString());
+
+ Assert.True(deserialized.TryGetProperty("number", out var numberProp));
+ Assert.Equal(123, numberProp.GetInt32());
+
+ Assert.True(deserialized.TryGetProperty("bool", out var boolProp));
+ Assert.True(boolProp.GetBoolean());
+
+ Assert.True(deserialized.TryGetProperty("array", out var arrayProp));
+ Assert.Equal(3, arrayProp.GetArrayLength());
+
+ Assert.True(deserialized.TryGetProperty("nested", out var nestedProp));
+ Assert.True(nestedProp.TryGetProperty("key", out var keyProp));
+ Assert.Equal("value", keyProp.GetString());
+ }
+
+ #endregion
+
+ #region JsonObject Tests
+
+ [Fact]
+ public void JsonObjectConverter_Serialize_SimpleObject_ShouldSucceed()
+ {
+ // Arrange
+ var jsonObject = new JsonObject
+ {
+ ["name"] = "Alice",
+ ["age"] = 28,
+ ["isActive"] = true
+ };
+
+ // Act
+ var json = _reflector.JsonSerializer.Serialize(jsonObject);
+ _output.WriteLine($"Serialized JsonObject: {json}");
+
+ // Assert
+ Assert.NotNull(json);
+ Assert.Contains("name", json);
+ Assert.Contains("Alice", json);
+ Assert.Contains("age", json);
+ Assert.Contains("28", json);
+ Assert.Contains("isActive", json);
+ Assert.Contains("true", json);
+ }
+
+ [Fact]
+ public void JsonObjectConverter_Serialize_NestedObject_ShouldSucceed()
+ {
+ // Arrange
+ var jsonObject = new JsonObject
+ {
+ ["user"] = new JsonObject
+ {
+ ["name"] = "Bob",
+ ["details"] = new JsonObject
+ {
+ ["email"] = "bob@example.com",
+ ["age"] = 35
+ }
+ }
+ };
+
+ // Act
+ var json = _reflector.JsonSerializer.Serialize(jsonObject);
+ _output.WriteLine($"Serialized nested JsonObject: {json}");
+
+ // Assert
+ Assert.NotNull(json);
+ Assert.Contains("user", json);
+ Assert.Contains("Bob", json);
+ Assert.Contains("details", json);
+ Assert.Contains("bob@example.com", json);
+ }
+
+ [Fact]
+ public void JsonObjectConverter_Serialize_EmptyObject_ShouldSucceed()
+ {
+ // Arrange
+ var jsonObject = new JsonObject();
+
+ // Act
+ var json = _reflector.JsonSerializer.Serialize(jsonObject);
+ _output.WriteLine($"Serialized empty JsonObject: {json}");
+
+ // Assert
+ Assert.NotNull(json);
+ Assert.Contains("{", json);
+ Assert.Contains("}", json);
+ }
+
+ [Fact]
+ public void JsonObjectConverter_Serialize_NullValue_ShouldSucceed()
+ {
+ // Arrange
+ JsonObject? jsonObject = null;
+
+ // Act
+ var json = _reflector.JsonSerializer.Serialize(jsonObject);
+ _output.WriteLine($"Serialized null JsonObject: {json}");
+
+ // Assert
+ Assert.NotNull(json);
+ Assert.Contains("null", json);
+ }
+
+ [Fact]
+ public void JsonObjectConverter_Deserialize_SimpleObject_ShouldSucceed()
+ {
+ // Arrange
+ var json = "{\"name\":\"Charlie\",\"score\":95.5}";
+
+ // Act
+ var jsonObject = _reflector.JsonSerializer.Deserialize(json);
+ var serializedBack = _reflector.JsonSerializer.Serialize(jsonObject);
+ _output.WriteLine($"Deserialized JsonObject: {serializedBack}");
+
+ // Assert
+ Assert.NotNull(jsonObject);
+ Assert.Equal("Charlie", jsonObject["name"]?.GetValue());
+ Assert.Equal(95.5, jsonObject["score"]?.GetValue());
+ }
+
+ [Fact]
+ public void JsonObjectConverter_Deserialize_WithMixedTypes_ShouldSucceed()
+ {
+ // Arrange
+ var json = "{\"string\":\"text\",\"number\":42,\"boolean\":false,\"null\":null,\"array\":[1,2,3]}";
+
+ // Act
+ var jsonObject = _reflector.JsonSerializer.Deserialize(json);
+ var serializedBack = _reflector.JsonSerializer.Serialize(jsonObject);
+ _output.WriteLine($"Deserialized mixed types JsonObject: {serializedBack}");
+
+ // Assert
+ Assert.NotNull(jsonObject);
+ Assert.Equal("text", jsonObject["string"]?.GetValue());
+ Assert.Equal(42, jsonObject["number"]?.GetValue());
+ Assert.False(jsonObject["boolean"]?.GetValue());
+ Assert.Null(jsonObject["null"]);
+ Assert.NotNull(jsonObject["array"]);
+ }
+
+ [Fact]
+ public void JsonObjectConverter_RoundTrip_ComplexObject_ShouldPreserveData()
+ {
+ // Arrange
+ var original = new JsonObject
+ {
+ ["id"] = 123,
+ ["name"] = "Test User",
+ ["metadata"] = new JsonObject
+ {
+ ["created"] = "2025-01-01",
+ ["tags"] = new JsonArray("important", "verified")
+ }
+ };
+
+ // Act
+ var serialized = _reflector.JsonSerializer.Serialize(original);
+ _output.WriteLine($"Serialized: {serialized}");
+
+ var deserialized = _reflector.JsonSerializer.Deserialize(serialized);
+ var reserialized = _reflector.JsonSerializer.Serialize(deserialized);
+ _output.WriteLine($"Reserialized: {reserialized}");
+
+ // Assert
+ Assert.Equal(serialized, reserialized);
+ }
+
+ [Fact]
+ public void JsonObjectConverter_Deserialize_Null_ShouldReturnNull()
+ {
+ // Arrange
+ var json = "null";
+
+ // Act
+ var jsonObject = _reflector.JsonSerializer.Deserialize(json);
+ _output.WriteLine($"Deserialized null: {jsonObject}");
+
+ // Assert
+ Assert.Null(jsonObject);
+ }
+
+ #endregion
+
+ #region JsonArray Tests
+
+ [Fact]
+ public void JsonArrayConverter_Serialize_IntegerArray_ShouldSucceed()
+ {
+ // Arrange
+ var jsonArray = new JsonArray(1, 2, 3, 4, 5);
+
+ // Act
+ var json = _reflector.JsonSerializer.Serialize(jsonArray);
+ _output.WriteLine($"Serialized JsonArray: {json}");
+
+ // Assert
+ Assert.NotNull(json);
+ Assert.Contains("1", json);
+ Assert.Contains("5", json);
+ }
+
+ [Fact]
+ public void JsonArrayConverter_Serialize_StringArray_ShouldSucceed()
+ {
+ // Arrange
+ var jsonArray = new JsonArray("apple", "banana", "cherry");
+
+ // Act
+ var json = _reflector.JsonSerializer.Serialize(jsonArray);
+ _output.WriteLine($"Serialized string JsonArray: {json}");
+
+ // Assert
+ Assert.NotNull(json);
+ Assert.Contains("apple", json);
+ Assert.Contains("banana", json);
+ Assert.Contains("cherry", json);
+ }
+
+ [Fact]
+ public void JsonArrayConverter_Serialize_MixedTypeArray_ShouldSucceed()
+ {
+ // Arrange
+ var jsonArray = new JsonArray(
+ "string",
+ 42,
+ true,
+ null,
+ new JsonObject { ["key"] = "value" }
+ );
+
+ // Act
+ var json = _reflector.JsonSerializer.Serialize(jsonArray);
+ _output.WriteLine($"Serialized mixed type JsonArray: {json}");
+
+ // Assert
+ Assert.NotNull(json);
+ Assert.Contains("string", json);
+ Assert.Contains("42", json);
+ Assert.Contains("true", json);
+ Assert.Contains("null", json);
+ Assert.Contains("key", json);
+ }
+
+ [Fact]
+ public void JsonArrayConverter_Serialize_NestedArrays_ShouldSucceed()
+ {
+ // Arrange
+ var jsonArray = new JsonArray(
+ new JsonArray(1, 2, 3),
+ new JsonArray(4, 5, 6),
+ new JsonArray(7, 8, 9)
+ );
+
+ // Act
+ var json = _reflector.JsonSerializer.Serialize(jsonArray);
+ _output.WriteLine($"Serialized nested JsonArray: {json}");
+
+ // Assert
+ Assert.NotNull(json);
+ Assert.Contains("[", json);
+ Assert.Contains("1", json);
+ Assert.Contains("9", json);
+ }
+
+ [Fact]
+ public void JsonArrayConverter_Serialize_EmptyArray_ShouldSucceed()
+ {
+ // Arrange
+ var jsonArray = new JsonArray();
+
+ // Act
+ var json = _reflector.JsonSerializer.Serialize(jsonArray);
+ _output.WriteLine($"Serialized empty JsonArray: {json}");
+
+ // Assert
+ Assert.NotNull(json);
+ Assert.Contains("[", json);
+ Assert.Contains("]", json);
+ }
+
+ [Fact]
+ public void JsonArrayConverter_Serialize_NullValue_ShouldSucceed()
+ {
+ // Arrange
+ JsonArray? jsonArray = null;
+
+ // Act
+ var json = _reflector.JsonSerializer.Serialize(jsonArray);
+ _output.WriteLine($"Serialized null JsonArray: {json}");
+
+ // Assert
+ Assert.NotNull(json);
+ Assert.Contains("null", json);
+ }
+
+ [Fact]
+ public void JsonArrayConverter_Deserialize_IntegerArray_ShouldSucceed()
+ {
+ // Arrange
+ var json = "[10,20,30,40,50]";
+
+ // Act
+ var jsonArray = _reflector.JsonSerializer.Deserialize(json);
+ var serializedBack = _reflector.JsonSerializer.Serialize(jsonArray);
+ _output.WriteLine($"Deserialized JsonArray: {serializedBack}");
+
+ // Assert
+ Assert.NotNull(jsonArray);
+ Assert.Equal(5, jsonArray.Count);
+ Assert.Equal(10, jsonArray[0]?.GetValue());
+ Assert.Equal(50, jsonArray[4]?.GetValue());
+ }
+
+ [Fact]
+ public void JsonArrayConverter_Deserialize_MixedTypes_ShouldSucceed()
+ {
+ // Arrange
+ var json = "[\"text\",123,true,null,{\"key\":\"value\"}]";
+
+ // Act
+ var jsonArray = _reflector.JsonSerializer.Deserialize(json);
+ var serializedBack = _reflector.JsonSerializer.Serialize(jsonArray);
+ _output.WriteLine($"Deserialized mixed types JsonArray: {serializedBack}");
+
+ // Assert
+ Assert.NotNull(jsonArray);
+ Assert.Equal(5, jsonArray.Count);
+ Assert.Equal("text", jsonArray[0]?.GetValue());
+ Assert.Equal(123, jsonArray[1]?.GetValue());
+ Assert.True(jsonArray[2]?.GetValue());
+ Assert.Null(jsonArray[3]);
+ Assert.IsType(jsonArray[4]?.AsObject());
+ }
+
+ [Fact]
+ public void JsonArrayConverter_RoundTrip_ComplexArray_ShouldPreserveData()
+ {
+ // Arrange
+ var original = new JsonArray(
+ 1,
+ "test",
+ new JsonObject { ["nested"] = "object" },
+ new JsonArray(true, false, null)
+ );
+
+ // Act
+ var serialized = _reflector.JsonSerializer.Serialize(original);
+ _output.WriteLine($"Serialized: {serialized}");
+
+ var deserialized = _reflector.JsonSerializer.Deserialize(serialized);
+ var reserialized = _reflector.JsonSerializer.Serialize(deserialized);
+ _output.WriteLine($"Reserialized: {reserialized}");
+
+ // Assert
+ Assert.Equal(serialized, reserialized);
+ }
+
+ [Fact]
+ public void JsonArrayConverter_Deserialize_Null_ShouldReturnNull()
+ {
+ // Arrange
+ var json = "null";
+
+ // Act
+ var jsonArray = _reflector.JsonSerializer.Deserialize(json);
+ _output.WriteLine($"Deserialized null: {jsonArray}");
+
+ // Assert
+ Assert.Null(jsonArray);
+ }
+
+ #endregion
+
+ #region Null Handling Tests
+
+ [Fact]
+ public void JsonElementConverter_DeserializeNull_AsNullableType_ShouldReturnDefault()
+ {
+ // Arrange
+ var json = "null";
+
+ // Act
+ var result = _reflector.JsonSerializer.Deserialize(json);
+ _output.WriteLine($"Deserialized null JsonElement: ValueKind={result.ValueKind}");
+
+ // Assert - When deserialized to a value type like JsonElement, null becomes Undefined
+ // This is expected behavior for System.Text.Json
+ Assert.True(result.ValueKind == JsonValueKind.Undefined || result.ValueKind == JsonValueKind.Null);
+ }
+
+ [Fact]
+ public void JsonObjectConverter_WithNullProperties_ShouldHandleGracefully()
+ {
+ // Arrange
+ var jsonObject = new JsonObject
+ {
+ ["notNull"] = "value",
+ ["isNull"] = null
+ };
+
+ // Act
+ var serialized = _reflector.JsonSerializer.Serialize(jsonObject);
+ _output.WriteLine($"Serialized: {serialized}");
+
+ var deserialized = _reflector.JsonSerializer.Deserialize(serialized);
+ var reserialized = _reflector.JsonSerializer.Serialize(deserialized);
+ _output.WriteLine($"Reserialized: {reserialized}");
+
+ // Assert
+ Assert.NotNull(deserialized);
+ Assert.Equal("value", deserialized["notNull"]?.GetValue());
+ Assert.Null(deserialized["isNull"]);
+ }
+
+ [Fact]
+ public void JsonArrayConverter_WithNullElements_ShouldHandleGracefully()
+ {
+ // Arrange
+ var jsonArray = new JsonArray(1, null, 3, null, 5);
+
+ // Act
+ var serialized = _reflector.JsonSerializer.Serialize(jsonArray);
+ _output.WriteLine($"Serialized: {serialized}");
+
+ var deserialized = _reflector.JsonSerializer.Deserialize(serialized);
+ var reserialized = _reflector.JsonSerializer.Serialize(deserialized);
+ _output.WriteLine($"Reserialized: {reserialized}");
+
+ // Assert
+ Assert.NotNull(deserialized);
+ Assert.Equal(5, deserialized.Count);
+ Assert.Equal(1, deserialized[0]?.GetValue());
+ Assert.Null(deserialized[1]);
+ Assert.Equal(3, deserialized[2]?.GetValue());
+ Assert.Null(deserialized[3]);
+ Assert.Equal(5, deserialized[4]?.GetValue());
+ }
+
+ #endregion
+
+ #region Edge Cases and Error Handling
+
+ [Fact]
+ public void JsonElementConverter_DeepNesting_ShouldSucceed()
+ {
+ // Arrange - Create deeply nested JSON (10 levels)
+ var json = "{\"l1\":{\"l2\":{\"l3\":{\"l4\":{\"l5\":{\"l6\":{\"l7\":{\"l8\":{\"l9\":{\"l10\":\"deep value\"}}}}}}}}}}";
+
+ // Act
+ var jsonElement = _reflector.JsonSerializer.Deserialize(json);
+
+ // Assert
+ var current = jsonElement;
+ for (int i = 1; i <= 10; i++)
+ {
+ if (i == 10)
+ {
+ Assert.True(current.TryGetProperty($"l{i}", out var finalProp));
+ Assert.Equal("deep value", finalProp.GetString());
+ }
+ else
+ {
+ Assert.True(current.TryGetProperty($"l{i}", out current));
+ }
+ }
+ }
+
+ [Fact]
+ public void JsonArrayConverter_LargeArray_ShouldSucceed()
+ {
+ // Arrange - Create array with 1000 elements
+ var largeArray = new JsonArray();
+ for (int i = 0; i < 1000; i++)
+ {
+ largeArray.Add(i);
+ }
+
+ // Act
+ var serialized = _reflector.JsonSerializer.Serialize(largeArray);
+ var deserialized = _reflector.JsonSerializer.Deserialize(serialized);
+
+ // Assert
+ Assert.NotNull(deserialized);
+ Assert.Equal(1000, deserialized.Count);
+ Assert.Equal(0, deserialized[0]?.GetValue());
+ Assert.Equal(999, deserialized[999]?.GetValue());
+ }
+
+ [Fact]
+ public void JsonObjectConverter_SpecialCharacters_ShouldPreserve()
+ {
+ // Arrange
+ var jsonObject = new JsonObject
+ {
+ ["emoji"] = "ππ",
+ ["unicode"] = "Hello \u4E16\u754C", // Chinese characters
+ ["escaped"] = "Line1\nLine2\tTabbed",
+ ["quotes"] = "She said \"hello\""
+ };
+
+ // Act
+ var serialized = _reflector.JsonSerializer.Serialize(jsonObject);
+ _output.WriteLine($"Serialized: {serialized}");
+
+ var deserialized = _reflector.JsonSerializer.Deserialize(serialized);
+ var reserialized = _reflector.JsonSerializer.Serialize(deserialized);
+ _output.WriteLine($"Reserialized: {reserialized}");
+
+ // Assert
+ Assert.NotNull(deserialized);
+ Assert.Equal("ππ", deserialized["emoji"]?.GetValue());
+ Assert.Contains("δΈη", deserialized["unicode"]?.GetValue() ?? "");
+ Assert.Contains("\n", deserialized["escaped"]?.GetValue());
+ Assert.Contains("\"", deserialized["quotes"]?.GetValue());
+ }
+
+ [Fact]
+ public void JsonElementConverter_NumericPrecision_ShouldPreserve()
+ {
+ // Arrange
+ var json = "{\"decimal\":123.456789012345,\"scientific\":1.23e-10}";
+
+ // Act
+ var jsonElement = _reflector.JsonSerializer.Deserialize(json);
+ var reserialized = _reflector.JsonSerializer.Serialize(jsonElement);
+ _output.WriteLine($"Original: {json}");
+ _output.WriteLine($"Reserialized: {reserialized}");
+
+ // Assert
+ Assert.True(jsonElement.TryGetProperty("decimal", out var decimalProp));
+ Assert.True(jsonElement.TryGetProperty("scientific", out var scientificProp));
+ }
+
+ #endregion
+
+ #region Integration Tests
+
+ [Fact]
+ public void AllConverters_WorkTogether_InComplexStructure()
+ {
+ // Arrange - Mix JsonElement, JsonObject, and JsonArray
+ var complexJson = @"{
+ ""element"": {""type"":""element"",""value"":123},
+ ""object"": {""name"":""Test Object"",""active"":true},
+ ""array"": [1,2,3,{""nested"":""value""}]
+ }";
+
+ // Act
+ var jsonElement = _reflector.JsonSerializer.Deserialize(complexJson);
+
+ // Extract parts
+ Assert.True(jsonElement.TryGetProperty("element", out var elementProp));
+ Assert.True(jsonElement.TryGetProperty("object", out var objectProp));
+ Assert.True(jsonElement.TryGetProperty("array", out var arrayProp));
+
+ // Serialize back
+ var reserialized = _reflector.JsonSerializer.Serialize(jsonElement);
+ _output.WriteLine($"Reserialized: {reserialized}");
+
+ // Assert
+ Assert.Contains("element", reserialized);
+ Assert.Contains("object", reserialized);
+ Assert.Contains("array", reserialized);
+ }
+
+ #endregion
+ }
+}
diff --git a/ReflectorNet/ReflectorNet.csproj b/ReflectorNet/ReflectorNet.csproj
index fb9102d..3569a83 100644
--- a/ReflectorNet/ReflectorNet.csproj
+++ b/ReflectorNet/ReflectorNet.csproj
@@ -9,7 +9,7 @@
com.IvanMurzak.ReflectorNet
- 2.1.1
+ 2.2.0
Ivan Murzak
Copyright Β© Ivan Murzak 2025
ReflectorNet is an advanced .NET reflection toolkit designed for AI-driven scenarios. Effortlessly search for C# methods using natural language queries, invoke any method by supplying arguments as JSON, and receive results as JSON. The library also provides a powerful API to inspect, modify, and manage in-memory object instances dynamically via JSON data. Ideal for automation, testing, and AI integration workflows.
diff --git a/ReflectorNet/src/Convertor/Json/JsonArrayJsonConverter.cs b/ReflectorNet/src/Convertor/Json/JsonArrayJsonConverter.cs
new file mode 100644
index 0000000..8c7115c
--- /dev/null
+++ b/ReflectorNet/src/Convertor/Json/JsonArrayJsonConverter.cs
@@ -0,0 +1,52 @@
+/*
+ * ReflectorNet
+ * Author: Ivan Murzak (https://github.com/IvanMurzak)
+ * Copyright (c) 2025 Ivan Murzak
+ * Licensed under the Apache License, Version 2.0. See LICENSE file in the project root for full license information.
+ */
+
+using System;
+using System.Text.Json;
+using System.Text.Json.Nodes;
+using com.IvanMurzak.ReflectorNet.Utils;
+
+namespace com.IvanMurzak.ReflectorNet.Json
+{
+ ///
+ /// JsonConverter that handles serialization and deserialization of JsonArray objects.
+ /// Supports schema generation for JSON arrays and conversion between JsonArray and JsonElement.
+ ///
+ public class JsonArrayJsonConverter : JsonNodeJsonConverter, IJsonSchemaConverter
+ {
+ // Schema for any JSON value type
+ public static readonly JsonNode JsonAnySchema = new JsonObject
+ {
+ [JsonSchema.AnyOf] = new JsonArray
+ {
+ new JsonObject { [JsonSchema.Type] = JsonSchema.Object, [JsonSchema.AdditionalProperties] = true },
+ new JsonObject { [JsonSchema.Type] = JsonSchema.Array, [JsonSchema.Items] = new JsonObject() },
+ new JsonObject { [JsonSchema.Type] = JsonSchema.String },
+ new JsonObject { [JsonSchema.Type] = JsonSchema.Number },
+ new JsonObject { [JsonSchema.Type] = JsonSchema.Boolean },
+ new JsonObject { [JsonSchema.Type] = JsonSchema.Null }
+ }
+ };
+ public static JsonNode Schema => new JsonObject
+ {
+ [JsonSchema.Type] = JsonSchema.Array,
+ [JsonSchema.Items] = JsonAnySchema
+ };
+ public static JsonNode SchemaRef => new JsonObject
+ {
+ [JsonSchema.Ref] = JsonSchema.RefValue + StaticId
+ };
+
+ public override JsonNode GetSchema() => Schema;
+ public override JsonNode GetSchemaRef() => SchemaRef;
+
+ protected override JsonArray? CreateJsonNode(JsonElement element)
+ {
+ return JsonArray.Create(element);
+ }
+ }
+}
\ No newline at end of file
diff --git a/ReflectorNet/src/Convertor/Json/JsonElementJsonConverter.cs b/ReflectorNet/src/Convertor/Json/JsonElementJsonConverter.cs
new file mode 100644
index 0000000..3b95877
--- /dev/null
+++ b/ReflectorNet/src/Convertor/Json/JsonElementJsonConverter.cs
@@ -0,0 +1,48 @@
+/*
+ * ReflectorNet
+ * Author: Ivan Murzak (https://github.com/IvanMurzak)
+ * Copyright (c) 2025 Ivan Murzak
+ * Licensed under the Apache License, Version 2.0. See LICENSE file in the project root for full license information.
+ */
+
+using System;
+using System.Text.Json;
+using System.Text.Json.Nodes;
+using com.IvanMurzak.ReflectorNet.Utils;
+
+namespace com.IvanMurzak.ReflectorNet.Json
+{
+ ///
+ /// JsonConverter that handles serialization and deserialization of JsonElement objects.
+ /// Supports reading and writing generic JSON values, including handling nulls.
+ ///
+ public class JsonElementJsonConverter : JsonSchemaConverter, IJsonSchemaConverter
+ {
+ public static JsonNode Schema => JsonArrayJsonConverter.JsonAnySchema;
+ public static JsonNode SchemaRef => new JsonObject
+ {
+ [JsonSchema.Ref] = JsonSchema.RefValue + StaticId
+ };
+
+ public override JsonNode GetSchema() => Schema;
+ public override JsonNode GetSchemaRef() => SchemaRef;
+
+ public override JsonElement Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ if (reader.TokenType == JsonTokenType.Null)
+ return default;
+
+ return JsonDocument.ParseValue(ref reader).RootElement.Clone();
+ }
+
+ public override void Write(Utf8JsonWriter writer, JsonElement value, JsonSerializerOptions options)
+ {
+ if (value.ValueKind == JsonValueKind.Null)
+ {
+ writer.WriteNullValue();
+ return;
+ }
+ value.WriteTo(writer);
+ }
+ }
+}
\ No newline at end of file
diff --git a/ReflectorNet/src/Convertor/Json/JsonNodeJsonConverter.cs b/ReflectorNet/src/Convertor/Json/JsonNodeJsonConverter.cs
new file mode 100644
index 0000000..9b1e8d9
--- /dev/null
+++ b/ReflectorNet/src/Convertor/Json/JsonNodeJsonConverter.cs
@@ -0,0 +1,54 @@
+/*
+ * ReflectorNet
+ * Author: Ivan Murzak (https://github.com/IvanMurzak)
+ * Copyright (c) 2025 Ivan Murzak
+ * Licensed under the Apache License, Version 2.0. See LICENSE file in the project root for full license information.
+ */
+
+using System;
+using System.Text.Json;
+using System.Text.Json.Nodes;
+
+namespace com.IvanMurzak.ReflectorNet.Json
+{
+ ///
+ /// Abstract base class for converting between JSON and types derived from JsonNode.
+ /// Provides extensibility for custom JsonNode handling via the CreateJsonNode method.
+ ///
+ public abstract class JsonNodeJsonConverter : JsonSchemaConverter, IJsonSchemaConverter
+ where T : JsonNode
+ {
+ protected abstract T? CreateJsonNode(JsonElement element);
+ public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ // Handle null values for nullable types
+ if (reader.TokenType == JsonTokenType.Null)
+ {
+ if (Nullable.GetUnderlyingType(typeToConvert) != null)
+ return null;
+
+ throw new JsonException($"Cannot convert null to non-nullable type {typeToConvert.GetTypeName(pretty: true)}.");
+ }
+
+ if (reader.TokenType is JsonTokenType.StartObject or JsonTokenType.StartArray)
+ {
+ using JsonDocument document = JsonDocument.ParseValue(ref reader);
+ // Clone the element to break the dependency on the JsonDocument
+ var clonedElement = document.RootElement.Clone();
+ return CreateJsonNode(clonedElement);
+ }
+
+ throw new JsonException($"Expected Null, StartObject or StartArray token but got {reader.TokenType} for type {typeToConvert.GetTypeName(pretty: true)}");
+ }
+
+ public override void Write(Utf8JsonWriter writer, T? value, JsonSerializerOptions options)
+ {
+ if (value == null)
+ {
+ writer.WriteNullValue();
+ return;
+ }
+ value.WriteTo(writer, options);
+ }
+ }
+}
\ No newline at end of file
diff --git a/ReflectorNet/src/Convertor/Json/JsonObjectJsonConverter.cs b/ReflectorNet/src/Convertor/Json/JsonObjectJsonConverter.cs
new file mode 100644
index 0000000..4dc2433
--- /dev/null
+++ b/ReflectorNet/src/Convertor/Json/JsonObjectJsonConverter.cs
@@ -0,0 +1,39 @@
+/*
+ * ReflectorNet
+ * Author: Ivan Murzak (https://github.com/IvanMurzak)
+ * Copyright (c) 2025 Ivan Murzak
+ * Licensed under the Apache License, Version 2.0. See LICENSE file in the project root for full license information.
+ */
+
+using System;
+using System.Text.Json;
+using System.Text.Json.Nodes;
+using com.IvanMurzak.ReflectorNet.Utils;
+
+namespace com.IvanMurzak.ReflectorNet.Json
+{
+ ///
+ /// JsonConverter that handles serialization and deserialization of JsonObject instances.
+ /// Supports conversion between JsonObject and JSON, and provides JSON schema information.
+ ///
+ public class JsonObjectJsonConverter : JsonNodeJsonConverter, IJsonSchemaConverter
+ {
+ public static JsonNode Schema => new JsonObject
+ {
+ [JsonSchema.Type] = JsonSchema.Object,
+ [JsonSchema.AdditionalProperties] = true
+ };
+ public static JsonNode SchemaRef => new JsonObject
+ {
+ [JsonSchema.Ref] = JsonSchema.RefValue + StaticId
+ };
+
+ public override JsonNode GetSchema() => Schema;
+ public override JsonNode GetSchemaRef() => SchemaRef;
+
+ protected override JsonObject? CreateJsonNode(JsonElement element)
+ {
+ return JsonObject.Create(element);
+ }
+ }
+}
\ No newline at end of file
diff --git a/ReflectorNet/src/Utils/Json/JsonSerializer.cs b/ReflectorNet/src/Utils/Json/JsonSerializer.cs
index fd97615..043f874 100644
--- a/ReflectorNet/src/Utils/Json/JsonSerializer.cs
+++ b/ReflectorNet/src/Utils/Json/JsonSerializer.cs
@@ -103,6 +103,11 @@ public JsonSerializer(Reflector reflector)
new GuidJsonConverter(),
new TimeSpanJsonConverter(),
+ // Json converters
+ new JsonElementJsonConverter(),
+ new JsonObjectJsonConverter(),
+ new JsonArrayJsonConverter(),
+
// Other converters
new MethodDataConverter(),
new MethodInfoConverter(),