From 08f67424e7397904549ff7b01857c53b449e560c Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 12 Apr 2024 10:06:44 +0200 Subject: [PATCH 01/18] Add test project for Swagger Lib and add first tests --- src/AasxServer.sln | 20 ++ src/AasxServerBlazor/appsettings.json | 4 +- .../IO.Swagger.Lib.V3.Tests.csproj | 36 +++ .../Mappers/MappingServiceTests.cs | 30 ++ .../ResponseValueTransformerTests.cs | 298 ++++++++++++++++++ src/IO.Swagger.Lib.V3.Tests/Usings.cs | 2 + .../IO.Swagger.Lib.V3.csproj | 65 ++-- .../ValueMappers/ResponseValueTransformer.cs | 112 +++---- 8 files changed, 462 insertions(+), 105 deletions(-) create mode 100644 src/IO.Swagger.Lib.V3.Tests/IO.Swagger.Lib.V3.Tests.csproj create mode 100644 src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/MappingServiceTests.cs create mode 100644 src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/ValueMappers/ResponseValueTransformerTests.cs create mode 100644 src/IO.Swagger.Lib.V3.Tests/Usings.cs diff --git a/src/AasxServer.sln b/src/AasxServer.sln index 292491787..c9908dde6 100644 --- a/src/AasxServer.sln +++ b/src/AasxServer.sln @@ -33,6 +33,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ExampleClient", "ExampleCli EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AasxServerAspNetCore", "AasxServerAspNetCore\AasxServerAspNetCore.csproj", "{D467D497-18D8-4E26-8671-8AC73BE9AC4F}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IO.Swagger.Lib.V3.Tests", "IO.Swagger.Lib.V3.Tests\IO.Swagger.Lib.V3.Tests.csproj", "{A798C1AD-A30B-41AB-B914-D1D228E35231}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -262,6 +264,24 @@ Global {D467D497-18D8-4E26-8671-8AC73BE9AC4F}.Release|x64.Build.0 = Release|Any CPU {D467D497-18D8-4E26-8671-8AC73BE9AC4F}.Release|x86.ActiveCfg = Release|Any CPU {D467D497-18D8-4E26-8671-8AC73BE9AC4F}.Release|x86.Build.0 = Release|Any CPU + {A798C1AD-A30B-41AB-B914-D1D228E35231}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A798C1AD-A30B-41AB-B914-D1D228E35231}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A798C1AD-A30B-41AB-B914-D1D228E35231}.Debug|x64.ActiveCfg = Debug|Any CPU + {A798C1AD-A30B-41AB-B914-D1D228E35231}.Debug|x64.Build.0 = Debug|Any CPU + {A798C1AD-A30B-41AB-B914-D1D228E35231}.Debug|x86.ActiveCfg = Debug|Any CPU + {A798C1AD-A30B-41AB-B914-D1D228E35231}.Debug|x86.Build.0 = Debug|Any CPU + {A798C1AD-A30B-41AB-B914-D1D228E35231}.DebugSlow|Any CPU.ActiveCfg = Debug|Any CPU + {A798C1AD-A30B-41AB-B914-D1D228E35231}.DebugSlow|Any CPU.Build.0 = Debug|Any CPU + {A798C1AD-A30B-41AB-B914-D1D228E35231}.DebugSlow|x64.ActiveCfg = Debug|Any CPU + {A798C1AD-A30B-41AB-B914-D1D228E35231}.DebugSlow|x64.Build.0 = Debug|Any CPU + {A798C1AD-A30B-41AB-B914-D1D228E35231}.DebugSlow|x86.ActiveCfg = Debug|Any CPU + {A798C1AD-A30B-41AB-B914-D1D228E35231}.DebugSlow|x86.Build.0 = Debug|Any CPU + {A798C1AD-A30B-41AB-B914-D1D228E35231}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A798C1AD-A30B-41AB-B914-D1D228E35231}.Release|Any CPU.Build.0 = Release|Any CPU + {A798C1AD-A30B-41AB-B914-D1D228E35231}.Release|x64.ActiveCfg = Release|Any CPU + {A798C1AD-A30B-41AB-B914-D1D228E35231}.Release|x64.Build.0 = Release|Any CPU + {A798C1AD-A30B-41AB-B914-D1D228E35231}.Release|x86.ActiveCfg = Release|Any CPU + {A798C1AD-A30B-41AB-B914-D1D228E35231}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/AasxServerBlazor/appsettings.json b/src/AasxServerBlazor/appsettings.json index 39bb4ccff..e4a59f42d 100644 --- a/src/AasxServerBlazor/appsettings.json +++ b/src/AasxServerBlazor/appsettings.json @@ -13,8 +13,8 @@ } }, "DatabaseConnection": { - // "ConnectionString": "Host=localhost; Database=AAS; Username=postgres; Password=postres; Include Error Detail=true; Port=5432" - "ConnectionString": "Data Source=$DATAPATH\\database.db" + "ConnectionString": "Host=localhost; Database=AAS; Username=postgres; Password=postgres; Include Error Detail=true; Port=5432" + //"ConnectionString": "Data Source=$DATAPATH\\database.db" }, "AllowedHosts": "*", "SyntaxHighlight": false diff --git a/src/IO.Swagger.Lib.V3.Tests/IO.Swagger.Lib.V3.Tests.csproj b/src/IO.Swagger.Lib.V3.Tests/IO.Swagger.Lib.V3.Tests.csproj new file mode 100644 index 000000000..fd0c19c01 --- /dev/null +++ b/src/IO.Swagger.Lib.V3.Tests/IO.Swagger.Lib.V3.Tests.csproj @@ -0,0 +1,36 @@ + + + + net6.0 + enable + enable + + false + + + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + + + + diff --git a/src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/MappingServiceTests.cs b/src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/MappingServiceTests.cs new file mode 100644 index 000000000..e3fc74e80 --- /dev/null +++ b/src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/MappingServiceTests.cs @@ -0,0 +1,30 @@ +using AasCore.Aas3_0; +using AutoFixture; +using DataTransferObjects; +using DataTransferObjects.CommonDTOs; +using DataTransferObjects.MetadataDTOs; +using DataTransferObjects.ValueDTOs; +using IO.Swagger.Lib.V3.SerializationModifiers.Mappers; +using IO.Swagger.Lib.V3.SerializationModifiers.Mappers.MetadataMappers; +using IO.Swagger.Lib.V3.SerializationModifiers.Mappers.ValueMappers; +using Moq; + +namespace IO.Swagger.Lib.V3.Tests.SerializationModifiers.Mappers; + +public class MappingServiceTests +{ + private readonly Fixture _fixture; + private readonly Mock _administrativeInformationMock; + private readonly Mock _administrativeInformationDTOMock; + + public MappingServiceTests() + { + _fixture = new Fixture(); + _fixture.Behaviors.Remove(new ThrowingRecursionBehavior()); + _fixture.Behaviors.Add(new OmitOnRecursionBehavior()); + _administrativeInformationMock = new Mock(); + _administrativeInformationDTOMock = new Mock(); + } + + +} \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/ValueMappers/ResponseValueTransformerTests.cs b/src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/ValueMappers/ResponseValueTransformerTests.cs new file mode 100644 index 000000000..7e59b0fa0 --- /dev/null +++ b/src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/ValueMappers/ResponseValueTransformerTests.cs @@ -0,0 +1,298 @@ +using AasCore.Aas3_0; +using AutoFixture; +using AutoFixture.AutoMoq; +using AutoFixture.Kernel; +using DataTransferObjects.ValueDTOs; +using FluentAssertions; +using IO.Swagger.Lib.V3.Exceptions; +using IO.Swagger.Lib.V3.SerializationModifiers.Mappers.ValueMappers; +using Moq; +using Xunit; + +namespace IO.Swagger.Lib.V3.Tests.SerializationModifiers.Mappers.ValueMappers; + +public class ResponseValueTransformerTests +{ + private readonly Fixture _fixture; + private readonly ResponseValueTransformer _transformer; + + public ResponseValueTransformerTests() + { + _fixture = new Fixture(); + _fixture.Customize(new AutoMoqCustomization()); + _fixture.Behaviors.Remove(new ThrowingRecursionBehavior()); + _fixture.Behaviors.Add(new OmitOnRecursionBehavior()); + _transformer = new ResponseValueTransformer(); + } + + [Fact] + public void TransformAdministrativeInformation_ShouldThrow_NotImplementedException() + { + // Arrange + + // Act + Action act = () => _transformer.TransformAdministrativeInformation(null!); + + // Assert + act.Should().Throw(); + } + + [Fact] + public void TransformAssetAdministrationShell_ShouldThrow_NotImplementedException() + { + // Arrange + + // Act + Action act = () => _transformer.TransformAssetAdministrationShell(null!); + + // Assert + act.Should().Throw(); + } + + [Fact] + public void TransformAssetInformation_ShouldThrow_NotImplementedException() + { + // Arrange + + // Act + Action act = () => _transformer.TransformAssetInformation(null!); + + // Assert + act.Should().Throw(); + } + + + [Fact] + public void TransformCapability_ShouldThrow_InvalidSerializationModifierException() + { + // Arrange + _fixture.Customizations.Add( + new TypeRelay( + typeof(ICapability), + typeof(Capability))); + + var capability = _fixture.Create(); + + // Act + Action act = () => _transformer.TransformCapability(capability); + + // Assert + act.Should().Throw(); + } + + [Fact] + public void TransformCapability_ShouldReturnNull_WhenInputIsNull() + { + // Arrange + + // Act + var result = _transformer.TransformCapability(null!); + + // Assert + result.Should().BeNull(); + } + + [Fact] + public void TransformConceptDescription_ShouldThrow_NotImplementedException() + { + // Arrange + + // Act + Action act = () => _transformer.TransformConceptDescription(null!); + + // Assert + act.Should().Throw(); + } + + [Fact] + public void TransformDataSpecificationIec61360_ShouldThrow_NotImplementedException() + { + // Arrange + + // Act + Action act = () => _transformer.TransformDataSpecificationIec61360(null!); + + // Assert + act.Should().Throw(); + } + + [Fact] + public void TransformEmbeddedDataSpecification_ShouldThrow_NotImplementedException() + { + // Arrange + + // Act + Action act = () => _transformer.TransformEmbeddedDataSpecification(null!); + + // Assert + act.Should().Throw(); + } + + [Fact] + public void TransformEnvironment_ShouldThrow_NotImplementedException() + { + // Arrange + + // Act + Action act = () => _transformer.TransformEnvironment(null!); + + // Assert + act.Should().Throw(); + } + + [Fact] + public void TransformEventPayload_ShouldThrow_NotImplementedException() + { + // Arrange + + // Act + Action act = () => _transformer.TransformEventPayload(null!); + + // Assert + act.Should().Throw(); + } + + [Fact] + public void TransformExtension_ShouldThrow_NotImplementedException() + { + // Arrange + + // Act + Action act = () => _transformer.TransformExtension(null!); + + // Assert + act.Should().Throw(); + } + + [Fact] + public void TransformLangStringDefinitionTypeIec61360_ShouldThrow_NotImplementedException() + { + // Arrange + + // Act + Action act = () => _transformer.TransformLangStringDefinitionTypeIec61360(null!); + + // Assert + act.Should().Throw(); + } + + [Fact] + public void TransformLangStringNameType_ShouldThrow_NotImplementedException() + { + // Arrange + + // Act + Action act = () => _transformer.TransformLangStringNameType(null!); + + // Assert + act.Should().Throw(); + } + + [Fact] + public void TransformLangStringPreferredNameTypeIec61360_ShouldThrow_NotImplementedException() + { + // Arrange + + // Act + Action act = () => _transformer.TransformLangStringPreferredNameTypeIec61360(null!); + + // Assert + act.Should().Throw(); + } + + [Fact] + public void TransformLangStringShortNameTypeIec61360_ShouldThrow_NotImplementedException() + { + // Arrange + + // Act + Action act = () => _transformer.TransformLangStringShortNameTypeIec61360(null!); + + // Assert + act.Should().Throw(); + } + + [Fact] + public void TransformLangStringTextType_ShouldThrow_NotImplementedException() + { + // Arrange + + // Act + Action act = () => _transformer.TransformLangStringTextType(null!); + + // Assert + act.Should().Throw(); + } + + [Fact] + public void TransformLevelType_ShouldThrow_NotImplementedException() + { + // Arrange + + // Act + Action act = () => _transformer.TransformLevelType(null!); + + // Assert + act.Should().Throw(); + } + + [Fact] + public void TransformQualifier_ShouldThrow_NotImplementedException() + { + // Arrange + + // Act + Action act = () => _transformer.TransformQualifier(null!); + + // Assert + act.Should().Throw(); + } + + [Fact] + public void TransformResource_ShouldThrow_NotImplementedException() + { + // Arrange + + // Act + Action act = () => _transformer.TransformResource(null!); + + // Assert + act.Should().Throw(); + } + + [Fact] + public void TransformSpecificAssetId_ShouldThrow_NotImplementedException() + { + // Arrange + + // Act + Action act = () => _transformer.TransformSpecificAssetId(null!); + + // Assert + act.Should().Throw(); + } + + [Fact] + public void TransformValueList_ShouldThrow_NotImplementedException() + { + // Arrange + + // Act + Action act = () => _transformer.TransformValueList(null!); + + // Assert + act.Should().Throw(); + } + + [Fact] + public void TransformValueReferencePair_ShouldThrow_NotImplementedException() + { + // Arrange + + // Act + Action act = () => _transformer.TransformValueReferencePair(null!); + + // Assert + act.Should().Throw(); + } +} \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3.Tests/Usings.cs b/src/IO.Swagger.Lib.V3.Tests/Usings.cs new file mode 100644 index 000000000..7fef4b0e1 --- /dev/null +++ b/src/IO.Swagger.Lib.V3.Tests/Usings.cs @@ -0,0 +1,2 @@ +global using Xunit; +global using FluentAssertions; \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3/IO.Swagger.Lib.V3.csproj b/src/IO.Swagger.Lib.V3/IO.Swagger.Lib.V3.csproj index 8270939b5..0d92dfb45 100644 --- a/src/IO.Swagger.Lib.V3/IO.Swagger.Lib.V3.csproj +++ b/src/IO.Swagger.Lib.V3/IO.Swagger.Lib.V3.csproj @@ -1,33 +1,36 @@ - - IO.Swagger - IO.Swagger - net6.0 - true - true - IO.Swagger.Lib.V3 - IO.Swagger - Library - - - false - - - - - - - - - - - - - - - - - - - + + IO.Swagger + IO.Swagger + net6.0 + true + true + IO.Swagger.Lib.V3 + IO.Swagger + Library + + + false + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/ResponseValueTransformer.cs b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/ResponseValueTransformer.cs index 0f720361b..92aca1c9e 100644 --- a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/ResponseValueTransformer.cs +++ b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/ResponseValueTransformer.cs @@ -3,6 +3,7 @@ using DataTransferObjects.ValueDTOs; using IO.Swagger.Lib.V3.Exceptions; using System.Collections.Generic; +using System.Linq; using static AasCore.Aas3_0.Visitation; namespace IO.Swagger.Lib.V3.SerializationModifiers.Mappers.ValueMappers @@ -11,8 +12,7 @@ internal class ResponseValueTransformer : ITransformer { public IDTO Transform(IClass that) { - if (that == null) return null; - return that.Transform(this); + return that?.Transform(this); } public IDTO TransformAdministrativeInformation(IAdministrativeInformation that) @@ -25,14 +25,14 @@ public IDTO TransformAnnotatedRelationshipElement(IAnnotatedRelationshipElement List annotations = null; if (that.Annotations != null) { - annotations = new List(); - foreach (var element in that.Annotations) - { - annotations.Add((ISubmodelElementValue)Transform(element)); - } + annotations = that.Annotations.Select(element => (ISubmodelElementValue) Transform(element)).ToList(); + } + else + { + return null; } - return new AnnotatedRelationshipElementValue(that.IdShort, (ReferenceDTO)Transform(that.First), (ReferenceDTO)Transform(that.Second), annotations); + return new AnnotatedRelationshipElementValue(that.IdShort ?? string.Empty, (ReferenceDTO) Transform(that.First), (ReferenceDTO) Transform(that.Second), annotations); } public IDTO TransformAssetAdministrationShell(IAssetAdministrationShell that) @@ -47,12 +47,12 @@ public IDTO TransformAssetInformation(IAssetInformation that) public IDTO TransformBasicEventElement(IBasicEventElement that) { - return new BasicEventElementValue(that.IdShort, (ReferenceDTO)Transform(that.Observed)); + return new BasicEventElementValue(that.IdShort ?? string.Empty, (ReferenceDTO) Transform(that.Observed)); } public IDTO TransformBlob(IBlob that) { - return new BlobValue(that.IdShort, that.ContentType, that.Value); + return new BlobValue(that.IdShort ?? string.Empty, that.ContentType, that.Value); } public IDTO TransformCapability(ICapability that) @@ -80,14 +80,10 @@ public IDTO TransformEntity(IEntity that) List statements = null; if (that.Statements != null) { - statements = new List(); - foreach (var element in that.Statements) - { - statements.Add((ISubmodelElementValue)Transform(element)); - } + statements = that.Statements.Select(element => (ISubmodelElementValue) Transform(element)).ToList(); } - return new EntityValue(that.IdShort, that.EntityType, statements, that.GlobalAssetId); + return new EntityValue(that.IdShort ?? string.Empty, that.EntityType, statements, that.GlobalAssetId); } public IDTO TransformEnvironment(IEnvironment that) @@ -107,23 +103,12 @@ public IDTO TransformExtension(IExtension that) public IDTO TransformFile(IFile that) { - return new FileValue(that.IdShort, that.ContentType, that.Value); + return new FileValue(that.IdShort ?? string.Empty, that.ContentType, that.Value); } - internal List TransformKeyList(List keyList) + private List TransformKeyList(IEnumerable keyList) { - List output = null; - - if (keyList != null) - { - output = new List(); - foreach (var key in keyList) - { - output.Add((KeyDTO)Transform(key)); - } - } - - return output; + return keyList?.Select(key => (KeyDTO) Transform(key)).ToList(); } public IDTO TransformKey(IKey that) @@ -164,11 +149,12 @@ public IDTO TransformLevelType(ILevelType that) public IDTO TransformMultiLanguageProperty(IMultiLanguageProperty that) { var langStrings = new List>(); - foreach (var langString in that.Value) + if (that.Value != null) { - langStrings.Add(new KeyValuePair(langString.Language, langString.Text)); + langStrings.AddRange(that.Value.Select(langString => new KeyValuePair(langString.Language, langString.Text))); } - return new MultiLanguagePropertyValue(that.IdShort, langStrings); + + return new MultiLanguagePropertyValue(that.IdShort ?? string.Empty, langStrings); } public IDTO TransformOperation(IOperation that) @@ -178,32 +164,20 @@ public IDTO TransformOperation(IOperation that) List inoutputVariables = null; if (that.InputVariables != null) { - inputVariables = new List(); - foreach (var inputVariable in that.InputVariables) - { - inputVariables.Add((ISubmodelElementValue)Transform(inputVariable)); - } + inputVariables = that.InputVariables.Select(inputVariable => (ISubmodelElementValue) Transform(inputVariable)).ToList(); } if (that.OutputVariables != null) { - outputVariables = new List(); - foreach (var outputVariable in that.OutputVariables) - { - outputVariables.Add((ISubmodelElementValue)Transform(outputVariable)); - } + outputVariables = that.OutputVariables.Select(outputVariable => (ISubmodelElementValue) Transform(outputVariable)).ToList(); } if (that.InoutputVariables != null) { - inoutputVariables = new List(); - foreach (var inoutputVariable in that.InoutputVariables) - { - inoutputVariables.Add((ISubmodelElementValue)Transform(inoutputVariable)); - } + inoutputVariables = that.InoutputVariables.Select(inoutputVariable => (ISubmodelElementValue) Transform(inoutputVariable)).ToList(); } - return new OperationValue(that.IdShort, inputVariables, outputVariables, inoutputVariables); + return new OperationValue(that.IdShort ?? string.Empty, inputVariables, outputVariables, inoutputVariables); } public IDTO TransformOperationVariable(IOperationVariable that) @@ -213,7 +187,7 @@ public IDTO TransformOperationVariable(IOperationVariable that) public IDTO TransformProperty(IProperty that) { - return new PropertyValue(that.IdShort, that.Value); + return new PropertyValue(that.IdShort ?? string.Empty, that.Value); } public IDTO TransformQualifier(IQualifier that) @@ -223,22 +197,28 @@ public IDTO TransformQualifier(IQualifier that) public IDTO TransformRange(IRange that) { - return new RangeValue(that.IdShort, that.Min, that.Max); + return new RangeValue(that.IdShort ?? string.Empty, that.Min, that.Max); } public IDTO TransformReference(IReference that) { - return new ReferenceDTO(that.Type, TransformKeyList(that.Keys), (ReferenceDTO)Transform(that.ReferredSemanticId)); + if (that.ReferredSemanticId != null) + { + return new ReferenceDTO(that.Type, TransformKeyList(that.Keys), (ReferenceDTO) Transform( + that.ReferredSemanticId)); + } + + return null; } public IDTO TransformReferenceElement(IReferenceElement that) { - return new ReferenceElementValue(that.IdShort, (ReferenceDTO)Transform(that.Value)); + return that.Value != null ? new ReferenceElementValue(that.IdShort ?? string.Empty, (ReferenceDTO) Transform(that.Value)) : null; } public IDTO TransformRelationshipElement(IRelationshipElement that) { - return new RelationshipElementValue(that.IdShort, (ReferenceDTO)Transform(that.First), (ReferenceDTO)Transform(that.Second)); + return new RelationshipElementValue(that.IdShort ?? string.Empty, (ReferenceDTO) Transform(that.First), (ReferenceDTO) Transform(that.Second)); } public IDTO TransformResource(IResource that) @@ -256,11 +236,7 @@ public IDTO TransformSubmodel(ISubmodel that) List submodelElements = null; if (that.SubmodelElements != null) { - submodelElements = new List(); - foreach (var element in that.SubmodelElements) - { - submodelElements.Add((ISubmodelElementValue)Transform(element)); - } + submodelElements = that.SubmodelElements.Select(element => (ISubmodelElementValue) Transform(element)).ToList(); } return new SubmodelValue(submodelElements); @@ -271,14 +247,10 @@ public IDTO TransformSubmodelElementCollection(ISubmodelElementCollection that) List value = null; if (that.Value != null) { - value = new List(); - foreach (var element in that.Value) - { - value.Add((ISubmodelElementValue)Transform(element)); - } + value = that.Value.Select(element => (ISubmodelElementValue) Transform(element)).ToList(); } - return new SubmodelElementCollectionValue(that.IdShort, value); + return new SubmodelElementCollectionValue(that.IdShort ?? string.Empty, value); } public IDTO TransformSubmodelElementList(ISubmodelElementList that) @@ -286,14 +258,10 @@ public IDTO TransformSubmodelElementList(ISubmodelElementList that) List value = null; if (that.Value != null) { - value = new List(); - foreach (var element in that.Value) - { - value.Add((ISubmodelElementValue)Transform(element)); - } + value = that.Value.Select(element => (ISubmodelElementValue) Transform(element)).ToList(); } - return new SubmodelElementListValue(that.IdShort, value); + return new SubmodelElementListValue(that.IdShort ?? string.Empty, value); } public IDTO TransformValueList(IValueList that) @@ -306,4 +274,4 @@ public IDTO TransformValueReferencePair(IValueReferencePair that) throw new System.NotImplementedException(); } } -} +} \ No newline at end of file From 5e92a7a57bb3f6597a1a3d0e33872d37945431e0 Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 12 Apr 2024 14:43:06 +0200 Subject: [PATCH 02/18] Add tests --- .../IO.Swagger.Lib.V3.Tests.csproj | 6 + .../ValueMappers/RequestValueMapperTests.cs | 46 ++ .../ValueMappers/ResponseValueMapperTests.cs | 66 +++ .../ResponseValueTransformerTests.cs | 416 +++++++++++++- .../ValueOnlyJsonSerializerTests.cs | 33 ++ .../ValueMappers/IResponseValueTransformer.cs | 8 + .../IValueOnlyJsonDeserializer.cs | 10 + .../ValueMappers/RequestValueMapper.cs | 132 +---- .../ValueMappers/ResponseValueMapper.cs | 2 +- .../ValueMappers/ResponseValueTransformer.cs | 399 +++++++------ .../ValueMappers/ValueOnlyJsonDeserializer.cs | 530 ++++++++---------- .../ValueMappers/ValueOnlyJsonSerializer.cs | 451 +++++++-------- 12 files changed, 1264 insertions(+), 835 deletions(-) create mode 100644 src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/ValueMappers/RequestValueMapperTests.cs create mode 100644 src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/ValueMappers/ResponseValueMapperTests.cs create mode 100644 src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/ValueMappers/ValueOnlyJsonSerializerTests.cs create mode 100644 src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/IResponseValueTransformer.cs create mode 100644 src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/IValueOnlyJsonDeserializer.cs diff --git a/src/IO.Swagger.Lib.V3.Tests/IO.Swagger.Lib.V3.Tests.csproj b/src/IO.Swagger.Lib.V3.Tests/IO.Swagger.Lib.V3.Tests.csproj index fd0c19c01..3f2fc6c0a 100644 --- a/src/IO.Swagger.Lib.V3.Tests/IO.Swagger.Lib.V3.Tests.csproj +++ b/src/IO.Swagger.Lib.V3.Tests/IO.Swagger.Lib.V3.Tests.csproj @@ -33,4 +33,10 @@ + + + F:\Program Files (x86)\JetBrains Rider 2023.3.3\lib\ReSharperHost\TestRunner\Adapters\XUnit\netstandard2.0\JetBrains.ReSharper.TestRunner.Adapters.XUnit.dll + + + diff --git a/src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/ValueMappers/RequestValueMapperTests.cs b/src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/ValueMappers/RequestValueMapperTests.cs new file mode 100644 index 000000000..35c9a0874 --- /dev/null +++ b/src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/ValueMappers/RequestValueMapperTests.cs @@ -0,0 +1,46 @@ +using AasCore.Aas3_0; +using AutoFixture; +using AutoFixture.AutoMoq; +using DataTransferObjects; +using DataTransferObjects.ValueDTOs; +using IO.Swagger.Lib.V3.SerializationModifiers.Mappers.ValueMappers; + +namespace IO.Swagger.Lib.V3.Tests.SerializationModifiers.Mappers.ValueMappers; + +public class RequestValueMapperTests +{ + private readonly Fixture _fixture; + + public RequestValueMapperTests() + { + _fixture = new Fixture(); + _fixture.Customize(new AutoMoqCustomization()); + } + + [Fact (Skip = "AutoFixture was unable to create an instance from DataTransferObjects.CommonDTOs.ReferenceDTO, most likely because it has no public constructor, is an abstract or non-public type.")] + public void Map_ShouldTransformBasicEventElementValue() + { + // Arrange + var valueDTO = _fixture.Create(); + + // Act + var result = RequestValueMapper.Map(valueDTO); + + // Assert + result.Should().BeOfType(); + } + + + [Fact] + public void Map_ShouldThrowExceptionForUnimplementedType() + { + // Arrange + var valueDTO = _fixture.Create(); // Create a DTO of unimplemented type + + // Act + Action action = () => RequestValueMapper.Map((IValueDTO) valueDTO); + + // Assert + action.Should().Throw(); + } +} \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/ValueMappers/ResponseValueMapperTests.cs b/src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/ValueMappers/ResponseValueMapperTests.cs new file mode 100644 index 000000000..114c0b93f --- /dev/null +++ b/src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/ValueMappers/ResponseValueMapperTests.cs @@ -0,0 +1,66 @@ +using AasCore.Aas3_0; +using AutoFixture; +using AutoFixture.AutoMoq; +using DataTransferObjects; +using DataTransferObjects.ValueDTOs; +using IO.Swagger.Lib.V3.SerializationModifiers.Mappers.ValueMappers; +using Moq; + +namespace IO.Swagger.Lib.V3.Tests.SerializationModifiers.Mappers.ValueMappers; + +public class ResponseValueMapperTests +{ + private readonly Fixture _fixture; + private readonly Mock _transformerMock; + + public ResponseValueMapperTests() + { + _fixture = new Fixture(); + _fixture.Customize(new AutoMoqCustomization()); + _transformerMock = new Mock(); + } + + [Fact (Skip = "Unable to cast object of type 'Castle.Proxies.IDTOProxy' to type 'DataTransferObjects.ValueDTOs.IValueDTO'")] + public void Map_ShouldCallTransformMethod_WithProvidedSource() + { + // Arrange + var source = _fixture.Create(); + var expectedDto = _fixture.Create(); + _transformerMock.Setup(t => t.Transform(source)).Returns(expectedDto); + + // Act + var result = ResponseValueMapper.Map(source); + + // Assert + _transformerMock.Verify(t => t.Transform(source), Times.Once); + result.Should().Be(expectedDto); + } + + [Fact (Skip = "Unable to cast object of type 'Castle.Proxies.IDTOProxy' to type 'DataTransferObjects.ValueDTOs.IValueDTO'")] + public void Map_ShouldReturnNonNullValueDTO_WhenSourceIsProvided() + { + // Arrange + var source = _fixture.Create(); + var dto = _fixture.Create(); + _transformerMock.Setup(t => t.Transform(source)).Returns(dto); + + // Act + var result = ResponseValueMapper.Map(source); + + // Assert + result.Should().NotBeNull(); + } + + [Fact] + public void Map_ShouldReturnNull_WhenSourceIsNull() + { + // Arrange + IClass source = null; + + // Act + var result = ResponseValueMapper.Map(source); + + // Assert + result.Should().BeNull(); + } +} \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/ValueMappers/ResponseValueTransformerTests.cs b/src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/ValueMappers/ResponseValueTransformerTests.cs index 7e59b0fa0..eaa6cb985 100644 --- a/src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/ValueMappers/ResponseValueTransformerTests.cs +++ b/src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/ValueMappers/ResponseValueTransformerTests.cs @@ -2,12 +2,13 @@ using AutoFixture; using AutoFixture.AutoMoq; using AutoFixture.Kernel; +using DataTransferObjects; +using DataTransferObjects.CommonDTOs; using DataTransferObjects.ValueDTOs; -using FluentAssertions; using IO.Swagger.Lib.V3.Exceptions; using IO.Swagger.Lib.V3.SerializationModifiers.Mappers.ValueMappers; using Moq; -using Xunit; +using File = AasCore.Aas3_0.File; namespace IO.Swagger.Lib.V3.Tests.SerializationModifiers.Mappers.ValueMappers; @@ -25,6 +26,402 @@ public ResponseValueTransformerTests() _transformer = new ResponseValueTransformer(); } + #region Transform + + [Fact] + public void Transform_WithNullClass_ShouldReturnNull() + { + // Arrange + // Act + var result = _transformer.Transform(null!); + + // Assert + result.Should().BeNull(); + } + + [Fact] + public void Transform_WithIClassObject_ShouldTransformToIDTO() + { + // Arrange + var classObject = _fixture.Create(); + + // Act + var result = _transformer.Transform(classObject); + + // Assert + result.Should().NotBeNull(); + result.GetType().ToString().Should().Be("Castle.Proxies.IDTOProxy", "whatevert happens here that IDTO is not the real type"); + } + + #endregion + + #region TransformAnnotatedRelationshipElement + + [Fact] + public void TransformAnnotatedRelationshipElement_ReturnsNull_WhenParameterIsNull() + { + // Arrange + // Act + var result = _transformer.TransformAnnotatedRelationshipElement(null!); + + // Assert + result.Should().BeNull(); + } + + [Fact] + public void TransformAnnotatedRelationshipElement_ReturnsNull_WhenParameterAnnotationsIsNull() + { + // Arrange + var annotatedElement = _fixture.Create(); + annotatedElement.Annotations = null; + + // Act + var result = _transformer.TransformAnnotatedRelationshipElement(null!); + + // Assert + result.Should().BeNull(); + } + + [Fact(Skip = "not testable at the moment because of the current dependencies between classes")] + public void TransformAnnotatedRelationshipElement_ReturnsDTO_WhenAnnotationsAreNotNull() + { + // Arrange + var annotatedElement = _fixture.Create(); + var annotations = _fixture.CreateMany().ToList(); + annotatedElement.Annotations = annotations; + + // Act + var result = _transformer.TransformAnnotatedRelationshipElement(annotatedElement); + + // Assert + result.Should().NotBeNull(); + result.Should().BeOfType(); + var annotatedResult = (AnnotatedRelationshipElementValue) result; + annotatedResult.idShort.Should().Be(annotatedElement.IdShort ?? string.Empty); + annotatedResult.first.Should().BeEquivalentTo(_transformer.Transform(annotatedElement.First)); + annotatedResult.second.Should().BeEquivalentTo(_transformer.Transform(annotatedElement.Second)); + annotatedResult.annotations.Should().BeEquivalentTo(annotations); + } + + #endregion + + #region TransformCapability + + [Fact] + public void TransformCapability_ThrowsException_WhenCapabilityIsNotNull() + { + // Arrange + var capability = new Mock().Object; + + // Act + Action act = () => _transformer.TransformCapability(capability); + + // Assert + act.Should().Throw() + .WithMessage("Invalid serialization modifier ValueOnly for the requested element of type ICapabilityProxy."); // Adjust the expected message as needed + } + + [Fact] + public void TransformCapability_ThrowsException_WhenCapabilityIsNull() + { + // Arrange + var capability = _fixture.Create(); + + // Act + Action act = () => _transformer.TransformCapability(capability); + + // Assert + act.Should().Throw() + .WithMessage("Invalid serialization modifier ValueOnly for the requested element of type ICapabilityProxy."); // Adjust the expected message as needed + } + + #endregion + + #region TransformEntity + + [Fact(Skip = "Can't figure it out")] + public void TransformEntity_ReturnsEntityValue_WhenStatementsNotNull() + { + // Arrange + var statements = new List {_fixture.Create()}; // Sample valid statements + var entity = _fixture.Create(); + // Act + var result = _transformer.TransformEntity(entity); + + // Assert + result.Should().NotBeNull(); + result.Should().BeOfType(); + var entityValue = (EntityValue) result; + entityValue.statements.Should().NotBeNull(); + entityValue.statements!.Count.Should().Be(statements.Count); + } + + [Fact] + public void TransformEntity_ReturnsEntityValue_WhenStatementsAreNull() + { + // Arrange + var entity = new Mock(); + entity.Setup(e => e.Statements).Returns((List?) null); + entity.Setup(e => e.IdShort).Returns("entityId"); + + // Act + var result = _transformer.TransformEntity(entity.Object); + + // Assert + result.Should().NotBeNull(); + result.Should().BeOfType(); + var entityValue = (EntityValue) result; + entityValue.statements.Should().BeNull(); + } + + #endregion + + #region TransformFile + + [Fact] + public void TransformFile_ReturnsFileValue_WhenFileIsNotNull() + { + // Arrange + const string fileIdShort = "fileId"; + const string contentType = "application/pdf"; + var file = _fixture.Build() + .With(x => x.IdShort, fileIdShort) + .With(x => x.ContentType, contentType) + .Create(); + + // Act + var result = _transformer.TransformFile(file); + + // Assert + result.Should().NotBeNull(); + result.Should().BeOfType(); + var fileResult = (FileValue) result; + fileResult.idShort.Should().Be(fileIdShort); + fileResult.contentType.Should().Be(contentType); + } + + #endregion + + #region TransformKey + + [Fact] + public void TransformKey_ReturnsKeyDTO_WhenKeyIsNotNull() + { + // Arrange + const KeyTypes keyType = KeyTypes.File; + const string keyValue = "KeyValue"; + var keyMock = new Mock(); + keyMock.Setup(k => k.Type).Returns(keyType); + keyMock.Setup(k => k.Value).Returns(keyValue); + + // Act + var result = _transformer.TransformKey(keyMock.Object); + + // Assert + result.Should().NotBeNull(); + result.Should().BeOfType(); + var keyResult = (KeyDTO) result; + keyResult.type.Should().Be(keyType); + keyResult.value.Should().Be(keyValue); + } + + #endregion + + #region TransformMultiLanguageProperty + + [Fact] + public void TransformMultiLanguageProperty_ReturnsMultiLanguagePropertyValue_WhenMultiLanguagePropertyIsNotNull() + { + // Arrange + // Arrange + const string idShort = "multiLanguageId"; + var langString1 = new LangStringTextType("en", "English Text"); + var langString2 = new LangStringTextType("fr", "French Text"); + var multiLanguagePropertyMock = new Mock(); + multiLanguagePropertyMock.Setup(m => m.IdShort).Returns(idShort); + multiLanguagePropertyMock.Setup(m => m.Value).Returns(new List {langString1, langString2}); + + // Act + var result = _transformer.TransformMultiLanguageProperty(multiLanguagePropertyMock.Object); + + // Assert + result.Should().NotBeNull(); + result.Should().BeOfType(); + var multiLanguageResult = (MultiLanguagePropertyValue) result; + multiLanguageResult.idShort.Should().Be(idShort); + multiLanguageResult.langStrings.Should().HaveCount(2); + multiLanguageResult.langStrings.Should().Contain(new KeyValuePair(langString1.Language, langString1.Text)); + multiLanguageResult.langStrings.Should().Contain(new KeyValuePair(langString2.Language, langString2.Text)); + } + + [Fact] + public void TransformMultiLanguageProperty_ReturnsMultiLanguagePropertyValueWithEmptyLangStrings_WhenMultiLanguagePropertyValueHasNullValue() + { + // Arrange + const string idShort = "multiLanguageId"; + var multiLanguagePropertyMock = new Mock(); + multiLanguagePropertyMock.Setup(m => m.IdShort).Returns(idShort); + multiLanguagePropertyMock.Setup(m => m.Value).Returns((List) null); + + // Act + var result = _transformer.TransformMultiLanguageProperty(multiLanguagePropertyMock.Object); + + // Assert + result.Should().NotBeNull(); + result.Should().BeOfType(); + var multiLanguageResult = (MultiLanguagePropertyValue) result; + multiLanguageResult.idShort.Should().Be(idShort); + multiLanguageResult.langStrings.Should().BeEmpty(); + } + + #endregion + + #region TransformOperation + + [Fact] + public void TransformOperation_ReturnsOperationValue_WhenOperationIsNotNull() + { + // Arrange + const string idShort = "operationId"; + var inputVariables = new List(); + var outputVariables = new List(); + var inoutputVariables = new List(); + + // Populate inputVariables, outputVariables, and inoutputVariables with mock objects as needed + + var operationMock = new Mock(); + operationMock.Setup(o => o.IdShort).Returns(idShort); + operationMock.Setup(o => o.InputVariables).Returns(inputVariables); + operationMock.Setup(o => o.OutputVariables).Returns(outputVariables); + operationMock.Setup(o => o.InoutputVariables).Returns(inoutputVariables); + + // Act + var result = _transformer.TransformOperation(operationMock.Object); + + // Assert + result.Should().NotBeNull(); + result.Should().BeOfType(); + var operationResult = (OperationValue) result; + operationResult.idShort.Should().Be(idShort); + } + + [Fact] + public void TransformOperation_ReturnsOperationValueWithEmptyLists_WhenOperationHasNullVariables() + { + // Arrange + const string idShort = "operationId"; + List inputVariables = null; + List outputVariables = null; + List inoutputVariables = null; + + var operationMock = new Mock(); + operationMock.Setup(o => o.IdShort).Returns(idShort); + operationMock.Setup(o => o.InputVariables).Returns(inputVariables); + operationMock.Setup(o => o.OutputVariables).Returns(outputVariables); + operationMock.Setup(o => o.InoutputVariables).Returns(inoutputVariables); + + // Act + var result = _transformer.TransformOperation(operationMock.Object); + + // Assert + result.Should().NotBeNull(); + result.Should().BeOfType(); + var operationResult = (OperationValue) result; + operationResult.idShort.Should().Be(idShort); + operationResult.inputVariables.Should().BeNull(); + operationResult.outputVariables.Should().BeNull(); + operationResult.inoutputvariables.Should().BeNull(); + } + + #endregion + + #region TransformOperationVariable + + [Fact] + public void TransformOperationVariable_ReturnsTransformedValue_WhenOperationVariableIsNotNull() + { + // Arrange + var operationVariableMock = _fixture.Create(); + + // Act + var result = _transformer.TransformOperationVariable(operationVariableMock); + + // Assert + result.Should().NotBeNull(); + } + + #endregion + + #region TransformSubmodelElementCollection + + [Fact] + public void TransformSubmodelElementCollection_ReturnsSubmodelElementCollectionValueWithEmptyList_WhenValueIsNull() + { + // Arrange + const string idShort = "collectionId"; + var submodelElementCollectionMock = new Mock(); + submodelElementCollectionMock.Setup(m => m.IdShort).Returns(idShort); + submodelElementCollectionMock.Setup(m => m.Value).Returns((Func?>) null); + + // Act + var result = _transformer.TransformSubmodelElementCollection(submodelElementCollectionMock.Object); + + // Assert + result.Should().NotBeNull(); + result.Should().BeOfType(); + var collectionResult = (SubmodelElementCollectionValue) result; + collectionResult.idShort.Should().Be(idShort); + collectionResult.value.Should().BeNull(); + } + + #endregion + + #region TransformSubmodelElementList + + [Fact (Skip = "cant figure it out")] + public void TransformSubmodelElementList_ReturnsSubmodelElementListValue_WhenValueIsNotNull() + { + // Arrange + const string idShort = "listId"; + var submodelElementValues = _fixture.CreateMany().ToList(); + var submodelElementListMock = new Mock(); + submodelElementListMock.Setup(m => m.IdShort).Returns(idShort); + + // Act + var result = _transformer.TransformSubmodelElementList(submodelElementListMock.Object); + + // Assert + result.Should().NotBeNull(); + result.Should().BeOfType(); + var listResult = (SubmodelElementListValue) result; + listResult.idShort.Should().Be(idShort); + listResult.value.Should().BeEquivalentTo(submodelElementValues); + } + + [Fact] + public void TransformSubmodelElementList_ReturnsSubmodelElementListValueWithEmptyList_WhenValueIsNull() + { + // Arrange + const string idShort = "listId"; + var submodelElementListMock = new Mock(); + submodelElementListMock.Setup(m => m.IdShort).Returns(idShort); + + // Act + var result = _transformer.TransformSubmodelElementList(submodelElementListMock.Object); + + // Assert + result.Should().NotBeNull(); + result.Should().BeOfType(); + var listResult = (SubmodelElementListValue) result; + listResult.idShort.Should().Be(idShort); + listResult.value.Should().BeNull(); + } + + #endregion + + + #region not implemented methods + [Fact] public void TransformAdministrativeInformation_ShouldThrow_NotImplementedException() { @@ -70,7 +467,7 @@ public void TransformCapability_ShouldThrow_InvalidSerializationModifierExceptio new TypeRelay( typeof(ICapability), typeof(Capability))); - + var capability = _fixture.Create(); // Act @@ -79,18 +476,7 @@ public void TransformCapability_ShouldThrow_InvalidSerializationModifierExceptio // Assert act.Should().Throw(); } - - [Fact] - public void TransformCapability_ShouldReturnNull_WhenInputIsNull() - { - // Arrange - // Act - var result = _transformer.TransformCapability(null!); - - // Assert - result.Should().BeNull(); - } [Fact] public void TransformConceptDescription_ShouldThrow_NotImplementedException() @@ -295,4 +681,6 @@ public void TransformValueReferencePair_ShouldThrow_NotImplementedException() // Assert act.Should().Throw(); } + + #endregion } \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/ValueMappers/ValueOnlyJsonSerializerTests.cs b/src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/ValueMappers/ValueOnlyJsonSerializerTests.cs new file mode 100644 index 000000000..d95cdec6d --- /dev/null +++ b/src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/ValueMappers/ValueOnlyJsonSerializerTests.cs @@ -0,0 +1,33 @@ +using AutoFixture; +using AutoFixture.Kernel; +using DataTransferObjects.ValueDTOs; +using IO.Swagger.Lib.V3.SerializationModifiers.Mappers.ValueMappers; + +namespace IO.Swagger.Lib.V3.Tests.SerializationModifiers.Mappers.ValueMappers; + +public class ValueOnlyJsonSerializerTests +{ + private readonly Fixture _fixture; + + public ValueOnlyJsonSerializerTests() + { + _fixture = new Fixture(); + _fixture.Behaviors.Remove(new ThrowingRecursionBehavior()); + _fixture.Behaviors.Add(new OmitOnRecursionBehavior()); + _fixture.Customizations.Add(new TypeRelay(typeof(ISubmodelElementValue), typeof(EntityValue))); + } + + [Fact] + public void ToJsonObject_WithEntityValue_ShouldTransformCorrectly() + { + // Arrange + var entityValue = _fixture.Create(); + + // Act + var result = ValueOnlyJsonSerializer.ToJsonObject(entityValue); + + // Assert + result.Should().NotBeNull(); + } + +} \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/IResponseValueTransformer.cs b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/IResponseValueTransformer.cs new file mode 100644 index 000000000..fa80bcb7c --- /dev/null +++ b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/IResponseValueTransformer.cs @@ -0,0 +1,8 @@ +using DataTransferObjects; + +namespace IO.Swagger.Lib.V3.SerializationModifiers.Mappers.ValueMappers; + +public interface IResponseValueTransformer +{ + IDTO Transform(IClass source); +} \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/IValueOnlyJsonDeserializer.cs b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/IValueOnlyJsonDeserializer.cs new file mode 100644 index 000000000..1b807afb1 --- /dev/null +++ b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/IValueOnlyJsonDeserializer.cs @@ -0,0 +1,10 @@ +using System.Text.Json.Nodes; +using DataTransferObjects.ValueDTOs; + +namespace IO.Swagger.Lib.V3.SerializationModifiers.Mappers.ValueMappers; + +public interface IValueOnlyJsonDeserializer +{ + IValueDTO DeserializeSubmodelElementValue(JsonNode node, string encodedSubmodelIdentifier = null, string idShortPath = null); + SubmodelValue DeserializeSubmodelValue(JsonNode node, string encodedSubmodelIdentifier); +} \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/RequestValueMapper.cs b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/RequestValueMapper.cs index 411690d7a..296983cc7 100644 --- a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/RequestValueMapper.cs +++ b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/RequestValueMapper.cs @@ -2,6 +2,7 @@ using DataTransferObjects.ValueDTOs; using System; using System.Collections.Generic; +using System.Linq; namespace IO.Swagger.Lib.V3.SerializationModifiers.Mappers.ValueMappers { @@ -10,66 +11,23 @@ public static class RequestValueMapper public static IClass Map(IValueDTO source) { if (source == null) throw new ArgumentNullException(nameof(source)); - switch (source) + return source switch { - case PropertyValue propertyValue: - { - return Transform(propertyValue); - } - case MultiLanguagePropertyValue multiLanguagePropertyValue: - { - return Transform(multiLanguagePropertyValue); - } - case RangeValue rangeValue: - { - return Transform(rangeValue); - } - case BlobValue blobValue: - { - return Transform(blobValue); - } - case FileValue fileValue: - { - return Transform(fileValue); - } - case AnnotatedRelationshipElementValue annotationElementValue: - { - return Transform(annotationElementValue); - } - case RelationshipElementValue relationshipElementValue: - { - return Transform(relationshipElementValue); - } - case ReferenceElementValue referenceElementValue: - { - return Transform(referenceElementValue); - } - case BasicEventElementValue basicEventElementValue: - { - return Transform(basicEventElementValue); - } - case EntityValue entityValue: - { - return Transform(entityValue); - } - case SubmodelElementCollectionValue submodelElementCollectionValue: - { - return Transform(submodelElementCollectionValue); - } - case SubmodelElementListValue submodelElementListValue: - { - return Transform(submodelElementListValue); - } - case SubmodelValue submodelValue: - { - return Transform(submodelValue); - } - default: - { - throw new NotImplementedException(); - } - } - + PropertyValue propertyValue => Transform(propertyValue), + MultiLanguagePropertyValue multiLanguagePropertyValue => Transform(multiLanguagePropertyValue), + RangeValue rangeValue => Transform(rangeValue), + BlobValue blobValue => Transform(blobValue), + FileValue fileValue => Transform(fileValue), + AnnotatedRelationshipElementValue annotationElementValue => Transform(annotationElementValue), + RelationshipElementValue relationshipElementValue => Transform(relationshipElementValue), + ReferenceElementValue referenceElementValue => Transform(referenceElementValue), + BasicEventElementValue basicEventElementValue => Transform(basicEventElementValue), + EntityValue entityValue => Transform(entityValue), + SubmodelElementCollectionValue submodelElementCollectionValue => Transform(submodelElementCollectionValue), + SubmodelElementListValue submodelElementListValue => Transform(submodelElementListValue), + SubmodelValue submodelValue => Transform(submodelValue), + _ => throw new NotImplementedException() + }; } private static IClass Transform(BasicEventElementValue valueDTO) @@ -82,11 +40,7 @@ private static IClass Transform(SubmodelValue valueDTO) List submodelElements = null; if (valueDTO.submodelElements != null) { - submodelElements = new List(); - foreach (var element in valueDTO.submodelElements) - { - submodelElements.Add((ISubmodelElement)Map(element)); - } + submodelElements = valueDTO.submodelElements.Select(element => (ISubmodelElement) Map(element)).ToList(); } return new Submodel(null, submodelElements: submodelElements); @@ -102,11 +56,7 @@ private static IClass Transform(SubmodelElementListValue valueDTO) List value = null; if (valueDTO.value != null) { - value = new List(); - foreach (var element in valueDTO.value) - { - value.Add((ISubmodelElement)Map(element)); - } + value = valueDTO.value.Select(element => (ISubmodelElement) Map(element)).ToList(); } return new SubmodelElementList(AasSubmodelElements.SubmodelElement, idShort: valueDTO.idShort, value: value); @@ -114,11 +64,7 @@ private static IClass Transform(SubmodelElementListValue valueDTO) private static IClass Transform(MultiLanguagePropertyValue valueDTO) { - var value = new List(); - foreach (var langString in valueDTO.langStrings) - { - value.Add(new LangStringTextType(langString.Key, langString.Value)); - } + var value = valueDTO.langStrings.Select(langString => new LangStringTextType(langString.Key, langString.Value)).Cast().ToList(); return new MultiLanguageProperty(idShort: valueDTO.idShort, value: value); } @@ -127,11 +73,7 @@ private static IClass Transform(SubmodelElementCollectionValue valueDTO) List value = null; if (valueDTO.value != null) { - value = new List(); - foreach (var element in valueDTO.value) - { - value.Add((ISubmodelElement)Map(element)); - } + value = valueDTO.value.Select(element => (ISubmodelElement) Map(element)).ToList(); } return new SubmodelElementCollection(idShort: valueDTO.idShort, value: value); @@ -142,12 +84,9 @@ private static IClass Transform(EntityValue valueDTO) List statements = null; if (valueDTO.statements != null) { - statements = new List(); - foreach (var element in valueDTO.statements) - { - statements.Add((ISubmodelElement)Map(element)); - } + statements = valueDTO.statements.Select(element => (ISubmodelElement) Map(element)).ToList(); } + return new Entity(valueDTO.entityType, idShort: valueDTO.idShort, statements: statements, globalAssetId: valueDTO.globalAssetId); } @@ -166,12 +105,9 @@ private static IClass Transform(AnnotatedRelationshipElementValue valueDTO) List annotations = null; if (valueDTO.annotations != null) { - annotations = new List(); - foreach (var element in valueDTO.annotations) - { - annotations.Add((IDataElement)Map(element)); - } + annotations = valueDTO.annotations.Select(element => (IDataElement) Map(element)).ToList(); } + return new AnnotatedRelationshipElement(TransformReference(valueDTO.first), TransformReference(valueDTO.second), idShort: valueDTO.idShort, annotations: annotations); } @@ -192,22 +128,12 @@ private static IClass Transform(PropertyValue valueDTO) private static IReference TransformReference(ReferenceDTO referenceDTO) { - if (referenceDTO == null) - return null; - return new Reference(referenceDTO.type, TransformKeys(referenceDTO.keys), TransformReference(referenceDTO.referredSemanticId)); + return referenceDTO == null ? null : new Reference(referenceDTO.type, TransformKeys(referenceDTO.keys), TransformReference(referenceDTO.referredSemanticId)); } - private static List TransformKeys(List keys) + private static List TransformKeys(IEnumerable keys) { - if (keys == null) return null; - - var result = new List(); - foreach (var key in keys) - { - result.Add(new Key(key.type, key.value)); - } - - return result; + return keys?.Select(key => new Key(key.type, key.value)).Cast().ToList(); } } -} +} \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/ResponseValueMapper.cs b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/ResponseValueMapper.cs index 0d1bff3d7..aa1297315 100644 --- a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/ResponseValueMapper.cs +++ b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/ResponseValueMapper.cs @@ -4,7 +4,7 @@ namespace IO.Swagger.Lib.V3.SerializationModifiers.Mappers.ValueMappers { public class ResponseValueMapper { - private static ResponseValueTransformer Transformer = new ResponseValueTransformer(); + private static readonly IResponseValueTransformer Transformer = new ResponseValueTransformer(); public static IValueDTO Map(IClass source) { diff --git a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/ResponseValueTransformer.cs b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/ResponseValueTransformer.cs index 92aca1c9e..6d3b67e9f 100644 --- a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/ResponseValueTransformer.cs +++ b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/ResponseValueTransformer.cs @@ -6,272 +6,271 @@ using System.Linq; using static AasCore.Aas3_0.Visitation; -namespace IO.Swagger.Lib.V3.SerializationModifiers.Mappers.ValueMappers +namespace IO.Swagger.Lib.V3.SerializationModifiers.Mappers.ValueMappers; + +internal class ResponseValueTransformer : ITransformer, IResponseValueTransformer { - internal class ResponseValueTransformer : ITransformer + public IDTO Transform(IClass that) { - public IDTO Transform(IClass that) - { - return that?.Transform(this); - } + return that?.Transform(this); + } - public IDTO TransformAdministrativeInformation(IAdministrativeInformation that) - { - throw new System.NotImplementedException(); - } + public IDTO TransformAdministrativeInformation(IAdministrativeInformation that) + { + throw new System.NotImplementedException(); + } - public IDTO TransformAnnotatedRelationshipElement(IAnnotatedRelationshipElement that) + public IDTO TransformAnnotatedRelationshipElement(IAnnotatedRelationshipElement that) + { + List annotations = null; + if (that is {Annotations: not null}) { - List annotations = null; - if (that.Annotations != null) - { - annotations = that.Annotations.Select(element => (ISubmodelElementValue) Transform(element)).ToList(); - } - else - { - return null; - } - - return new AnnotatedRelationshipElementValue(that.IdShort ?? string.Empty, (ReferenceDTO) Transform(that.First), (ReferenceDTO) Transform(that.Second), annotations); + annotations = that.Annotations.Select(element => (ISubmodelElementValue) Transform(element)).ToList(); } - - public IDTO TransformAssetAdministrationShell(IAssetAdministrationShell that) + else { - throw new System.NotImplementedException(); + return null; } - public IDTO TransformAssetInformation(IAssetInformation that) - { - throw new System.NotImplementedException(); - } + return new AnnotatedRelationshipElementValue(that.IdShort ?? string.Empty, (ReferenceDTO) Transform(that.First), (ReferenceDTO) Transform(that.Second), annotations); + } - public IDTO TransformBasicEventElement(IBasicEventElement that) - { - return new BasicEventElementValue(that.IdShort ?? string.Empty, (ReferenceDTO) Transform(that.Observed)); - } + public IDTO TransformAssetAdministrationShell(IAssetAdministrationShell that) + { + throw new System.NotImplementedException(); + } - public IDTO TransformBlob(IBlob that) - { - return new BlobValue(that.IdShort ?? string.Empty, that.ContentType, that.Value); - } + public IDTO TransformAssetInformation(IAssetInformation that) + { + throw new System.NotImplementedException(); + } - public IDTO TransformCapability(ICapability that) - { - throw new InvalidSerializationModifierException("ValueOnly", that.GetType().Name); - } + public IDTO TransformBasicEventElement(IBasicEventElement that) + { + return new BasicEventElementValue(that.IdShort ?? string.Empty, (ReferenceDTO) Transform(that.Observed)); + } - public IDTO TransformConceptDescription(IConceptDescription that) - { - throw new System.NotImplementedException(); - } + public IDTO TransformBlob(IBlob that) + { + return new BlobValue(that.IdShort ?? string.Empty, that.ContentType, that.Value); + } - public IDTO TransformDataSpecificationIec61360(IDataSpecificationIec61360 that) - { - throw new System.NotImplementedException(); - } + public IDTO TransformCapability(ICapability that) + { + throw new InvalidSerializationModifierException("ValueOnly", that.GetType().Name); + } - public IDTO TransformEmbeddedDataSpecification(IEmbeddedDataSpecification that) - { - throw new System.NotImplementedException(); - } + public IDTO TransformConceptDescription(IConceptDescription that) + { + throw new System.NotImplementedException(); + } - public IDTO TransformEntity(IEntity that) - { - List statements = null; - if (that.Statements != null) - { - statements = that.Statements.Select(element => (ISubmodelElementValue) Transform(element)).ToList(); - } + public IDTO TransformDataSpecificationIec61360(IDataSpecificationIec61360 that) + { + throw new System.NotImplementedException(); + } - return new EntityValue(that.IdShort ?? string.Empty, that.EntityType, statements, that.GlobalAssetId); - } + public IDTO TransformEmbeddedDataSpecification(IEmbeddedDataSpecification that) + { + throw new System.NotImplementedException(); + } - public IDTO TransformEnvironment(IEnvironment that) + public IDTO TransformEntity(IEntity that) + { + List statements = null; + if (that.Statements != null) { - throw new System.NotImplementedException(); + statements = that.Statements.Select(element => (ISubmodelElementValue) Transform(element)).ToList(); } - public IDTO TransformEventPayload(IEventPayload that) - { - throw new System.NotImplementedException(); - } + return new EntityValue(that.IdShort ?? string.Empty, that.EntityType, statements, that.GlobalAssetId); + } - public IDTO TransformExtension(IExtension that) - { - throw new System.NotImplementedException(); - } + public IDTO TransformEnvironment(IEnvironment that) + { + throw new System.NotImplementedException(); + } - public IDTO TransformFile(IFile that) - { - return new FileValue(that.IdShort ?? string.Empty, that.ContentType, that.Value); - } + public IDTO TransformEventPayload(IEventPayload that) + { + throw new System.NotImplementedException(); + } - private List TransformKeyList(IEnumerable keyList) - { - return keyList?.Select(key => (KeyDTO) Transform(key)).ToList(); - } + public IDTO TransformExtension(IExtension that) + { + throw new System.NotImplementedException(); + } - public IDTO TransformKey(IKey that) - { - return new KeyDTO(that.Type, that.Value); - } + public IDTO TransformFile(IFile that) + { + return new FileValue(that.IdShort ?? string.Empty, that.ContentType, that.Value); + } - public IDTO TransformLangStringDefinitionTypeIec61360(ILangStringDefinitionTypeIec61360 that) - { - throw new System.NotImplementedException(); - } + private List TransformKeyList(IEnumerable keyList) + { + return keyList?.Select(key => (KeyDTO) Transform(key)).ToList(); + } - public IDTO TransformLangStringNameType(ILangStringNameType that) - { - throw new System.NotImplementedException(); - } + public IDTO TransformKey(IKey that) + { + return new KeyDTO(that.Type, that.Value); + } - public IDTO TransformLangStringPreferredNameTypeIec61360(ILangStringPreferredNameTypeIec61360 that) - { - throw new System.NotImplementedException(); - } + public IDTO TransformLangStringDefinitionTypeIec61360(ILangStringDefinitionTypeIec61360 that) + { + throw new System.NotImplementedException(); + } - public IDTO TransformLangStringShortNameTypeIec61360(ILangStringShortNameTypeIec61360 that) - { - throw new System.NotImplementedException(); - } + public IDTO TransformLangStringNameType(ILangStringNameType that) + { + throw new System.NotImplementedException(); + } - public IDTO TransformLangStringTextType(ILangStringTextType that) - { - throw new System.NotImplementedException(); - } + public IDTO TransformLangStringPreferredNameTypeIec61360(ILangStringPreferredNameTypeIec61360 that) + { + throw new System.NotImplementedException(); + } - public IDTO TransformLevelType(ILevelType that) - { - throw new System.NotImplementedException(); - } + public IDTO TransformLangStringShortNameTypeIec61360(ILangStringShortNameTypeIec61360 that) + { + throw new System.NotImplementedException(); + } - public IDTO TransformMultiLanguageProperty(IMultiLanguageProperty that) - { - var langStrings = new List>(); - if (that.Value != null) - { - langStrings.AddRange(that.Value.Select(langString => new KeyValuePair(langString.Language, langString.Text))); - } + public IDTO TransformLangStringTextType(ILangStringTextType that) + { + throw new System.NotImplementedException(); + } - return new MultiLanguagePropertyValue(that.IdShort ?? string.Empty, langStrings); - } + public IDTO TransformLevelType(ILevelType that) + { + throw new System.NotImplementedException(); + } - public IDTO TransformOperation(IOperation that) + public IDTO TransformMultiLanguageProperty(IMultiLanguageProperty that) + { + var langStrings = new List>(); + if (that.Value != null) { - List inputVariables = null; - List outputVariables = null; - List inoutputVariables = null; - if (that.InputVariables != null) - { - inputVariables = that.InputVariables.Select(inputVariable => (ISubmodelElementValue) Transform(inputVariable)).ToList(); - } - - if (that.OutputVariables != null) - { - outputVariables = that.OutputVariables.Select(outputVariable => (ISubmodelElementValue) Transform(outputVariable)).ToList(); - } - - if (that.InoutputVariables != null) - { - inoutputVariables = that.InoutputVariables.Select(inoutputVariable => (ISubmodelElementValue) Transform(inoutputVariable)).ToList(); - } - - return new OperationValue(that.IdShort ?? string.Empty, inputVariables, outputVariables, inoutputVariables); + langStrings.AddRange(that.Value.Select(langString => new KeyValuePair(langString.Language, langString.Text))); } - public IDTO TransformOperationVariable(IOperationVariable that) - { - return Transform(that.Value); - } + return new MultiLanguagePropertyValue(that.IdShort ?? string.Empty, langStrings); + } - public IDTO TransformProperty(IProperty that) + public IDTO TransformOperation(IOperation that) + { + List inputVariables = null; + List outputVariables = null; + List inoutputVariables = null; + if (that.InputVariables != null) { - return new PropertyValue(that.IdShort ?? string.Empty, that.Value); + inputVariables = that.InputVariables.Select(inputVariable => (ISubmodelElementValue) Transform(inputVariable)).ToList(); } - public IDTO TransformQualifier(IQualifier that) + if (that.OutputVariables != null) { - throw new System.NotImplementedException(); + outputVariables = that.OutputVariables.Select(outputVariable => (ISubmodelElementValue) Transform(outputVariable)).ToList(); } - public IDTO TransformRange(IRange that) + if (that.InoutputVariables != null) { - return new RangeValue(that.IdShort ?? string.Empty, that.Min, that.Max); + inoutputVariables = that.InoutputVariables.Select(inoutputVariable => (ISubmodelElementValue) Transform(inoutputVariable)).ToList(); } - public IDTO TransformReference(IReference that) - { - if (that.ReferredSemanticId != null) - { - return new ReferenceDTO(that.Type, TransformKeyList(that.Keys), (ReferenceDTO) Transform( - that.ReferredSemanticId)); - } + return new OperationValue(that.IdShort ?? string.Empty, inputVariables, outputVariables, inoutputVariables); + } - return null; - } + public IDTO TransformOperationVariable(IOperationVariable that) + { + return Transform(that.Value); + } - public IDTO TransformReferenceElement(IReferenceElement that) - { - return that.Value != null ? new ReferenceElementValue(that.IdShort ?? string.Empty, (ReferenceDTO) Transform(that.Value)) : null; - } + public IDTO TransformProperty(IProperty that) + { + return new PropertyValue(that.IdShort ?? string.Empty, that.Value); + } - public IDTO TransformRelationshipElement(IRelationshipElement that) - { - return new RelationshipElementValue(that.IdShort ?? string.Empty, (ReferenceDTO) Transform(that.First), (ReferenceDTO) Transform(that.Second)); - } + public IDTO TransformQualifier(IQualifier that) + { + throw new System.NotImplementedException(); + } - public IDTO TransformResource(IResource that) - { - throw new System.NotImplementedException(); - } + public IDTO TransformRange(IRange that) + { + return new RangeValue(that.IdShort ?? string.Empty, that.Min, that.Max); + } - public IDTO TransformSpecificAssetId(ISpecificAssetId that) + public IDTO TransformReference(IReference that) + { + if (that.ReferredSemanticId != null) { - throw new System.NotImplementedException(); + return new ReferenceDTO(that.Type, TransformKeyList(that.Keys), (ReferenceDTO) Transform( + that.ReferredSemanticId)); } - public IDTO TransformSubmodel(ISubmodel that) - { - List submodelElements = null; - if (that.SubmodelElements != null) - { - submodelElements = that.SubmodelElements.Select(element => (ISubmodelElementValue) Transform(element)).ToList(); - } + return null; + } - return new SubmodelValue(submodelElements); - } + public IDTO TransformReferenceElement(IReferenceElement that) + { + return that.Value != null ? new ReferenceElementValue(that.IdShort ?? string.Empty, (ReferenceDTO) Transform(that.Value)) : null; + } - public IDTO TransformSubmodelElementCollection(ISubmodelElementCollection that) - { - List value = null; - if (that.Value != null) - { - value = that.Value.Select(element => (ISubmodelElementValue) Transform(element)).ToList(); - } + public IDTO TransformRelationshipElement(IRelationshipElement that) + { + return new RelationshipElementValue(that.IdShort ?? string.Empty, (ReferenceDTO) Transform(that.First), (ReferenceDTO) Transform(that.Second)); + } - return new SubmodelElementCollectionValue(that.IdShort ?? string.Empty, value); - } + public IDTO TransformResource(IResource that) + { + throw new System.NotImplementedException(); + } - public IDTO TransformSubmodelElementList(ISubmodelElementList that) - { - List value = null; - if (that.Value != null) - { - value = that.Value.Select(element => (ISubmodelElementValue) Transform(element)).ToList(); - } + public IDTO TransformSpecificAssetId(ISpecificAssetId that) + { + throw new System.NotImplementedException(); + } - return new SubmodelElementListValue(that.IdShort ?? string.Empty, value); + public IDTO TransformSubmodel(ISubmodel that) + { + List submodelElements = null; + if (that.SubmodelElements != null) + { + submodelElements = that.SubmodelElements.Select(element => (ISubmodelElementValue) Transform(element)).ToList(); } - public IDTO TransformValueList(IValueList that) + return new SubmodelValue(submodelElements); + } + + public IDTO TransformSubmodelElementCollection(ISubmodelElementCollection that) + { + List value = null; + if (that.Value != null) { - throw new System.NotImplementedException(); + value = that.Value.Select(element => (ISubmodelElementValue) Transform(element)).ToList(); } - public IDTO TransformValueReferencePair(IValueReferencePair that) + return new SubmodelElementCollectionValue(that.IdShort ?? string.Empty, value); + } + + public IDTO TransformSubmodelElementList(ISubmodelElementList that) + { + List value = null; + if (that.Value != null) { - throw new System.NotImplementedException(); + value = that.Value.Select(element => (ISubmodelElementValue) Transform(element)).ToList(); } + + return new SubmodelElementListValue(that.IdShort ?? string.Empty, value); + } + + public IDTO TransformValueList(IValueList that) + { + throw new System.NotImplementedException(); + } + + public IDTO TransformValueReferencePair(IValueReferencePair that) + { + throw new System.NotImplementedException(); } } \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/ValueOnlyJsonDeserializer.cs b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/ValueOnlyJsonDeserializer.cs index 855845052..164c27d06 100644 --- a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/ValueOnlyJsonDeserializer.cs +++ b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/ValueOnlyJsonDeserializer.cs @@ -6,353 +6,319 @@ using Newtonsoft.Json; using System; using System.Collections.Generic; +using System.Linq; using System.Text.Json.Nodes; -namespace IO.Swagger.Lib.V3.SerializationModifiers.Mappers.ValueMappers +namespace IO.Swagger.Lib.V3.SerializationModifiers.Mappers.ValueMappers; + +public class ValueOnlyJsonDeserializer : IValueOnlyJsonDeserializer { - public interface IValueOnlyJsonDeserializer + private readonly ISubmodelService _submodelService; + private readonly IBase64UrlDecoderService _decoderService; + + public ValueOnlyJsonDeserializer(ISubmodelService submodelService, IBase64UrlDecoderService decoderService) { - IValueDTO DeserializeSubmodelElementValue(JsonNode node, string encodedSubmodelIdentifier = null, string idShortPath = null); - SubmodelValue DeserializeSubmodelValue(JsonNode node, string encodedSubmodelIdentifier); + _submodelService = submodelService ?? throw new ArgumentNullException(nameof(submodelService)); + _decoderService = decoderService ?? throw new ArgumentNullException(nameof(submodelService)); } - public class ValueOnlyJsonDeserializer : IValueOnlyJsonDeserializer + + public IValueDTO DeserializeSubmodelElementValue(JsonNode node, string encodedSubmodelIdentifier = null, string idShortPath = null) { - private readonly ISubmodelService _submodelService; - private readonly IBase64UrlDecoderService _decoderService; + if (node == null) throw new ArgumentNullException(nameof(node)); - public ValueOnlyJsonDeserializer(ISubmodelService submodelService, IBase64UrlDecoderService decoderService) + IValueDTO output = null; + + if (node is not JsonObject jsonObject) { - _submodelService = submodelService ?? throw new ArgumentNullException(nameof(submodelService)); - _decoderService = decoderService ?? throw new ArgumentNullException(nameof(submodelService)); + return output; } - public IValueDTO DeserializeSubmodelElementValue(JsonNode node, string encodedSubmodelIdentifier = null, string idShortPath = null) + + foreach (var (idShort, value) in jsonObject) { - if (node == null) throw new ArgumentNullException(nameof(node)); + output = Deserialize(idShort, value, encodedSubmodelIdentifier, idShortPath); + } - IValueDTO output = null; + return output; + } - if (node is JsonObject jsonObject) + private IValueDTO Deserialize(string idShort, JsonNode value, string encodedSubmodelIdentifier, string idShortPath) + { + IValueDTO output = null; + switch (value) + { + case JsonValue jsonValue: { - foreach (var keyValue in jsonObject) - { - string idShort = keyValue.Key; - var value = keyValue.Value; - output = Deserialize(idShort, value, encodedSubmodelIdentifier, idShortPath); - } + //Property + jsonValue.TryGetValue(out string propertyValue); + output = new PropertyValue(idShort, propertyValue); + break; } - - return output; - } - - private IValueDTO Deserialize(string idShort, JsonNode value, string encodedSubmodelIdentifier, string idShortPath) - { - IValueDTO output = null; - switch (value) + case JsonObject valueObject: { - case JsonValue jsonValue: - { - //Property - jsonValue.TryGetValue(out string propertyValue); - output = new PropertyValue(idShort, propertyValue); - break; - } - case JsonObject valueObject: - { - output = ParseJsonValueObject(idShort, valueObject, encodedSubmodelIdentifier, idShortPath); - break; - } - case JsonArray valueArray: - { - output = ParseJsonValueArray(idShort, valueArray, encodedSubmodelIdentifier, idShortPath); - break; - } - default: - { - throw new InvalidOperationException(); - } + output = ParseJsonValueObject(idShort, valueObject, encodedSubmodelIdentifier, idShortPath); + break; } - - return output; - } - - private IValueDTO ParseJsonValueArray(string idShort, JsonArray valueArray, string encodedSubmodelIdentifier, string idShortPath) - { - //This is Multilingual Property or SMEList - var decodedSubmodelId = _decoderService.Decode("submodelId", encodedSubmodelIdentifier); - var element = _submodelService.GetSubmodelElementByPath(decodedSubmodelId, idShortPath); - if (element != null) + case JsonArray valueArray: { - if (element is MultiLanguageProperty) - { - return CreateMultilanguagePropertyValue(idShort, valueArray); - } - else if (element is SubmodelElementList smeList) - { - return CreateSubmodelElementList(idShort, valueArray, smeList, encodedSubmodelIdentifier, idShortPath); - } - else - { - throw new JsonDeserializationException(idShort, "Element is neither MutlilanguageProperty nor SubmodelElementList"); - } + output = ParseJsonValueArray(idShort, valueArray, encodedSubmodelIdentifier, idShortPath); + break; + } + default: + { + throw new InvalidOperationException(); } - return null; } - private IValueDTO CreateSubmodelElementList(string idShort, JsonArray valueArray, SubmodelElementList smeList, string encodedSubmodelIdentifier, string idShortPath) + return output; + } + + private IValueDTO ParseJsonValueArray(string idShort, JsonArray valueArray, string encodedSubmodelIdentifier, string idShortPath) + { + //This is Multilingual Property or SMEList + var decodedSubmodelId = _decoderService.Decode("submodelId", encodedSubmodelIdentifier); + var element = _submodelService.GetSubmodelElementByPath(decodedSubmodelId, idShortPath); + if (element != null) { - var value = new List(); - foreach (var element in valueArray) + return element switch { - var elementValueDTO = Deserialize(null, element, encodedSubmodelIdentifier, idShortPath); - value.Add((ISubmodelElementValue)elementValueDTO); - } - - return new SubmodelElementListValue(idShort, value); + MultiLanguageProperty => CreateMultilanguagePropertyValue(idShort, valueArray), + SubmodelElementList smeList => CreateSubmodelElementList(idShort, valueArray, smeList, encodedSubmodelIdentifier, idShortPath), + _ => throw new JsonDeserializationException(idShort, "Element is neither MutlilanguageProperty nor SubmodelElementList") + }; } - private IValueDTO CreateMultilanguagePropertyValue(string idShort, JsonArray valueArray) - { - var langStrings = new List>(); + return null; + } - foreach (var item in valueArray) - { - if (item is JsonObject jsonObject) - { - GetPropertyFromJsonObject(jsonObject, out string propertyName, out string propertyValue); - langStrings.Add(new KeyValuePair(propertyName, propertyValue)); - } - } + private IValueDTO CreateSubmodelElementList(string idShort, JsonArray valueArray, SubmodelElementList smeList, string encodedSubmodelIdentifier, string idShortPath) + { + var value = valueArray.Select(element => Deserialize(null, element, encodedSubmodelIdentifier, idShortPath)) + .Select(elementValueDTO => (ISubmodelElementValue) elementValueDTO).ToList(); - return new MultiLanguagePropertyValue(idShort, langStrings); + return new SubmodelElementListValue(idShort, value); + } + + private IValueDTO CreateMultilanguagePropertyValue(string idShort, JsonArray valueArray) + { + var langStrings = new List>(); + + foreach (var item in valueArray) + { + if (item is not JsonObject jsonObject) continue; + GetPropertyFromJsonObject(jsonObject, out string propertyName, out string propertyValue); + langStrings.Add(new KeyValuePair(propertyName, propertyValue)); } - private void GetPropertyFromJsonObject(JsonObject jsonObject, out string propertyName, out string propertyValue) + return new MultiLanguagePropertyValue(idShort, langStrings); + } + + private static void GetPropertyFromJsonObject(JsonObject jsonObject, out string propertyName, out string propertyValue) + { + propertyName = null; + propertyValue = null; + foreach (var item in jsonObject) { - propertyName = null; propertyValue = null; - foreach (var item in jsonObject) - { - propertyName = item.Key; - var jsonValue = item.Value as JsonValue; - jsonValue.TryGetValue(out propertyValue); - } + propertyName = item.Key; + var jsonValue = item.Value as JsonValue; + jsonValue.TryGetValue(out propertyValue); } + } - private IValueDTO ParseJsonValueObject(string idShort, JsonObject valueObject, string encodedSubmodelIdentifier = null, string idShortPath = null) + private IValueDTO ParseJsonValueObject(string idShort, JsonObject valueObject, string encodedSubmodelIdentifier = null, string idShortPath = null) + { + if (valueObject == null) throw new ArgumentNullException($"{nameof(valueObject)}"); + if (valueObject.ContainsKey("min") && valueObject.ContainsKey("max")) { - if (valueObject == null) throw new ArgumentNullException(); - if (valueObject.ContainsKey("min") && valueObject.ContainsKey("max")) - { - //Range - return CreateRangeValue(idShort, valueObject); - } - else if (valueObject.ContainsKey("contentType")) + //Range + return CreateRangeValue(idShort, valueObject); + } + else if (valueObject.ContainsKey("contentType")) + { + //If it contains both contentType and Value, both File and Blob are possible. Hence, we need to retrieve actual elements from the server + var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", encodedSubmodelIdentifier); + idShortPath ??= idShort; + var submodelElement = _submodelService.GetSubmodelElementByPath(decodedSubmodelIdentifier, idShortPath); + if (submodelElement != null) { - //If it contains both contentType and Value, both File and Blob are possible. Hence, we need to retrieve actual elements from the server - var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", encodedSubmodelIdentifier); - if (idShortPath == null) - idShortPath = idShort; - var submodelElement = _submodelService.GetSubmodelElementByPath(decodedSubmodelIdentifier, idShortPath); - if (submodelElement != null) + return submodelElement switch { - if (submodelElement is File) - { - return CreateFileValue(idShort, valueObject); - } - else if (submodelElement is Blob) - { - return CreateBlobValue(idShort, valueObject); - } - else - { - throw new JsonDeserializationException(idShort, "Element is neither File nor Blob."); - } - } - } - else if (valueObject.ContainsKey("annotations") && valueObject.ContainsKey("first") && valueObject.ContainsKey("second")) - { - return CreateAnnotedRelationshipElementValue(idShort, valueObject, encodedSubmodelIdentifier, idShortPath); - } - else if (valueObject.ContainsKey("first") && valueObject.ContainsKey("second")) - { - return CreateRelationshipElementValue(idShort, valueObject); - } - else if (valueObject.ContainsKey("type") && valueObject.ContainsKey("keys")) - { - return CreateReferenceElementValue(idShort, valueObject); - } - else if (valueObject.ContainsKey("entityType")) - { - return CreateEntityValue(idShort, valueObject, encodedSubmodelIdentifier, idShortPath); + File => CreateFileValue(idShort, valueObject), + Blob => CreateBlobValue(idShort, valueObject), + _ => throw new JsonDeserializationException(idShort, "Element is neither File nor Blob.") + }; } - else if (valueObject.ContainsKey("observed")) - { - return CreateBasicEventElement(idShort, valueObject); - } - else - { - //This can be SubmodelElementCollection - return CreateSubmodelElementCollectionValue(idShort, valueObject, encodedSubmodelIdentifier, idShortPath); - } - - return null; } - - private IValueDTO CreateSubmodelElementCollectionValue(string idShort, JsonObject valueObject, string encodedSubmodelIdentifier, string idShortPath) + else if (valueObject.ContainsKey("annotations") && valueObject.ContainsKey("first") && valueObject.ContainsKey("second")) { - var submodelElements = new List(); - - foreach (var item in valueObject) - { - var newNode = new JsonObject(new[] { KeyValuePair.Create(item.Key, JsonNode.Parse(item.Value.ToJsonString())) }); - if (idShortPath == null) - idShortPath = idShort; - var newIdShortPath = idShortPath + "." + item.Key; - var submodelElement = DeserializeSubmodelElementValue(newNode, encodedSubmodelIdentifier, newIdShortPath); - submodelElements.Add((ISubmodelElementValue)submodelElement); - } - - return new SubmodelElementCollectionValue(idShort, submodelElements); + return CreateAnnotedRelationshipElementValue(idShort, valueObject, encodedSubmodelIdentifier, idShortPath); } - - private IValueDTO CreateBasicEventElement(string idShort, JsonObject valueObject) + else if (valueObject.ContainsKey("first") && valueObject.ContainsKey("second")) { - ReferenceDTO observed = null; - var observedNode = valueObject["observed"] as JsonNode; - if (observedNode != null) - { - observed = JsonConvert.DeserializeObject(valueObject.ToString()); - } - return new BasicEventElementValue(idShort, observed); + return CreateRelationshipElementValue(idShort, valueObject); } - - private IValueDTO CreateEntityValue(string idShort, JsonObject valueObject, string encodedSubmodelIdentifier, string idShortPath) + else if (valueObject.ContainsKey("type") && valueObject.ContainsKey("keys")) + { + return CreateReferenceElementValue(idShort, valueObject); + } + else if (valueObject.ContainsKey("entityType")) + { + return CreateEntityValue(idShort, valueObject, encodedSubmodelIdentifier, idShortPath); + } + else if (valueObject.ContainsKey("observed")) + { + return CreateBasicEventElement(idShort, valueObject); + } + else { - string entityType = null; - string globalAssetId = null; - List statements = null; + //This can be SubmodelElementCollection + return CreateSubmodelElementCollectionValue(idShort, valueObject, encodedSubmodelIdentifier, idShortPath); + } - JsonValue entityTypeNode = valueObject["entityType"] as JsonValue; - entityTypeNode?.TryGetValue(out entityType); + return null; + } - var globalAssetIdNode = valueObject["globalAssetId"] as JsonValue; - globalAssetIdNode?.TryGetValue(out globalAssetId); + private IValueDTO CreateSubmodelElementCollectionValue(string idShort, JsonObject valueObject, string encodedSubmodelIdentifier, string idShortPath) + { + var submodelElements = new List(); - var statementsNode = valueObject["statements"] as JsonObject; - if (statementsNode != null) - { - statements = new List(); - foreach (var item in statementsNode) - { - var newNode = new JsonObject(new[] { KeyValuePair.Create(item.Key, JsonNode.Parse(item.Value.ToJsonString())) }); - var newIdShortPath = idShortPath + "." + item.Key; - var statement = DeserializeSubmodelElementValue(newNode, encodedSubmodelIdentifier, newIdShortPath); - statements.Add((ISubmodelElementValue)statement); - } - } - return new EntityValue(idShort, (EntityType)Stringification.EntityTypeFromString(entityType), statements, globalAssetId); + foreach (var item in valueObject) + { + var newNode = new JsonObject(new[] {KeyValuePair.Create(item.Key, JsonNode.Parse(item.Value.ToJsonString()))}); + if (idShortPath == null) + idShortPath = idShort; + var newIdShortPath = idShortPath + "." + item.Key; + var submodelElement = DeserializeSubmodelElementValue(newNode, encodedSubmodelIdentifier, newIdShortPath); + submodelElements.Add((ISubmodelElementValue) submodelElement); } - private IValueDTO CreateReferenceElementValue(string idShort, JsonObject valueObject) + return new SubmodelElementCollectionValue(idShort, submodelElements); + } + + private static IValueDTO CreateBasicEventElement(string idShort, JsonNode valueObject) + { + ReferenceDTO observed = null; + if (valueObject["observed"] != null) { - ReferenceDTO referenceDTO = JsonConvert.DeserializeObject(valueObject.ToString()); - return new ReferenceElementValue(idShort, referenceDTO); + observed = JsonConvert.DeserializeObject(valueObject.ToString()); } - private IValueDTO CreateRelationshipElementValue(string idShort, JsonObject valueObject) - { - ReferenceDTO firstDTO = null, secondDTO = null; - JsonNode firstNode = valueObject["first"]; - if (firstNode != null) - { - firstDTO = JsonConvert.DeserializeObject(firstNode.ToString()); - } - JsonNode secondNode = valueObject["second"]; - if (secondNode != null) - { - secondDTO = JsonConvert.DeserializeObject(firstNode.ToString()); - } + return new BasicEventElementValue(idShort, observed); + } - return new RelationshipElementValue(idShort, firstDTO, secondDTO); - } + private IValueDTO CreateEntityValue(string idShort, JsonNode valueObject, string encodedSubmodelIdentifier, string idShortPath) + { + string entityType = null; + string globalAssetId = null; + List statements = null; - private IValueDTO CreateAnnotedRelationshipElementValue(string idShort, JsonObject valueObject, string encodedSubmodelIdentifier, string idShortPath) - { - ReferenceDTO firstDTO = null, secondDTO = null; - JsonNode firstNode = valueObject["first"]; - if (firstNode != null) - { - firstDTO = JsonConvert.DeserializeObject(firstNode.ToString()); - } - JsonNode secondNode = valueObject["second"]; - if (secondNode != null) - { - secondDTO = JsonConvert.DeserializeObject(firstNode.ToString()); - } + var entityTypeNode = valueObject["entityType"] as JsonValue; + entityTypeNode?.TryGetValue(out entityType); - JsonArray annotationsNode = valueObject["annotations"] as JsonArray; - if (annotationsNode != null) - { - var annotations = new List(); - foreach (var annotationNode in annotationsNode) - { - var annotation = DeserializeSubmodelElementValue(annotationNode, encodedSubmodelIdentifier, idShortPath); - annotations.Add((ISubmodelElementValue)annotation); - } - return new AnnotatedRelationshipElementValue(idShort, firstDTO, secondDTO, annotations); - } + var globalAssetIdNode = valueObject["globalAssetId"] as JsonValue; + globalAssetIdNode?.TryGetValue(out globalAssetId); - return new AnnotatedRelationshipElementValue(idShort, firstDTO, secondDTO); + var statementsNode = valueObject["statements"] as JsonObject; + if (statementsNode != null) + { + statements = (from item in statementsNode + let newNode = new JsonObject(new[] {KeyValuePair.Create(item.Key, JsonNode.Parse(item.Value.ToJsonString()))}) + let newIdShortPath = idShortPath + "." + item.Key + select DeserializeSubmodelElementValue(newNode, encodedSubmodelIdentifier, newIdShortPath) + into statement + select (ISubmodelElementValue) statement).ToList(); } - private IValueDTO CreateBlobValue(string idShort, JsonObject valueObject) - { - string contentType = null; - var contentTypeNode = valueObject["contentType"] as JsonValue; - contentTypeNode?.TryGetValue(out contentType); + return new EntityValue(idShort, (EntityType) Stringification.EntityTypeFromString(entityType), statements, globalAssetId); + } - var valueNode = valueObject["value"] as JsonValue; - if (valueNode != null) - { - valueNode.TryGetValue(out string value); - return new BlobValue(idShort, contentType, System.Convert.FromBase64String(value)); - } + private static IValueDTO CreateReferenceElementValue(string idShort, JsonObject valueObject) + { + var referenceDTO = JsonConvert.DeserializeObject(valueObject.ToString()); + return new ReferenceElementValue(idShort, referenceDTO); + } - return new BlobValue(idShort, contentType); + private static IValueDTO CreateRelationshipElementValue(string idShort, JsonObject valueObject) + { + ReferenceDTO firstDTO = null, secondDTO = null; + var firstNode = valueObject["first"]; + if (firstNode != null) + { + firstDTO = JsonConvert.DeserializeObject(firstNode.ToString()); } - private IValueDTO CreateFileValue(string idShort, JsonObject valueObject) + var secondNode = valueObject["second"]; + if (secondNode != null) { - string contentType = null, value = null; - var contentTypeNode = valueObject["contentType"] as JsonValue; - contentTypeNode?.TryGetValue(out contentType); - var valueNode = valueObject["value"] as JsonValue; - valueNode?.TryGetValue(out value); - return new FileValue(idShort, contentType, value); + secondDTO = JsonConvert.DeserializeObject(firstNode.ToString()); } - private static IValueDTO CreateRangeValue(string idShort, JsonObject valueObject) - { - string min = null, max = null; - var minNode = valueObject["min"] as JsonValue; - minNode?.TryGetValue(out min); - var maxNode = valueObject["max"] as JsonValue; - maxNode?.TryGetValue(out max); + return new RelationshipElementValue(idShort, firstDTO, secondDTO); + } - return new RangeValue(idShort, min, max); + private IValueDTO CreateAnnotedRelationshipElementValue(string idShort, JsonNode valueObject, string encodedSubmodelIdentifier, string idShortPath) + { + ReferenceDTO firstDTO = null, secondDTO = null; + var firstNode = valueObject["first"]; + if (firstNode != null) + { + firstDTO = JsonConvert.DeserializeObject(firstNode.ToString()); } - public SubmodelValue DeserializeSubmodelValue(JsonNode node, string encodedSubmodelIdentifier) + var secondNode = valueObject["second"]; + if (secondNode != null) { - var submodelElements = new List(); - var jsonObject = node as JsonObject; - foreach (var item in jsonObject) - { - var newNode = new JsonObject(new[] { KeyValuePair.Create(item.Key, JsonNode.Parse(item.Value.ToJsonString())) }); - var submodelElement = DeserializeSubmodelElementValue(newNode, encodedSubmodelIdentifier); - submodelElements.Add((ISubmodelElementValue)submodelElement); - } - - return new SubmodelValue(submodelElements); + secondDTO = JsonConvert.DeserializeObject(firstNode.ToString()); } + + var annotationsNode = valueObject["annotations"] as JsonArray; + if (annotationsNode == null) return new AnnotatedRelationshipElementValue(idShort, firstDTO, secondDTO); + var annotations = annotationsNode.Select(annotationNode => DeserializeSubmodelElementValue(annotationNode, encodedSubmodelIdentifier, idShortPath)) + .Select(annotation => (ISubmodelElementValue) annotation).ToList(); + return new AnnotatedRelationshipElementValue(idShort, firstDTO, secondDTO, annotations); + } + + private static IValueDTO CreateBlobValue(string idShort, JsonObject valueObject) + { + string contentType = null; + var contentTypeNode = valueObject["contentType"] as JsonValue; + contentTypeNode?.TryGetValue(out contentType); + + if (valueObject["value"] is not JsonValue valueNode) return new BlobValue(idShort, contentType); + valueNode.TryGetValue(out string value); + return new BlobValue(idShort, contentType, System.Convert.FromBase64String(value)); + } + + private IValueDTO CreateFileValue(string idShort, JsonNode valueObject) + { + string contentType = null, value = null; + var contentTypeNode = valueObject["contentType"] as JsonValue; + contentTypeNode?.TryGetValue(out contentType); + var valueNode = valueObject["value"] as JsonValue; + valueNode?.TryGetValue(out value); + return new FileValue(idShort, contentType, value); + } + + private static IValueDTO CreateRangeValue(string idShort, JsonNode valueObject) + { + string min = null, max = null; + var minNode = valueObject["min"] as JsonValue; + minNode?.TryGetValue(out min); + var maxNode = valueObject["max"] as JsonValue; + maxNode?.TryGetValue(out max); + + return new RangeValue(idShort, min, max); + } + + public SubmodelValue DeserializeSubmodelValue(JsonNode node, string encodedSubmodelIdentifier) + { + var jsonObject = node as JsonObject; + var submodelElements = (from item in jsonObject + select new JsonObject(new[] {KeyValuePair.Create(item.Key, JsonNode.Parse(item.Value.ToJsonString()))}) + into newNode + select DeserializeSubmodelElementValue(newNode, encodedSubmodelIdentifier) + into submodelElement + select (ISubmodelElementValue) submodelElement).ToList(); + + return new SubmodelValue(submodelElements); } -} +} \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/ValueOnlyJsonSerializer.cs b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/ValueOnlyJsonSerializer.cs index 80bcc452c..dd145fafc 100644 --- a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/ValueOnlyJsonSerializer.cs +++ b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/ValueOnlyJsonSerializer.cs @@ -1,328 +1,309 @@ using DataTransferObjects.CommonDTOs; using DataTransferObjects.ValueDTOs; using System; +using System.Linq; using System.Text.Json; using System.Text.Json.Nodes; -namespace IO.Swagger.Lib.V3.SerializationModifiers.Mappers.ValueMappers +namespace IO.Swagger.Lib.V3.SerializationModifiers.Mappers.ValueMappers; + +public static class ValueOnlyJsonSerializer { - public static class ValueOnlyJsonSerializer + internal static JsonNode ToJsonObject(IValueDTO that) { - internal static JsonNode ToJsonObject(IValueDTO that) + return that switch { - if (that == null) - throw new ArgumentNullException(nameof(that)); - if (that is PropertyValue propertyValue) - { - return Transform(propertyValue); - } - else if (that is MultiLanguagePropertyValue multiLanguagePropertyValue) - { - return Transform(multiLanguagePropertyValue); - } - else if (that is BasicEventElementValue basicEventElementValue) - { - return Transform(basicEventElementValue); - } - else if (that is BlobValue blobValue) - { - return Transform(blobValue); - } - else if (that is FileValue fileValue) - { - return Transform(fileValue); - } - else if (that is RangeValue rangeValue) - { - return Transform(rangeValue); - } - else if (that is ReferenceElementValue referenceElementValue) - { - return Transform(referenceElementValue); - } - else if (that is RelationshipElementValue relationshipElementValue) - { - return Transform(relationshipElementValue); - } - else if (that is SubmodelElementCollectionValue submodelElementCollectionValue) - { - return Transform(submodelElementCollectionValue); - } - else if (that is SubmodelElementListValue submodelElementListValue) - { - return Transform(submodelElementListValue); - } - else if (that is AnnotatedRelationshipElementValue annotatedRelEleValue) - { - return Transform(annotatedRelEleValue); - } - else if (that is EntityValue EntityValue) - { - return Transform(EntityValue); - } - else if (that is SubmodelValue submodelValue) - { - return Transform(submodelValue); - } - + null => throw new ArgumentNullException(nameof(that)), + PropertyValue propertyValue => Transform(propertyValue), + MultiLanguagePropertyValue multiLanguagePropertyValue => Transform(multiLanguagePropertyValue), + BasicEventElementValue basicEventElementValue => Transform(basicEventElementValue), + BlobValue blobValue => Transform(blobValue), + FileValue fileValue => Transform(fileValue), + RangeValue rangeValue => Transform(rangeValue), + ReferenceElementValue referenceElementValue => Transform(referenceElementValue), + RelationshipElementValue relationshipElementValue => Transform(relationshipElementValue), + SubmodelElementCollectionValue submodelElementCollectionValue => Transform(submodelElementCollectionValue), + SubmodelElementListValue submodelElementListValue => Transform(submodelElementListValue), + AnnotatedRelationshipElementValue annotatedRelEleValue => Transform(annotatedRelEleValue), + EntityValue EntityValue => Transform(EntityValue), + SubmodelValue submodelValue => Transform(submodelValue), + _ => null + }; + } - return null; - } + private static JsonNode Transform(EntityValue entityValue) + { + var result = new JsonObject(); - private static JsonNode Transform(EntityValue entityValue) + var statements = new JsonObject(); + if (entityValue.statements != null) { - var result = new JsonObject(); - - var statements = new JsonObject(); - if (entityValue.statements != null) + foreach (var element in entityValue.statements) { - foreach (var element in entityValue.statements) + var elementObject = ToJsonObject(element) as JsonObject; + foreach (var keyValue in elementObject) { - var elementObject = ToJsonObject(element) as JsonObject; - foreach (var keyValue in elementObject) - { - var valueString = keyValue.Value.ToJsonString(); - var valueNode = JsonSerializer.Deserialize(valueString); - statements[keyValue.Key] = valueNode; - } + var valueString = keyValue.Value.ToJsonString(); + var valueNode = JsonSerializer.Deserialize(valueString); + statements[keyValue.Key] = valueNode; } } + } - var valueObject = new JsonObject(); - valueObject["statements"] = statements; - valueObject["entityType"] = Jsonization.Serialize.EntityTypeToJsonValue(entityValue.entityType); - valueObject["globalAssetId"] = entityValue.globalAssetId; + var valueObject = new JsonObject(); + valueObject["statements"] = statements; + valueObject["entityType"] = Jsonization.Serialize.EntityTypeToJsonValue(entityValue.entityType); + valueObject["globalAssetId"] = entityValue.globalAssetId; - result[entityValue.idShort] = valueObject; + result[entityValue.idShort] = valueObject; - return result; - } + return result; + } - private static JsonNode Transform(AnnotatedRelationshipElementValue annotatedRelEleValue) - { - var result = new JsonObject(); + private static JsonNode Transform(AnnotatedRelationshipElementValue annotatedRelEleValue) + { + var result = new JsonObject(); - var annotations = new JsonArray(); - if (annotatedRelEleValue.annotations != null) + var annotations = new JsonArray(); + if (annotatedRelEleValue.annotations != null) + { + foreach (var elementObject in annotatedRelEleValue.annotations.Select(element => ToJsonObject(element))) { - foreach (var element in annotatedRelEleValue.annotations) - { - var elementObject = ToJsonObject(element); - annotations.Add(elementObject); - } + annotations.Add(elementObject); } + } + + var valueObject = new JsonObject + { + ["first"] = Transform(annotatedRelEleValue.first), + ["second"] = Transform(annotatedRelEleValue.second), + ["annotations"] = annotations + }; - var valueObject = new JsonObject(); - valueObject["first"] = Transform(annotatedRelEleValue.first); - valueObject["second"] = Transform(annotatedRelEleValue.second); - valueObject["annotations"] = annotations; + result[annotatedRelEleValue.idShort] = valueObject; - result[annotatedRelEleValue.idShort] = valueObject; + return result; + } + private static JsonNode Transform(SubmodelValue submodelValue) + { + var result = new JsonObject(); + if (submodelValue.submodelElements == null) + { return result; } - private static JsonNode Transform(SubmodelValue submodelValue) + foreach (var element in submodelValue.submodelElements) { - var result = new JsonObject(); - if (submodelValue.submodelElements != null) + var elementObject = ToJsonObject(element) as JsonObject; + foreach (var keyValue in elementObject) { - foreach (var element in submodelValue.submodelElements) - { - var elementObject = ToJsonObject(element) as JsonObject; - foreach (var keyValue in elementObject) - { - var valueString = keyValue.Value.ToJsonString(); - var valueNode = JsonSerializer.Deserialize(valueString); - result[keyValue.Key] = valueNode; - } - } + var valueString = keyValue.Value.ToJsonString(); + var valueNode = JsonSerializer.Deserialize(valueString); + result[keyValue.Key] = valueNode; } - - return result; } - private static JsonObject Transform(SubmodelElementListValue submodelElementListValue) - { - var result = new JsonObject(); + return result; + } + + private static JsonObject Transform(SubmodelElementListValue submodelElementListValue) + { + var result = new JsonObject(); - var valueArray = new JsonArray(); - if (submodelElementListValue.value != null) + var valueArray = new JsonArray(); + if (submodelElementListValue.value != null) + { + foreach (var valueNode in from element in submodelElementListValue.value + select ToJsonObject(element) as JsonObject + into elementObject + from keyValue in elementObject + select keyValue.Value.ToJsonString() + into valueString + select JsonSerializer.Deserialize(valueString)) { - foreach (var element in submodelElementListValue.value) - { - var elementObject = ToJsonObject(element) as JsonObject; - foreach (var keyValue in elementObject) - { - var valueString = keyValue.Value.ToJsonString(); - var valueNode = JsonSerializer.Deserialize(valueString); - valueArray.Add(valueNode); - } - } + valueArray.Add(valueNode); } + } - result[submodelElementListValue.idShort] = valueArray; + result[submodelElementListValue.idShort] = valueArray; - return result; - } + return result; + } - private static JsonObject Transform(SubmodelElementCollectionValue submodelElementCollectionValue) - { - var result = new JsonObject(); + private static JsonObject Transform(SubmodelElementCollectionValue submodelElementCollectionValue) + { + var result = new JsonObject(); - var valueObject = new JsonObject(); - if (submodelElementCollectionValue.value != null) + var valueObject = new JsonObject(); + if (submodelElementCollectionValue.value != null) + { + foreach (var element in submodelElementCollectionValue.value) { - foreach (var element in submodelElementCollectionValue.value) + var elementObject = ToJsonObject(element) as JsonObject; + foreach (var keyValue in elementObject) { - var elementObject = ToJsonObject(element) as JsonObject; - foreach (var keyValue in elementObject) - { - var valueString = keyValue.Value.ToJsonString(); - var valueNode = JsonSerializer.Deserialize(valueString); - valueObject[keyValue.Key] = valueNode; - } + var valueString = keyValue.Value.ToJsonString(); + var valueNode = JsonSerializer.Deserialize(valueString); + valueObject[keyValue.Key] = valueNode; } } - - result[submodelElementCollectionValue.idShort] = valueObject; - - return result; } - private static JsonObject Transform(RelationshipElementValue relationshipElementValue) - { - var result = new JsonObject(); - - var valueObject = new JsonObject(); - valueObject["first"] = Transform(relationshipElementValue.first); - valueObject["second"] = Transform(relationshipElementValue.second); + result[submodelElementCollectionValue.idShort] = valueObject; - result[relationshipElementValue.idShort] = valueObject; + return result; + } - return result; - } + private static JsonObject Transform(RelationshipElementValue relationshipElementValue) + { + var result = new JsonObject(); - private static JsonObject Transform(ReferenceElementValue referenceElementValue) + var valueObject = new JsonObject { - var result = new JsonObject(); + ["first"] = Transform(relationshipElementValue.first), + ["second"] = Transform(relationshipElementValue.second) + }; - result[referenceElementValue.idShort] = Transform(referenceElementValue.value); + result[relationshipElementValue.idShort] = valueObject; - return result; - } + return result; + } - private static JsonObject Transform(RangeValue rangeValue) + private static JsonObject Transform(ReferenceElementValue referenceElementValue) + { + var result = new JsonObject { - var result = new JsonObject(); + [referenceElementValue.idShort] = Transform(referenceElementValue.value) + }; - var valueObject = new JsonObject(); - valueObject["min"] = rangeValue.min; - valueObject["max"] = rangeValue.max; - - result[rangeValue.idShort] = valueObject; + return result; + } - return result; - } + private static JsonObject Transform(RangeValue rangeValue) + { + var result = new JsonObject(); - private static JsonObject Transform(FileValue fileValue) + var valueObject = new JsonObject { - var result = new JsonObject(); + ["min"] = rangeValue.min, + ["max"] = rangeValue.max + }; - var valueObject = new JsonObject(); - valueObject["contentType"] = fileValue.contentType; - valueObject["value"] = fileValue.value; + result[rangeValue.idShort] = valueObject; - result[fileValue.idShort] = valueObject; + return result; + } - return result; - } + private static JsonObject Transform(FileValue fileValue) + { + var result = new JsonObject(); - private static JsonObject Transform(BlobValue blobValue) + var valueObject = new JsonObject { - var result = new JsonObject(); + ["contentType"] = fileValue.contentType, + ["value"] = fileValue.value + }; - var valueObject = new JsonObject(); - valueObject["contentType"] = blobValue.contentType; - if (blobValue.value != null) - { - valueObject["value"] = JsonValue.Create(System.Convert.ToBase64String(blobValue.value)); - } + result[fileValue.idShort] = valueObject; - result[blobValue.idShort] = valueObject; + return result; + } - return result; - } + private static JsonObject Transform(BlobValue blobValue) + { + var result = new JsonObject(); - private static JsonObject Transform(BasicEventElementValue basicEventElementValue) + var valueObject = new JsonObject { - var result = new JsonObject(); + ["contentType"] = blobValue.contentType + }; + if (blobValue.value != null) + { + valueObject["value"] = JsonValue.Create(System.Convert.ToBase64String(blobValue.value)); + } - var valueObject = new JsonObject(); - valueObject["observed"] = Transform(basicEventElementValue.observed); + result[blobValue.idShort] = valueObject; - result[basicEventElementValue.idShort] = valueObject; + return result; + } - return result; - } + private static JsonObject Transform(BasicEventElementValue basicEventElementValue) + { + var result = new JsonObject(); - private static JsonNode Transform(ReferenceDTO that) + var valueObject = new JsonObject { - var result = new JsonObject(); + ["observed"] = Transform(basicEventElementValue.observed) + }; - result["type"] = Jsonization.Serialize.ReferenceTypesToJsonValue( - that.type); + result[basicEventElementValue.idShort] = valueObject; - if (that.referredSemanticId != null) - { - result["referredSemanticId"] = Transform( - that.referredSemanticId); - } + return result; + } - var arrayKeys = new JsonArray(); - foreach (KeyDTO item in that.keys) - { - arrayKeys.Add(Transform(item)); - } - result["keys"] = arrayKeys; + private static JsonNode Transform(ReferenceDTO that) + { + var result = new JsonObject + { + ["type"] = Jsonization.Serialize.ReferenceTypesToJsonValue( + that.type) + }; - return result; + if (that.referredSemanticId != null) + { + result["referredSemanticId"] = Transform( + that.referredSemanticId); } - private static JsonNode Transform(KeyDTO that) + var arrayKeys = new JsonArray(); + foreach (var item in that.keys) { - var result = new JsonObject(); - - result["type"] = Jsonization.Serialize.KeyTypesToJsonValue( - that.type); + arrayKeys.Add(Transform(item)); + } - result["value"] = JsonValue.Create( - that.value); + result["keys"] = arrayKeys; - return result; - } + return result; + } - private static JsonObject Transform(MultiLanguagePropertyValue multiLanguagePropertyValue) + private static JsonNode Transform(KeyDTO that) + { + var result = new JsonObject { - var result = new JsonObject(); + ["type"] = Jsonization.Serialize.KeyTypesToJsonValue( + that.type), + ["value"] = JsonValue.Create( + that.value) + }; + + return result; + } - var arrayLangStrings = new JsonArray(); - foreach (var item in multiLanguagePropertyValue.langStrings) + private static JsonObject Transform(MultiLanguagePropertyValue multiLanguagePropertyValue) + { + var result = new JsonObject(); + + var arrayLangStrings = new JsonArray(); + if (multiLanguagePropertyValue.langStrings != null) + foreach (var langNode in multiLanguagePropertyValue.langStrings.Select(item => new JsonObject + { + [item.Key] = item.Value + })) { - var langNode = new JsonObject(); - langNode[item.Key] = item.Value; arrayLangStrings.Add(langNode); } - result[multiLanguagePropertyValue.idShort] = arrayLangStrings; - return result; - } + result[multiLanguagePropertyValue.idShort] = arrayLangStrings; + return result; + } - private static JsonObject Transform(PropertyValue propertyValue) + private static JsonObject Transform(PropertyValue propertyValue) + { + var result = new JsonObject { - var result = new JsonObject(); - result[propertyValue.idShort] = propertyValue.value; - return result; - } + [propertyValue.idShort] = propertyValue.value + }; + return result; } -} +} \ No newline at end of file From c8a792687ab818ef8b6265aebe03950a44f87a3a Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 12 Apr 2024 14:55:19 +0200 Subject: [PATCH 03/18] add testclasses, but they don't work yet --- .../ValueOnlyJsonDeserializerTests.cs | 51 ++++++++++++++++ .../ValueOnlyJsonSerializerTests.cs | 60 ++++++++++++------- 2 files changed, 89 insertions(+), 22 deletions(-) create mode 100644 src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/ValueMappers/ValueOnlyJsonDeserializerTests.cs diff --git a/src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/ValueMappers/ValueOnlyJsonDeserializerTests.cs b/src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/ValueMappers/ValueOnlyJsonDeserializerTests.cs new file mode 100644 index 000000000..c0723990d --- /dev/null +++ b/src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/ValueMappers/ValueOnlyJsonDeserializerTests.cs @@ -0,0 +1,51 @@ +using System; +using System.Text.Json.Nodes; +using AasxServerStandardBib.Logging; +using AasxServerStandardBib.Services; +using AutoFixture; +using AutoFixture.Kernel; +using IO.Swagger.Lib.V3.SerializationModifiers.Mappers.ValueMappers; +using Moq; +using Xunit; + +namespace IO.Swagger.Lib.V3.Tests.SerializationModifiers.Mappers.ValueMappers +{ + public class ValueOnlyJsonDeserializerTests + { + private readonly Fixture _fixture; + private readonly ValueOnlyJsonDeserializer _deserializer; + + public ValueOnlyJsonDeserializerTests() + { + _fixture = new Fixture(); + _fixture.Behaviors.Remove(new ThrowingRecursionBehavior()); + _fixture.Behaviors.Add(new OmitOnRecursionBehavior()); + _fixture.Customizations.Add( + new TypeRelay( + typeof(AasxServerStandardBib.Interfaces.ISubmodelService), + typeof(SubmodelService))); + + // Mocking the IAppLogger interface + var mockLogger = new Mock>(); + _fixture.Inject(mockLogger.Object); + + _deserializer = _fixture.Create(); + } + + // Write your test methods here + [Fact (Skip = "untestable class")] + public void DeserializeSubmodelElementValue_WithNonNullNode_ShouldReturnNotNull() + { + // Arrange + var node = _fixture.Create(); + + // Act + var result = _deserializer.DeserializeSubmodelElementValue(node); + + // Assert + result.Should().NotBeNull(); + } + + // Add more test methods as needed + } +} \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/ValueMappers/ValueOnlyJsonSerializerTests.cs b/src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/ValueMappers/ValueOnlyJsonSerializerTests.cs index d95cdec6d..08681f804 100644 --- a/src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/ValueMappers/ValueOnlyJsonSerializerTests.cs +++ b/src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/ValueMappers/ValueOnlyJsonSerializerTests.cs @@ -2,32 +2,48 @@ using AutoFixture.Kernel; using DataTransferObjects.ValueDTOs; using IO.Swagger.Lib.V3.SerializationModifiers.Mappers.ValueMappers; +using Xunit; +using FluentAssertions; -namespace IO.Swagger.Lib.V3.Tests.SerializationModifiers.Mappers.ValueMappers; - -public class ValueOnlyJsonSerializerTests +namespace IO.Swagger.Lib.V3.Tests.SerializationModifiers.Mappers.ValueMappers { - private readonly Fixture _fixture; - - public ValueOnlyJsonSerializerTests() + public class ValueOnlyJsonSerializerTests { - _fixture = new Fixture(); - _fixture.Behaviors.Remove(new ThrowingRecursionBehavior()); - _fixture.Behaviors.Add(new OmitOnRecursionBehavior()); - _fixture.Customizations.Add(new TypeRelay(typeof(ISubmodelElementValue), typeof(EntityValue))); - } + private readonly Fixture _fixture; + + public ValueOnlyJsonSerializerTests() + { + _fixture = new Fixture(); + _fixture.Behaviors.Remove(new ThrowingRecursionBehavior()); + _fixture.Behaviors.Add(new OmitOnRecursionBehavior()); + _fixture.Customizations.Add(new TypeRelay(typeof(ISubmodelElementValue), typeof(EntityValue))); + _fixture.Customizations.Add(new TypeRelay(typeof(EntityValue), typeof(EntityValue))); + } - [Fact] - public void ToJsonObject_WithEntityValue_ShouldTransformCorrectly() - { - // Arrange - var entityValue = _fixture.Create(); + [Fact(Skip = "Only one is testable, the others will break. needs a refactored implementation class first.")] + public void ToJsonObject_WithEntityValue_ShouldTransformCorrectly() + { + // Arrange + var entityValue = _fixture.Create(); - // Act - var result = ValueOnlyJsonSerializer.ToJsonObject(entityValue); + // Act + var result = ValueOnlyJsonSerializer.ToJsonObject(entityValue); - // Assert - result.Should().NotBeNull(); + // Assert + result.Should().NotBeNull(); + } + + [Fact] + public void ToJsonObject_WithSubmodelValue_ShouldTransformCorrectly() + { + // Arrange + var submodelValue = _fixture.Create(); + + // Act + var result = ValueOnlyJsonSerializer.ToJsonObject(submodelValue); + + // Assert + result.Should().NotBeNull(); + } } - -} \ No newline at end of file +} From eae5096df1ff4567502b4776944333959a4ccd6c Mon Sep 17 00:00:00 2001 From: Oliver Date: Fri, 12 Apr 2024 15:57:58 +0200 Subject: [PATCH 04/18] extraction and add tests --- src/AasxServerBlazor/Startup.cs | 2 + .../ValueObjectParserTests.cs | 131 ++++++++ .../IValueOnlyJsonDeserializer.cs | 17 ++ .../JsonObjectParser/IValueObjectParser.cs | 20 ++ .../JsonObjectParser/ValueObjectParser.cs | 156 ++++++++++ .../ValueMappers/ValueOnlyJsonDeserializer.cs | 281 +++--------------- 6 files changed, 373 insertions(+), 234 deletions(-) create mode 100644 src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/ValueMappers/JsonObjectParser/ValueObjectParserTests.cs create mode 100644 src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/JsonObjectParser/IValueObjectParser.cs create mode 100644 src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/JsonObjectParser/ValueObjectParser.cs diff --git a/src/AasxServerBlazor/Startup.cs b/src/AasxServerBlazor/Startup.cs index 2cca49dfc..981492d68 100644 --- a/src/AasxServerBlazor/Startup.cs +++ b/src/AasxServerBlazor/Startup.cs @@ -32,6 +32,7 @@ using System; using System.Collections.Generic; using System.IO; +using IO.Swagger.Lib.V3.SerializationModifiers.Mappers.ValueMappers.JsonObjectParser; namespace AasxServerBlazor { @@ -109,6 +110,7 @@ public void ConfigureServices(IServiceCollection services) services.AddTransient(); services.AddTransient(); services.AddTransient(); + services.AddTransient(); services.AddTransient(); services.AddTransient(); services.AddTransient(); diff --git a/src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/ValueMappers/JsonObjectParser/ValueObjectParserTests.cs b/src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/ValueMappers/JsonObjectParser/ValueObjectParserTests.cs new file mode 100644 index 000000000..03517e737 --- /dev/null +++ b/src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/ValueMappers/JsonObjectParser/ValueObjectParserTests.cs @@ -0,0 +1,131 @@ +using System.Text; +using System.Text.Json.Nodes; +using AasxServerStandardBib.Interfaces; +using AutoFixture; +using AutoFixture.AutoMoq; +using DataTransferObjects.ValueDTOs; +using IO.Swagger.Lib.V3.Interfaces; +using IO.Swagger.Lib.V3.SerializationModifiers.Mappers.ValueMappers.JsonObjectParser; +using Moq; + +namespace IO.Swagger.Lib.V3.Tests.SerializationModifiers.Mappers.ValueMappers.JsonObjectParser; + +public class ValueObjectParserTests +{ + private readonly Fixture _fixture; + private readonly Mock _submodelServiceMock; + private readonly Mock _decoderServiceMock; + + public ValueObjectParserTests() + { + _fixture = new Fixture(); + var customization = new SupportMutableValueTypesCustomization(); + customization.Customize(_fixture); + _fixture.Customize(new AutoMoqCustomization()); + _submodelServiceMock = _fixture.Freeze>(); + _decoderServiceMock = _fixture.Freeze>(); + } + + [Fact] + public void Parse_WithRangeValue_ReturnsRangeValue() + { + // Arrange + var idShort = "range"; + var valueObject = new JsonObject(new Dictionary + { + ["min"] = "1", + ["max"] = "10" + }); + var parser = _fixture.Create(); + + // Act + var result = parser.Parse(idShort, valueObject, null, null); + + // Assert + result.Should().BeOfType(); + var rangeValue = (RangeValue) result; + rangeValue.idShort.Should().Be(idShort); + rangeValue.min.Should().Be("1"); + rangeValue.max.Should().Be("10"); + } + + [Fact] + public void Parse_WithBlobValue_ReturnsBlobValue() + { + // Arrange + const string idShort = "blob"; + const string base64String = "VGhpcyBpcyB0ZXN0IGJsb2IgdmFsaWQ="; // Valid Base64 string for "This is test blob valid" + + var valueObject = new JsonObject(new Dictionary + { + ["contentType"] = "image/jpeg", + ["value"] = base64String + }); + var parser = _fixture.Create(); + + // Act + var result = parser.Parse(idShort, valueObject, null, null); + + // Assert + result.Should().BeOfType(); + var blobValue = (BlobValue) result; + blobValue.idShort.Should().Be(idShort); + } + + + [Fact] + public void Parse_WithAnnotatedRelationshipElementValue_ReturnsAnnotatedRelationshipElementValue() + { + // Arrange + const string idShort = "annotated_relationship"; + var valueObject = new JsonObject(new Dictionary + { + ["annotations"] = new JsonArray(new JsonObject(), new JsonObject()), + ["first"] = new JsonObject(), + ["second"] = new JsonObject() + }); + var parser = _fixture.Create(); + + // Act + var result = parser.Parse(idShort, valueObject, null, null); + + // Assert + result.Should().BeOfType(); + } + + [Fact] + public void Parse_WithRelationshipElementValue_ReturnsRelationshipElementValue() + { + // Arrange + var idShort = "relationship"; + var valueObject = new JsonObject(new Dictionary + { + ["first"] = new JsonObject(), + ["second"] = new JsonObject() + }); + var parser = _fixture.Create(); + + // Act + var result = parser.Parse(idShort, valueObject, null, null); + + // Assert + result.Should().BeOfType(); + } + + [Fact] + public void Parse_WithReferenceElementValue_ReturnsReferenceElementValue() + { + // Arrange + const string idShort = "reference"; + var valueObject = new JsonObject(new Dictionary + { + }); + var parser = _fixture.Create(); + + // Act + var result = parser.Parse(idShort, valueObject, null, null); + + // Assert + result.Should().BeOfType(); + } +} \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/IValueOnlyJsonDeserializer.cs b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/IValueOnlyJsonDeserializer.cs index 1b807afb1..d8152afa2 100644 --- a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/IValueOnlyJsonDeserializer.cs +++ b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/IValueOnlyJsonDeserializer.cs @@ -3,8 +3,25 @@ namespace IO.Swagger.Lib.V3.SerializationModifiers.Mappers.ValueMappers; +/// +/// Interface for deserializing JSON nodes representing submodel elements and values. +/// public interface IValueOnlyJsonDeserializer { + /// + /// Deserialize a JSON node representing a submodel element value. + /// + /// The JSON node to deserialize. + /// The encoded identifier of the submodel, if applicable. + /// The path of the submodel element within the submodel, if applicable. + /// The deserialized submodel element value. IValueDTO DeserializeSubmodelElementValue(JsonNode node, string encodedSubmodelIdentifier = null, string idShortPath = null); + + /// + /// Deserialize a JSON node representing a submodel value. + /// + /// The JSON node to deserialize. + /// The encoded identifier of the submodel. + /// The deserialized submodel value. SubmodelValue DeserializeSubmodelValue(JsonNode node, string encodedSubmodelIdentifier); } \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/JsonObjectParser/IValueObjectParser.cs b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/JsonObjectParser/IValueObjectParser.cs new file mode 100644 index 000000000..d8db3e73a --- /dev/null +++ b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/JsonObjectParser/IValueObjectParser.cs @@ -0,0 +1,20 @@ +using System.Text.Json.Nodes; +using DataTransferObjects.ValueDTOs; + +namespace IO.Swagger.Lib.V3.SerializationModifiers.Mappers.ValueMappers.JsonObjectParser; + +/// +/// Interface for parsing JSON objects into value data transfer objects (DTOs). +/// +public interface IValueObjectParser +{ + /// + /// Parses a JSON object and returns the corresponding value DTO. + /// + /// The ID short of the value DTO. + /// The JSON object to parse. + /// The encoded submodel identifier. + /// The ID short path. + /// The parsed value DTO. + IValueDTO Parse(string idShort, JsonObject valueObject, string encodedSubmodelIdentifier, string idShortPath); +} diff --git a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/JsonObjectParser/ValueObjectParser.cs b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/JsonObjectParser/ValueObjectParser.cs new file mode 100644 index 000000000..a8a9c0047 --- /dev/null +++ b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/JsonObjectParser/ValueObjectParser.cs @@ -0,0 +1,156 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.Json; +using System.Text.Json.Nodes; +using AasxServerStandardBib.Interfaces; +using DataTransferObjects.CommonDTOs; +using DataTransferObjects.ValueDTOs; +using IO.Swagger.Lib.V3.Exceptions; +using IO.Swagger.Lib.V3.Interfaces; +using Newtonsoft.Json; + +namespace IO.Swagger.Lib.V3.SerializationModifiers.Mappers.ValueMappers.JsonObjectParser; + +/// +public class ValueObjectParser : IValueObjectParser +{ + private readonly ISubmodelService _submodelService; + private readonly IBase64UrlDecoderService _decoderService; + + /// + public ValueObjectParser(ISubmodelService submodelService, IBase64UrlDecoderService decoderService) + { + _submodelService = submodelService ?? throw new ArgumentNullException(nameof(submodelService)); + _decoderService = decoderService ?? throw new ArgumentNullException(nameof(submodelService)); + } + + /// + public IValueDTO Parse(string idShort, JsonObject valueObject, string encodedSubmodelIdentifier, string idShortPath) + { + if (valueObject == null) + throw new ArgumentNullException(nameof(valueObject)); + + if (valueObject.ContainsKey("min") && valueObject.ContainsKey("max")) + return CreateRangeValue(idShort, valueObject); + + if (valueObject.ContainsKey("contentType")) + return CreateBlobValue(idShort, valueObject); + + if (valueObject.ContainsKey("annotations") && valueObject.ContainsKey("first") && valueObject.ContainsKey("second")) + return CreateAnnotatedRelationshipElementValue(idShort, valueObject, encodedSubmodelIdentifier, idShortPath); + + if (valueObject.ContainsKey("first") && valueObject.ContainsKey("second")) + return CreateRelationshipElementValue(idShort, valueObject); + + if (valueObject.ContainsKey("type") && valueObject.ContainsKey("keys")) + return CreateReferenceElementValue(idShort, valueObject); + + if (valueObject.ContainsKey("entityType")) + return CreateEntityValue(idShort, valueObject, encodedSubmodelIdentifier, idShortPath); + + return valueObject.ContainsKey("observed") + ? CreateBasicEventElement(idShort, valueObject) + : CreateSubmodelElementCollectionValue(idShort, valueObject, encodedSubmodelIdentifier, idShortPath); + } + + private static IValueDTO CreateRangeValue(string idShort, JsonNode valueObject) + { + var min = valueObject["min"]?.ToString(); + var max = valueObject["max"]?.ToString(); + return new RangeValue(idShort, min, max); + } + + private static IValueDTO CreateBlobValue(string idShort, JsonNode valueObject) + { + if (valueObject["contentType"] is not JsonValue contentTypeNode) + throw new JsonDeserializationException(idShort, "ContentType missing"); + + var contentType = contentTypeNode.ToJsonString(); + if (valueObject["value"] is not JsonValue valueNode) + throw new JsonDeserializationException(idShort, "Value missing"); + + var value = Convert.FromBase64String(valueNode.ToString()); + return new BlobValue(idShort, contentType, value); + } + + private IValueDTO CreateAnnotatedRelationshipElementValue(string idShort, JsonNode valueObject, string encodedSubmodelIdentifier, string idShortPath) + { + var firstDto = GetReferenceDto(valueObject["first"]); + var secondDto = GetReferenceDto(valueObject["second"]); + + var annotations = new List(); + if (valueObject["annotations"] is JsonArray annotationsNode) + { + annotations.AddRange(annotationsNode.Select(annotationNode => DeserializeSubmodelElementValue(annotationNode, encodedSubmodelIdentifier, idShortPath)) + .Select(annotation => annotation as ISubmodelElementValue)); + } + + return new AnnotatedRelationshipElementValue(idShort, firstDto, secondDto, annotations); + } + + private static IValueDTO CreateRelationshipElementValue(string idShort, JsonNode valueObject) + { + var firstDto = GetReferenceDto(valueObject["first"]); + var secondDto = GetReferenceDto(valueObject["second"]); + return new RelationshipElementValue(idShort, firstDto, secondDto); + } + + private static IValueDTO CreateReferenceElementValue(string idShort, JsonNode valueObject) + { + var referenceDto = JsonConvert.DeserializeObject(valueObject.ToString()); + return new ReferenceElementValue(idShort, referenceDto); + } + + private IValueDTO CreateEntityValue(string idShort, JsonNode valueObject, string encodedSubmodelIdentifier, string idShortPath) + { + var entityType = valueObject["entityType"]?.ToString(); + var globalAssetId = valueObject["globalAssetId"]?.ToString(); + + var statements = new List(); + if (valueObject["statements"] is JsonObject statementsNode) + { + statements.AddRange(from item in statementsNode + let newNode = new JsonObject(new[] {KeyValuePair.Create(item.Key, JsonNode.Parse(item.Value.ToJsonString()))}) + let newIdShortPath = $"{idShortPath}.{item.Key}" + select DeserializeSubmodelElementValue(newNode, encodedSubmodelIdentifier, newIdShortPath) + into statement + select statement as ISubmodelElementValue); + } + + return new EntityValue(idShort, (EntityType) Stringification.EntityTypeFromString(entityType), statements, globalAssetId); + } + + private static IValueDTO CreateBasicEventElement(string idShort, JsonNode valueObject) + { + var observed = GetReferenceDto(valueObject["observed"]); + return new BasicEventElementValue(idShort, observed); + } + + private IValueDTO CreateSubmodelElementCollectionValue(string idShort, JsonObject valueObject, string encodedSubmodelIdentifier, string idShortPath) + { + var submodelElements = new List(); + + foreach (var item in valueObject) + { + var newNode = new JsonObject(new[] {KeyValuePair.Create(item.Key, JsonNode.Parse(item.Value.ToJsonString()))}); + idShortPath ??= idShort; + var newIdShortPath = $"{idShortPath}.{item.Key}"; + var submodelElement = DeserializeSubmodelElementValue(newNode, encodedSubmodelIdentifier, newIdShortPath); + submodelElements.Add(submodelElement as ISubmodelElementValue); + } + + return new SubmodelElementCollectionValue(idShort, submodelElements); + } + + private static ReferenceDTO GetReferenceDto(JsonNode node) + { + return node != null ? JsonConvert.DeserializeObject(node.ToString()) : null; + } + + private IValueDTO DeserializeSubmodelElementValue(JsonNode node, string encodedSubmodelIdentifier, string idShortPath = null) + { + var parser = new ValueObjectParser(_submodelService, _decoderService); + return parser.Parse(idShortPath, node as JsonObject, encodedSubmodelIdentifier, idShortPath); + } +} \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/ValueOnlyJsonDeserializer.cs b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/ValueOnlyJsonDeserializer.cs index 164c27d06..be5b33f81 100644 --- a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/ValueOnlyJsonDeserializer.cs +++ b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/ValueOnlyJsonDeserializer.cs @@ -1,27 +1,31 @@ using AasxServerStandardBib.Interfaces; -using DataTransferObjects.CommonDTOs; using DataTransferObjects.ValueDTOs; using IO.Swagger.Lib.V3.Exceptions; using IO.Swagger.Lib.V3.Interfaces; -using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Linq; using System.Text.Json.Nodes; +using IO.Swagger.Lib.V3.SerializationModifiers.Mappers.ValueMappers.JsonObjectParser; namespace IO.Swagger.Lib.V3.SerializationModifiers.Mappers.ValueMappers; +/// public class ValueOnlyJsonDeserializer : IValueOnlyJsonDeserializer { private readonly ISubmodelService _submodelService; private readonly IBase64UrlDecoderService _decoderService; + private readonly IValueObjectParser _valueObjectParser; - public ValueOnlyJsonDeserializer(ISubmodelService submodelService, IBase64UrlDecoderService decoderService) + /// + public ValueOnlyJsonDeserializer(ISubmodelService submodelService, IBase64UrlDecoderService decoderService, IValueObjectParser valueObjectParser) { _submodelService = submodelService ?? throw new ArgumentNullException(nameof(submodelService)); _decoderService = decoderService ?? throw new ArgumentNullException(nameof(submodelService)); + _valueObjectParser = valueObjectParser ?? throw new ArgumentNullException(nameof(valueObjectParser)); } + /// public IValueDTO DeserializeSubmodelElementValue(JsonNode node, string encodedSubmodelIdentifier = null, string idShortPath = null) { if (node == null) throw new ArgumentNullException(nameof(node)); @@ -43,71 +47,54 @@ public IValueDTO DeserializeSubmodelElementValue(JsonNode node, string encodedSu private IValueDTO Deserialize(string idShort, JsonNode value, string encodedSubmodelIdentifier, string idShortPath) { - IValueDTO output = null; - switch (value) + return value switch { - case JsonValue jsonValue: - { - //Property - jsonValue.TryGetValue(out string propertyValue); - output = new PropertyValue(idShort, propertyValue); - break; - } - case JsonObject valueObject: - { - output = ParseJsonValueObject(idShort, valueObject, encodedSubmodelIdentifier, idShortPath); - break; - } - case JsonArray valueArray: - { - output = ParseJsonValueArray(idShort, valueArray, encodedSubmodelIdentifier, idShortPath); - break; - } - default: - { - throw new InvalidOperationException(); - } - } - - return output; + JsonValue jsonValue => new PropertyValue(idShort, jsonValue.ToJsonString()), + JsonObject valueObject => ParseJsonValueObject(idShort, valueObject, encodedSubmodelIdentifier, idShortPath), + JsonArray valueArray => ParseJsonValueArray(idShort, valueArray, encodedSubmodelIdentifier, idShortPath), + _ => throw new InvalidOperationException() + }; } private IValueDTO ParseJsonValueArray(string idShort, JsonArray valueArray, string encodedSubmodelIdentifier, string idShortPath) { - //This is Multilingual Property or SMEList var decodedSubmodelId = _decoderService.Decode("submodelId", encodedSubmodelIdentifier); var element = _submodelService.GetSubmodelElementByPath(decodedSubmodelId, idShortPath); - if (element != null) + + if (element == null) { - return element switch - { - MultiLanguageProperty => CreateMultilanguagePropertyValue(idShort, valueArray), - SubmodelElementList smeList => CreateSubmodelElementList(idShort, valueArray, smeList, encodedSubmodelIdentifier, idShortPath), - _ => throw new JsonDeserializationException(idShort, "Element is neither MutlilanguageProperty nor SubmodelElementList") - }; + return null; } - return null; + return element switch + { + MultiLanguageProperty => CreateMultilanguagePropertyValue(idShort, valueArray), + SubmodelElementList smeList => CreateSubmodelElementList(idShort, valueArray, smeList, encodedSubmodelIdentifier, idShortPath), + _ => throw new JsonDeserializationException(idShort, "Element is neither MultilanguageProperty nor SubmodelElementList") + }; } private IValueDTO CreateSubmodelElementList(string idShort, JsonArray valueArray, SubmodelElementList smeList, string encodedSubmodelIdentifier, string idShortPath) { var value = valueArray.Select(element => Deserialize(null, element, encodedSubmodelIdentifier, idShortPath)) - .Select(elementValueDTO => (ISubmodelElementValue) elementValueDTO).ToList(); + .Select(elementValueDTO => (ISubmodelElementValue) elementValueDTO) + .ToList(); return new SubmodelElementListValue(idShort, value); } - private IValueDTO CreateMultilanguagePropertyValue(string idShort, JsonArray valueArray) + private static IValueDTO CreateMultilanguagePropertyValue(string idShort, JsonArray valueArray) { - var langStrings = new List>(); - - foreach (var item in valueArray) + var langStrings = valueArray.Select(item => { - if (item is not JsonObject jsonObject) continue; - GetPropertyFromJsonObject(jsonObject, out string propertyName, out string propertyValue); - langStrings.Add(new KeyValuePair(propertyName, propertyValue)); - } + if (item is not JsonObject jsonObject) + { + return default; + } + + GetPropertyFromJsonObject(jsonObject, out var propertyName, out var propertyValue); + return new KeyValuePair(propertyName, propertyValue); + }).ToList(); return new MultiLanguagePropertyValue(idShort, langStrings); } @@ -116,208 +103,34 @@ private static void GetPropertyFromJsonObject(JsonObject jsonObject, out string { propertyName = null; propertyValue = null; + foreach (var item in jsonObject) { propertyName = item.Key; - var jsonValue = item.Value as JsonValue; - jsonValue.TryGetValue(out propertyValue); - } - } - - private IValueDTO ParseJsonValueObject(string idShort, JsonObject valueObject, string encodedSubmodelIdentifier = null, string idShortPath = null) - { - if (valueObject == null) throw new ArgumentNullException($"{nameof(valueObject)}"); - if (valueObject.ContainsKey("min") && valueObject.ContainsKey("max")) - { - //Range - return CreateRangeValue(idShort, valueObject); - } - else if (valueObject.ContainsKey("contentType")) - { - //If it contains both contentType and Value, both File and Blob are possible. Hence, we need to retrieve actual elements from the server - var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", encodedSubmodelIdentifier); - idShortPath ??= idShort; - var submodelElement = _submodelService.GetSubmodelElementByPath(decodedSubmodelIdentifier, idShortPath); - if (submodelElement != null) + if (item.Value is JsonValue jsonValue) { - return submodelElement switch - { - File => CreateFileValue(idShort, valueObject), - Blob => CreateBlobValue(idShort, valueObject), - _ => throw new JsonDeserializationException(idShort, "Element is neither File nor Blob.") - }; + propertyValue = jsonValue.ToJsonString(); } } - else if (valueObject.ContainsKey("annotations") && valueObject.ContainsKey("first") && valueObject.ContainsKey("second")) - { - return CreateAnnotedRelationshipElementValue(idShort, valueObject, encodedSubmodelIdentifier, idShortPath); - } - else if (valueObject.ContainsKey("first") && valueObject.ContainsKey("second")) - { - return CreateRelationshipElementValue(idShort, valueObject); - } - else if (valueObject.ContainsKey("type") && valueObject.ContainsKey("keys")) - { - return CreateReferenceElementValue(idShort, valueObject); - } - else if (valueObject.ContainsKey("entityType")) - { - return CreateEntityValue(idShort, valueObject, encodedSubmodelIdentifier, idShortPath); - } - else if (valueObject.ContainsKey("observed")) - { - return CreateBasicEventElement(idShort, valueObject); - } - else - { - //This can be SubmodelElementCollection - return CreateSubmodelElementCollectionValue(idShort, valueObject, encodedSubmodelIdentifier, idShortPath); - } - - return null; } - private IValueDTO CreateSubmodelElementCollectionValue(string idShort, JsonObject valueObject, string encodedSubmodelIdentifier, string idShortPath) - { - var submodelElements = new List(); - - foreach (var item in valueObject) - { - var newNode = new JsonObject(new[] {KeyValuePair.Create(item.Key, JsonNode.Parse(item.Value.ToJsonString()))}); - if (idShortPath == null) - idShortPath = idShort; - var newIdShortPath = idShortPath + "." + item.Key; - var submodelElement = DeserializeSubmodelElementValue(newNode, encodedSubmodelIdentifier, newIdShortPath); - submodelElements.Add((ISubmodelElementValue) submodelElement); - } - - return new SubmodelElementCollectionValue(idShort, submodelElements); - } - - private static IValueDTO CreateBasicEventElement(string idShort, JsonNode valueObject) - { - ReferenceDTO observed = null; - if (valueObject["observed"] != null) - { - observed = JsonConvert.DeserializeObject(valueObject.ToString()); - } - - return new BasicEventElementValue(idShort, observed); - } - - private IValueDTO CreateEntityValue(string idShort, JsonNode valueObject, string encodedSubmodelIdentifier, string idShortPath) - { - string entityType = null; - string globalAssetId = null; - List statements = null; - - var entityTypeNode = valueObject["entityType"] as JsonValue; - entityTypeNode?.TryGetValue(out entityType); - - var globalAssetIdNode = valueObject["globalAssetId"] as JsonValue; - globalAssetIdNode?.TryGetValue(out globalAssetId); - - var statementsNode = valueObject["statements"] as JsonObject; - if (statementsNode != null) - { - statements = (from item in statementsNode - let newNode = new JsonObject(new[] {KeyValuePair.Create(item.Key, JsonNode.Parse(item.Value.ToJsonString()))}) - let newIdShortPath = idShortPath + "." + item.Key - select DeserializeSubmodelElementValue(newNode, encodedSubmodelIdentifier, newIdShortPath) - into statement - select (ISubmodelElementValue) statement).ToList(); - } - - return new EntityValue(idShort, (EntityType) Stringification.EntityTypeFromString(entityType), statements, globalAssetId); - } - - private static IValueDTO CreateReferenceElementValue(string idShort, JsonObject valueObject) - { - var referenceDTO = JsonConvert.DeserializeObject(valueObject.ToString()); - return new ReferenceElementValue(idShort, referenceDTO); - } - - private static IValueDTO CreateRelationshipElementValue(string idShort, JsonObject valueObject) + private IValueDTO ParseJsonValueObject(string idShort, JsonObject valueObject, string encodedSubmodelIdentifier = null, string idShortPath = null) { - ReferenceDTO firstDTO = null, secondDTO = null; - var firstNode = valueObject["first"]; - if (firstNode != null) - { - firstDTO = JsonConvert.DeserializeObject(firstNode.ToString()); - } - - var secondNode = valueObject["second"]; - if (secondNode != null) - { - secondDTO = JsonConvert.DeserializeObject(firstNode.ToString()); - } + if (valueObject == null) throw new ArgumentNullException($"{nameof(valueObject)}"); - return new RelationshipElementValue(idShort, firstDTO, secondDTO); + return _valueObjectParser.Parse(idShort, valueObject, encodedSubmodelIdentifier, idShortPath); } - private IValueDTO CreateAnnotedRelationshipElementValue(string idShort, JsonNode valueObject, string encodedSubmodelIdentifier, string idShortPath) + /// + public SubmodelValue DeserializeSubmodelValue(JsonNode node, string encodedSubmodelIdentifier) { - ReferenceDTO firstDTO = null, secondDTO = null; - var firstNode = valueObject["first"]; - if (firstNode != null) - { - firstDTO = JsonConvert.DeserializeObject(firstNode.ToString()); - } + if (node is not JsonObject jsonObject) throw new ArgumentException("Node must be a JsonObject", nameof(node)); - var secondNode = valueObject["second"]; - if (secondNode != null) + var submodelElements = jsonObject.Select(item => { - secondDTO = JsonConvert.DeserializeObject(firstNode.ToString()); - } - - var annotationsNode = valueObject["annotations"] as JsonArray; - if (annotationsNode == null) return new AnnotatedRelationshipElementValue(idShort, firstDTO, secondDTO); - var annotations = annotationsNode.Select(annotationNode => DeserializeSubmodelElementValue(annotationNode, encodedSubmodelIdentifier, idShortPath)) - .Select(annotation => (ISubmodelElementValue) annotation).ToList(); - return new AnnotatedRelationshipElementValue(idShort, firstDTO, secondDTO, annotations); - } - - private static IValueDTO CreateBlobValue(string idShort, JsonObject valueObject) - { - string contentType = null; - var contentTypeNode = valueObject["contentType"] as JsonValue; - contentTypeNode?.TryGetValue(out contentType); - - if (valueObject["value"] is not JsonValue valueNode) return new BlobValue(idShort, contentType); - valueNode.TryGetValue(out string value); - return new BlobValue(idShort, contentType, System.Convert.FromBase64String(value)); - } - - private IValueDTO CreateFileValue(string idShort, JsonNode valueObject) - { - string contentType = null, value = null; - var contentTypeNode = valueObject["contentType"] as JsonValue; - contentTypeNode?.TryGetValue(out contentType); - var valueNode = valueObject["value"] as JsonValue; - valueNode?.TryGetValue(out value); - return new FileValue(idShort, contentType, value); - } - - private static IValueDTO CreateRangeValue(string idShort, JsonNode valueObject) - { - string min = null, max = null; - var minNode = valueObject["min"] as JsonValue; - minNode?.TryGetValue(out min); - var maxNode = valueObject["max"] as JsonValue; - maxNode?.TryGetValue(out max); - - return new RangeValue(idShort, min, max); - } - - public SubmodelValue DeserializeSubmodelValue(JsonNode node, string encodedSubmodelIdentifier) - { - var jsonObject = node as JsonObject; - var submodelElements = (from item in jsonObject - select new JsonObject(new[] {KeyValuePair.Create(item.Key, JsonNode.Parse(item.Value.ToJsonString()))}) - into newNode - select DeserializeSubmodelElementValue(newNode, encodedSubmodelIdentifier) - into submodelElement - select (ISubmodelElementValue) submodelElement).ToList(); + var newNode = new JsonObject(new[] {KeyValuePair.Create(item.Key, JsonNode.Parse(item.Value.ToJsonString()))}); + return DeserializeSubmodelElementValue(newNode, encodedSubmodelIdentifier); + }).OfType().ToList(); return new SubmodelValue(submodelElements); } From 6bdd680d3d483e7f4cf75c4f1be7a5d1d4e78020 Mon Sep 17 00:00:00 2001 From: Oliver Fries Date: Mon, 15 Apr 2024 14:34:19 +0200 Subject: [PATCH 05/18] Fix naming and testing --- .../ValueOnlyJsonSerializerTests.cs | 4 ++-- .../Formatters/AasResponseFormatter.cs | 6 +++--- .../ValueMappers/IResponseValueTransformer.cs | 8 ++++++++ .../ValueMappers/IValueDtoSerializer.cs | 18 ++++++++++++++++++ .../ValueMappers/ResponseValueTransformer.cs | 1 + .../ValueMappers/ValueOnlyJsonSerializer.cs | 19 ++++++++++--------- 6 files changed, 42 insertions(+), 14 deletions(-) create mode 100644 src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/IValueDtoSerializer.cs diff --git a/src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/ValueMappers/ValueOnlyJsonSerializerTests.cs b/src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/ValueMappers/ValueOnlyJsonSerializerTests.cs index 08681f804..cad5c7563 100644 --- a/src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/ValueMappers/ValueOnlyJsonSerializerTests.cs +++ b/src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/ValueMappers/ValueOnlyJsonSerializerTests.cs @@ -27,7 +27,7 @@ public void ToJsonObject_WithEntityValue_ShouldTransformCorrectly() var entityValue = _fixture.Create(); // Act - var result = ValueOnlyJsonSerializer.ToJsonObject(entityValue); + var result = new ValueOnlyJsonSerializer().ToJsonObject(entityValue); // Assert result.Should().NotBeNull(); @@ -40,7 +40,7 @@ public void ToJsonObject_WithSubmodelValue_ShouldTransformCorrectly() var submodelValue = _fixture.Create(); // Act - var result = ValueOnlyJsonSerializer.ToJsonObject(submodelValue); + var result = new ValueOnlyJsonSerializer().ToJsonObject(submodelValue); // Assert result.Should().NotBeNull(); diff --git a/src/IO.Swagger.Lib.V3/Formatters/AasResponseFormatter.cs b/src/IO.Swagger.Lib.V3/Formatters/AasResponseFormatter.cs index f2d1589f7..e9260f5cf 100644 --- a/src/IO.Swagger.Lib.V3/Formatters/AasResponseFormatter.cs +++ b/src/IO.Swagger.Lib.V3/Formatters/AasResponseFormatter.cs @@ -126,7 +126,7 @@ public override Task WriteResponseBodyAsync(OutputFormatterWriteContext context) cursor = pagedResult.paging_metadata.cursor; foreach (var item in pagedResult.result) { - var json = ValueOnlyJsonSerializer.ToJsonObject(item); + var json = new ValueOnlyJsonSerializer().ToJsonObject(item); jsonArray.Add(json); } } @@ -144,7 +144,7 @@ public override Task WriteResponseBodyAsync(OutputFormatterWriteContext context) } else if (typeof(IValueDTO).IsAssignableFrom(context.ObjectType)) { - JsonNode json = ValueOnlyJsonSerializer.ToJsonObject((IValueDTO)context.Object); + JsonNode json = new ValueOnlyJsonSerializer().ToJsonObject((IValueDTO)context.Object); var writer = new Utf8JsonWriter(response.Body); json.WriteTo(writer); writer.FlushAsync().GetAwaiter().GetResult(); @@ -161,7 +161,7 @@ public override Task WriteResponseBodyAsync(OutputFormatterWriteContext context) foreach (var item in contextObjectType) { - var json = ValueOnlyJsonSerializer.ToJsonObject(item); + var json = new ValueOnlyJsonSerializer().ToJsonObject(item); jsonArray.Add(json); } var writer = new Utf8JsonWriter(response.Body); diff --git a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/IResponseValueTransformer.cs b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/IResponseValueTransformer.cs index fa80bcb7c..54f8e5205 100644 --- a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/IResponseValueTransformer.cs +++ b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/IResponseValueTransformer.cs @@ -2,7 +2,15 @@ namespace IO.Swagger.Lib.V3.SerializationModifiers.Mappers.ValueMappers; +/// +/// Represents a contract for transforming an instance into an instance. +/// public interface IResponseValueTransformer { + /// + /// Transforms the provided object into an instance. + /// + /// The source object to be transformed. + /// An instance of representing the transformed data. IDTO Transform(IClass source); } \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/IValueDtoSerializer.cs b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/IValueDtoSerializer.cs new file mode 100644 index 000000000..3a207a92d --- /dev/null +++ b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/IValueDtoSerializer.cs @@ -0,0 +1,18 @@ +using DataTransferObjects.CommonDTOs; +using System.Text.Json.Nodes; +using DataTransferObjects.ValueDTOs; + +namespace IO.Swagger.Lib.V3.SerializationModifiers.Mappers.ValueMappers; + +/// +/// Defines methods to serialize instances into JSON objects. +/// +public interface IValueOnlyJsonSerializer +{ + /// + /// Serializes the provided into a . + /// + /// The to serialize. + /// A representing the serialized . + JsonNode ToJsonObject(IValueDTO valueDto); +} \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/ResponseValueTransformer.cs b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/ResponseValueTransformer.cs index 6d3b67e9f..9359d11f1 100644 --- a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/ResponseValueTransformer.cs +++ b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/ResponseValueTransformer.cs @@ -8,6 +8,7 @@ namespace IO.Swagger.Lib.V3.SerializationModifiers.Mappers.ValueMappers; +/// internal class ResponseValueTransformer : ITransformer, IResponseValueTransformer { public IDTO Transform(IClass that) diff --git a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/ValueOnlyJsonSerializer.cs b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/ValueOnlyJsonSerializer.cs index dd145fafc..276a0cde5 100644 --- a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/ValueOnlyJsonSerializer.cs +++ b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/ValueOnlyJsonSerializer.cs @@ -7,13 +7,14 @@ namespace IO.Swagger.Lib.V3.SerializationModifiers.Mappers.ValueMappers; -public static class ValueOnlyJsonSerializer +/// +public class ValueOnlyJsonSerializer : IValueOnlyJsonSerializer { - internal static JsonNode ToJsonObject(IValueDTO that) + public JsonNode ToJsonObject(IValueDTO valueDto) { - return that switch + return valueDto switch { - null => throw new ArgumentNullException(nameof(that)), + null => throw new ArgumentNullException(nameof(valueDto)), PropertyValue propertyValue => Transform(propertyValue), MultiLanguagePropertyValue multiLanguagePropertyValue => Transform(multiLanguagePropertyValue), BasicEventElementValue basicEventElementValue => Transform(basicEventElementValue), @@ -31,7 +32,7 @@ internal static JsonNode ToJsonObject(IValueDTO that) }; } - private static JsonNode Transform(EntityValue entityValue) + private JsonNode Transform(EntityValue entityValue) { var result = new JsonObject(); @@ -60,7 +61,7 @@ private static JsonNode Transform(EntityValue entityValue) return result; } - private static JsonNode Transform(AnnotatedRelationshipElementValue annotatedRelEleValue) + private JsonNode Transform(AnnotatedRelationshipElementValue annotatedRelEleValue) { var result = new JsonObject(); @@ -85,7 +86,7 @@ private static JsonNode Transform(AnnotatedRelationshipElementValue annotatedRel return result; } - private static JsonNode Transform(SubmodelValue submodelValue) + private JsonNode Transform(SubmodelValue submodelValue) { var result = new JsonObject(); if (submodelValue.submodelElements == null) @@ -107,7 +108,7 @@ private static JsonNode Transform(SubmodelValue submodelValue) return result; } - private static JsonObject Transform(SubmodelElementListValue submodelElementListValue) + private JsonObject Transform(SubmodelElementListValue submodelElementListValue) { var result = new JsonObject(); @@ -131,7 +132,7 @@ select JsonSerializer.Deserialize(valueString)) return result; } - private static JsonObject Transform(SubmodelElementCollectionValue submodelElementCollectionValue) + private JsonObject Transform(SubmodelElementCollectionValue submodelElementCollectionValue) { var result = new JsonObject(); From e7801c564563ef6cc417e90a2cdcf7666b56e0bb Mon Sep 17 00:00:00 2001 From: Oliver Fries Date: Mon, 15 Apr 2024 15:05:37 +0200 Subject: [PATCH 06/18] build up for more tests --- .../Mappers/MappingServiceTests.cs | 33 +- .../ValueMappers/RequestValueMapperTests.cs | 4 +- .../ValueMappers/ResponseValueMapperTests.cs | 6 +- .../Mappers/MappingService.cs | 132 +++--- .../MetadataMappers/IRequestMetadataMapper.cs | 16 + .../IResponseMetadataMapper.cs | 16 + .../MetadataMappers/RequestMetadataMapper.cs | 419 ++++++++---------- .../MetadataMappers/ResponseMetadataMapper.cs | 11 +- .../ValueMappers/IRequestValueMapper.cs | 19 + .../ValueMappers/IResponseValueMapper.cs | 16 + .../ValueMappers/RequestValueMapper.cs | 22 +- .../ValueMappers/ResponseValueMapper.cs | 18 +- 12 files changed, 388 insertions(+), 324 deletions(-) create mode 100644 src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/MetadataMappers/IRequestMetadataMapper.cs create mode 100644 src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/MetadataMappers/IResponseMetadataMapper.cs create mode 100644 src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/IRequestValueMapper.cs create mode 100644 src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/IResponseValueMapper.cs diff --git a/src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/MappingServiceTests.cs b/src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/MappingServiceTests.cs index e3fc74e80..6b7a43d09 100644 --- a/src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/MappingServiceTests.cs +++ b/src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/MappingServiceTests.cs @@ -1,9 +1,6 @@ using AasCore.Aas3_0; using AutoFixture; -using DataTransferObjects; using DataTransferObjects.CommonDTOs; -using DataTransferObjects.MetadataDTOs; -using DataTransferObjects.ValueDTOs; using IO.Swagger.Lib.V3.SerializationModifiers.Mappers; using IO.Swagger.Lib.V3.SerializationModifiers.Mappers.MetadataMappers; using IO.Swagger.Lib.V3.SerializationModifiers.Mappers.ValueMappers; @@ -16,7 +13,13 @@ public class MappingServiceTests private readonly Fixture _fixture; private readonly Mock _administrativeInformationMock; private readonly Mock _administrativeInformationDTOMock; + private readonly MappingService _mappingService; + private readonly Mock _responseMetadataMapperMock; + private readonly Mock _responseValueMapperMock; + private readonly Mock _requestMetadataMapperMock; + private readonly Mock _requestValueMapperMock; + public MappingServiceTests() { _fixture = new Fixture(); @@ -24,7 +27,31 @@ public MappingServiceTests() _fixture.Behaviors.Add(new OmitOnRecursionBehavior()); _administrativeInformationMock = new Mock(); _administrativeInformationDTOMock = new Mock(); + + _responseMetadataMapperMock = new Mock(); + _responseValueMapperMock = new Mock(); + _requestMetadataMapperMock = new Mock(); + _requestValueMapperMock = new Mock(); + + _mappingService = new MappingService( + _responseMetadataMapperMock.Object, + _responseValueMapperMock.Object, + _requestMetadataMapperMock.Object, + _requestValueMapperMock.Object); } + [Fact] + public void Map_WithNullMappingResolverKey_ThrowsException() + { + // Arrange + string mappingResolverKey = null; + + // Act + Action act = () => _mappingService.Map(It.IsAny(), mappingResolverKey); + // Assert + act.Should().Throw().WithMessage("Could not resolve serializer modifier mapper."); + } + + //TODO: add more tests } \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/ValueMappers/RequestValueMapperTests.cs b/src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/ValueMappers/RequestValueMapperTests.cs index 35c9a0874..71526924d 100644 --- a/src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/ValueMappers/RequestValueMapperTests.cs +++ b/src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/ValueMappers/RequestValueMapperTests.cs @@ -24,7 +24,7 @@ public void Map_ShouldTransformBasicEventElementValue() var valueDTO = _fixture.Create(); // Act - var result = RequestValueMapper.Map(valueDTO); + var result = new RequestValueMapper().Map(valueDTO); // Assert result.Should().BeOfType(); @@ -38,7 +38,7 @@ public void Map_ShouldThrowExceptionForUnimplementedType() var valueDTO = _fixture.Create(); // Create a DTO of unimplemented type // Act - Action action = () => RequestValueMapper.Map((IValueDTO) valueDTO); + Action action = () => new RequestValueMapper().Map((IValueDTO) valueDTO); // Assert action.Should().Throw(); diff --git a/src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/ValueMappers/ResponseValueMapperTests.cs b/src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/ValueMappers/ResponseValueMapperTests.cs index 114c0b93f..b793ea2ef 100644 --- a/src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/ValueMappers/ResponseValueMapperTests.cs +++ b/src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/ValueMappers/ResponseValueMapperTests.cs @@ -29,7 +29,7 @@ public void Map_ShouldCallTransformMethod_WithProvidedSource() _transformerMock.Setup(t => t.Transform(source)).Returns(expectedDto); // Act - var result = ResponseValueMapper.Map(source); + var result = new ResponseValueMapper().Map(source); // Assert _transformerMock.Verify(t => t.Transform(source), Times.Once); @@ -45,7 +45,7 @@ public void Map_ShouldReturnNonNullValueDTO_WhenSourceIsProvided() _transformerMock.Setup(t => t.Transform(source)).Returns(dto); // Act - var result = ResponseValueMapper.Map(source); + var result = new ResponseValueMapper().Map(source); // Assert result.Should().NotBeNull(); @@ -58,7 +58,7 @@ public void Map_ShouldReturnNull_WhenSourceIsNull() IClass source = null; // Act - var result = ResponseValueMapper.Map(source); + var result = new ResponseValueMapper().Map(source); // Assert result.Should().BeNull(); diff --git a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/MappingService.cs b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/MappingService.cs index 7aad3edd1..a3f118a58 100644 --- a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/MappingService.cs +++ b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/MappingService.cs @@ -5,88 +5,88 @@ using IO.Swagger.Lib.V3.SerializationModifiers.Mappers.ValueMappers; using System; using System.Collections.Generic; +using System.Linq; -namespace IO.Swagger.Lib.V3.SerializationModifiers.Mappers +namespace IO.Swagger.Lib.V3.SerializationModifiers.Mappers; + +/// +public class MappingService : IMappingService { - public class MappingService : IMappingService + private readonly IResponseMetadataMapper _responseMetadataMapper; + private readonly IResponseValueMapper _responseValueMapper; + private readonly IRequestMetadataMapper _requestMetadataMapper; + private readonly IRequestValueMapper _requestValueMapper; + + public MappingService(IResponseMetadataMapper responseMetadataMapper, IResponseValueMapper responseValueMapper, IRequestMetadataMapper requestMetadataMapper, + IRequestValueMapper requestValueMapper) + { + _responseMetadataMapper = responseMetadataMapper; + _responseValueMapper = responseValueMapper; + _requestMetadataMapper = requestMetadataMapper; + _requestValueMapper = requestValueMapper; + } + + /// + public IDTO Map(IClass source, string mappingResolverKey) { - public IDTO Map(IClass source, string mappingResolverKey) + if (mappingResolverKey == null) { - if (mappingResolverKey == null) - { - throw new Exception($"Could not resolve serializer modifier mapper."); - } + throw new Exception($"Could not resolve serializer modifier mapper."); + } - if (mappingResolverKey.Equals("metadata", StringComparison.OrdinalIgnoreCase)) - { - return ResponseMetadataMapper.Map(source); - } - else if (mappingResolverKey.Equals("value", StringComparison.OrdinalIgnoreCase)) - { - return ResponseValueMapper.Map(source); - } - else - { - throw new Exception($"Invalid modifier mapping resolved key"); - } + if (mappingResolverKey.Equals("metadata", StringComparison.OrdinalIgnoreCase)) + { + return _responseMetadataMapper.Map(source); } - public List Map(List sourceList, string mappingResolverKey) + if (mappingResolverKey.Equals("value", StringComparison.OrdinalIgnoreCase)) { - if (mappingResolverKey == null) - { - throw new Exception($"Could not resolve serializer modifier mapper."); - } + //TODO: somehow it was never seen that this is an issue.... + return _requestValueMapper.Map(source); + } - if (mappingResolverKey.Equals("metadata", StringComparison.OrdinalIgnoreCase)) - { - var output = new List(); + throw new Exception("Invalid modifier mapping resolved key"); + } - foreach (var source in sourceList) - { - var dto = ResponseMetadataMapper.Map(source); - output.Add(dto); - } + /// + public List Map(List sourceList, string mappingResolverKey) + { + if (mappingResolverKey == null) + { + throw new Exception($"Could not resolve serializer modifier mapper."); + } - return output; - } - else if (mappingResolverKey.Equals("value", StringComparison.OrdinalIgnoreCase)) - { - var output = new List(); + if (mappingResolverKey.Equals("metadata", StringComparison.OrdinalIgnoreCase)) + { + return sourceList.Select(_responseMetadataMapper.Map).ToList(); + } + + if (mappingResolverKey.Equals("value", StringComparison.OrdinalIgnoreCase)) + { + return sourceList.Select(_responseValueMapper.Map).Cast().ToList(); + } - foreach (var source in sourceList) - { - var dto = ResponseValueMapper.Map(source); - output.Add(dto); - } + throw new Exception($"Invalid modifier mapping resolved key"); + } - return output; - } - else - { - throw new Exception($"Invalid modifier mapping resolved key"); - } + /// + public IClass Map(IDTO dto, string mappingResolverKey) + { + if (mappingResolverKey == null) + { + throw new Exception($"Could not resolve serializer modifier mapper."); } - public IClass Map(IDTO dto, string mappingResolverKey) + if (mappingResolverKey.Equals("metadata", StringComparison.OrdinalIgnoreCase) && dto is IMetadataDTO metadataDTO) { - if (mappingResolverKey == null) - { - throw new Exception($"Could not resolve serializer modifier mapper."); - } + return _requestMetadataMapper.Map(metadataDTO); + } - if (mappingResolverKey.Equals("metadata", StringComparison.OrdinalIgnoreCase) && dto is IMetadataDTO metadataDTO) - { - return RequestMetadataMapper.Map(metadataDTO); - } - else if (mappingResolverKey.Equals("value", StringComparison.OrdinalIgnoreCase) && dto is IValueDTO valueDTO) - { - return RequestValueMapper.Map(valueDTO); - } - else - { - throw new Exception($"Invalid modifier mapping resolved key"); - } + if (mappingResolverKey.Equals("value", StringComparison.OrdinalIgnoreCase) && dto is IValueDTO valueDTO) + { + return _requestValueMapper.Map(valueDTO); } + + throw new Exception($"Invalid modifier mapping resolved key"); } -} +} \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/MetadataMappers/IRequestMetadataMapper.cs b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/MetadataMappers/IRequestMetadataMapper.cs new file mode 100644 index 000000000..65d126e93 --- /dev/null +++ b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/MetadataMappers/IRequestMetadataMapper.cs @@ -0,0 +1,16 @@ +using DataTransferObjects.MetadataDTOs; + +namespace IO.Swagger.Lib.V3.SerializationModifiers.Mappers.MetadataMappers; + +/// +/// Provides functionality to map request metadata. +/// +public interface IRequestMetadataMapper +{ + /// + /// Maps a metadata DTO to an appropriate class. + /// + /// The metadata DTO to map. + /// The mapped class. + IClass Map(IMetadataDTO source); +} \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/MetadataMappers/IResponseMetadataMapper.cs b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/MetadataMappers/IResponseMetadataMapper.cs new file mode 100644 index 000000000..9a35ad221 --- /dev/null +++ b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/MetadataMappers/IResponseMetadataMapper.cs @@ -0,0 +1,16 @@ +using DataTransferObjects; + +namespace IO.Swagger.Lib.V3.SerializationModifiers.Mappers.MetadataMappers; + +/// +/// Represents a transformer for response metadata. +/// +public interface IResponseMetadataMapper +{ + /// + /// Transforms a source class to a DTO representing metadata. + /// + /// The source class to transform. + /// The transformed DTO representing metadata. + public IDTO Map(IClass source); +} \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/MetadataMappers/RequestMetadataMapper.cs b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/MetadataMappers/RequestMetadataMapper.cs index 41f058290..70cd42a6e 100644 --- a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/MetadataMappers/RequestMetadataMapper.cs +++ b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/MetadataMappers/RequestMetadataMapper.cs @@ -1,276 +1,237 @@ using DataTransferObjects.CommonDTOs; using DataTransferObjects.MetadataDTOs; using System.Collections.Generic; +using System.Linq; -namespace IO.Swagger.Lib.V3.SerializationModifiers.Mappers.MetadataMappers +namespace IO.Swagger.Lib.V3.SerializationModifiers.Mappers.MetadataMappers; + +/// +public class RequestMetadataMapper : IRequestMetadataMapper { - public static class RequestMetadataMapper + /// + public IClass Map(IMetadataDTO source) { - public static IClass Map(IMetadataDTO source) - { - if (source is PropertyMetadata propertyMetadata) - return Transform(propertyMetadata); - if (source is MultiLanguagePropertyMetadata multiLanguagePropertyMetadata) - return Transform(multiLanguagePropertyMetadata); - if (source is BasicEventElementMetadata basicEventElementMetadata) - return Transform(basicEventElementMetadata); - if (source is BlobMetadata blobMetadata) - return Transform(blobMetadata); - if (source is FileMetadata fileMetadata) - return Transform(fileMetadata); - if (source is RangeMetadata rangeMetadata) - return Transform(rangeMetadata); - if (source is ReferenceElementMetadata referenceElementMetadata) - return Transform(referenceElementMetadata); - if (source is RelationshipElementMetadata relationshipElementMetadata) - return Transform(relationshipElementMetadata); - if (source is SubmodelElementCollectionMetadata submodelElementCollectionMetadata) - return Transform(submodelElementCollectionMetadata); - if (source is SubmodelElementListMetadata submodelElementListMetadata) - return Transform(submodelElementListMetadata); - if (source is AnnotatedRelationshipElementMetadata annotationElementMetadata) - return Transform(annotationElementMetadata); - if (source is EntityMetadata entityMetadata) - return Transform(entityMetadata); - if (source is SubmodelMetadata submodelMetadata) - return Transform(submodelMetadata); - - return null; - } + return source switch + { + PropertyMetadata propertyMetadata => Transform(propertyMetadata), + MultiLanguagePropertyMetadata multiLanguagePropertyMetadata => Transform(multiLanguagePropertyMetadata), + BasicEventElementMetadata basicEventElementMetadata => Transform(basicEventElementMetadata), + BlobMetadata blobMetadata => Transform(blobMetadata), + FileMetadata fileMetadata => Transform(fileMetadata), + RangeMetadata rangeMetadata => Transform(rangeMetadata), + ReferenceElementMetadata referenceElementMetadata => Transform(referenceElementMetadata), + RelationshipElementMetadata relationshipElementMetadata => Transform(relationshipElementMetadata), + SubmodelElementCollectionMetadata submodelElementCollectionMetadata => Transform(submodelElementCollectionMetadata), + SubmodelElementListMetadata submodelElementListMetadata => Transform(submodelElementListMetadata), + AnnotatedRelationshipElementMetadata annotationElementMetadata => Transform(annotationElementMetadata), + EntityMetadata entityMetadata => Transform(entityMetadata), + SubmodelMetadata submodelMetadata => Transform(submodelMetadata), + _ => null + }; + } - private static ISubmodel Transform(SubmodelMetadata metadata) + private ISubmodel Transform(SubmodelMetadata metadata) + { + List submodelElements = null; + if (metadata.submodelElements != null) { - List submodelElements = null; - if (metadata.submodelElements != null) - { - submodelElements = new List(); - foreach (var element in metadata.submodelElements) - { - submodelElements.Add((ISubmodelElement)Map(element)); - } - } - return new Submodel(metadata.id, TransformExtensions(metadata.extensions), metadata.category, metadata.idShort, TransformLangStringNameTypeList(metadata.displayName), TransformLangStringTextTypeList(metadata.description), TransformAdministrationInformation(metadata.administration), metadata.kind, TransformReference(metadata.semanticId), TransformReferenceList(metadata.supplementalSemanticIds), TransformQualifierList(metadata.qualifiers), TransformEmbeddedDataSpecList(metadata.embeddedDataSpecifications), submodelElements); + submodelElements = metadata.submodelElements.Select(element => (ISubmodelElement) Map(element)).ToList(); } + return new Submodel(metadata.id, TransformExtensions(metadata.extensions), metadata.category, metadata.idShort, TransformLangStringNameTypeList(metadata.displayName), + TransformLangStringTextTypeList(metadata.description), TransformAdministrationInformation(metadata.administration), metadata.kind, + TransformReference(metadata.semanticId), TransformReferenceList(metadata.supplementalSemanticIds), TransformQualifierList(metadata.qualifiers), + TransformEmbeddedDataSpecList(metadata.embeddedDataSpecifications), submodelElements); + } - private static IEntity Transform(EntityMetadata metadata) + private IEntity Transform(EntityMetadata metadata) + { + List statements = null; + if (metadata.statements != null) { - List statements = null; - if (metadata.statements != null) - { - statements = new List(); - foreach (var element in metadata.statements) - { - statements.Add((ISubmodelElement)Map(element)); - } - } - return new Entity(metadata.entityType, TransformExtensions(metadata.extensions), metadata.category, metadata.idShort, TransformLangStringNameTypeList(metadata.displayName), TransformLangStringTextTypeList(metadata.description), TransformReference(metadata.semanticId), TransformReferenceList(metadata.supplementalSemanticIds), TransformQualifierList(metadata.qualifiers), TransformEmbeddedDataSpecList(metadata.embeddedDataSpecifications), statements); + statements = metadata.statements.Select(element => (ISubmodelElement) Map(element)).ToList(); } - private static IAnnotatedRelationshipElement Transform(AnnotatedRelationshipElementMetadata metadata) - { - List annotations = null; - if (metadata.annotations != null) - { - annotations = new List(); - foreach (var element in metadata.annotations) - { - annotations.Add((IDataElement)Map(element)); - } - } - return new AnnotatedRelationshipElement(null, null, TransformExtensions(metadata.extensions), metadata.category, metadata.idShort, TransformLangStringNameTypeList(metadata.displayName), TransformLangStringTextTypeList(metadata.description), TransformReference(metadata.semanticId), TransformReferenceList(metadata.supplementalSemanticIds), TransformQualifierList(metadata.qualifiers), TransformEmbeddedDataSpecList(metadata.embeddedDataSpecifications), annotations); - } + return new Entity(metadata.entityType, TransformExtensions(metadata.extensions), metadata.category, metadata.idShort, TransformLangStringNameTypeList(metadata.displayName), + TransformLangStringTextTypeList(metadata.description), TransformReference(metadata.semanticId), TransformReferenceList(metadata.supplementalSemanticIds), + TransformQualifierList(metadata.qualifiers), TransformEmbeddedDataSpecList(metadata.embeddedDataSpecifications), statements); + } - private static ISubmodelElementList Transform(SubmodelElementListMetadata metadata) + private IAnnotatedRelationshipElement Transform(AnnotatedRelationshipElementMetadata metadata) + { + List annotations = null; + if (metadata.annotations != null) { - List value = null; - if (metadata.value != null) - { - value = new List(); - foreach (var element in metadata.value) - { - value.Add((ISubmodelElement)Map(element)); - } - } - return new SubmodelElementList(metadata.typeValueListElement, TransformExtensions(metadata.extensions), metadata.category, metadata.idShort, TransformLangStringNameTypeList(metadata.displayName), TransformLangStringTextTypeList(metadata.description), TransformReference(metadata.semanticId), TransformReferenceList(metadata.supplementalSemanticIds), TransformQualifierList(metadata.qualifiers), TransformEmbeddedDataSpecList(metadata.embeddedDataSpecifications), metadata.orderRelevant, TransformReference(metadata.semanticIdListElement), metadata.valueTypeListElement, value); + annotations = metadata.annotations.Select(element => (IDataElement) Map(element)).ToList(); } - private static ISubmodelElementCollection Transform(SubmodelElementCollectionMetadata metadata) - { - List value = null; - if (metadata.value != null) - { - value = new List(); - foreach (var element in metadata.value) - { - value.Add((ISubmodelElement)Map(element)); - } - } - return new SubmodelElementCollection(TransformExtensions(metadata.extensions), metadata.category, metadata.idShort, TransformLangStringNameTypeList(metadata.displayName), TransformLangStringTextTypeList(metadata.description), TransformReference(metadata.semanticId), TransformReferenceList(metadata.supplementalSemanticIds), TransformQualifierList(metadata.qualifiers), TransformEmbeddedDataSpecList(metadata.embeddedDataSpecifications), value); - } + return new AnnotatedRelationshipElement(null, null, TransformExtensions(metadata.extensions), metadata.category, metadata.idShort, + TransformLangStringNameTypeList(metadata.displayName), TransformLangStringTextTypeList(metadata.description), TransformReference(metadata.semanticId), + TransformReferenceList(metadata.supplementalSemanticIds), TransformQualifierList(metadata.qualifiers), + TransformEmbeddedDataSpecList(metadata.embeddedDataSpecifications), annotations); + } - private static IRelationshipElement Transform(RelationshipElementMetadata metadata) + private ISubmodelElementList Transform(SubmodelElementListMetadata metadata) + { + List value = null; + if (metadata.value != null) { - return new RelationshipElement(null, null, TransformExtensions(metadata.extensions), metadata.category, metadata.idShort, TransformLangStringNameTypeList(metadata.displayName), TransformLangStringTextTypeList(metadata.description), TransformReference(metadata.semanticId), TransformReferenceList(metadata.supplementalSemanticIds), TransformQualifierList(metadata.qualifiers), TransformEmbeddedDataSpecList(metadata.embeddedDataSpecifications)); + value = metadata.value.Select(element => (ISubmodelElement) Map(element)).ToList(); } - private static IReferenceElement Transform(ReferenceElementMetadata metadata) - { - return new ReferenceElement(TransformExtensions(metadata.extensions), metadata.category, metadata.idShort, TransformLangStringNameTypeList(metadata.displayName), TransformLangStringTextTypeList(metadata.description), TransformReference(metadata.semanticId), TransformReferenceList(metadata.supplementalSemanticIds), TransformQualifierList(metadata.qualifiers), TransformEmbeddedDataSpecList(metadata.embeddedDataSpecifications)); - } + return new SubmodelElementList(metadata.typeValueListElement, TransformExtensions(metadata.extensions), metadata.category, metadata.idShort, + TransformLangStringNameTypeList(metadata.displayName), TransformLangStringTextTypeList(metadata.description), TransformReference(metadata.semanticId), + TransformReferenceList(metadata.supplementalSemanticIds), TransformQualifierList(metadata.qualifiers), + TransformEmbeddedDataSpecList(metadata.embeddedDataSpecifications), metadata.orderRelevant, TransformReference(metadata.semanticIdListElement), + metadata.valueTypeListElement, value); + } - private static IRange Transform(RangeMetadata metadata) + private ISubmodelElementCollection Transform(SubmodelElementCollectionMetadata metadata) + { + List value = null; + if (metadata.value != null) { - return new AasCore.Aas3_0.Range(metadata.valueType, TransformExtensions(metadata.extensions), metadata.category, metadata.idShort, TransformLangStringNameTypeList(metadata.displayName), TransformLangStringTextTypeList(metadata.description), TransformReference(metadata.semanticId), TransformReferenceList(metadata.supplementalSemanticIds), TransformQualifierList(metadata.qualifiers), TransformEmbeddedDataSpecList(metadata.embeddedDataSpecifications)); + value = metadata.value.Select(element => (ISubmodelElement) Map(element)).ToList(); } - private static IFile Transform(FileMetadata metadata) - { - return new File(null, TransformExtensions(metadata.extensions), metadata.category, metadata.idShort, TransformLangStringNameTypeList(metadata.displayName), TransformLangStringTextTypeList(metadata.description), TransformReference(metadata.semanticId), TransformReferenceList(metadata.supplementalSemanticIds), TransformQualifierList(metadata.qualifiers), TransformEmbeddedDataSpecList(metadata.embeddedDataSpecifications)); - } + return new SubmodelElementCollection(TransformExtensions(metadata.extensions), metadata.category, metadata.idShort, TransformLangStringNameTypeList(metadata.displayName), + TransformLangStringTextTypeList(metadata.description), TransformReference(metadata.semanticId), TransformReferenceList(metadata.supplementalSemanticIds), + TransformQualifierList(metadata.qualifiers), TransformEmbeddedDataSpecList(metadata.embeddedDataSpecifications), value); + } - private static IBlob Transform(BlobMetadata metadata) - { - return new Blob(null, TransformExtensions(metadata.extensions), metadata.category, metadata.idShort, TransformLangStringNameTypeList(metadata.displayName), TransformLangStringTextTypeList(metadata.description), TransformReference(metadata.semanticId), TransformReferenceList(metadata.supplementalSemanticIds), TransformQualifierList(metadata.qualifiers), TransformEmbeddedDataSpecList(metadata.embeddedDataSpecifications)); - } + private static IRelationshipElement Transform(RelationshipElementMetadata metadata) + { + return new RelationshipElement(null, null, TransformExtensions(metadata.extensions), metadata.category, metadata.idShort, + TransformLangStringNameTypeList(metadata.displayName), TransformLangStringTextTypeList(metadata.description), TransformReference(metadata.semanticId), + TransformReferenceList(metadata.supplementalSemanticIds), TransformQualifierList(metadata.qualifiers), + TransformEmbeddedDataSpecList(metadata.embeddedDataSpecifications)); + } - private static IBasicEventElement Transform(BasicEventElementMetadata metadata) - { - return new BasicEventElement(null, metadata.direction, metadata.state, TransformExtensions(metadata.extensions), metadata.category, metadata.idShort, TransformLangStringNameTypeList(metadata.displayName), TransformLangStringTextTypeList(metadata.description), TransformReference(metadata.semanticId), TransformReferenceList(metadata.supplementalSemanticIds), TransformQualifierList(metadata.qualifiers), TransformEmbeddedDataSpecList(metadata.embeddedDataSpecifications), metadata.messageTopic, TransformReference(metadata.messageBroker), metadata.lastUpdate, metadata.minInterval, metadata.maxInterval); - } + private static IReferenceElement Transform(ReferenceElementMetadata metadata) + { + return new ReferenceElement(TransformExtensions(metadata.extensions), metadata.category, metadata.idShort, TransformLangStringNameTypeList(metadata.displayName), + TransformLangStringTextTypeList(metadata.description), TransformReference(metadata.semanticId), TransformReferenceList(metadata.supplementalSemanticIds), + TransformQualifierList(metadata.qualifiers), TransformEmbeddedDataSpecList(metadata.embeddedDataSpecifications)); + } - private static IMultiLanguageProperty Transform(MultiLanguagePropertyMetadata multiLanguagePropertyMetadata) - { - return new MultiLanguageProperty(TransformExtensions(multiLanguagePropertyMetadata.extensions), multiLanguagePropertyMetadata.category, multiLanguagePropertyMetadata.idShort, TransformLangStringNameTypeList(multiLanguagePropertyMetadata.displayName), TransformLangStringTextTypeList(multiLanguagePropertyMetadata.description), TransformReference(multiLanguagePropertyMetadata.semanticId), TransformReferenceList(multiLanguagePropertyMetadata.supplementalSemanticIds), TransformQualifierList(multiLanguagePropertyMetadata.qualifiers), TransformEmbeddedDataSpecList(multiLanguagePropertyMetadata.embeddedDataSpecifications)); - } + private static IRange Transform(RangeMetadata metadata) + { + return new Range(metadata.valueType, TransformExtensions(metadata.extensions), metadata.category, metadata.idShort, + TransformLangStringNameTypeList(metadata.displayName), TransformLangStringTextTypeList(metadata.description), TransformReference(metadata.semanticId), + TransformReferenceList(metadata.supplementalSemanticIds), TransformQualifierList(metadata.qualifiers), + TransformEmbeddedDataSpecList(metadata.embeddedDataSpecifications)); + } - private static IProperty Transform(PropertyMetadata propertyMetadata) - { - return new Property(propertyMetadata.valueType, TransformExtensions(propertyMetadata.extensions), propertyMetadata.category, propertyMetadata.idShort, TransformLangStringNameTypeList(propertyMetadata.displayName), TransformLangStringTextTypeList(propertyMetadata.description), TransformReference(propertyMetadata.semanticId), TransformReferenceList(propertyMetadata.supplementalSemanticIds), TransformQualifierList(propertyMetadata.qualifiers), TransformEmbeddedDataSpecList(propertyMetadata.embeddedDataSpecifications)); - } + private static IFile Transform(FileMetadata metadata) + { + return new File(null, TransformExtensions(metadata.extensions), metadata.category, metadata.idShort, TransformLangStringNameTypeList(metadata.displayName), + TransformLangStringTextTypeList(metadata.description), TransformReference(metadata.semanticId), TransformReferenceList(metadata.supplementalSemanticIds), + TransformQualifierList(metadata.qualifiers), TransformEmbeddedDataSpecList(metadata.embeddedDataSpecifications)); + } - private static List TransformLangStringNameTypeList(List langStringNameTypeList) - { - if (langStringNameTypeList == null) return null; - var result = new List(); - foreach (var langString in langStringNameTypeList) - { - result.Add(TransformLangStringNameType(langString)); - } - - return result; - } + private static IBlob Transform(BlobMetadata metadata) + { + return new Blob(null, TransformExtensions(metadata.extensions), metadata.category, metadata.idShort, TransformLangStringNameTypeList(metadata.displayName), + TransformLangStringTextTypeList(metadata.description), TransformReference(metadata.semanticId), TransformReferenceList(metadata.supplementalSemanticIds), + TransformQualifierList(metadata.qualifiers), TransformEmbeddedDataSpecList(metadata.embeddedDataSpecifications)); + } - private static ILangStringNameType TransformLangStringNameType(LangStringNameTypeDTO langString) - { - return new LangStringNameType(langString.language, langString.text); - } + private static IBasicEventElement Transform(BasicEventElementMetadata metadata) + { + return new BasicEventElement(null, metadata.direction, metadata.state, TransformExtensions(metadata.extensions), metadata.category, metadata.idShort, + TransformLangStringNameTypeList(metadata.displayName), TransformLangStringTextTypeList(metadata.description), TransformReference(metadata.semanticId), + TransformReferenceList(metadata.supplementalSemanticIds), TransformQualifierList(metadata.qualifiers), + TransformEmbeddedDataSpecList(metadata.embeddedDataSpecifications), metadata.messageTopic, TransformReference(metadata.messageBroker), metadata.lastUpdate, + metadata.minInterval, metadata.maxInterval); + } - private static List TransformLangStringTextTypeList(List langStringTextTypeList) - { - if (langStringTextTypeList == null) return null; - var result = new List(); - foreach (var langString in langStringTextTypeList) - { - result.Add(TransformLangStringTextType(langString)); - } - - return result; - } + private static IMultiLanguageProperty Transform(MultiLanguagePropertyMetadata multiLanguagePropertyMetadata) + { + return new MultiLanguageProperty(TransformExtensions(multiLanguagePropertyMetadata.extensions), multiLanguagePropertyMetadata.category, + multiLanguagePropertyMetadata.idShort, TransformLangStringNameTypeList(multiLanguagePropertyMetadata.displayName), + TransformLangStringTextTypeList(multiLanguagePropertyMetadata.description), TransformReference(multiLanguagePropertyMetadata.semanticId), + TransformReferenceList(multiLanguagePropertyMetadata.supplementalSemanticIds), TransformQualifierList(multiLanguagePropertyMetadata.qualifiers), + TransformEmbeddedDataSpecList(multiLanguagePropertyMetadata.embeddedDataSpecifications)); + } - private static ILangStringTextType TransformLangStringTextType(LangStringTextTypeDTO langString) - { - return new LangStringTextType(langString.language, langString.text); - } + private static IProperty Transform(PropertyMetadata propertyMetadata) + { + return new Property(propertyMetadata.valueType, TransformExtensions(propertyMetadata.extensions), propertyMetadata.category, propertyMetadata.idShort, + TransformLangStringNameTypeList(propertyMetadata.displayName), TransformLangStringTextTypeList(propertyMetadata.description), + TransformReference(propertyMetadata.semanticId), TransformReferenceList(propertyMetadata.supplementalSemanticIds), TransformQualifierList(propertyMetadata.qualifiers), + TransformEmbeddedDataSpecList(propertyMetadata.embeddedDataSpecifications)); + } - private static List TransformExtensions(List extensions) - { - if (extensions == null) - return null; - var result = new List(); - foreach (var extension in extensions) - { - result.Add(new Extension(extension.name, TransformReference(extension.semanticId), TransformReferenceList(extension.supplementalSemanticIds), extension.valueType, extension.value)); - } - - return result; - } + private static List TransformLangStringNameTypeList(IEnumerable langStringNameTypeList) + { + return langStringNameTypeList?.Select(TransformLangStringNameType).ToList(); + } - private static List TransformReferenceList(List references) - { - if (references == null) return null; - var result = new List(); - foreach (var reference in references) - { - result.Add(TransformReference(reference)); - } - - return result; - } + private static ILangStringNameType TransformLangStringNameType(LangStringNameTypeDTO langString) + { + return new LangStringNameType(langString.language, langString.text); + } - private static IReference TransformReference(ReferenceDTO referenceDTO) - { - if (referenceDTO == null) - return null; - return new Reference(referenceDTO.type, TransformKeys(referenceDTO.keys), TransformReference(referenceDTO.referredSemanticId)); - } + private static List TransformLangStringTextTypeList(IEnumerable langStringTextTypeList) + { + return langStringTextTypeList?.Select(TransformLangStringTextType).ToList(); + } - private static List TransformKeys(List keys) - { - if (keys == null) return null; + private static ILangStringTextType TransformLangStringTextType(LangStringTextTypeDTO langString) + { + return new LangStringTextType(langString.language, langString.text); + } - var result = new List(); - foreach (var key in keys) - { - result.Add(new Key(key.type, key.value)); - } + private static List TransformExtensions(IEnumerable extensions) + { + return extensions?.Select(extension => new Extension(extension.name, TransformReference(extension.semanticId), TransformReferenceList(extension.supplementalSemanticIds), + extension.valueType, extension.value)).Cast().ToList(); + } - return result; - } + private static List TransformReferenceList(IEnumerable references) + { + return references?.Select(TransformReference).ToList(); + } - private static List TransformQualifierList(List qualifiers) - { - if (qualifiers == null) return null; - var result = new List(); - foreach (var qualifier in qualifiers) - { - result.Add(TransformQualifier(qualifier)); - } - - return result; - } + private static IReference TransformReference(ReferenceDTO referenceDTO) + { + return referenceDTO == null ? null : new Reference(referenceDTO.type, TransformKeys(referenceDTO.keys), TransformReference(referenceDTO.referredSemanticId)); + } - private static IQualifier TransformQualifier(QualifierDTO qualifierDTO) - { - if (qualifierDTO == null) - return null; - return new Qualifier(qualifierDTO.type, qualifierDTO.valueType, TransformReference(qualifierDTO.semanticId), TransformReferenceList(qualifierDTO.supplementalSemanticIds), qualifierDTO.kind, qualifierDTO.value, TransformReference(qualifierDTO.valueId)); - } + private static List TransformKeys(IEnumerable keys) + { + return keys?.Select(key => new Key(key.type, key.value)).Cast().ToList(); + } - private static List TransformEmbeddedDataSpecList(List embeddedDataSpecifications) - { - if (embeddedDataSpecifications == null) return null; - var result = new List(); - foreach (var embDataSpec in embeddedDataSpecifications) - { - result.Add(TransformEmbeddedDataSpecification(embDataSpec)); - } - - return result; - } + private static List TransformQualifierList(IEnumerable qualifiers) + { + return qualifiers?.Select(TransformQualifier).ToList(); + } - private static IEmbeddedDataSpecification TransformEmbeddedDataSpecification(EmbeddedDataSpecificationDTO embDataSpecDTO) - { - if (embDataSpecDTO == null) - return null; - return new EmbeddedDataSpecification(TransformReference(embDataSpecDTO.dataSpecification), null); - } + private static IQualifier TransformQualifier(QualifierDTO qualifierDTO) + { + return qualifierDTO == null + ? null + : new Qualifier(qualifierDTO.type, qualifierDTO.valueType, TransformReference(qualifierDTO.semanticId), TransformReferenceList(qualifierDTO.supplementalSemanticIds), + qualifierDTO.kind, qualifierDTO.value, TransformReference(qualifierDTO.valueId)); + } - private static IAdministrativeInformation TransformAdministrationInformation(AdministrativeInformationDTO metadata) - { - if (metadata == null) return null; - return new AdministrativeInformation(TransformEmbeddedDataSpecList(metadata.embeddedDataSpecifications), metadata.version, metadata.revision, TransformReference(metadata.creator), metadata.templateId); - } + private static List TransformEmbeddedDataSpecList(IEnumerable embeddedDataSpecifications) + { + return embeddedDataSpecifications?.Select(TransformEmbeddedDataSpecification).ToList(); + } + + private static IEmbeddedDataSpecification TransformEmbeddedDataSpecification(EmbeddedDataSpecificationDTO embDataSpecDTO) + { + return embDataSpecDTO == null ? null : new EmbeddedDataSpecification(TransformReference(embDataSpecDTO.dataSpecification), null); + } + + private static IAdministrativeInformation TransformAdministrationInformation(AdministrativeInformationDTO metadata) + { + return metadata == null + ? null + : new AdministrativeInformation(TransformEmbeddedDataSpecList(metadata.embeddedDataSpecifications), metadata.version, metadata.revision, + TransformReference(metadata.creator), metadata.templateId); } -} +} \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/MetadataMappers/ResponseMetadataMapper.cs b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/MetadataMappers/ResponseMetadataMapper.cs index 7098a487a..15bc6f535 100644 --- a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/MetadataMappers/ResponseMetadataMapper.cs +++ b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/MetadataMappers/ResponseMetadataMapper.cs @@ -2,13 +2,14 @@ namespace IO.Swagger.Lib.V3.SerializationModifiers.Mappers.MetadataMappers { - public class ResponseMetadataMapper + /// + public class ResponseMetadataMapper : IResponseMetadataMapper { - private static ResponseMetadataTransformer Transformer = new ResponseMetadataTransformer(); + private static ResponseMetadataTransformer _transformer = new(); - public static IDTO Map(IClass source) + public IDTO Map(IClass source) { - return Transformer.Transform(source); + return _transformer.Transform(source); } } -} +} \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/IRequestValueMapper.cs b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/IRequestValueMapper.cs new file mode 100644 index 000000000..79414b475 --- /dev/null +++ b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/IRequestValueMapper.cs @@ -0,0 +1,19 @@ +using DataTransferObjects; +using DataTransferObjects.ValueDTOs; + +namespace IO.Swagger.Lib.V3.SerializationModifiers.Mappers.ValueMappers; + +/// +/// Provides functionality to map request values. +/// +public interface IRequestValueMapper +{ + /// + /// Maps a value DTO to an appropriate class. + /// + /// The value DTO to map. + /// The mapped class. + IClass Map(IValueDTO source); + + IDTO Map(IClass source); +} \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/IResponseValueMapper.cs b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/IResponseValueMapper.cs new file mode 100644 index 000000000..6484e6392 --- /dev/null +++ b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/IResponseValueMapper.cs @@ -0,0 +1,16 @@ +using DataTransferObjects.ValueDTOs; + +namespace IO.Swagger.Lib.V3.SerializationModifiers.Mappers.ValueMappers; + +/// +/// Provides functionality to map response values. +/// +public interface IResponseValueMapper +{ + /// + /// Maps a source class to a value DTO. + /// + /// The source class to map. + /// The mapped value DTO. + public IValueDTO Map(IClass source); +} \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/RequestValueMapper.cs b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/RequestValueMapper.cs index 296983cc7..ad47a076f 100644 --- a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/RequestValueMapper.cs +++ b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/RequestValueMapper.cs @@ -3,12 +3,15 @@ using System; using System.Collections.Generic; using System.Linq; +using DataTransferObjects; namespace IO.Swagger.Lib.V3.SerializationModifiers.Mappers.ValueMappers { - public static class RequestValueMapper + /// + public class RequestValueMapper : IRequestValueMapper { - public static IClass Map(IValueDTO source) + /// + public IClass Map(IValueDTO source) { if (source == null) throw new ArgumentNullException(nameof(source)); return source switch @@ -30,12 +33,17 @@ public static IClass Map(IValueDTO source) }; } + public IDTO Map(IClass source) + { + throw new NotImplementedException(); + } + private static IClass Transform(BasicEventElementValue valueDTO) { return new BasicEventElement(TransformReference(valueDTO.observed), Direction.Output, StateOfEvent.On, idShort: valueDTO.idShort); } - private static IClass Transform(SubmodelValue valueDTO) + private IClass Transform(SubmodelValue valueDTO) { List submodelElements = null; if (valueDTO.submodelElements != null) @@ -51,7 +59,7 @@ private static IClass Transform(RangeValue valueDTO) return new AasCore.Aas3_0.Range(DataTypeDefXsd.String, idShort: valueDTO.idShort, min: valueDTO.min, max: valueDTO.max); } - private static IClass Transform(SubmodelElementListValue valueDTO) + private IClass Transform(SubmodelElementListValue valueDTO) { List value = null; if (valueDTO.value != null) @@ -68,7 +76,7 @@ private static IClass Transform(MultiLanguagePropertyValue valueDTO) return new MultiLanguageProperty(idShort: valueDTO.idShort, value: value); } - private static IClass Transform(SubmodelElementCollectionValue valueDTO) + private IClass Transform(SubmodelElementCollectionValue valueDTO) { List value = null; if (valueDTO.value != null) @@ -79,7 +87,7 @@ private static IClass Transform(SubmodelElementCollectionValue valueDTO) return new SubmodelElementCollection(idShort: valueDTO.idShort, value: value); } - private static IClass Transform(EntityValue valueDTO) + private IClass Transform(EntityValue valueDTO) { List statements = null; if (valueDTO.statements != null) @@ -100,7 +108,7 @@ private static IClass Transform(RelationshipElementValue valueDTO) return new RelationshipElement(TransformReference(valueDTO.first), TransformReference(valueDTO.second), idShort: valueDTO.idShort); } - private static IClass Transform(AnnotatedRelationshipElementValue valueDTO) + private IClass Transform(AnnotatedRelationshipElementValue valueDTO) { List annotations = null; if (valueDTO.annotations != null) diff --git a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/ResponseValueMapper.cs b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/ResponseValueMapper.cs index aa1297315..663071076 100644 --- a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/ResponseValueMapper.cs +++ b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/ResponseValueMapper.cs @@ -1,14 +1,14 @@ using DataTransferObjects.ValueDTOs; -namespace IO.Swagger.Lib.V3.SerializationModifiers.Mappers.ValueMappers +namespace IO.Swagger.Lib.V3.SerializationModifiers.Mappers.ValueMappers; + +/// +public class ResponseValueMapper : IResponseValueMapper { - public class ResponseValueMapper - { - private static readonly IResponseValueTransformer Transformer = new ResponseValueTransformer(); + private static readonly IResponseValueTransformer Transformer = new ResponseValueTransformer(); - public static IValueDTO Map(IClass source) - { - return (IValueDTO)Transformer.Transform(source); - } + public IValueDTO Map(IClass source) + { + return (IValueDTO) Transformer.Transform(source); } -} +} \ No newline at end of file From f492ba28a3e10801e770f7f17360876c23c3ed90 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 15 Apr 2024 20:22:38 +0200 Subject: [PATCH 07/18] fix startup and add tests --- src/AasxServerBlazor/Startup.cs | 39 +++-- .../Mappers/MappingServiceTests.cs | 143 +++++++++++++++++- .../RequestMetadataMapperTest.cs | 56 +++++++ ...ssetAdministrationShellRepositoryAPIApi.cs | 2 +- .../Mappers/IMappingService.cs | 27 +++- .../Mappers/MappingService.cs | 9 +- .../SerializationModifiersValidator.cs | 2 +- 7 files changed, 252 insertions(+), 26 deletions(-) create mode 100644 src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/MetadataMappers/RequestMetadataMapperTest.cs diff --git a/src/AasxServerBlazor/Startup.cs b/src/AasxServerBlazor/Startup.cs index 981492d68..070906c50 100644 --- a/src/AasxServerBlazor/Startup.cs +++ b/src/AasxServerBlazor/Startup.cs @@ -32,6 +32,7 @@ using System; using System.Collections.Generic; using System.IO; +using IO.Swagger.Lib.V3.SerializationModifiers.Mappers.MetadataMappers; using IO.Swagger.Lib.V3.SerializationModifiers.Mappers.ValueMappers.JsonObjectParser; namespace AasxServerBlazor @@ -92,31 +93,37 @@ public void ConfigureServices(IServiceCollection services) services.AddControllers(); services.AddLazyResolution(); + services.AddScoped(typeof(IAppLogger<>), typeof(LoggerAdapter<>)); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); - services.AddScoped(typeof(IAppLogger<>), typeof(LoggerAdapter<>)); - services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); + services.AddTransient(); services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); services.AddTransient(); - services.AddTransient(); + services.AddTransient(); services.AddTransient(); + services.AddTransient(); + services.AddTransient(); services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); services.AddTransient(); - services.AddTransient(); - services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); // Add GraphQL services services diff --git a/src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/MappingServiceTests.cs b/src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/MappingServiceTests.cs index 6b7a43d09..093d89a10 100644 --- a/src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/MappingServiceTests.cs +++ b/src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/MappingServiceTests.cs @@ -1,6 +1,9 @@ using AasCore.Aas3_0; using AutoFixture; +using DataTransferObjects; using DataTransferObjects.CommonDTOs; +using DataTransferObjects.MetadataDTOs; +using DataTransferObjects.ValueDTOs; using IO.Swagger.Lib.V3.SerializationModifiers.Mappers; using IO.Swagger.Lib.V3.SerializationModifiers.Mappers.MetadataMappers; using IO.Swagger.Lib.V3.SerializationModifiers.Mappers.ValueMappers; @@ -19,7 +22,7 @@ public class MappingServiceTests private readonly Mock _requestMetadataMapperMock; private readonly Mock _requestValueMapperMock; - + public MappingServiceTests() { _fixture = new Fixture(); @@ -27,12 +30,12 @@ public MappingServiceTests() _fixture.Behaviors.Add(new OmitOnRecursionBehavior()); _administrativeInformationMock = new Mock(); _administrativeInformationDTOMock = new Mock(); - + _responseMetadataMapperMock = new Mock(); _responseValueMapperMock = new Mock(); _requestMetadataMapperMock = new Mock(); _requestValueMapperMock = new Mock(); - + _mappingService = new MappingService( _responseMetadataMapperMock.Object, _responseValueMapperMock.Object, @@ -52,6 +55,136 @@ public void Map_WithNullMappingResolverKey_ThrowsException() // Assert act.Should().Throw().WithMessage("Could not resolve serializer modifier mapper."); } - - //TODO: add more tests + + [Fact] + public void Map_WithInvalidMappingResolverKey_ThrowsException() + { + // Arrange + var mappingResolverKey = "invalid_key"; + + // Act + Action act = () => _mappingService.Map(It.IsAny(), mappingResolverKey); + + // Assert + act.Should().Throw().WithMessage("Invalid modifier mapping resolved key"); + } + + [Fact] + public void MapList_WithNullMappingResolverKey_ThrowsException() + { + // Arrange + string mappingResolverKey = null; + + // Act + Action act = () => _mappingService.Map(new List(), mappingResolverKey); + + // Assert + act.Should().Throw().WithMessage("Could not resolve serializer modifier mapper."); + } + + [Fact] + public void MapList_WithInvalidMappingResolverKey_ThrowsException() + { + // Arrange + var mappingResolverKey = "invalid_key"; + + // Act + Action act = () => _mappingService.Map(new List(), mappingResolverKey); + + // Assert + act.Should().Throw().WithMessage("Invalid modifier mapping resolved key"); + } + + [Fact] + public void MapDTO_WithNullMappingResolverKey_ThrowsException() + { + // Arrange + string mappingResolverKey = null; + + // Act + Action act = () => _mappingService.Map(It.IsAny(), mappingResolverKey); + + // Assert + act.Should().Throw().WithMessage("Could not resolve serializer modifier mapper."); + } + + [Fact] + public void MapDTO_WithInvalidMappingResolverKey_ThrowsException() + { + // Arrange + var mappingResolverKey = "invalid_key"; + var dtoMock = new Mock(); + + // Act + Action act = () => _mappingService.Map(dtoMock.Object, mappingResolverKey); + + // Assert + act.Should().Throw().WithMessage("Invalid modifier mapping resolved key"); + } + + [Fact] + public void Map_WithMetadataMappingResolverKey_ReturnsMappedDTO() + { + // Arrange + string mappingResolverKey = "metadata"; + var source = new Mock(); + var mappedDtoMock = new Mock(); + _responseMetadataMapperMock.Setup(m => m.Map(It.IsAny())).Returns(mappedDtoMock.Object); + + // Act + var result = _mappingService.Map(source.Object, mappingResolverKey); + + // Assert + result.Should().Be(mappedDtoMock.Object); + } + + + [Fact] + public void MapList_WithMetadataMappingResolverKey_ReturnsMappedDTOList() + { + // Arrange + var mappingResolverKey = "metadata"; + var sourceList = new List {new Mock().Object}; + var mappedDtoListMock = new List {new Mock().Object}; + _responseMetadataMapperMock.Setup(m => m.Map(It.IsAny())).Returns(mappedDtoListMock[0]); + + // Act + var result = _mappingService.Map(sourceList, mappingResolverKey); + + // Assert + result.Should().BeEquivalentTo(mappedDtoListMock); + } + + + [Fact] + public void MapDTO_WithMetadataMappingResolverKeyAndMetadataDTO_ReturnsMappedClass() + { + // Arrange + var mappingResolverKey = "metadata"; + var dtoMock = new Mock(); + var mappedClassMock = new Mock(); + _requestMetadataMapperMock.Setup(m => m.Map(It.IsAny())).Returns(mappedClassMock.Object); + + // Act + var result = _mappingService.Map(dtoMock.Object, mappingResolverKey); + + // Assert + result.Should().Be(mappedClassMock.Object); + } + + [Fact] + public void MapDTO_WithValueMappingResolverKeyAndValueDTO_ReturnsMappedClass() + { + // Arrange + var mappingResolverKey = "value"; + var dtoMock = new Mock(); + var mappedClassMock = new Mock(); + _requestValueMapperMock.Setup(m => m.Map(It.IsAny())).Returns(mappedClassMock.Object); + + // Act + var result = _mappingService.Map(dtoMock.Object, mappingResolverKey); + + // Assert + result.Should().Be(mappedClassMock.Object); + } } \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/MetadataMappers/RequestMetadataMapperTest.cs b/src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/MetadataMappers/RequestMetadataMapperTest.cs new file mode 100644 index 000000000..935a4bf96 --- /dev/null +++ b/src/IO.Swagger.Lib.V3.Tests/SerializationModifiers/Mappers/MetadataMappers/RequestMetadataMapperTest.cs @@ -0,0 +1,56 @@ +using Xunit; +using Moq; +using FluentAssertions; +using IO.Swagger.Lib.V3.SerializationModifiers.Mappers.MetadataMappers; +using DataTransferObjects.MetadataDTOs; +using DataTransferObjects.CommonDTOs; +using AasCore.Aas3_0; +using System.Collections.Generic; +using AutoFixture; + +namespace IO.Swagger.Lib.V3.Tests.SerializationModifiers.Mappers.MetadataMappers; + +public class RequestMetadataMapperTests +{ + private readonly Fixture _fixture; + private readonly RequestMetadataMapper _mapper; + private readonly Mock _metadataDTOMock; + + public RequestMetadataMapperTests() + { + _fixture = new Fixture(); + _fixture.Behaviors.Remove(new ThrowingRecursionBehavior()); + _fixture.Behaviors.Add(new OmitOnRecursionBehavior()); + + _mapper = new RequestMetadataMapper(); + _metadataDTOMock = new Mock(); + } + + + [Fact] + public void Map_WithNullSource_ReturnsNull() + { + // Arrange + IMetadataDTO source = null; + + // Act + var result = _mapper.Map(source); + + // Assert + result.Should().BeNull(); + } + + + [Fact(Skip = "Tests need a better way for mocking and transforming")] + public void Map_WithPropertyMetadata_ReturnsTransformedProperty() + { + // Arrange + var propertyMetadata = _fixture.Create(); + + // Act + var result = _mapper.Map(propertyMetadata); + + // Assert + result.Should().BeOfType(); + } +} \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3/Controllers/AssetAdministrationShellRepositoryAPIApi.cs b/src/IO.Swagger.Lib.V3/Controllers/AssetAdministrationShellRepositoryAPIApi.cs index b92e5bd28..fc0bf872f 100644 --- a/src/IO.Swagger.Lib.V3/Controllers/AssetAdministrationShellRepositoryAPIApi.cs +++ b/src/IO.Swagger.Lib.V3/Controllers/AssetAdministrationShellRepositoryAPIApi.cs @@ -1995,7 +1995,7 @@ public virtual IActionResult PatchSubmodelElementValueByPathValueOnly([FromBody] _logger.LogInformation($"Received request to update the submodel element at {idShortPath} in the submodel with id {decodedSubmodelIdentifier} and the AAS with id {decodedAasIdentifier} by value."); //Reverse mapping from Metadata to submodel element - ISubmodelElement submodelElement = _mappingService.Map(body, "value") as ISubmodelElement; + var submodelElement = _mappingService.Map(body, "value") as ISubmodelElement; //TODO: this is where the 'fun' begins //Update _aasService.UpdateSubmodelElementByPath(decodedAasIdentifier, decodedSubmodelIdentifier, idShortPath, submodelElement); diff --git a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/IMappingService.cs b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/IMappingService.cs index 7ca8e1771..475308c38 100644 --- a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/IMappingService.cs +++ b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/IMappingService.cs @@ -3,10 +3,33 @@ namespace IO.Swagger.Lib.V3.SerializationModifiers.Mappers { + /// + /// Interface for mapping between domain classes and DTOs using different mapping strategies. + /// public interface IMappingService { + /// + /// Maps a single source domain class to a DTO based on the specified mapping resolver key. + /// + /// The source domain class to be mapped. + /// The key used to resolve the mapping strategy. + /// The mapped DTO. IDTO Map(IClass source, string mappingResolverKey); - List Map(List sourceList, string mappingResolverKey); + + /// + /// Maps a collection of source domain classes to DTOs based on the specified mapping resolver key. + /// + /// The collection of source domain classes to be mapped. + /// The key used to resolve the mapping strategy. + /// The list of mapped DTOs. + List Map(IEnumerable sourceList, string mappingResolverKey); + + /// + /// Maps a DTO to a domain class based on the specified mapping resolver key. + /// + /// The DTO to be mapped. + /// The key used to resolve the mapping strategy. + /// The mapped domain class. IClass Map(IDTO dto, string mappingResolverKey); } -} +} \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/MappingService.cs b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/MappingService.cs index a3f118a58..6d0b76dd6 100644 --- a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/MappingService.cs +++ b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/MappingService.cs @@ -17,6 +17,13 @@ public class MappingService : IMappingService private readonly IRequestMetadataMapper _requestMetadataMapper; private readonly IRequestValueMapper _requestValueMapper; + /// + /// Initializes a new instance of the class. + /// + /// The mapper for response metadata DTOs. + /// The mapper for response value DTOs. + /// The mapper for request metadata DTOs. + /// The mapper for request value DTOs. public MappingService(IResponseMetadataMapper responseMetadataMapper, IResponseValueMapper responseValueMapper, IRequestMetadataMapper requestMetadataMapper, IRequestValueMapper requestValueMapper) { @@ -49,7 +56,7 @@ public IDTO Map(IClass source, string mappingResolverKey) } /// - public List Map(List sourceList, string mappingResolverKey) + public List Map(IEnumerable sourceList, string mappingResolverKey) { if (mappingResolverKey == null) { diff --git a/src/IO.Swagger.Lib.V3/SerializationModifiers/SerializationModifiersValidator.cs b/src/IO.Swagger.Lib.V3/SerializationModifiers/SerializationModifiersValidator.cs index 1c1f24e52..9441a116d 100644 --- a/src/IO.Swagger.Lib.V3/SerializationModifiers/SerializationModifiersValidator.cs +++ b/src/IO.Swagger.Lib.V3/SerializationModifiers/SerializationModifiersValidator.cs @@ -73,7 +73,7 @@ public static void Validate(object resource, LevelEnum level, ExtentEnum extent) public static void Validate(List resources, LevelEnum level, ExtentEnum extent) { - foreach (IClass resource in resources) + foreach (var resource in resources) Validate(resource, level, extent); } } From a59c12142234efdc1a623ceafe787f28975a8fd8 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 15 Apr 2024 20:49:03 +0200 Subject: [PATCH 08/18] simple clean ups --- .../Formatters/AasResponseFormatter.cs | 84 ++++++++----------- .../Models/SerializationModifiersEnum.cs | 6 +- .../SerializationModifiersValidator.cs | 2 +- 3 files changed, 42 insertions(+), 50 deletions(-) diff --git a/src/IO.Swagger.Lib.V3/Formatters/AasResponseFormatter.cs b/src/IO.Swagger.Lib.V3/Formatters/AasResponseFormatter.cs index e9260f5cf..6c233d12b 100644 --- a/src/IO.Swagger.Lib.V3/Formatters/AasResponseFormatter.cs +++ b/src/IO.Swagger.Lib.V3/Formatters/AasResponseFormatter.cs @@ -1,12 +1,10 @@ using AdminShellNS.Lib.V3.Models; using DataTransferObjects; -using DataTransferObjects.ValueDTOs; using IO.Swagger.Lib.V3.SerializationModifiers; using IO.Swagger.Lib.V3.SerializationModifiers.Mappers.ValueMappers; using IO.Swagger.Models; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.Formatters; -using Microsoft.Extensions.Primitives; using Microsoft.Net.Http.Headers; using System; using System.Collections; @@ -15,6 +13,7 @@ using System.Text.Json; using System.Text.Json.Nodes; using System.Threading.Tasks; +using IValueDTO = DataTransferObjects.ValueDTOs.IValueDTO; namespace IO.Swagger.Lib.V3.Formatters { @@ -25,7 +24,8 @@ public AasResponseFormatter() this.SupportedMediaTypes.Clear(); this.SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/json")); } - public static bool IsGenericListOfIClass(object o) + + private static bool IsGenericListOfIClass(object o) { var oType = o.GetType(); return oType.IsGenericType && @@ -33,20 +33,19 @@ public static bool IsGenericListOfIClass(object o) (typeof(IClass).IsAssignableFrom(oType.GetGenericArguments()[0]))); } - public static bool IsGenericListOfIValueDTO(object o) + private static bool IsGenericListOfIValueDTO(object o) { var oType = o.GetType(); - bool IsValueDTO = false; - if (o is List list) + var IsValueDTO = false; + if (o is not List list) + return false; + if (list[0] is IValueDTO) { - if (list[0] is IValueDTO) - { - IsValueDTO = true; - } + IsValueDTO = true; } return oType.IsGenericType && - (oType.GetGenericTypeDefinition() == typeof(List<>) && - IsValueDTO); + (oType.GetGenericTypeDefinition() == typeof(List<>) && + IsValueDTO); } public override bool CanWriteResult(OutputFormatterCanWriteContext context) @@ -75,16 +74,15 @@ public override bool CanWriteResult(OutputFormatterCanWriteContext context) { return base.CanWriteResult(context); } - else - return false; + + return false; } public override Task WriteResponseBodyAsync(OutputFormatterWriteContext context) { - var httpContext = context.HttpContext; var response = context.HttpContext.Response; //SerializationModifier - GetSerializationMidifiersFromRequest(context.HttpContext.Request, out LevelEnum level, out ExtentEnum extent); + GetSerializationModifiersFromRequest(context.HttpContext.Request, out var level, out var extent); if (typeof(IClass).IsAssignableFrom(context.ObjectType)) @@ -92,7 +90,7 @@ public override Task WriteResponseBodyAsync(OutputFormatterWriteContext context) //Validate modifiers SerializationModifiersValidator.Validate((IClass)context.Object, level, extent); - JsonObject json = Jsonization.Serialize.ToJsonObject((IClass)context.Object); + var json = Jsonization.Serialize.ToJsonObject((IClass)context.Object); var writer = new Utf8JsonWriter(response.Body); json.WriteTo(writer); writer.FlushAsync().GetAwaiter().GetResult(); @@ -101,16 +99,11 @@ public override Task WriteResponseBodyAsync(OutputFormatterWriteContext context) { var jsonArray = new JsonArray(); - IList genericList = (IList)context.Object; - List contextObjectType = new List(); - foreach (var generic in genericList) - { - contextObjectType.Add((IClass)generic); - } + var genericList = (IList)context.Object; + var contextObjectType = genericList.Cast().ToList(); - foreach (var item in contextObjectType) + foreach (var json in contextObjectType.Select(Jsonization.Serialize.ToJsonObject)) { - var json = Jsonization.Serialize.ToJsonObject(item); jsonArray.Add(json); } var writer = new Utf8JsonWriter(response.Body); @@ -124,14 +117,15 @@ public override Task WriteResponseBodyAsync(OutputFormatterWriteContext context) if (context.Object is ValueOnlyPagedResult pagedResult) { cursor = pagedResult.paging_metadata.cursor; - foreach (var item in pagedResult.result) + foreach (var json in pagedResult.result.Select(item => new ValueOnlyJsonSerializer().ToJsonObject(item))) { - var json = new ValueOnlyJsonSerializer().ToJsonObject(item); jsonArray.Add(json); } } - JsonObject jsonNode = new JsonObject(); - jsonNode["result"] = jsonArray; + var jsonNode = new JsonObject + { + ["result"] = jsonArray + }; var pagingMetadata = new JsonObject(); if (cursor != null) { @@ -144,7 +138,7 @@ public override Task WriteResponseBodyAsync(OutputFormatterWriteContext context) } else if (typeof(IValueDTO).IsAssignableFrom(context.ObjectType)) { - JsonNode json = new ValueOnlyJsonSerializer().ToJsonObject((IValueDTO)context.Object); + var json = new ValueOnlyJsonSerializer().ToJsonObject((IValueDTO)context.Object); var writer = new Utf8JsonWriter(response.Body); json.WriteTo(writer); writer.FlushAsync().GetAwaiter().GetResult(); @@ -152,16 +146,11 @@ public override Task WriteResponseBodyAsync(OutputFormatterWriteContext context) else if (IsGenericListOfIValueDTO(context.Object)) { var jsonArray = new JsonArray(); - IList genericList = (IList)context.Object; - List contextObjectType = new List(); - foreach (var generic in genericList) - { - contextObjectType.Add((IValueDTO)generic); - } + var genericList = (IList)context.Object; + var contextObjectType = genericList.Cast().ToList(); - foreach (var item in contextObjectType) + foreach (var json in contextObjectType.Select(item => new ValueOnlyJsonSerializer().ToJsonObject(item))) { - var json = new ValueOnlyJsonSerializer().ToJsonObject(item); jsonArray.Add(json); } var writer = new Utf8JsonWriter(response.Body); @@ -175,14 +164,15 @@ public override Task WriteResponseBodyAsync(OutputFormatterWriteContext context) if (context.Object is PagedResult pagedResult) { cursor = pagedResult.paging_metadata.cursor; - foreach (var item in pagedResult.result) + foreach (var json in pagedResult.result.Select(Jsonization.Serialize.ToJsonObject)) { - var json = Jsonization.Serialize.ToJsonObject(item); jsonArray.Add(json); } } - JsonObject jsonNode = new JsonObject(); - jsonNode["result"] = jsonArray; + var jsonNode = new JsonObject + { + ["result"] = jsonArray + }; var pagingMetadata = new JsonObject(); if (cursor != null) { @@ -197,9 +187,9 @@ public override Task WriteResponseBodyAsync(OutputFormatterWriteContext context) return Task.FromResult(response); } - private void GetSerializationMidifiersFromRequest(HttpRequest request, out LevelEnum level, out ExtentEnum extent) + private void GetSerializationModifiersFromRequest(HttpRequest request, out LevelEnum level, out ExtentEnum extent) { - request.Query.TryGetValue("level", out StringValues levelValues); + request.Query.TryGetValue("level", out var levelValues); if (levelValues.Any()) { Enum.TryParse(levelValues.First(), out level); @@ -209,10 +199,10 @@ private void GetSerializationMidifiersFromRequest(HttpRequest request, out Level level = LevelEnum.Deep; } - request.Query.TryGetValue("extent", out StringValues extenValues); - if (extenValues.Any()) + request.Query.TryGetValue("extent", out var extendValues); + if (extendValues.Any()) { - Enum.TryParse(extenValues.First(), out extent); + Enum.TryParse(extendValues.First(), out extent); } else { diff --git a/src/IO.Swagger.Lib.V3/Models/SerializationModifiersEnum.cs b/src/IO.Swagger.Lib.V3/Models/SerializationModifiersEnum.cs index cc6d78498..b72566556 100644 --- a/src/IO.Swagger.Lib.V3/Models/SerializationModifiersEnum.cs +++ b/src/IO.Swagger.Lib.V3/Models/SerializationModifiersEnum.cs @@ -6,7 +6,8 @@ namespace IO.Swagger.Models public enum LevelEnum { Deep, - Core + Core, + None } [JsonConverter(typeof(JsonStringEnumConverter))] @@ -23,7 +24,8 @@ public enum ContentEnum public enum ExtentEnum { WithoutBlobValue, - WithBlobValue + WithBlobValue, + None } diff --git a/src/IO.Swagger.Lib.V3/SerializationModifiers/SerializationModifiersValidator.cs b/src/IO.Swagger.Lib.V3/SerializationModifiers/SerializationModifiersValidator.cs index 9441a116d..07aa78dd1 100644 --- a/src/IO.Swagger.Lib.V3/SerializationModifiers/SerializationModifiersValidator.cs +++ b/src/IO.Swagger.Lib.V3/SerializationModifiers/SerializationModifiersValidator.cs @@ -7,7 +7,7 @@ namespace IO.Swagger.Lib.V3.SerializationModifiers { - public static class SerializationModifiersValidator + public class SerializationModifiersValidator { //As per new APIs, content is not handled here public static void Validate(object resource, LevelEnum level, ExtentEnum extent) From 32e43521354049487e33890aab4bec134bfcd812 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 15 Apr 2024 20:53:31 +0200 Subject: [PATCH 09/18] simple clean ups --- .../SerializationModifiersValidator.cs | 146 ++++++++++-------- 1 file changed, 79 insertions(+), 67 deletions(-) diff --git a/src/IO.Swagger.Lib.V3/SerializationModifiers/SerializationModifiersValidator.cs b/src/IO.Swagger.Lib.V3/SerializationModifiers/SerializationModifiersValidator.cs index 07aa78dd1..534842329 100644 --- a/src/IO.Swagger.Lib.V3/SerializationModifiers/SerializationModifiersValidator.cs +++ b/src/IO.Swagger.Lib.V3/SerializationModifiers/SerializationModifiersValidator.cs @@ -1,80 +1,92 @@ - -using DataTransferObjects.MetadataDTOs; +using DataTransferObjects.MetadataDTOs; using DataTransferObjects.ValueDTOs; using IO.Swagger.Lib.V3.Exceptions; using IO.Swagger.Models; -using System.Collections.Generic; +using System; -namespace IO.Swagger.Lib.V3.SerializationModifiers +namespace IO.Swagger.Lib.V3.SerializationModifiers; + +/// +/// Provides methods for validating serialization modifiers of resources. +/// +public class SerializationModifiersValidator { - public class SerializationModifiersValidator + /// + /// Validates the serialization modifiers of the specified resource. + /// + /// The resource to validate. + /// The level of the resource. + /// The extent of the resource. + /// Thrown when is null. + public static void Validate(object resource, LevelEnum level, ExtentEnum extent) { - //As per new APIs, content is not handled here - public static void Validate(object resource, LevelEnum level, ExtentEnum extent) + if (resource == null) { - switch (resource) - { - case BasicEventElementMetadata: - case BasicEventElementValue: - case BasicEventElement: - case Capability: - case Operation: - { - if (level == LevelEnum.Core) - { - throw new InvalidSerializationModifierException(level.ToString(), resource.GetType().Name); - } + throw new ArgumentNullException(nameof(resource)); + } - if (extent == ExtentEnum.WithBlobValue) - { - throw new InvalidSerializationModifierException(extent.ToString(), resource.GetType().Name); - } - break; - } - case BlobMetadata: - case BlobValue: - case Blob: - { - if (level == LevelEnum.Core) - { - throw new InvalidSerializationModifierException(level.ToString(), resource.GetType().Name); - } - break; - } - case SubmodelElementListMetadata: - case SubmodelElementListValue: - case SubmodelElementCollectionMetadata: - case SubmodelElementCollectionValue: - case AnnotatedRelationshipElementMetadata: - case AnnotatedRelationshipElementValue: - case EntityMetadata: - case EntityValue: - case OperationMetadata: - case OperationValue: - { - break; - } - case ISubmodelElementMetadata: - case ISubmodelElementValue: - case IDataElement: - { - if (level == LevelEnum.Core) - { - throw new InvalidSerializationModifierException(level.ToString(), resource.GetType().Name); - } - if (extent == ExtentEnum.WithBlobValue) - { - throw new InvalidSerializationModifierException(extent.ToString(), resource.GetType().Name); - } - break; - } - } + if (level == LevelEnum.Core || extent == ExtentEnum.WithBlobValue) + { + ValidateForException(resource, level, extent); } + } + + private static void ValidateForException(object resource, LevelEnum level, ExtentEnum extent) + { + var resourceType = resource.GetType(); - public static void Validate(List resources, LevelEnum level, ExtentEnum extent) + if (IsUnsupportedType(resourceType)) { - foreach (var resource in resources) - Validate(resource, level, extent); + throw new InvalidSerializationModifierException(GetModifierString(level, extent), resourceType.Name); } } -} + + private static bool IsUnsupportedType(Type resourceType) + { + return resourceType switch + { + not null when IsBasicType(resourceType) => true, + not null when IsBlobType(resourceType) => true, + not null when IsSubmodelType(resourceType) => true, + _ => false + }; + } + + private static bool IsBasicType(Type resourceType) + { + return resourceType == typeof(BasicEventElementMetadata) || + resourceType == typeof(BasicEventElementValue) || + resourceType == typeof(BasicEventElement) || + resourceType == typeof(Capability) || + resourceType == typeof(Operation); + } + + private static bool IsBlobType(Type resourceType) + { + return resourceType == typeof(BlobMetadata) || + resourceType == typeof(BlobValue) || + resourceType == typeof(Blob); + } + + private static bool IsSubmodelType(Type resourceType) + { + return resourceType == typeof(ISubmodelElementMetadata) || + resourceType == typeof(ISubmodelElementValue) || + resourceType == typeof(IDataElement) || + resourceType == typeof(SubmodelElementListMetadata) || + resourceType == typeof(SubmodelElementListValue) || + resourceType == typeof(SubmodelElementCollectionMetadata) || + resourceType == typeof(SubmodelElementCollectionValue) || + resourceType == typeof(AnnotatedRelationshipElementMetadata) || + resourceType == typeof(AnnotatedRelationshipElementValue) || + resourceType == typeof(EntityMetadata) || + resourceType == typeof(EntityValue) || + resourceType == typeof(OperationMetadata) || + resourceType == typeof(OperationValue); + } + + private static string GetModifierString(LevelEnum level, ExtentEnum extent) + { + return level == LevelEnum.Core ? level.ToString() : extent.ToString(); + } +} \ No newline at end of file From a77170a98e1ffce07840040180ee26c4610f2a60 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 15 Apr 2024 21:00:42 +0200 Subject: [PATCH 10/18] split functions --- .../Formatters/AasResponseFormatter.cs | 272 ++++++++++-------- 1 file changed, 150 insertions(+), 122 deletions(-) diff --git a/src/IO.Swagger.Lib.V3/Formatters/AasResponseFormatter.cs b/src/IO.Swagger.Lib.V3/Formatters/AasResponseFormatter.cs index 6c233d12b..7e3c3844f 100644 --- a/src/IO.Swagger.Lib.V3/Formatters/AasResponseFormatter.cs +++ b/src/IO.Swagger.Lib.V3/Formatters/AasResponseFormatter.cs @@ -7,8 +7,8 @@ using Microsoft.AspNetCore.Mvc.Formatters; using Microsoft.Net.Http.Headers; using System; -using System.Collections; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text.Json; using System.Text.Json.Nodes; @@ -29,8 +29,8 @@ private static bool IsGenericListOfIClass(object o) { var oType = o.GetType(); return oType.IsGenericType && - (oType.GetGenericTypeDefinition() == typeof(List<>) && - (typeof(IClass).IsAssignableFrom(oType.GetGenericArguments()[0]))); + (oType.GetGenericTypeDefinition() == typeof(List<>) && + (typeof(IClass).IsAssignableFrom(oType.GetGenericArguments()[0]))); } private static bool IsGenericListOfIValueDTO(object o) @@ -43,6 +43,7 @@ private static bool IsGenericListOfIValueDTO(object o) { IsValueDTO = true; } + return oType.IsGenericType && (oType.GetGenericTypeDefinition() == typeof(List<>) && IsValueDTO); @@ -50,144 +51,171 @@ private static bool IsGenericListOfIValueDTO(object o) public override bool CanWriteResult(OutputFormatterCanWriteContext context) { - if (typeof(IClass).IsAssignableFrom(context.ObjectType)) + var objectType = context.ObjectType; + var obj = context.Object; + + return typeof(IClass).IsAssignableFrom(objectType) || + typeof(ValueOnlyPagedResult).IsAssignableFrom(objectType) || + typeof(IValueDTO).IsAssignableFrom(objectType) || + IsGenericListOfIClass(obj) || + IsGenericListOfIValueDTO(obj) || + typeof(PagedResult).IsAssignableFrom(objectType); + } + + + public override async Task WriteResponseBodyAsync(OutputFormatterWriteContext context) + { + var response = context.HttpContext.Response; + + GetSerializationModifiersFromRequest(context.HttpContext.Request, out var level, out var extent); + + if (TryWriteJsonObject(response.Body, context.Object, level, extent)) { - return base.CanWriteResult(context); + await response.Body.FlushAsync(); } - if (typeof(ValueOnlyPagedResult).IsAssignableFrom(context.ObjectType)) + } + + + private bool TryWriteJsonObject(Stream responseBody, object obj, LevelEnum level, ExtentEnum extent) + { + var writer = new Utf8JsonWriter(responseBody); + + switch (obj) + { + case IClass classObj: + SerializationModifiersValidator.Validate(classObj, level, extent); + Jsonization.Serialize.ToJsonObject(classObj).WriteTo(writer); + break; + case IList genericListOfClass: + WriteJsonArray(writer, genericListOfClass.Select(Jsonization.Serialize.ToJsonObject)); + break; + case ValueOnlyPagedResult valuePagedResult: + WriteValueOnlyPagedResult2(writer, valuePagedResult); + break; + case IValueDTO valueDto: + new ValueOnlyJsonSerializer().ToJsonObject(valueDto).WriteTo(writer); + break; + case IList genericListOfValueDto: + WriteJsonArray(writer, genericListOfValueDto.Select(item => new ValueOnlyJsonSerializer().ToJsonObject(item))); + break; + case PagedResult pagedResult: + WritePagedResult2(writer, pagedResult); + break; + default: + return false; + } + + writer.Flush(); + return true; + } + + private void WriteJsonArray(Utf8JsonWriter writer, IEnumerable nodes) + { + var jsonArray = new JsonArray(); + foreach (var node in nodes) { - return base.CanWriteResult(context); + jsonArray.Add(node); } - if (typeof(IValueDTO).IsAssignableFrom(context.ObjectType)) + + jsonArray.WriteTo(writer); + } + + + private void WriteValueOnlyPagedResult2(Utf8JsonWriter writer, ValueOnlyPagedResult valuePagedResult) + { + var jsonArray = new JsonArray(); + string cursor = valuePagedResult.paging_metadata?.cursor; + + foreach (var json in valuePagedResult.result.Select(item => new ValueOnlyJsonSerializer().ToJsonObject(item))) { - return base.CanWriteResult(context); + jsonArray.Add(json); } - if (IsGenericListOfIClass(context.Object)) + + var jsonNode = new JsonObject { - return base.CanWriteResult(context); + ["result"] = jsonArray + }; + + if (cursor != null) + { + jsonNode["paging_metadata"] = new JsonObject {["cursor"] = cursor}; } - if (IsGenericListOfIValueDTO(context.Object)) + + jsonNode.WriteTo(writer); + } + + private void WritePagedResult2(Utf8JsonWriter writer, PagedResult pagedResult) + { + var jsonArray = new JsonArray(); + string cursor = pagedResult.paging_metadata?.cursor; + + foreach (var json in pagedResult.result.Select(Jsonization.Serialize.ToJsonObject)) { - return base.CanWriteResult(context); + jsonArray.Add(json); } - if (typeof(PagedResult).IsAssignableFrom(context.ObjectType)) + + var jsonNode = new JsonObject + { + ["result"] = jsonArray + }; + + if (cursor != null) { - return base.CanWriteResult(context); + jsonNode["paging_metadata"] = new JsonObject {["cursor"] = cursor}; } - return false; + jsonNode.WriteTo(writer); } - public override Task WriteResponseBodyAsync(OutputFormatterWriteContext context) + + + private void WriteValueOnlyPagedResult(Utf8JsonWriter writer, ValueOnlyPagedResult valuePagedResult) { - var response = context.HttpContext.Response; + var jsonArray = new JsonArray(); + var cursor = valuePagedResult.paging_metadata?.cursor; - //SerializationModifier - GetSerializationModifiersFromRequest(context.HttpContext.Request, out var level, out var extent); + foreach (var json in valuePagedResult.result.Select(item => new ValueOnlyJsonSerializer().ToJsonObject(item))) + { + jsonArray.Add(json); + } + + var jsonNode = new JsonObject + { + ["result"] = jsonArray + }; + if (cursor != null) + { + jsonNode["paging_metadata"] = new JsonObject {["cursor"] = cursor}; + } - if (typeof(IClass).IsAssignableFrom(context.ObjectType)) - { - //Validate modifiers - SerializationModifiersValidator.Validate((IClass)context.Object, level, extent); - - var json = Jsonization.Serialize.ToJsonObject((IClass)context.Object); - var writer = new Utf8JsonWriter(response.Body); - json.WriteTo(writer); - writer.FlushAsync().GetAwaiter().GetResult(); - } - else if (IsGenericListOfIClass(context.Object)) - { - - var jsonArray = new JsonArray(); - var genericList = (IList)context.Object; - var contextObjectType = genericList.Cast().ToList(); - - foreach (var json in contextObjectType.Select(Jsonization.Serialize.ToJsonObject)) - { - jsonArray.Add(json); - } - var writer = new Utf8JsonWriter(response.Body); - jsonArray.WriteTo(writer); - writer.FlushAsync().GetAwaiter().GetResult(); - } - else if (typeof(ValueOnlyPagedResult).IsAssignableFrom(context.ObjectType)) - { - var jsonArray = new JsonArray(); - string cursor = null; - if (context.Object is ValueOnlyPagedResult pagedResult) - { - cursor = pagedResult.paging_metadata.cursor; - foreach (var json in pagedResult.result.Select(item => new ValueOnlyJsonSerializer().ToJsonObject(item))) - { - jsonArray.Add(json); - } - } - var jsonNode = new JsonObject - { - ["result"] = jsonArray - }; - var pagingMetadata = new JsonObject(); - if (cursor != null) - { - pagingMetadata["cursor"] = cursor; - } - jsonNode["paging_metadata"] = pagingMetadata; - var writer = new Utf8JsonWriter(response.Body); - jsonNode.WriteTo(writer); - writer.FlushAsync().GetAwaiter().GetResult(); - } - else if (typeof(IValueDTO).IsAssignableFrom(context.ObjectType)) - { - var json = new ValueOnlyJsonSerializer().ToJsonObject((IValueDTO)context.Object); - var writer = new Utf8JsonWriter(response.Body); - json.WriteTo(writer); - writer.FlushAsync().GetAwaiter().GetResult(); - } - else if (IsGenericListOfIValueDTO(context.Object)) - { - var jsonArray = new JsonArray(); - var genericList = (IList)context.Object; - var contextObjectType = genericList.Cast().ToList(); - - foreach (var json in contextObjectType.Select(item => new ValueOnlyJsonSerializer().ToJsonObject(item))) - { - jsonArray.Add(json); - } - var writer = new Utf8JsonWriter(response.Body); - jsonArray.WriteTo(writer); - writer.FlushAsync().GetAwaiter().GetResult(); - } - else if (typeof(PagedResult).IsAssignableFrom(context.ObjectType)) - { - var jsonArray = new JsonArray(); - string cursor = null; - if (context.Object is PagedResult pagedResult) - { - cursor = pagedResult.paging_metadata.cursor; - foreach (var json in pagedResult.result.Select(Jsonization.Serialize.ToJsonObject)) - { - jsonArray.Add(json); - } - } - var jsonNode = new JsonObject - { - ["result"] = jsonArray - }; - var pagingMetadata = new JsonObject(); - if (cursor != null) - { - pagingMetadata["cursor"] = cursor; - } - jsonNode["paging_metadata"] = pagingMetadata; - var writer = new Utf8JsonWriter(response.Body); - jsonNode.WriteTo(writer); - writer.FlushAsync().GetAwaiter().GetResult(); - } - - return Task.FromResult(response); + jsonNode.WriteTo(writer); } - private void GetSerializationModifiersFromRequest(HttpRequest request, out LevelEnum level, out ExtentEnum extent) + private static void WritePagedResult(Utf8JsonWriter writer, PagedResult pagedResult) + { + var jsonArray = new JsonArray(); + var cursor = pagedResult.paging_metadata?.cursor; + + foreach (var json in pagedResult.result.Select(Jsonization.Serialize.ToJsonObject)) + { + jsonArray.Add(json); + } + + var jsonNode = new JsonObject + { + ["result"] = jsonArray + }; + + if (cursor != null) + { + jsonNode["paging_metadata"] = new JsonObject {["cursor"] = cursor}; + } + + jsonNode.WriteTo(writer); + } + + + private static void GetSerializationModifiersFromRequest(HttpRequest request, out LevelEnum level, out ExtentEnum extent) { request.Query.TryGetValue("level", out var levelValues); if (levelValues.Any()) @@ -210,4 +238,4 @@ private void GetSerializationModifiersFromRequest(HttpRequest request, out Level } } } -} +} \ No newline at end of file From e9766c386a9cf6df6f58cb1506434c3a88bb246f Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 15 Apr 2024 21:30:55 +0200 Subject: [PATCH 11/18] Extraction of functionality and add tests --- .../Formatters/JsonSerializerStrategyTests.cs | 79 ++++++ .../Formatters/AasResponseFormatter.cs | 262 +++--------------- .../Formatters/IJsonSerializerStrategy.cs | 28 ++ .../Formatters/JsonSerializerStrategy.cs | 130 +++++++++ .../ValueMappers/RequestValueMapper.cs | 2 +- 5 files changed, 277 insertions(+), 224 deletions(-) create mode 100644 src/IO.Swagger.Lib.V3.Tests/Formatters/JsonSerializerStrategyTests.cs create mode 100644 src/IO.Swagger.Lib.V3/Formatters/IJsonSerializerStrategy.cs create mode 100644 src/IO.Swagger.Lib.V3/Formatters/JsonSerializerStrategy.cs diff --git a/src/IO.Swagger.Lib.V3.Tests/Formatters/JsonSerializerStrategyTests.cs b/src/IO.Swagger.Lib.V3.Tests/Formatters/JsonSerializerStrategyTests.cs new file mode 100644 index 000000000..180cf4464 --- /dev/null +++ b/src/IO.Swagger.Lib.V3.Tests/Formatters/JsonSerializerStrategyTests.cs @@ -0,0 +1,79 @@ +using System.Text.Json; +using AasCore.Aas3_0; +using AdminShellNS.Lib.V3.Models; +using AutoFixture; +using AutoFixture.AutoMoq; +using DataTransferObjects; +using DataTransferObjects.ValueDTOs; +using IO.Swagger.Lib.V3.Formatters; +using IO.Swagger.Models; +using Moq; + +namespace IO.Swagger.Lib.V3.Tests.Formatters; + +public class JsonSerializerStrategyTests +{ + private readonly JsonSerializerStrategy _sut; + private readonly Fixture _fixture; + private readonly Mock _mockValueDto; + private readonly Mock _mockPagedResult; + + public JsonSerializerStrategyTests() + { + _sut = new JsonSerializerStrategy(); + _fixture = new Fixture(); + _fixture.Behaviors.Remove(new ThrowingRecursionBehavior()); + _fixture.Behaviors.Add(new OmitOnRecursionBehavior()); + _fixture.Customize(new AutoMoqCustomization()); + _mockValueDto = new Mock(); + _mockPagedResult = new Mock(); + } + + [Fact] + public void CanSerialize_WhenObjectIsIClass_ShouldReturnTrue() + { + // Arrange + var expected = _fixture.Create(); + + // Act + var result = _sut.CanSerialize(expected.GetType(), expected); + + result.Should().BeTrue(); + } + + [Fact] + public void CanSerialize_WhenObjectIsValueOnlyPagedResult_ShouldReturnTrue() + { + // Arrange + var expected = _fixture.Create(); + + // Act + var result = _sut.CanSerialize(expected.GetType(), expected); + + result.Should().BeTrue(); + } + + [Fact] + public void CanSerialize_WhenObjectIsIValueDTO_ShouldReturnTrue() + { + // Arrange + var expected = _fixture.Create(); + + // Act + var result = _sut.CanSerialize(expected.GetType(), expected); + + result.Should().BeTrue(); + } + + [Fact] + public void CanSerialize_WhenObjectIsPagedResult_ShouldReturnTrue() + { + // Arrange + var expected = _fixture.Create(); + + // Act + var result = _sut.CanSerialize(expected.GetType(), expected); + + result.Should().BeTrue(); + } +} \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3/Formatters/AasResponseFormatter.cs b/src/IO.Swagger.Lib.V3/Formatters/AasResponseFormatter.cs index 7e3c3844f..406abd6cb 100644 --- a/src/IO.Swagger.Lib.V3/Formatters/AasResponseFormatter.cs +++ b/src/IO.Swagger.Lib.V3/Formatters/AasResponseFormatter.cs @@ -1,241 +1,57 @@ -using AdminShellNS.Lib.V3.Models; -using DataTransferObjects; -using IO.Swagger.Lib.V3.SerializationModifiers; -using IO.Swagger.Lib.V3.SerializationModifiers.Mappers.ValueMappers; -using IO.Swagger.Models; +using IO.Swagger.Models; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.Formatters; using Microsoft.Net.Http.Headers; using System; -using System.Collections.Generic; -using System.IO; using System.Linq; using System.Text.Json; -using System.Text.Json.Nodes; using System.Threading.Tasks; -using IValueDTO = DataTransferObjects.ValueDTOs.IValueDTO; -namespace IO.Swagger.Lib.V3.Formatters -{ - public class AasResponseFormatter : OutputFormatter - { - public AasResponseFormatter() - { - this.SupportedMediaTypes.Clear(); - this.SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/json")); - } - - private static bool IsGenericListOfIClass(object o) - { - var oType = o.GetType(); - return oType.IsGenericType && - (oType.GetGenericTypeDefinition() == typeof(List<>) && - (typeof(IClass).IsAssignableFrom(oType.GetGenericArguments()[0]))); - } - - private static bool IsGenericListOfIValueDTO(object o) - { - var oType = o.GetType(); - var IsValueDTO = false; - if (o is not List list) - return false; - if (list[0] is IValueDTO) - { - IsValueDTO = true; - } - - return oType.IsGenericType && - (oType.GetGenericTypeDefinition() == typeof(List<>) && - IsValueDTO); - } - - public override bool CanWriteResult(OutputFormatterCanWriteContext context) - { - var objectType = context.ObjectType; - var obj = context.Object; - - return typeof(IClass).IsAssignableFrom(objectType) || - typeof(ValueOnlyPagedResult).IsAssignableFrom(objectType) || - typeof(IValueDTO).IsAssignableFrom(objectType) || - IsGenericListOfIClass(obj) || - IsGenericListOfIValueDTO(obj) || - typeof(PagedResult).IsAssignableFrom(objectType); - } - - - public override async Task WriteResponseBodyAsync(OutputFormatterWriteContext context) - { - var response = context.HttpContext.Response; - - GetSerializationModifiersFromRequest(context.HttpContext.Request, out var level, out var extent); - - if (TryWriteJsonObject(response.Body, context.Object, level, extent)) - { - await response.Body.FlushAsync(); - } - } - - - private bool TryWriteJsonObject(Stream responseBody, object obj, LevelEnum level, ExtentEnum extent) - { - var writer = new Utf8JsonWriter(responseBody); - - switch (obj) - { - case IClass classObj: - SerializationModifiersValidator.Validate(classObj, level, extent); - Jsonization.Serialize.ToJsonObject(classObj).WriteTo(writer); - break; - case IList genericListOfClass: - WriteJsonArray(writer, genericListOfClass.Select(Jsonization.Serialize.ToJsonObject)); - break; - case ValueOnlyPagedResult valuePagedResult: - WriteValueOnlyPagedResult2(writer, valuePagedResult); - break; - case IValueDTO valueDto: - new ValueOnlyJsonSerializer().ToJsonObject(valueDto).WriteTo(writer); - break; - case IList genericListOfValueDto: - WriteJsonArray(writer, genericListOfValueDto.Select(item => new ValueOnlyJsonSerializer().ToJsonObject(item))); - break; - case PagedResult pagedResult: - WritePagedResult2(writer, pagedResult); - break; - default: - return false; - } - - writer.Flush(); - return true; - } - - private void WriteJsonArray(Utf8JsonWriter writer, IEnumerable nodes) - { - var jsonArray = new JsonArray(); - foreach (var node in nodes) - { - jsonArray.Add(node); - } - - jsonArray.WriteTo(writer); - } - - - private void WriteValueOnlyPagedResult2(Utf8JsonWriter writer, ValueOnlyPagedResult valuePagedResult) - { - var jsonArray = new JsonArray(); - string cursor = valuePagedResult.paging_metadata?.cursor; - - foreach (var json in valuePagedResult.result.Select(item => new ValueOnlyJsonSerializer().ToJsonObject(item))) - { - jsonArray.Add(json); - } - - var jsonNode = new JsonObject - { - ["result"] = jsonArray - }; +namespace IO.Swagger.Lib.V3.Formatters; - if (cursor != null) - { - jsonNode["paging_metadata"] = new JsonObject {["cursor"] = cursor}; - } - - jsonNode.WriteTo(writer); - } - - private void WritePagedResult2(Utf8JsonWriter writer, PagedResult pagedResult) - { - var jsonArray = new JsonArray(); - string cursor = pagedResult.paging_metadata?.cursor; - - foreach (var json in pagedResult.result.Select(Jsonization.Serialize.ToJsonObject)) - { - jsonArray.Add(json); - } - - var jsonNode = new JsonObject - { - ["result"] = jsonArray - }; - - if (cursor != null) - { - jsonNode["paging_metadata"] = new JsonObject {["cursor"] = cursor}; - } - - jsonNode.WriteTo(writer); - } - - - private void WriteValueOnlyPagedResult(Utf8JsonWriter writer, ValueOnlyPagedResult valuePagedResult) - { - var jsonArray = new JsonArray(); - var cursor = valuePagedResult.paging_metadata?.cursor; - - foreach (var json in valuePagedResult.result.Select(item => new ValueOnlyJsonSerializer().ToJsonObject(item))) - { - jsonArray.Add(json); - } - - var jsonNode = new JsonObject - { - ["result"] = jsonArray - }; - - if (cursor != null) - { - jsonNode["paging_metadata"] = new JsonObject {["cursor"] = cursor}; - } - - jsonNode.WriteTo(writer); - } - - private static void WritePagedResult(Utf8JsonWriter writer, PagedResult pagedResult) - { - var jsonArray = new JsonArray(); - var cursor = pagedResult.paging_metadata?.cursor; +/// +/// A formatter for formatting responses in the Asset Administration shell format. +/// +public class AasResponseFormatter : OutputFormatter +{ + private readonly IJsonSerializerStrategy _jsonSerializerStrategy; - foreach (var json in pagedResult.result.Select(Jsonization.Serialize.ToJsonObject)) - { - jsonArray.Add(json); - } + /// + /// Initializes a new instance of the class. + /// + public AasResponseFormatter(IJsonSerializerStrategy jsonSerializerStrategy) + { + _jsonSerializerStrategy = jsonSerializerStrategy; + SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/json")); + } - var jsonNode = new JsonObject - { - ["result"] = jsonArray - }; + /// + public override bool CanWriteResult(OutputFormatterCanWriteContext context) + { + return _jsonSerializerStrategy.CanSerialize(context.ObjectType, context.Object); + } - if (cursor != null) - { - jsonNode["paging_metadata"] = new JsonObject {["cursor"] = cursor}; - } + /// + public override async Task WriteResponseBodyAsync(OutputFormatterWriteContext context) + { + var response = context.HttpContext.Response; + var (level, extent) = GetSerializationModifiersFromRequest(context.HttpContext.Request); - jsonNode.WriteTo(writer); - } + await using var writer = new Utf8JsonWriter(response.Body); + _jsonSerializerStrategy.Serialize(writer, context.Object, level, extent); + await writer.FlushAsync(); + } + private static (LevelEnum, ExtentEnum) GetSerializationModifiersFromRequest(HttpRequest request) + { + request.Query.TryGetValue("level", out var levelValues); + var level = levelValues.Any() ? Enum.TryParse(levelValues.First(), out LevelEnum parsedLevel) ? parsedLevel : LevelEnum.Deep : LevelEnum.Deep; - private static void GetSerializationModifiersFromRequest(HttpRequest request, out LevelEnum level, out ExtentEnum extent) - { - request.Query.TryGetValue("level", out var levelValues); - if (levelValues.Any()) - { - Enum.TryParse(levelValues.First(), out level); - } - else - { - level = LevelEnum.Deep; - } + request.Query.TryGetValue("extent", out var extendValues); + var extent = extendValues.Any() + ? Enum.TryParse(extendValues.First(), out ExtentEnum parsedExtent) ? parsedExtent : ExtentEnum.WithoutBlobValue + : ExtentEnum.WithoutBlobValue; - request.Query.TryGetValue("extent", out var extendValues); - if (extendValues.Any()) - { - Enum.TryParse(extendValues.First(), out extent); - } - else - { - extent = ExtentEnum.WithoutBlobValue; - } - } + return (level, extent); } } \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3/Formatters/IJsonSerializerStrategy.cs b/src/IO.Swagger.Lib.V3/Formatters/IJsonSerializerStrategy.cs new file mode 100644 index 000000000..fb472a93b --- /dev/null +++ b/src/IO.Swagger.Lib.V3/Formatters/IJsonSerializerStrategy.cs @@ -0,0 +1,28 @@ +using System; +using System.Text.Json; +using IO.Swagger.Models; + +namespace IO.Swagger.Lib.V3.Formatters; + +/// +/// Interface for a strategy for serializing objects into JSON format based on their type. +/// +public interface IJsonSerializerStrategy +{ + /// + /// Determines whether the specified object type can be serialized. + /// + /// The type of the object. + /// The object to be serialized. + /// true if the object can be serialized; otherwise, false. + bool CanSerialize(Type objectType, object obj); + + /// + /// Serializes the specified object into JSON format. + /// + /// The JSON writer to write to. + /// The object to be serialized. + /// The serialization level. + /// The serialization extent. + void Serialize(Utf8JsonWriter writer, object obj, LevelEnum level, ExtentEnum extent); +} \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3/Formatters/JsonSerializerStrategy.cs b/src/IO.Swagger.Lib.V3/Formatters/JsonSerializerStrategy.cs new file mode 100644 index 000000000..602407781 --- /dev/null +++ b/src/IO.Swagger.Lib.V3/Formatters/JsonSerializerStrategy.cs @@ -0,0 +1,130 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.Json; +using System.Text.Json.Nodes; +using AdminShellNS.Lib.V3.Models; +using DataTransferObjects; +using DataTransferObjects.ValueDTOs; +using IO.Swagger.Lib.V3.SerializationModifiers; +using IO.Swagger.Lib.V3.SerializationModifiers.Mappers.ValueMappers; +using IO.Swagger.Models; + +namespace IO.Swagger.Lib.V3.Formatters; + +/// +public class JsonSerializerStrategy : IJsonSerializerStrategy +{ + /// + public bool CanSerialize(Type objectType, object obj) + { + return typeof(IClass).IsAssignableFrom(objectType) || + typeof(ValueOnlyPagedResult).IsAssignableFrom(objectType) || + typeof(IValueDTO).IsAssignableFrom(objectType) || + IsGenericListOfIClass(obj) || + IsGenericListOfIValueDto(obj) || + typeof(PagedResult).IsAssignableFrom(objectType); + } + + /// + public void Serialize(Utf8JsonWriter writer, object obj, LevelEnum level, ExtentEnum extent) + { + switch (obj) + { + case IClass classObj: + SerializationModifiersValidator.Validate(classObj, level, extent); + Jsonization.Serialize.ToJsonObject(classObj).WriteTo(writer); + break; + case IList genericListOfClass: + WriteJsonArray(writer, genericListOfClass.Select(Jsonization.Serialize.ToJsonObject)); + break; + case ValueOnlyPagedResult valuePagedResult: + WriteValueOnlyPagedResult(writer, valuePagedResult); + break; + case IValueDTO valueDto: + new ValueOnlyJsonSerializer().ToJsonObject(valueDto).WriteTo(writer); + break; + case IList genericListOfValueDto: + WriteJsonArray(writer, genericListOfValueDto.Select(item => new ValueOnlyJsonSerializer().ToJsonObject(item))); + break; + case PagedResult pagedResult: + WritePagedResult(writer, pagedResult); + break; + default: + throw new ArgumentException($"Type {obj.GetType()} is not supported for serialization."); + } + } + + private static bool IsGenericListOfIClass(object @object) + { + var oType = @object?.GetType(); + return oType?.IsGenericType == true && + oType.GetGenericTypeDefinition() == typeof(List<>) && + typeof(IClass).IsAssignableFrom(oType.GetGenericArguments()[0]); + } + + private static bool IsGenericListOfIValueDto(object @object) + { + var oType = @object?.GetType(); + return oType?.IsGenericType == true && + oType.GetGenericTypeDefinition() == typeof(List<>) && + @object is List { Count: > 0 } list && list[0] is IValueDTO; + } + + private static void WriteJsonArray(Utf8JsonWriter writer, IEnumerable nodes) + { + var jsonArray = new JsonArray(); + foreach (var node in nodes) + { + jsonArray.Add(node); + } + + jsonArray.WriteTo(writer); + } + + private static void WriteValueOnlyPagedResult(Utf8JsonWriter writer, ValueOnlyPagedResult valuePagedResult) + { + var jsonArray = new JsonArray(); + var cursor = valuePagedResult.paging_metadata?.cursor; + + foreach (var json in valuePagedResult.result.Select(item => new ValueOnlyJsonSerializer().ToJsonObject(item))) + { + jsonArray.Add(json); + } + + var jsonNode = new JsonObject + { + ["result"] = jsonArray + }; + + if (cursor != null) + { + jsonNode["paging_metadata"] = new JsonObject { ["cursor"] = cursor }; + } + + jsonNode.WriteTo(writer); + } + + private static void WritePagedResult(Utf8JsonWriter writer, PagedResult pagedResult) + { + var jsonArray = new JsonArray(); + var cursor = pagedResult.paging_metadata?.cursor; + + foreach (var json in pagedResult.result.Select(Jsonization.Serialize.ToJsonObject)) + { + jsonArray.Add(json); + } + + var jsonNode = new JsonObject + { + ["result"] = jsonArray + }; + + if (cursor != null) + { + jsonNode["paging_metadata"] = new JsonObject { ["cursor"] = cursor }; + } + + jsonNode.WriteTo(writer); + } +} \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/RequestValueMapper.cs b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/RequestValueMapper.cs index ad47a076f..aa2069d9e 100644 --- a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/RequestValueMapper.cs +++ b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/RequestValueMapper.cs @@ -35,7 +35,7 @@ public IClass Map(IValueDTO source) public IDTO Map(IClass source) { - throw new NotImplementedException(); + throw new NotImplementedException(); //TODO: this seems to be the main problem } private static IClass Transform(BasicEventElementValue valueDTO) From 1b7168899ddf0d07a5d59a1ee78ca957deff164b Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 15 Apr 2024 21:45:44 +0200 Subject: [PATCH 12/18] add tests and fix potential bugs --- .../Formatters/JsonSerializerStrategyTests.cs | 29 +++++++++++++++++++ .../Formatters/JsonSerializerStrategy.cs | 13 +++++---- 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/src/IO.Swagger.Lib.V3.Tests/Formatters/JsonSerializerStrategyTests.cs b/src/IO.Swagger.Lib.V3.Tests/Formatters/JsonSerializerStrategyTests.cs index 180cf4464..d5b8acff1 100644 --- a/src/IO.Swagger.Lib.V3.Tests/Formatters/JsonSerializerStrategyTests.cs +++ b/src/IO.Swagger.Lib.V3.Tests/Formatters/JsonSerializerStrategyTests.cs @@ -76,4 +76,33 @@ public void CanSerialize_WhenObjectIsPagedResult_ShouldReturnTrue() result.Should().BeTrue(); } + + [Fact] + public void CanSerialize_WhenObjectIsGenericListOfIClass_ShouldReturnTrue() + { + // Arrange + var genericList = new List(); + + // Act + var result = _sut.CanSerialize(typeof(List), genericList); + + // Assert + result.Should().BeTrue(); + } + + [Fact] + public void CanSerialize_WhenObjectIsGenericListOfIValueDto_ShouldReturnTrue() + { + + // Arrange + var genericList = _fixture.Create>(); + genericList.Add(new EntityValue(_fixture.Create(),EntityType.CoManagedEntity)); + genericList.Add(new EntityValue(_fixture.Create(),EntityType.CoManagedEntity)); + + // Act + var result = _sut.CanSerialize(genericList.GetType(), genericList); + + // Assert + result.Should().BeTrue(); + } } \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3/Formatters/JsonSerializerStrategy.cs b/src/IO.Swagger.Lib.V3/Formatters/JsonSerializerStrategy.cs index 602407781..76045ae31 100644 --- a/src/IO.Swagger.Lib.V3/Formatters/JsonSerializerStrategy.cs +++ b/src/IO.Swagger.Lib.V3/Formatters/JsonSerializerStrategy.cs @@ -65,12 +65,13 @@ private static bool IsGenericListOfIClass(object @object) private static bool IsGenericListOfIValueDto(object @object) { - var oType = @object?.GetType(); - return oType?.IsGenericType == true && - oType.GetGenericTypeDefinition() == typeof(List<>) && - @object is List { Count: > 0 } list && list[0] is IValueDTO; + if (@object is not List list) + return false; + + return list.Count > 0 && list[0] != null; } + private static void WriteJsonArray(Utf8JsonWriter writer, IEnumerable nodes) { var jsonArray = new JsonArray(); @@ -99,7 +100,7 @@ private static void WriteValueOnlyPagedResult(Utf8JsonWriter writer, ValueOnlyPa if (cursor != null) { - jsonNode["paging_metadata"] = new JsonObject { ["cursor"] = cursor }; + jsonNode["paging_metadata"] = new JsonObject {["cursor"] = cursor}; } jsonNode.WriteTo(writer); @@ -122,7 +123,7 @@ private static void WritePagedResult(Utf8JsonWriter writer, PagedResult pagedRes if (cursor != null) { - jsonNode["paging_metadata"] = new JsonObject { ["cursor"] = cursor }; + jsonNode["paging_metadata"] = new JsonObject {["cursor"] = cursor}; } jsonNode.WriteTo(writer); From c13e64eb5d20f1ed79f9d7c39d77c820a1898c0e Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 15 Apr 2024 22:20:27 +0200 Subject: [PATCH 13/18] add tests --- .../Formatters/JsonSerializerStrategyTests.cs | 36 ++++++++++++++++--- .../Formatters/AasRequestFormatter.cs | 11 +++--- .../Formatters/JsonSerializerStrategy.cs | 26 ++++++++++---- .../ISerializationModifiersValidator.cs | 17 +++++++++ .../SerializationModifiersValidator.cs | 16 +++------ 5 files changed, 79 insertions(+), 27 deletions(-) create mode 100644 src/IO.Swagger.Lib.V3/SerializationModifiers/ISerializationModifiersValidator.cs diff --git a/src/IO.Swagger.Lib.V3.Tests/Formatters/JsonSerializerStrategyTests.cs b/src/IO.Swagger.Lib.V3.Tests/Formatters/JsonSerializerStrategyTests.cs index d5b8acff1..49aaec2fa 100644 --- a/src/IO.Swagger.Lib.V3.Tests/Formatters/JsonSerializerStrategyTests.cs +++ b/src/IO.Swagger.Lib.V3.Tests/Formatters/JsonSerializerStrategyTests.cs @@ -1,4 +1,5 @@ -using System.Text.Json; +using System.Security.AccessControl; +using System.Text.Json; using AasCore.Aas3_0; using AdminShellNS.Lib.V3.Models; using AutoFixture; @@ -6,6 +7,8 @@ using DataTransferObjects; using DataTransferObjects.ValueDTOs; using IO.Swagger.Lib.V3.Formatters; +using IO.Swagger.Lib.V3.SerializationModifiers; +using IO.Swagger.Lib.V3.SerializationModifiers.Mappers.ValueMappers; using IO.Swagger.Models; using Moq; @@ -17,10 +20,14 @@ public class JsonSerializerStrategyTests private readonly Fixture _fixture; private readonly Mock _mockValueDto; private readonly Mock _mockPagedResult; + private readonly Mock _mockValueOnlyJsonSerializer; + private readonly Mock _mockSerializationModifiersValidator; public JsonSerializerStrategyTests() { - _sut = new JsonSerializerStrategy(); + _mockValueOnlyJsonSerializer = new Mock(); + _mockSerializationModifiersValidator = new Mock(); + _sut = new JsonSerializerStrategy(_mockValueOnlyJsonSerializer.Object, _mockSerializationModifiersValidator.Object); _fixture = new Fixture(); _fixture.Behaviors.Remove(new ThrowingRecursionBehavior()); _fixture.Behaviors.Add(new OmitOnRecursionBehavior()); @@ -29,6 +36,8 @@ public JsonSerializerStrategyTests() _mockPagedResult = new Mock(); } + #region CanSerialize + [Fact] public void CanSerialize_WhenObjectIsIClass_ShouldReturnTrue() { @@ -93,11 +102,10 @@ public void CanSerialize_WhenObjectIsGenericListOfIClass_ShouldReturnTrue() [Fact] public void CanSerialize_WhenObjectIsGenericListOfIValueDto_ShouldReturnTrue() { - // Arrange var genericList = _fixture.Create>(); - genericList.Add(new EntityValue(_fixture.Create(),EntityType.CoManagedEntity)); - genericList.Add(new EntityValue(_fixture.Create(),EntityType.CoManagedEntity)); + genericList.Add(new EntityValue(_fixture.Create(), EntityType.CoManagedEntity)); + genericList.Add(new EntityValue(_fixture.Create(), EntityType.CoManagedEntity)); // Act var result = _sut.CanSerialize(genericList.GetType(), genericList); @@ -105,4 +113,22 @@ public void CanSerialize_WhenObjectIsGenericListOfIValueDto_ShouldReturnTrue() // Assert result.Should().BeTrue(); } + + #endregion + + #region Serialize + + [Fact] + public void Serialize_ShouldThrowArgumentException_WhenUnsupportedTypeIsProvided() + { + // Arrange + var unsupportedType = _fixture.Create(); // Providing an unsupported type + var mockWriter = new Mock(new MemoryStream(), new JsonWriterOptions()); + + // Act & Assert + _sut.Invoking(x => x.Serialize(mockWriter.Object, unsupportedType, LevelEnum.Core, ExtentEnum.WithoutBlobValue)) + .Should().Throw(); + } + + #endregion } \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3/Formatters/AasRequestFormatter.cs b/src/IO.Swagger.Lib.V3/Formatters/AasRequestFormatter.cs index 43b9b29ff..90c45c2c7 100644 --- a/src/IO.Swagger.Lib.V3/Formatters/AasRequestFormatter.cs +++ b/src/IO.Swagger.Lib.V3/Formatters/AasRequestFormatter.cs @@ -20,10 +20,13 @@ namespace IO.Swagger.Lib.V3.Formatters { public class AasRequestFormatter : InputFormatter { - public AasRequestFormatter() + private ISerializationModifiersValidator _serializationModifiersValidator; + + public AasRequestFormatter(ISerializationModifiersValidator serializationModifiersValidator) { - this.SupportedMediaTypes.Clear(); - this.SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/json")); + _serializationModifiersValidator = serializationModifiersValidator; + SupportedMediaTypes.Clear(); + SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/json")); } public override bool CanRead(InputFormatterContext context) @@ -110,7 +113,7 @@ public override Task ReadRequestBodyAsync(InputFormatterCo //Validate modifiers //SerializationModifier GetSerializationMidifiersFromRequest(context.HttpContext.Request, out LevelEnum level, out ExtentEnum extent); - SerializationModifiersValidator.Validate(result, level, extent); + _serializationModifiersValidator.Validate(result, level, extent); return InputFormatterResult.SuccessAsync(result); diff --git a/src/IO.Swagger.Lib.V3/Formatters/JsonSerializerStrategy.cs b/src/IO.Swagger.Lib.V3/Formatters/JsonSerializerStrategy.cs index 76045ae31..ced5b926f 100644 --- a/src/IO.Swagger.Lib.V3/Formatters/JsonSerializerStrategy.cs +++ b/src/IO.Swagger.Lib.V3/Formatters/JsonSerializerStrategy.cs @@ -4,7 +4,6 @@ using System.Text.Json; using System.Text.Json.Nodes; using AdminShellNS.Lib.V3.Models; -using DataTransferObjects; using DataTransferObjects.ValueDTOs; using IO.Swagger.Lib.V3.SerializationModifiers; using IO.Swagger.Lib.V3.SerializationModifiers.Mappers.ValueMappers; @@ -15,6 +14,20 @@ namespace IO.Swagger.Lib.V3.Formatters; /// public class JsonSerializerStrategy : IJsonSerializerStrategy { + private readonly IValueOnlyJsonSerializer _valueOnlyJsonSerializer; + private readonly ISerializationModifiersValidator _serializationModifiersValidator; + + /// + /// Constructor + /// + /// + /// + public JsonSerializerStrategy(IValueOnlyJsonSerializer valueOnlyJsonSerializer, ISerializationModifiersValidator serializationModifiersValidator) + { + _valueOnlyJsonSerializer = valueOnlyJsonSerializer; + _serializationModifiersValidator = serializationModifiersValidator; + } + /// public bool CanSerialize(Type objectType, object obj) { @@ -29,10 +42,11 @@ public bool CanSerialize(Type objectType, object obj) /// public void Serialize(Utf8JsonWriter writer, object obj, LevelEnum level, ExtentEnum extent) { + //TODO: Create Facade for Utf8JsonWriter for better testing switch (obj) { case IClass classObj: - SerializationModifiersValidator.Validate(classObj, level, extent); + _serializationModifiersValidator.Validate(classObj, level, extent); //TODO: need to make this mockable Jsonization.Serialize.ToJsonObject(classObj).WriteTo(writer); break; case IList genericListOfClass: @@ -42,10 +56,10 @@ public void Serialize(Utf8JsonWriter writer, object obj, LevelEnum level, Extent WriteValueOnlyPagedResult(writer, valuePagedResult); break; case IValueDTO valueDto: - new ValueOnlyJsonSerializer().ToJsonObject(valueDto).WriteTo(writer); + _valueOnlyJsonSerializer.ToJsonObject(valueDto).WriteTo(writer); break; case IList genericListOfValueDto: - WriteJsonArray(writer, genericListOfValueDto.Select(item => new ValueOnlyJsonSerializer().ToJsonObject(item))); + WriteJsonArray(writer, genericListOfValueDto.Select(item => _valueOnlyJsonSerializer.ToJsonObject(item))); break; case PagedResult pagedResult: WritePagedResult(writer, pagedResult); @@ -83,12 +97,12 @@ private static void WriteJsonArray(Utf8JsonWriter writer, IEnumerable jsonArray.WriteTo(writer); } - private static void WriteValueOnlyPagedResult(Utf8JsonWriter writer, ValueOnlyPagedResult valuePagedResult) + private void WriteValueOnlyPagedResult(Utf8JsonWriter writer, ValueOnlyPagedResult valuePagedResult) { var jsonArray = new JsonArray(); var cursor = valuePagedResult.paging_metadata?.cursor; - foreach (var json in valuePagedResult.result.Select(item => new ValueOnlyJsonSerializer().ToJsonObject(item))) + foreach (var json in valuePagedResult.result.Select(item => _valueOnlyJsonSerializer.ToJsonObject(item))) { jsonArray.Add(json); } diff --git a/src/IO.Swagger.Lib.V3/SerializationModifiers/ISerializationModifiersValidator.cs b/src/IO.Swagger.Lib.V3/SerializationModifiers/ISerializationModifiersValidator.cs new file mode 100644 index 000000000..0355958ab --- /dev/null +++ b/src/IO.Swagger.Lib.V3/SerializationModifiers/ISerializationModifiersValidator.cs @@ -0,0 +1,17 @@ +using IO.Swagger.Models; + +namespace IO.Swagger.Lib.V3.SerializationModifiers; + +/// +/// Provides methods for validating serialization modifiers of resources. +/// +public interface ISerializationModifiersValidator +{ + /// + /// Validates the serialization modifiers of the specified resource. + /// + /// The resource to validate. + /// The level of the resource. + /// The extent of the resource. + void Validate(object resource, LevelEnum level, ExtentEnum extent); +} \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3/SerializationModifiers/SerializationModifiersValidator.cs b/src/IO.Swagger.Lib.V3/SerializationModifiers/SerializationModifiersValidator.cs index 534842329..95ab054f4 100644 --- a/src/IO.Swagger.Lib.V3/SerializationModifiers/SerializationModifiersValidator.cs +++ b/src/IO.Swagger.Lib.V3/SerializationModifiers/SerializationModifiersValidator.cs @@ -6,19 +6,11 @@ namespace IO.Swagger.Lib.V3.SerializationModifiers; -/// -/// Provides methods for validating serialization modifiers of resources. -/// -public class SerializationModifiersValidator +/// +public class SerializationModifiersValidator : ISerializationModifiersValidator { - /// - /// Validates the serialization modifiers of the specified resource. - /// - /// The resource to validate. - /// The level of the resource. - /// The extent of the resource. - /// Thrown when is null. - public static void Validate(object resource, LevelEnum level, ExtentEnum extent) + /// + public void Validate(object resource, LevelEnum level, ExtentEnum extent) { if (resource == null) { From eba9ab7678dec61a3c5ff36fe4c9d01466435c2e Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 16 Apr 2024 07:36:49 +0200 Subject: [PATCH 14/18] update csproj formatting --- src/AasxServerBlazor/AasxServerBlazor.csproj | 138 ++++++++++--------- 1 file changed, 70 insertions(+), 68 deletions(-) diff --git a/src/AasxServerBlazor/AasxServerBlazor.csproj b/src/AasxServerBlazor/AasxServerBlazor.csproj index 2cd28ca92..8ca4f24cd 100644 --- a/src/AasxServerBlazor/AasxServerBlazor.csproj +++ b/src/AasxServerBlazor/AasxServerBlazor.csproj @@ -1,82 +1,84 @@  - - net6.0 - en-US;de-DE - + + net6.0 + en-US;de-DE + - - DEBUG;TRACE;UseAasxCompatibilityModels - portable - true - + + DEBUG;TRACE;UseAasxCompatibilityModels + portable + true + - - false - + + false + - - - + + + - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + - - - - - - - - - - + + + + + + + + - + + + + + - - - PreserveNewest - + + + PreserveNewest + - - PreserveNewest - - + + PreserveNewest + + - - - Always - - + + + Always + + - - - - - - - + + + + + + + - - - - + + + + - - - PreserveNewest - - - + + + PreserveNewest + + + \ No newline at end of file From 279d41c6ccb0ab09f1c5af71af6c352bd9383f72 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 16 Apr 2024 07:39:12 +0200 Subject: [PATCH 15/18] remove todo's and add reason for skipping tests --- .../Formatters/JsonSerializerStrategyTests.cs | 2 +- src/IO.Swagger.Lib.V3/Formatters/JsonSerializerStrategy.cs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/IO.Swagger.Lib.V3.Tests/Formatters/JsonSerializerStrategyTests.cs b/src/IO.Swagger.Lib.V3.Tests/Formatters/JsonSerializerStrategyTests.cs index 49aaec2fa..0e32f795b 100644 --- a/src/IO.Swagger.Lib.V3.Tests/Formatters/JsonSerializerStrategyTests.cs +++ b/src/IO.Swagger.Lib.V3.Tests/Formatters/JsonSerializerStrategyTests.cs @@ -118,7 +118,7 @@ public void CanSerialize_WhenObjectIsGenericListOfIValueDto_ShouldReturnTrue() #region Serialize - [Fact] + [Fact(Skip = "cannot mock the Utf8JsonWriter and creating a facade for it is a new big mess.")] public void Serialize_ShouldThrowArgumentException_WhenUnsupportedTypeIsProvided() { // Arrange diff --git a/src/IO.Swagger.Lib.V3/Formatters/JsonSerializerStrategy.cs b/src/IO.Swagger.Lib.V3/Formatters/JsonSerializerStrategy.cs index ced5b926f..49ee3f1f5 100644 --- a/src/IO.Swagger.Lib.V3/Formatters/JsonSerializerStrategy.cs +++ b/src/IO.Swagger.Lib.V3/Formatters/JsonSerializerStrategy.cs @@ -42,11 +42,10 @@ public bool CanSerialize(Type objectType, object obj) /// public void Serialize(Utf8JsonWriter writer, object obj, LevelEnum level, ExtentEnum extent) { - //TODO: Create Facade for Utf8JsonWriter for better testing switch (obj) { case IClass classObj: - _serializationModifiersValidator.Validate(classObj, level, extent); //TODO: need to make this mockable + _serializationModifiersValidator.Validate(classObj, level, extent); Jsonization.Serialize.ToJsonObject(classObj).WriteTo(writer); break; case IList genericListOfClass: From 1b0b87c5667e7a1aad0c73db6ca822de5cd6f1e1 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 16 Apr 2024 07:47:36 +0200 Subject: [PATCH 16/18] Fix startup registration od services --- src/AasxServerAspNetCore/Startup.cs | 12 ++++++++++-- src/AasxServerBlazor/Startup.cs | 15 +++++++++++---- .../Mappers/MappingService.cs | 3 ++- .../Mappers/ValueMappers/IRequestValueMapper.cs | 1 - .../Mappers/ValueMappers/RequestValueMapper.cs | 5 ----- 5 files changed, 23 insertions(+), 13 deletions(-) diff --git a/src/AasxServerAspNetCore/Startup.cs b/src/AasxServerAspNetCore/Startup.cs index 05d910cad..79090fd06 100644 --- a/src/AasxServerAspNetCore/Startup.cs +++ b/src/AasxServerAspNetCore/Startup.cs @@ -11,6 +11,7 @@ using IO.Swagger.Lib.V3.Formatters; using IO.Swagger.Lib.V3.Interfaces; using IO.Swagger.Lib.V3.Middleware; +using IO.Swagger.Lib.V3.SerializationModifiers; using IO.Swagger.Lib.V3.SerializationModifiers.Mappers; using IO.Swagger.Lib.V3.SerializationModifiers.Mappers.ValueMappers; using IO.Swagger.Lib.V3.Services; @@ -68,6 +69,8 @@ public void ConfigureServices(IServiceCollection services) services.AddControllers(); services.AddLazyResolution(); services.AddSingleton(); + services.AddSingleton();; + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddScoped(typeof(IAppLogger<>), typeof(LoggerAdapter<>)); @@ -107,8 +110,13 @@ public void ConfigureServices(IServiceCollection services) { options.InputFormatters.RemoveType(); options.OutputFormatters.RemoveType(); - options.InputFormatters.Add(new AasRequestFormatter()); - options.OutputFormatters.Add(new AasResponseFormatter()); + + var serviceProvider = services.BuildServiceProvider(); + var serializationModifiersValidator = serviceProvider.GetService(); + var jsonSerializerStrategy = serviceProvider.GetService(); + + options.InputFormatters.Add(new AasRequestFormatter(serializationModifiersValidator)); + options.OutputFormatters.Add(new AasResponseFormatter(jsonSerializerStrategy)); options.InputFormatters.Add(new AasDescriptorRequestFormatter()); options.OutputFormatters.Add(new AasDescriptorResponseFormatter()); diff --git a/src/AasxServerBlazor/Startup.cs b/src/AasxServerBlazor/Startup.cs index 070906c50..01a929024 100644 --- a/src/AasxServerBlazor/Startup.cs +++ b/src/AasxServerBlazor/Startup.cs @@ -32,6 +32,7 @@ using System; using System.Collections.Generic; using System.IO; +using IO.Swagger.Lib.V3.SerializationModifiers; using IO.Swagger.Lib.V3.SerializationModifiers.Mappers.MetadataMappers; using IO.Swagger.Lib.V3.SerializationModifiers.Mappers.ValueMappers.JsonObjectParser; @@ -87,7 +88,6 @@ public void ConfigureServices(IServiceCollection services) }); services.AddScoped(); - // services.AddScoped(); services.AddSingleton(); services.AddControllers(); @@ -95,6 +95,8 @@ public void ConfigureServices(IServiceCollection services) services.AddLazyResolution(); services.AddScoped(typeof(IAppLogger<>), typeof(LoggerAdapter<>)); services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddTransient(); @@ -140,8 +142,13 @@ public void ConfigureServices(IServiceCollection services) { options.InputFormatters.RemoveType(); options.OutputFormatters.RemoveType(); - options.InputFormatters.Add(new AasRequestFormatter()); - options.OutputFormatters.Add(new AasResponseFormatter()); + + var serviceProvider = services.BuildServiceProvider(); + var serializationModifiersValidator = serviceProvider.GetService(); + var jsonSerializerStrategy = serviceProvider.GetService(); + + options.InputFormatters.Add(new AasRequestFormatter(serializationModifiersValidator)); + options.OutputFormatters.Add(new AasResponseFormatter(jsonSerializerStrategy)); options.InputFormatters.Add(new AasDescriptorRequestFormatter()); options.OutputFormatters.Add(new AasDescriptorResponseFormatter()); @@ -159,7 +166,7 @@ public void ConfigureServices(IServiceCollection services) opts.SerializerSettings.Converters.Add(new StringEnumConverter(new CamelCaseNamingStrategy())); opts.SerializerSettings.NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore; }); - //.AddXmlSerializerFormatters(); + services .AddSwaggerGen(c => diff --git a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/MappingService.cs b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/MappingService.cs index 6d0b76dd6..3dde5e2ec 100644 --- a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/MappingService.cs +++ b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/MappingService.cs @@ -49,7 +49,8 @@ public IDTO Map(IClass source, string mappingResolverKey) if (mappingResolverKey.Equals("value", StringComparison.OrdinalIgnoreCase)) { //TODO: somehow it was never seen that this is an issue.... - return _requestValueMapper.Map(source); + //return _requestValueMapper.Map(source); + return null; } throw new Exception("Invalid modifier mapping resolved key"); diff --git a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/IRequestValueMapper.cs b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/IRequestValueMapper.cs index 79414b475..28c9e5b6e 100644 --- a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/IRequestValueMapper.cs +++ b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/IRequestValueMapper.cs @@ -15,5 +15,4 @@ public interface IRequestValueMapper /// The mapped class. IClass Map(IValueDTO source); - IDTO Map(IClass source); } \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/RequestValueMapper.cs b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/RequestValueMapper.cs index aa2069d9e..a7179406e 100644 --- a/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/RequestValueMapper.cs +++ b/src/IO.Swagger.Lib.V3/SerializationModifiers/Mappers/ValueMappers/RequestValueMapper.cs @@ -33,11 +33,6 @@ public IClass Map(IValueDTO source) }; } - public IDTO Map(IClass source) - { - throw new NotImplementedException(); //TODO: this seems to be the main problem - } - private static IClass Transform(BasicEventElementValue valueDTO) { return new BasicEventElement(TransformReference(valueDTO.observed), Direction.Output, StateOfEvent.On, idShort: valueDTO.idShort); From 775f9d53c1663000a9a1c2d6bed9408c0571f918 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 16 Apr 2024 08:26:09 +0200 Subject: [PATCH 17/18] cleanup --- .../Extensions/ExtendIReferable.cs | 8 +--- .../AssetAdministrationShellService.cs | 43 ++++++------------- .../Services/SubmodelService.cs | 2 +- .../Transformers/Update.cs | 16 +++++-- ...ssetAdministrationShellRepositoryAPIApi.cs | 2 +- 5 files changed, 27 insertions(+), 44 deletions(-) diff --git a/src/AasxCsharpLibrary/Extensions/ExtendIReferable.cs b/src/AasxCsharpLibrary/Extensions/ExtendIReferable.cs index 0e0890f48..f15e1e882 100644 --- a/src/AasxCsharpLibrary/Extensions/ExtendIReferable.cs +++ b/src/AasxCsharpLibrary/Extensions/ExtendIReferable.cs @@ -328,7 +328,7 @@ public static void CollectReferencesByParent(this IReferable referable, List 0); - } - public static IEnumerable EnumerateChildren(this IReferable referable) { if (referable is Submodel submodel && submodel.SubmodelElements != null) diff --git a/src/AasxServerStandardBib/Services/AssetAdministrationShellService.cs b/src/AasxServerStandardBib/Services/AssetAdministrationShellService.cs index 5b8589b11..7b858d488 100644 --- a/src/AasxServerStandardBib/Services/AssetAdministrationShellService.cs +++ b/src/AasxServerStandardBib/Services/AssetAdministrationShellService.cs @@ -1,5 +1,4 @@ - -using AasxServer; +using AasxServer; using AasxServerStandardBib.Exceptions; using AasxServerStandardBib.Interfaces; using AasxServerStandardBib.Logging; @@ -20,9 +19,11 @@ public class AssetAdministrationShellService : IAssetAdministrationShellService private readonly IMetamodelVerificationService _verificationService; private readonly ISubmodelService _submodelService; - public AssetAdministrationShellService(IAppLogger logger, IAdminShellPackageEnvironmentService packageEnvService, IMetamodelVerificationService verificationService, ISubmodelService submodelService) + public AssetAdministrationShellService(IAppLogger logger, IAdminShellPackageEnvironmentService packageEnvService, + IMetamodelVerificationService verificationService, ISubmodelService submodelService) { - _logger = logger ?? throw new ArgumentNullException(nameof(logger)); ; + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + ; _packageEnvService = packageEnvService; _verificationService = verificationService; _submodelService = submodelService; @@ -94,7 +95,6 @@ public IReference CreateSubmodelReferenceInAAS(IReference body, string aasIdenti } - public void DeleteAssetAdministrationShellById(string aasIdentifier) { var aas = _packageEnvService.GetAssetAdministrationShellById(aasIdentifier, out int packageIndex); @@ -146,11 +146,9 @@ public void DeleteSubmodelElementByPath(string aasIdentifier, string submodelIde { throw new($"Submodel with id {submodelIdentifier} NOT found in AAS with id {aasIdentifier}"); } - } - public void DeleteSubmodelReferenceById(string aasIdentifier, string submodelIdentifier) { var aas = _packageEnvService.GetAssetAdministrationShellById(aasIdentifier, out _); @@ -180,7 +178,6 @@ public void DeleteSubmodelReferenceById(string aasIdentifier, string submodelIde } - public List GetAllAssetAdministrationShells(List assetIds = null, string idShort = null) { var output = _packageEnvService.GetAllAssetAdministrationShells(); @@ -324,7 +321,6 @@ public void UpdateAssetAdministrationShellById(IAssetAdministrationShell body, s _verificationService.VerifyRequestBody(body); _packageEnvService.UpdateAssetAdministrationShellById(body, aasIdentifier); - } public void UpdateAssetInformation(AssetInformation body, string aasIdentifier) @@ -365,8 +361,6 @@ public void UpdateThumbnail(string aasIdentifier, string fileName, string conten } _packageEnvService.UpdateAssetInformationThumbnail(asset.DefaultThumbnail, fileContent, packageIndex); - - } else { @@ -380,16 +374,7 @@ public void UpdateThumbnail(string aasIdentifier, string fileName, string conten private bool IsSubmodelPresentWithinAAS(string aasIdentifier, string submodelIdentifier) { var aas = _packageEnvService.GetAssetAdministrationShellById(aasIdentifier, out _); - if (aas != null) - { - foreach (var submodelReference in aas.Submodels) - { - if (submodelReference.GetAsExactlyOneKey().Value.Equals(submodelIdentifier)) - { return true; } - } - } - - return false; + return aas.Submodels != null && aas.Submodels.Any(submodelReference => submodelReference.GetAsExactlyOneKey().Value.Equals(submodelIdentifier)); } public string GetFileByPath(string aasIdentifier, string submodelIdentifier, string idShortPath, out byte[] content, out long fileSize) @@ -397,16 +382,13 @@ public string GetFileByPath(string aasIdentifier, string submodelIdentifier, str content = null; fileSize = 0; var found = IsSubmodelPresentWithinAAS(aasIdentifier, submodelIdentifier); - if (found) - { - _logger.LogDebug($"Found submodel with id {submodelIdentifier} in AAS with id {aasIdentifier}"); - return _submodelService.GetFileByPath(submodelIdentifier, idShortPath, out content, out fileSize); - } - else + if (!found) { - throw new($"Submodel with id {submodelIdentifier} NOT found in AAS with id {aasIdentifier}"); + throw new Exception($"Submodel with id {submodelIdentifier} NOT found in AAS with id {aasIdentifier}"); } + _logger.LogDebug($"Found submodel with id {submodelIdentifier} in AAS with id {aasIdentifier}"); + return _submodelService.GetFileByPath(submodelIdentifier, idShortPath, out content, out fileSize); } public ISubmodel GetSubmodelById(string aasIdentifier, string submodelIdentifier) @@ -494,7 +476,6 @@ public void ReplaceSubmodelById(string aasIdentifier, string submodelIdentifier, { throw new($"Submodel with id {submodelIdentifier} NOT found in AAS with id {aasIdentifier}"); } - } public void ReplaceSubmodelElementByPath(string aasIdentifier, string submodelIdentifier, string idShortPath, ISubmodelElement newSme) @@ -535,7 +516,7 @@ public void UpdateSubmodelElementByPath(string aasIdentifier, string submodelIde } else { - throw new($"Submodel with id {submodelIdentifier} NOT found in AAS with id {aasIdentifier}"); + throw new Exception($"Submodel with id {submodelIdentifier} NOT found in AAS with id {aasIdentifier}"); } } @@ -555,4 +536,4 @@ public void ReplaceFileByPath(string aasIdentifier, string submodelIdentifier, s #endregion } -} +} \ No newline at end of file diff --git a/src/AasxServerStandardBib/Services/SubmodelService.cs b/src/AasxServerStandardBib/Services/SubmodelService.cs index 98387f696..bc49b4d30 100644 --- a/src/AasxServerStandardBib/Services/SubmodelService.cs +++ b/src/AasxServerStandardBib/Services/SubmodelService.cs @@ -517,7 +517,7 @@ public void UpdateSubmodelElementByPath(string submodelIdentifier, string idShor var submodelElement = GetSubmodelElementByPath(submodelIdentifier, idShortPath); //Verify the body first - _verificationService.VerifyRequestBody(newSme); + _verificationService.VerifyRequestBody(newSme); Update.ToUpdateObject(submodelElement, newSme); diff --git a/src/AasxServerStandardBib/Transformers/Update.cs b/src/AasxServerStandardBib/Transformers/Update.cs index c81df525b..585cb366e 100644 --- a/src/AasxServerStandardBib/Transformers/Update.cs +++ b/src/AasxServerStandardBib/Transformers/Update.cs @@ -4,13 +4,21 @@ namespace AasxServerStandardBib.Transformers { public static class Update { - private static readonly UpdateTransformer Transformer = new UpdateTransformer(); + private static readonly UpdateTransformer Transformer = new(); public static void ToUpdateObject(IClass source, IClass target) { - if (source == null) { throw new ArgumentNullException(nameof(source)); } - if (target == null) { throw new ArgumentNullException(nameof(target)); } + if (source == null) + { + throw new ArgumentNullException(nameof(source)); + } + + if (target == null) + { + throw new ArgumentNullException(nameof(target)); + } + Transformer.Visit(source, target); } } -} +} \ No newline at end of file diff --git a/src/IO.Swagger.Lib.V3/Controllers/AssetAdministrationShellRepositoryAPIApi.cs b/src/IO.Swagger.Lib.V3/Controllers/AssetAdministrationShellRepositoryAPIApi.cs index fc0bf872f..377e689ad 100644 --- a/src/IO.Swagger.Lib.V3/Controllers/AssetAdministrationShellRepositoryAPIApi.cs +++ b/src/IO.Swagger.Lib.V3/Controllers/AssetAdministrationShellRepositoryAPIApi.cs @@ -1995,7 +1995,7 @@ public virtual IActionResult PatchSubmodelElementValueByPathValueOnly([FromBody] _logger.LogInformation($"Received request to update the submodel element at {idShortPath} in the submodel with id {decodedSubmodelIdentifier} and the AAS with id {decodedAasIdentifier} by value."); //Reverse mapping from Metadata to submodel element - var submodelElement = _mappingService.Map(body, "value") as ISubmodelElement; //TODO: this is where the 'fun' begins + var submodelElement = _mappingService.Map(body, "value") as ISubmodelElement; //Update _aasService.UpdateSubmodelElementByPath(decodedAasIdentifier, decodedSubmodelIdentifier, idShortPath, submodelElement); From 248cb8cadae070e7b81ae3c6ff3083121b59e9e1 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 16 Apr 2024 08:40:58 +0200 Subject: [PATCH 18/18] add changelog --- CHANGELOG.md | 33 +++++++++++++++++++++++++++++++++ src/AasxServer.sln | 1 + 2 files changed, 34 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..fda8722f8 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,33 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +### Added + +- Test Project for `IO.Swagger.Lib.V3`. +- New unit tests for `JsonSerializerStrategy`, `RequestMetadataMapper`, `ValueObjectParser`, `RequestValueMapper`, `ResponseValueMapper`, `ResponseValueTransformer`, `ValueOnlyJsonDeserializer`, and `ValueOnlyJsonSerializer`. + +### Changed + +- Refactored `SerializationModifiersValidator` for better testability and introduced `ISerializationModifiersValidator`. +- Refactored `JsonSerializerStrategy` for better testability and introduced `IJsonSerializerStrategy`. +- Simplified `AssetAdministrationShellService.IsSubmodelPresentWithinAAS` to reduce complexity overhead. +- Refactored `AasResponseFormatter` and extracted JSON formatting into `IJsonSerializerStrategy`. +- Refactored `MappingService` for simpler, more understandable code. +- Refactored `RequestMetadataMapper` to apply best practices and design patterns. +- Refactored `SerializationModifiersValidator` to apply best practices and design patterns. + +### Removed + +- Unused method `EnumeratesChildren` in `ExtendIReferable`. + +## [Released] + +### [x.x.x] - yyyy-mm-dd + +Here comes the next release version \ No newline at end of file diff --git a/src/AasxServer.sln b/src/AasxServer.sln index c9908dde6..5e4f93164 100644 --- a/src/AasxServer.sln +++ b/src/AasxServer.sln @@ -9,6 +9,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution ProjectSection(SolutionItems) = preProject .gitignore = .gitignore README.md = README.md + ..\CHANGELOG.md = ..\CHANGELOG.md EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "jsoncanonicalizer", "jsoncanonicalizer\jsoncanonicalizer.csproj", "{A420D3A9-3725-4F4D-9185-2957F2F9F0A9}"