fix(commons): LoadLegacy handles mixed-type JSON values (number/bool/string)
This commit is contained in:
@@ -118,8 +118,27 @@ public static class OpcUaEndpointConfigSerializer
|
|||||||
|
|
||||||
private static OpcUaEndpointConfig LoadLegacy(string json)
|
private static OpcUaEndpointConfig LoadLegacy(string json)
|
||||||
{
|
{
|
||||||
var dict = JsonSerializer.Deserialize<Dictionary<string, string>>(json)
|
using var doc = JsonDocument.Parse(json);
|
||||||
?? new Dictionary<string, string>();
|
if (doc.RootElement.ValueKind != JsonValueKind.Object)
|
||||||
|
throw new JsonException("Legacy JSON must be a flat object.");
|
||||||
|
|
||||||
|
var dict = new Dictionary<string, string>();
|
||||||
|
foreach (var prop in doc.RootElement.EnumerateObject())
|
||||||
|
{
|
||||||
|
// JsonElement.ToString() returns the raw value for primitives:
|
||||||
|
// "1000" for numbers, "true"/"false" for booleans, the string content
|
||||||
|
// for strings. Nested objects/arrays serialize to their JSON; we don't
|
||||||
|
// expect those in the legacy flat-dict shape, but FromFlatDict will
|
||||||
|
// simply ignore unknown keys.
|
||||||
|
dict[prop.Name] = prop.Value.ValueKind switch
|
||||||
|
{
|
||||||
|
JsonValueKind.String => prop.Value.GetString() ?? "",
|
||||||
|
JsonValueKind.Number => prop.Value.GetRawText(),
|
||||||
|
JsonValueKind.True => "True",
|
||||||
|
JsonValueKind.False => "False",
|
||||||
|
_ => prop.Value.ToString()
|
||||||
|
};
|
||||||
|
}
|
||||||
return FromFlatDict(dict);
|
return FromFlatDict(dict);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -114,6 +114,27 @@ public class OpcUaEndpointConfigSerializerTests
|
|||||||
Assert.Equal("opc.tcp://x:4840", config.EndpointUrl);
|
Assert.Equal("opc.tcp://x:4840", config.EndpointUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Deserialize_LegacyWithMixedTypeValues_PreservesAllFields()
|
||||||
|
{
|
||||||
|
// Real-world legacy producer emitted mixed JSON value types:
|
||||||
|
// string for endpoint, number for publishInterval, etc.
|
||||||
|
var legacyJson = """
|
||||||
|
{"endpoint":"opc.tcp://scadalink-opcua:50000","securityMode":"None","publishInterval":1000,"AutoAcceptUntrustedCerts":false,"SessionTimeoutMs":45000}
|
||||||
|
""";
|
||||||
|
|
||||||
|
var (config, isLegacy) = OpcUaEndpointConfigSerializer.Deserialize(legacyJson);
|
||||||
|
|
||||||
|
Assert.True(isLegacy);
|
||||||
|
Assert.Equal("opc.tcp://scadalink-opcua:50000", config.EndpointUrl);
|
||||||
|
Assert.Equal(OpcUaSecurityMode.None, config.SecurityMode);
|
||||||
|
Assert.False(config.AutoAcceptUntrustedCerts);
|
||||||
|
Assert.Equal(45000, config.SessionTimeoutMs);
|
||||||
|
// publishInterval is not a recognized key (the real key is PublishingIntervalMs);
|
||||||
|
// FromFlatDict ignores unknown keys, so PublishingIntervalMs stays at its POCO default of 1000.
|
||||||
|
Assert.Equal(1000, config.PublishingIntervalMs);
|
||||||
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData("not json at all")]
|
[InlineData("not json at all")]
|
||||||
[InlineData("[1,2,3]")]
|
[InlineData("[1,2,3]")]
|
||||||
|
|||||||
Reference in New Issue
Block a user