From 85d6994d642041d71c49f1c677150325fb091cf5 Mon Sep 17 00:00:00 2001 From: atheate Date: Thu, 29 Oct 2026 11:01:22 +0100 Subject: [PATCH] Fix #400 --- .../PsmDeSerializerTestFixture.cs | 10 ++++++ SysML2.NET.Serializer.Json/DeSerializer.cs | 32 +++++++++++++++++ SysML2.NET.Serializer.Json/IDeSerializer.cs | 35 +++++++++++++++++++ .../PSM/PsmDeSerializationDispatcher.cs | 16 +++++++++ 4 files changed, 93 insertions(+) diff --git a/SysML2.NET.Serializer.Json.Tests/PsmDeSerializerTestFixture.cs b/SysML2.NET.Serializer.Json.Tests/PsmDeSerializerTestFixture.cs index 4a5f1d6de..df7554662 100644 --- a/SysML2.NET.Serializer.Json.Tests/PsmDeSerializerTestFixture.cs +++ b/SysML2.NET.Serializer.Json.Tests/PsmDeSerializerTestFixture.cs @@ -86,6 +86,11 @@ public void VerifyDeSerializeResponse() Assert.That(() => this.deSerializer.DeSerializeResponse(notAnObject, SerializationModeKind.JSON, false), Throws.TypeOf()); + + using var unknownType = ToStream("""{ "@type": "ProjectResponse", "name": "the name" }"""); + + Assert.That(() => this.deSerializer.DeSerializeResponse(unknownType, SerializationModeKind.JSON, false), + Throws.TypeOf().With.Message.Contains("ProjectResponse")); } [Test] @@ -121,6 +126,11 @@ public void VerifyDeSerializeRequest() Assert.That(() => this.deSerializer.DeSerializeRequest(mismatched, SerializationModeKind.JSON, false), Throws.TypeOf()); + + using var unknownType = ToStream("""{ "@type": "BranchRequest", "name": "feature" }"""); + + Assert.That(() => this.deSerializer.DeSerializeRequest(unknownType, SerializationModeKind.JSON, false), + Throws.TypeOf().With.Message.Contains("BranchRequest")); } [Test] diff --git a/SysML2.NET.Serializer.Json/DeSerializer.cs b/SysML2.NET.Serializer.Json/DeSerializer.cs index 2461790d6..a1ef0a2b1 100644 --- a/SysML2.NET.Serializer.Json/DeSerializer.cs +++ b/SysML2.NET.Serializer.Json/DeSerializer.cs @@ -163,6 +163,10 @@ public async Task> DeSerializeAsync(Stream stream, Seri /// The to use /// Asserts that the deserializer should deserialize derived properties if present or if they are ignored /// an instance of + /// Thrown when the payload is not valid JSON, declares an unknown @type, or is not a + /// Thrown when an object carries no @type discriminator or the payload exceeds the maximum length + /// Thrown when a property value has a JSON token type that the property does not accept + /// Thrown when the is not supported public T DeSerializeRequest(Stream stream, SerializationModeKind serializationModeKind, bool deserializeDerivedProperties) where T : IRequest { return ReadPooled(stream, (byte[] buffer, int length) => this.ReadSingle(buffer, length, serializationModeKind, deserializeDerivedProperties, true)); @@ -176,6 +180,10 @@ public T DeSerializeRequest(Stream stream, SerializationModeKind serializatio /// The to use /// Asserts that the deserializer should deserialize derived properties if present or if they are ignored /// an + /// Thrown when the payload is not valid JSON, declares an unknown @type, or is not a + /// Thrown when an object carries no @type discriminator or the payload exceeds the maximum length + /// Thrown when a property value has a JSON token type that the property does not accept + /// Thrown when the is not supported public IEnumerable DeSerializeRequests(Stream stream, SerializationModeKind serializationModeKind, bool deserializeDerivedProperties) where T : IRequest { return ReadPooled(stream, (byte[] buffer, int length) => this.ReadMany(buffer, length, serializationModeKind, deserializeDerivedProperties, true)); @@ -189,6 +197,10 @@ public IEnumerable DeSerializeRequests(Stream stream, SerializationModeKin /// The to use /// Asserts that the deserializer should deserialize derived properties if present or if they are ignored /// an instance of + /// Thrown when the payload is not valid JSON, declares an unknown @type, or is not a + /// Thrown when an object carries no @type discriminator or the payload exceeds the maximum length + /// Thrown when a property value has a JSON token type that the property does not accept + /// Thrown when the is not supported public T DeSerializeResponse(Stream stream, SerializationModeKind serializationModeKind, bool deserializeDerivedProperties) where T : IResponse { return ReadPooled(stream, (byte[] buffer, int length) => this.ReadSingle(buffer, length, serializationModeKind, deserializeDerivedProperties, false)); @@ -202,6 +214,10 @@ public T DeSerializeResponse(Stream stream, SerializationModeKind serializati /// The to use /// Asserts that the deserializer should deserialize derived properties if present or if they are ignored /// an + /// Thrown when the payload is not valid JSON, declares an unknown @type, or is not a + /// Thrown when an object carries no @type discriminator or the payload exceeds the maximum length + /// Thrown when a property value has a JSON token type that the property does not accept + /// Thrown when the is not supported public IEnumerable DeSerializeResponses(Stream stream, SerializationModeKind serializationModeKind, bool deserializeDerivedProperties) where T : IResponse { return ReadPooled(stream, (byte[] buffer, int length) => this.ReadMany(buffer, length, serializationModeKind, deserializeDerivedProperties, false)); @@ -216,6 +232,10 @@ public IEnumerable DeSerializeResponses(Stream stream, SerializationModeKi /// Asserts that the deserializer should deserialize derived properties if present or if they are ignored /// The used to cancel the operation /// an instance of + /// Thrown when the payload is not valid JSON, declares an unknown @type, or is not a + /// Thrown when an object carries no @type discriminator or the payload exceeds the maximum length + /// Thrown when a property value has a JSON token type that the property does not accept + /// Thrown when the is not supported public Task DeSerializeRequestAsync(Stream stream, SerializationModeKind serializationModeKind, bool deserializeDerivedProperties, CancellationToken cancellationToken) where T : IRequest { return ReadPooledAsync(stream, (byte[] buffer, int length) => this.ReadSingle(buffer, length, serializationModeKind, deserializeDerivedProperties, true), cancellationToken); @@ -230,6 +250,10 @@ public Task DeSerializeRequestAsync(Stream stream, SerializationModeKind s /// Asserts that the deserializer should deserialize derived properties if present or if they are ignored /// The used to cancel the operation /// an + /// Thrown when the payload is not valid JSON, declares an unknown @type, or is not a + /// Thrown when an object carries no @type discriminator or the payload exceeds the maximum length + /// Thrown when a property value has a JSON token type that the property does not accept + /// Thrown when the is not supported public async Task> DeSerializeRequestsAsync(Stream stream, SerializationModeKind serializationModeKind, bool deserializeDerivedProperties, CancellationToken cancellationToken) where T : IRequest { return await ReadPooledAsync(stream, (byte[] buffer, int length) => this.ReadMany(buffer, length, serializationModeKind, deserializeDerivedProperties, true), cancellationToken); @@ -244,6 +268,10 @@ public async Task> DeSerializeRequestsAsync(Stream stream, Ser /// Asserts that the deserializer should deserialize derived properties if present or if they are ignored /// The used to cancel the operation /// an instance of + /// Thrown when the payload is not valid JSON, declares an unknown @type, or is not a + /// Thrown when an object carries no @type discriminator or the payload exceeds the maximum length + /// Thrown when a property value has a JSON token type that the property does not accept + /// Thrown when the is not supported public Task DeSerializeResponseAsync(Stream stream, SerializationModeKind serializationModeKind, bool deserializeDerivedProperties, CancellationToken cancellationToken) where T : IResponse { return ReadPooledAsync(stream, (byte[] buffer, int length) => this.ReadSingle(buffer, length, serializationModeKind, deserializeDerivedProperties, false), cancellationToken); @@ -258,6 +286,10 @@ public Task DeSerializeResponseAsync(Stream stream, SerializationModeKind /// Asserts that the deserializer should deserialize derived properties if present or if they are ignored /// The used to cancel the operation /// an + /// Thrown when the payload is not valid JSON, declares an unknown @type, or is not a + /// Thrown when an object carries no @type discriminator or the payload exceeds the maximum length + /// Thrown when a property value has a JSON token type that the property does not accept + /// Thrown when the is not supported public async Task> DeSerializeResponsesAsync(Stream stream, SerializationModeKind serializationModeKind, bool deserializeDerivedProperties, CancellationToken cancellationToken) where T : IResponse { return await ReadPooledAsync(stream, (byte[] buffer, int length) => this.ReadMany(buffer, length, serializationModeKind, deserializeDerivedProperties, false), cancellationToken); diff --git a/SysML2.NET.Serializer.Json/IDeSerializer.cs b/SysML2.NET.Serializer.Json/IDeSerializer.cs index bf0e715a4..cd3d39abe 100644 --- a/SysML2.NET.Serializer.Json/IDeSerializer.cs +++ b/SysML2.NET.Serializer.Json/IDeSerializer.cs @@ -9,8 +9,11 @@ namespace SysML2.NET.Serializer.Json { + using System; using System.Collections.Generic; using System.IO; + using System.Runtime.Serialization; + using System.Text.Json; using System.Threading; using System.Threading.Tasks; @@ -71,6 +74,10 @@ public interface IDeSerializer /// The to use /// Asserts that the deserializer should deserialize derived properties if present or if they are ignored /// an instance of + /// Thrown when the payload is not valid JSON, declares an unknown @type, or is not a + /// Thrown when an object carries no @type discriminator or the payload exceeds the maximum length + /// Thrown when a property value has a JSON token type that the property does not accept + /// Thrown when the is not supported T DeSerializeRequest(Stream stream, SerializationModeKind serializationModeKind, bool deserializeDerivedProperties) where T : IRequest; /// @@ -81,6 +88,10 @@ public interface IDeSerializer /// The to use /// Asserts that the deserializer should deserialize derived properties if present or if they are ignored /// an + /// Thrown when the payload is not valid JSON, declares an unknown @type, or is not a + /// Thrown when an object carries no @type discriminator or the payload exceeds the maximum length + /// Thrown when a property value has a JSON token type that the property does not accept + /// Thrown when the is not supported IEnumerable DeSerializeRequests(Stream stream, SerializationModeKind serializationModeKind, bool deserializeDerivedProperties) where T : IRequest; /// @@ -91,6 +102,10 @@ public interface IDeSerializer /// The to use /// Asserts that the deserializer should deserialize derived properties if present or if they are ignored /// an instance of + /// Thrown when the payload is not valid JSON, declares an unknown @type, or is not a + /// Thrown when an object carries no @type discriminator or the payload exceeds the maximum length + /// Thrown when a property value has a JSON token type that the property does not accept + /// Thrown when the is not supported T DeSerializeResponse(Stream stream, SerializationModeKind serializationModeKind, bool deserializeDerivedProperties) where T : IResponse; /// @@ -101,6 +116,10 @@ public interface IDeSerializer /// The to use /// Asserts that the deserializer should deserialize derived properties if present or if they are ignored /// an + /// Thrown when the payload is not valid JSON, declares an unknown @type, or is not a + /// Thrown when an object carries no @type discriminator or the payload exceeds the maximum length + /// Thrown when a property value has a JSON token type that the property does not accept + /// Thrown when the is not supported IEnumerable DeSerializeResponses(Stream stream, SerializationModeKind serializationModeKind, bool deserializeDerivedProperties) where T : IResponse; /// @@ -112,6 +131,10 @@ public interface IDeSerializer /// Asserts that the deserializer should deserialize derived properties if present or if they are ignored /// The used to cancel the operation /// an instance of + /// Thrown when the payload is not valid JSON, declares an unknown @type, or is not a + /// Thrown when an object carries no @type discriminator or the payload exceeds the maximum length + /// Thrown when a property value has a JSON token type that the property does not accept + /// Thrown when the is not supported Task DeSerializeRequestAsync(Stream stream, SerializationModeKind serializationModeKind, bool deserializeDerivedProperties, CancellationToken cancellationToken) where T : IRequest; /// @@ -123,6 +146,10 @@ public interface IDeSerializer /// Asserts that the deserializer should deserialize derived properties if present or if they are ignored /// The used to cancel the operation /// an + /// Thrown when the payload is not valid JSON, declares an unknown @type, or is not a + /// Thrown when an object carries no @type discriminator or the payload exceeds the maximum length + /// Thrown when a property value has a JSON token type that the property does not accept + /// Thrown when the is not supported Task> DeSerializeRequestsAsync(Stream stream, SerializationModeKind serializationModeKind, bool deserializeDerivedProperties, CancellationToken cancellationToken) where T : IRequest; /// @@ -134,6 +161,10 @@ public interface IDeSerializer /// Asserts that the deserializer should deserialize derived properties if present or if they are ignored /// The used to cancel the operation /// an instance of + /// Thrown when the payload is not valid JSON, declares an unknown @type, or is not a + /// Thrown when an object carries no @type discriminator or the payload exceeds the maximum length + /// Thrown when a property value has a JSON token type that the property does not accept + /// Thrown when the is not supported Task DeSerializeResponseAsync(Stream stream, SerializationModeKind serializationModeKind, bool deserializeDerivedProperties, CancellationToken cancellationToken) where T : IResponse; /// @@ -145,6 +176,10 @@ public interface IDeSerializer /// Asserts that the deserializer should deserialize derived properties if present or if they are ignored /// The used to cancel the operation /// an + /// Thrown when the payload is not valid JSON, declares an unknown @type, or is not a + /// Thrown when an object carries no @type discriminator or the payload exceeds the maximum length + /// Thrown when a property value has a JSON token type that the property does not accept + /// Thrown when the is not supported Task> DeSerializeResponsesAsync(Stream stream, SerializationModeKind serializationModeKind, bool deserializeDerivedProperties, CancellationToken cancellationToken) where T : IResponse; } } diff --git a/SysML2.NET.Serializer.Json/PSM/PsmDeSerializationDispatcher.cs b/SysML2.NET.Serializer.Json/PSM/PsmDeSerializationDispatcher.cs index 33a6cb227..ba7e89bc0 100644 --- a/SysML2.NET.Serializer.Json/PSM/PsmDeSerializationDispatcher.cs +++ b/SysML2.NET.Serializer.Json/PSM/PsmDeSerializationDispatcher.cs @@ -122,10 +122,18 @@ internal static IDataRequest ReadDataRequest(ref Utf8JsonReader reader, Serializ /// /// Thrown when the object carries no @type discriminator /// + /// + /// Thrown when the @type discriminator is not defined by the response family + /// internal static IResponse ReadResponse(ref Utf8JsonReader reader, SerializationModeKind serializationModeKind, bool deserializeDerivedProperties, ILoggerFactory loggerFactory) { var typeName = ReadTypeName(reader); + if (!ResponseDeSerializationProvider.IsTypeSupported(typeName)) + { + throw new JsonException($"The @type {typeName} is not a known response type."); + } + return ResponseDeSerializationProvider.Provide(typeName)(ref reader, serializationModeKind, deserializeDerivedProperties, loggerFactory); } @@ -150,10 +158,18 @@ internal static IResponse ReadResponse(ref Utf8JsonReader reader, SerializationM /// /// Thrown when the object carries no @type discriminator /// + /// + /// Thrown when the @type discriminator is not defined by the request family + /// internal static IRequest ReadRequest(ref Utf8JsonReader reader, SerializationModeKind serializationModeKind, bool deserializeDerivedProperties, ILoggerFactory loggerFactory) { var typeName = ReadTypeName(reader); + if (!RequestDeSerializationProvider.IsTypeSupported(typeName)) + { + throw new JsonException($"The @type {typeName} is not a known request type."); + } + return RequestDeSerializationProvider.Provide(typeName)(ref reader, serializationModeKind, deserializeDerivedProperties, loggerFactory); }