mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
.NET: Fix JSON arrays of objects parsed as empty records when no schema is defined (#4199)
* fix: use HasSchema check in DetermineElementType to prevent empty records When parsing JSON arrays containing objects without a predefined schema, `DetermineElementType()` was creating a `VariableType` with an empty (non-null) schema via `targetType.Schema?.Select(...) ?? []`. This caused `ParseRecord` to take the schema-based parsing path, iterating over zero schema fields and silently discarding all JSON properties. The fix checks `targetType.HasSchema` and falls back to `VariableType.RecordType` (which has `Schema = null`) when no schema is defined, ensuring `ParseRecord` takes the dynamic `ParseValues()` path that preserves all JSON properties. Closes #4195 * test: add regression tests for schema-less JSON array-of-objects parsing (#4195) Add two regression tests to JsonDocumentExtensionsTests: 1. ParseRecord_ObjectWithArrayOfObjects_NoSchema_PreservesNestedProperties - Parses a JSON object containing an array of objects using VariableType.RecordType (no schema) and verifies that nested object properties (name, role) are preserved in each element. - This is the exact scenario from issue #4195 where objects in arrays were being returned as empty dictionaries. 2. ParseList_ArrayOfObjects_NoSchema_PreservesProperties - Parses a JSON array of objects directly via ParseList with VariableType.ListType (no schema) and verifies all properties are preserved. Both tests follow the existing Arrange/Act/Assert pattern and would have failed before the DetermineElementType() fix (empty dictionaries instead of populated ones).
This commit is contained in:
committed by
GitHub
Unverified
parent
23fe2c16b3
commit
2ad0caf069
+3
-1
@@ -111,7 +111,9 @@ internal static class JsonDocumentExtensions
|
||||
VariableType? currentType =
|
||||
element.ValueKind switch
|
||||
{
|
||||
JsonValueKind.Object => VariableType.Record(targetType.Schema?.Select(kvp => (kvp.Key, kvp.Value)) ?? []),
|
||||
JsonValueKind.Object => targetType.HasSchema
|
||||
? VariableType.Record(targetType.Schema!.Select(kvp => (kvp.Key, kvp.Value)))
|
||||
: VariableType.RecordType,
|
||||
JsonValueKind.String => typeof(string),
|
||||
JsonValueKind.True => typeof(bool),
|
||||
JsonValueKind.False => typeof(bool),
|
||||
|
||||
+75
@@ -384,4 +384,79 @@ public sealed class JsonDocumentExtensionsTests
|
||||
// Act / Assert
|
||||
Assert.Throws<DeclarativeActionException>(() => document.ParseList(typeof(int[])));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Regression test for #4195: When a JSON object contains an array of objects
|
||||
/// and is parsed with <c>VariableType.RecordType</c> (no schema), the nested
|
||||
/// object properties must be preserved. Before the fix, DetermineElementType()
|
||||
/// created an empty-schema VariableType, causing ParseRecord to take the
|
||||
/// ParseSchema path (zero fields) and return empty dictionaries.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void ParseRecord_ObjectWithArrayOfObjects_NoSchema_PreservesNestedProperties()
|
||||
{
|
||||
// Arrange
|
||||
JsonDocument document = JsonDocument.Parse(
|
||||
"""
|
||||
{
|
||||
"items": [
|
||||
{ "name": "Alice", "role": "Engineer" },
|
||||
{ "name": "Bob", "role": "Designer" },
|
||||
{ "name": "Carol", "role": "PM" }
|
||||
]
|
||||
}
|
||||
""");
|
||||
|
||||
// Act
|
||||
Dictionary<string, object?> result = document.ParseRecord(VariableType.RecordType);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.ContainsKey("items"));
|
||||
List<object?> items = Assert.IsType<List<object?>>(result["items"]);
|
||||
Assert.Equal(3, items.Count);
|
||||
|
||||
Dictionary<string, object?> first = Assert.IsType<Dictionary<string, object?>>(items[0]);
|
||||
Assert.Equal("Alice", first["name"]);
|
||||
Assert.Equal("Engineer", first["role"]);
|
||||
|
||||
Dictionary<string, object?> second = Assert.IsType<Dictionary<string, object?>>(items[1]);
|
||||
Assert.Equal("Bob", second["name"]);
|
||||
Assert.Equal("Designer", second["role"]);
|
||||
|
||||
Dictionary<string, object?> third = Assert.IsType<Dictionary<string, object?>>(items[2]);
|
||||
Assert.Equal("Carol", third["name"]);
|
||||
Assert.Equal("PM", third["role"]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Regression test for #4195: When a JSON array of objects is parsed directly
|
||||
/// via <c>ParseList</c> with <c>VariableType.ListType</c> (no schema), all
|
||||
/// object properties must be preserved in each element.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void ParseList_ArrayOfObjects_NoSchema_PreservesProperties()
|
||||
{
|
||||
// Arrange
|
||||
JsonDocument document = JsonDocument.Parse(
|
||||
"""
|
||||
[
|
||||
{ "name": "Alice", "role": "Engineer" },
|
||||
{ "name": "Bob", "role": "Designer" }
|
||||
]
|
||||
""");
|
||||
|
||||
// Act
|
||||
List<object?> result = document.ParseList(VariableType.ListType);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(2, result.Count);
|
||||
|
||||
Dictionary<string, object?> first = Assert.IsType<Dictionary<string, object?>>(result[0]);
|
||||
Assert.Equal("Alice", first["name"]);
|
||||
Assert.Equal("Engineer", first["role"]);
|
||||
|
||||
Dictionary<string, object?> second = Assert.IsType<Dictionary<string, object?>>(result[1]);
|
||||
Assert.Equal("Bob", second["name"]);
|
||||
Assert.Equal("Designer", second["role"]);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user