Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: keep nil values during (de)serialization #14127

Merged
merged 1 commit into from
Nov 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ private void ParseFieldProperty(ElementMetadata element, StringBuilder classBuil
else
{
elementOrder += 1;
AddXmlElementAnnotation(element, classBuilder, elementOrder);
AddXmlElementAnnotation(element, classBuilder, elementOrder, !isValueType && (element.Nillable ?? false));

// Temporary fix - as long as we use System.Text.Json for serialization and Newtonsoft.Json for
// deserialization, we need both JsonProperty and JsonPropertyName annotations.
Expand Down Expand Up @@ -265,16 +265,21 @@ private void ParseGroupProperty(ElementMetadata element, StringBuilder classBuil
}
}

private void AddXmlElementAnnotation(ElementMetadata element, StringBuilder classBuilder, int elementOrder)
private void AddXmlElementAnnotation(ElementMetadata element, StringBuilder classBuilder, int elementOrder, bool addNillableAttribute = false)
{
if (element.OrderOblivious)
string additionalAttributeParams = string.Empty;
if (!element.OrderOblivious)
{
classBuilder.AppendLine($"""{Indent(2)}[XmlElement("{element.XName}")]""");
additionalAttributeParams += $", Order = {elementOrder}";
}
else

if (addNillableAttribute)
{
classBuilder.AppendLine($"""{Indent(2)}[XmlElement("{element.XName}", Order = {elementOrder})]""");
additionalAttributeParams += ", IsNullable = true";
}


classBuilder.AppendLine($"""{Indent(2)}[XmlElement("{element.XName}"{additionalAttributeParams})]""");
}

private void AddShouldSerializeForTagContent(ElementMetadata element, StringBuilder classBuilder, ModelMetadata modelMetadata)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public void JsonSchemaWithStringFieldInUriFormatShouldConvertToCSharp(string jso
.Then.CompiledAssembly.Should().NotBeNull();
}

private void GeneratedClassesShouldBeEquivalentToExpected(string expectedCsharpClassPath)
private void GeneratedClassesShouldBeEquivalentToExpected(string expectedCsharpClassPath, bool overwriteExpected = false)
{
string expectedClasses = SharedResourcesHelper.LoadTestDataAsString(expectedCsharpClassPath);

Expand All @@ -86,7 +86,10 @@ private void GeneratedClassesShouldBeEquivalentToExpected(string expectedCsharpC
_testOutput.WriteLine(CSharpClasses);

// Save the current generated classes to the expected file so they can be compared with git diff.
SharedResourcesHelper.WriteUpdatedTestData(expectedCsharpClassPath, CSharpClasses);
if (overwriteExpected)
{
SharedResourcesHelper.WriteUpdatedTestData(expectedCsharpClassPath, CSharpClasses);
}

var expectedAssembly = Compiler.CompileToAssembly(expectedClasses);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.IO;
using System.Text;
using System.Xml.Serialization;
using SharedResources.Tests;

namespace DataModeling.Tests.Utils
{
Expand All @@ -20,7 +21,7 @@ public static object Deserialize(string xml, Type type)
public static string SerializeXml(object o)
{
var xmlSerializer = new XmlSerializer(o.GetType());
using var textWriter = new StringWriter();
using var textWriter = new Utf8StringWriter();
xmlSerializer.Serialize(textWriter, o);
return textWriter.ToString();
}
Expand Down
46 changes: 46 additions & 0 deletions backend/tests/DataModeling.Tests/XmlDeserializeSerializeTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using System;
using System.Linq;
using System.Xml.Linq;
using System.Xml.Serialization;
using DataModeling.Tests.BaseClasses;
using DataModeling.Tests.Utils;
using FluentAssertions;
using SharedResources.Tests;
using Xunit;

namespace DataModeling.Tests;

public class XmlDeserializeSerializeTests : CsharpModelConversionTestsBase<XmlDeserializeSerializeTests>
{
[Theory]
[InlineData("Model/XmlSchema/XsAll/xsall-example.xsd", "Model/Xml/XsAll/xsall-example-nillable-sample.xml")]
public void XmlDeserializeSerializeShouldKeepNillValue(string xsdSchemaPath, string xmlPath)
{
Given.That.XsdSchemaLoaded(xsdSchemaPath)
.When.LoadedXsdSchemaConvertedToJsonSchema()
.And.ConvertedJsonSchemaConvertedToModelMetadata()
.And.ModelMetadataConvertedToCsharpClass()
.And.CSharpClassesCompiledToAssembly()
.Then.CompiledAssembly.Should().NotBeNull();

And.DeserializeAndSerializeShouldProduceSameXml(xmlPath);
}

private void DeserializeAndSerializeShouldProduceSameXml(string xmlPath)
{
Type csharpType = CompiledAssembly.Types().Single(type => type.CustomAttributes.Any(att => att.AttributeType == typeof(XmlRootAttribute)));

string loadedXml = SharedResourcesHelper.LoadTestDataAsString(xmlPath);

// Deserialize xml to new object of type csharpType
object deserializedObject = SerializationHelper.Deserialize(loadedXml, csharpType);

// serialize xml back to string
string serializedXml = SerializationHelper.SerializeXml(deserializedObject);

// Compare the original xml with the serialized xml
var expected = XDocument.Parse(loadedXml);
var result = XDocument.Parse(serializedXml);
Assert.True(XNode.DeepEquals(expected, result));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,12 @@ public class Applikasjon
[JsonPropertyName("beskrivelse")]
public string beskrivelse { get; set; }

[XmlElement("miljoe", Order = 6)]
[XmlElement("miljoe", Order = 6, IsNullable = true)]
[JsonProperty("miljoe")]
[JsonPropertyName("miljoe")]
public string miljoe { get; set; }

[XmlElement("nettleserApplikasjonWebadresse", Order = 7)]
[XmlElement("nettleserApplikasjonWebadresse", Order = 7, IsNullable = true)]
[JsonProperty("nettleserApplikasjonWebadresse")]
[JsonPropertyName("nettleserApplikasjonWebadresse")]
public string nettleserApplikasjonWebadresse { get; set; }
Expand All @@ -77,32 +77,32 @@ public class Applikasjon

public class APIRessurs
{
[XmlElement("profile", Order = 1)]
[XmlElement("profile", Order = 1, IsNullable = true)]
[JsonProperty("profile")]
[JsonPropertyName("profile")]
public string profile { get; set; }

[XmlElement("organizationReportee", Order = 2)]
[XmlElement("organizationReportee", Order = 2, IsNullable = true)]
[JsonProperty("organizationReportee")]
[JsonPropertyName("organizationReportee")]
public string organizationReportee { get; set; }

[XmlElement("meldingsboks", Order = 3)]
[XmlElement("meldingsboks", Order = 3, IsNullable = true)]
[JsonProperty("meldingsboks")]
[JsonPropertyName("meldingsboks")]
public string meldingsboks { get; set; }

[XmlElement("lookup", Order = 4)]
[XmlElement("lookup", Order = 4, IsNullable = true)]
[JsonProperty("lookup")]
[JsonPropertyName("lookup")]
public string lookup { get; set; }

[XmlElement("broker", Order = 5)]
[XmlElement("broker", Order = 5, IsNullable = true)]
[JsonProperty("broker")]
[JsonPropertyName("broker")]
public string broker { get; set; }

[XmlElement("autorisasjon", Order = 6)]
[XmlElement("autorisasjon", Order = 6, IsNullable = true)]
[JsonProperty("autorisasjon")]
[JsonPropertyName("autorisasjon")]
public string autorisasjon { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,12 @@ public class Tjenesteeier
[JsonPropertyName("sektor")]
public string sektor { get; set; }

[XmlElement("navnNynorsk", Order = 4)]
[XmlElement("navnNynorsk", Order = 4, IsNullable = true)]
[JsonProperty("navnNynorsk")]
[JsonPropertyName("navnNynorsk")]
public string navnNynorsk { get; set; }

[XmlElement("navnEngelsk", Order = 5)]
[XmlElement("navnEngelsk", Order = 5, IsNullable = true)]
[JsonProperty("navnEngelsk")]
[JsonPropertyName("navnEngelsk")]
public string navnEngelsk { get; set; }
Expand Down
2 changes: 1 addition & 1 deletion testdata/Model/CSharp/Gitea/dat-skjema.cs
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ public class InnholdSkjema
public bool? BekreftRiktig { get; set; }

[RegularExpression(@"^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$")]
[XmlElement("AnsatteInnen", Order = 4)]
[XmlElement("AnsatteInnen", Order = 4, IsNullable = true)]
[JsonProperty("AnsatteInnen")]
[JsonPropertyName("AnsatteInnen")]
public string AnsatteInnen { get; set; }
Expand Down
12 changes: 6 additions & 6 deletions testdata/Model/CSharp/Gitea/nbib-melding.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,32 +12,32 @@ namespace Altinn.App.Models
[XmlRoot(ElementName="Message")]
public class MessageV1
{
[XmlElement("ProcessTask", Order = 1)]
[XmlElement("ProcessTask", Order = 1, IsNullable = true)]
[JsonProperty("ProcessTask")]
[JsonPropertyName("ProcessTask")]
public string ProcessTask { get; set; }

[XmlElement("ServiceName", Order = 2)]
[XmlElement("ServiceName", Order = 2, IsNullable = true)]
[JsonProperty("ServiceName")]
[JsonPropertyName("ServiceName")]
public string ServiceName { get; set; }

[XmlElement("Title", Order = 3)]
[XmlElement("Title", Order = 3, IsNullable = true)]
[JsonProperty("Title")]
[JsonPropertyName("Title")]
public string Title { get; set; }

[XmlElement("Body", Order = 4)]
[XmlElement("Body", Order = 4, IsNullable = true)]
[JsonProperty("Body")]
[JsonPropertyName("Body")]
public string Body { get; set; }

[XmlElement("Reference", Order = 5)]
[XmlElement("Reference", Order = 5, IsNullable = true)]
[JsonProperty("Reference")]
[JsonPropertyName("Reference")]
public string Reference { get; set; }

[XmlElement("Sender", Order = 6)]
[XmlElement("Sender", Order = 6, IsNullable = true)]
[JsonProperty("Sender")]
[JsonPropertyName("Sender")]
public string Sender { get; set; }
Expand Down
2 changes: 1 addition & 1 deletion testdata/Model/CSharp/Gitea/skjema.cs
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ public class InnholdSkjema
public string SamfunnskritiskBransje { get; set; }

[RegularExpression(@"^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$")]
[XmlElement("BenyttesFraDato", Order = 15)]
[XmlElement("BenyttesFraDato", Order = 15, IsNullable = true)]
[JsonProperty("BenyttesFraDato")]
[JsonPropertyName("BenyttesFraDato")]
public string BenyttesFraDato { get; set; }
Expand Down
Loading
Loading