Skip to content

Commit 1b773c5

Browse files
committed
Fix YAML and XML serialization, remove now useless Converters
1 parent 732d9a7 commit 1b773c5

7 files changed

Lines changed: 78 additions & 134 deletions

File tree

Lines changed: 31 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
using System.Globalization;
12
using System.Text.Json;
3+
using System.Text.Json.Nodes;
24
using System.Text.Json.Serialization;
35
using System.Text.Json.Serialization.Metadata;
46
using System.Xml;
@@ -84,104 +86,50 @@ private static string xml_to_json(string XML)
8486
AllowTrailingCommas = true,
8587
WriteIndented = true,
8688
};
87-
88-
public static JsonSerializerOptions ImportBundleOptions = new()
89-
{
90-
TypeInfoResolver = new DefaultJsonTypeInfoResolver(),
91-
NumberHandling =
92-
JsonNumberHandling.AllowNamedFloatingPointLiterals | JsonNumberHandling.AllowReadingFromString,
93-
AllowTrailingCommas = true,
94-
WriteIndented = true,
95-
Converters =
96-
{
97-
new Converters.FlexibleBooleanConverter(),
98-
new Converters.FlexibleStringConverter(),
99-
new Converters.FlexibleListStringConverter()
100-
}
101-
};
10289
}
10390

104-
internal class Converters
91+
public static class JsonNodeExtensions
10592
{
106-
public class FlexibleBooleanConverter : JsonConverter<bool>
93+
/// <summary>
94+
/// Safely gets a child node by key, returning null if the key does not exist.
95+
/// </summary>
96+
public static T GetVal<T>(this JsonNode node)
10797
{
108-
public override bool Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
109-
{
110-
return reader.TokenType switch
111-
{
112-
JsonTokenType.True => true,
113-
JsonTokenType.False => false,
114-
JsonTokenType.String => bool.TryParse(reader.GetString(), out var b) ? b :
115-
int.TryParse(reader.GetString(), out var i) ? i != 0 :
116-
throw new JsonException("Invalid string for boolean."),
117-
JsonTokenType.Number => reader.TryGetInt32(out var i2) ? i2 != 0 :
118-
throw new JsonException("Invalid number for boolean."),
119-
_ => throw new JsonException("Invalid token for boolean.")
120-
};
121-
}
98+
if (typeof(T) == typeof(double) && node.GetValueKind() is JsonValueKind.String)
99+
return (T)(object)double.Parse(node.GetValue<string>(), CultureInfo.InvariantCulture);
122100

123-
public override void Write(Utf8JsonWriter writer, bool value, JsonSerializerOptions options)
124-
{
125-
writer.WriteBooleanValue(value);
126-
}
127-
}
101+
if (typeof(T) == typeof(int) && node.GetValueKind() is JsonValueKind.String)
102+
return (T)(object)int.Parse(node.GetValue<string>());
128103

129-
public class FlexibleStringConverter : JsonConverter<string>
130-
{
131-
public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
132-
{
133-
if (reader.TokenType == JsonTokenType.StartObject)
134-
{
135-
using var doc = JsonDocument.ParseValue(ref reader);
136-
return "";
137-
}
138-
return reader.GetString() ?? "";
139-
}
104+
if (typeof(T) == typeof(bool) && node.GetValueKind() is JsonValueKind.String)
105+
return (T)(object)bool.Parse(node.GetValue<string>());
140106

141-
public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options)
107+
if (typeof(T) == typeof(string) && node.GetValueKind() is JsonValueKind.Object)
142108
{
143-
writer.WriteStringValue(value);
109+
return (T)(object)"";
144110
}
111+
112+
return node.GetValue<T>();
145113
}
146114

147-
public class FlexibleListStringConverter : JsonConverter<List<string>>
115+
/// <summary>
116+
/// The same as JsonNode.AsArray, but can convert objects whose keys are integers to arrays
117+
/// </summary>
118+
/// <param name="node"></param>
119+
/// <returns></returns>
120+
public static JsonArray AsArray2(this JsonNode node)
148121
{
149-
public override List<string> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
122+
if (node is JsonValue val)
150123
{
151-
if (reader.TokenType == JsonTokenType.StartObject)
152-
{
153-
using var doc = JsonDocument.ParseValue(ref reader);
154-
return [];
155-
}
156-
if (reader.TokenType == JsonTokenType.String)
157-
{
158-
return [reader.GetString() ?? ""];
159-
}
160-
if (reader.TokenType == JsonTokenType.StartArray)
161-
{
162-
var list = new List<string>();
163-
while (reader.Read())
164-
{
165-
if (reader.TokenType == JsonTokenType.EndArray)
166-
break;
167-
if (reader.TokenType == JsonTokenType.String)
168-
list.Add(reader.GetString() ?? string.Empty);
169-
}
170-
return list;
171-
}
172-
throw new JsonException($"Unexpected token {reader.TokenType} when reading List<string>.");
124+
JsonArray result = new();
125+
result.Add(val.DeepClone());
126+
return result;
173127
}
174-
175-
public override void Write(Utf8JsonWriter writer, List<string> value, JsonSerializerOptions options)
128+
else if (node is JsonObject obj && !obj.Any())
176129
{
177-
writer.WriteStartArray();
178-
foreach (var str in value)
179-
{
180-
writer.WriteStringValue(str);
181-
}
182-
writer.WriteEndArray();
130+
return new JsonArray();
183131
}
132+
133+
return node.AsArray();
184134
}
185135
}
186-
187-

src/UniGetUI.PackageEngine.Serializable/SerializableBundle.cs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System.Text.Json.Nodes;
22
using UniGetUI.PackageEngine.Serializable;
3+
using UniGetUI.Core.Data;
34

45
namespace UniGetUI.PackageEngine.Classes.Serializable
56
{
@@ -39,18 +40,20 @@ public override SerializableBundle Copy()
3940

4041
public override void LoadFromJson(JsonNode data)
4142
{
42-
this.export_version = data[nameof(export_version)]?.GetValue<double>() ?? 0;
43-
this.incompatible_packages_info = data[nameof(incompatible_packages_info)]?.GetValue<string>() ?? IncompatMessage;
43+
this.export_version = data[nameof(export_version)]?.GetVal<double>() ?? 0;
44+
this.incompatible_packages_info = data[nameof(incompatible_packages_info)]?.GetVal<string>() ?? IncompatMessage;
4445
this.packages = new List<SerializablePackage>();
4546
this.incompatible_packages = new List<SerializableIncompatiblePackage>();
4647

47-
foreach (JsonNode pkg in data[nameof(packages)] as JsonArray ?? [])
48+
foreach (JsonNode? pkg in data[nameof(packages)]?.AsArray2() ?? new())
4849
{
50+
if (pkg is null) throw new InvalidDataException("JsonNode? pkg was null, when it shouldn't");
4951
packages.Add(new SerializablePackage(pkg));
5052
}
5153

52-
foreach (JsonNode inc_pkg in data[nameof(incompatible_packages)] as JsonArray ?? [])
54+
foreach (JsonNode? inc_pkg in data[nameof(incompatible_packages)]?.AsArray2() ?? new())
5355
{
56+
if (inc_pkg is null) throw new InvalidDataException("JsonNode? inc_pkg was null, when it shouldn't");
5457
incompatible_packages.Add(new SerializableIncompatiblePackage(inc_pkg));
5558
}
5659
}

src/UniGetUI.PackageEngine.Serializable/SerializableIncompatiblePackage.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Text.Json.Nodes;
2+
using UniGetUI.Core.Data;
23
using UniGetUI.PackageEngine.Serializable;
34

45
namespace UniGetUI.PackageEngine.Classes.Serializable
@@ -20,10 +21,10 @@ public override SerializableIncompatiblePackage Copy()
2021

2122
public override void LoadFromJson(JsonNode data)
2223
{
23-
this.Id = data[nameof(Id)]?.GetValue<string>() ?? "";
24-
this.Name = data[nameof(Name)]?.GetValue<string>() ?? "";
25-
this.Version = data[nameof(Version)]?.GetValue<string>() ?? "";
26-
this.Source = data[nameof(Source)]?.GetValue<string>() ?? "";
24+
this.Id = data[nameof(Id)]?.GetVal<string>() ?? "";
25+
this.Name = data[nameof(Name)]?.GetVal<string>() ?? "";
26+
this.Version = data[nameof(Version)]?.GetVal<string>() ?? "";
27+
this.Source = data[nameof(Source)]?.GetVal<string>() ?? "";
2728
}
2829

2930
public SerializableIncompatiblePackage(JsonNode data) : base(data)

src/UniGetUI.PackageEngine.Serializable/SerializableInstallationOptions.cs

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Text.Json.Nodes;
2+
using UniGetUI.Core.Data;
23

34
namespace UniGetUI.PackageEngine.Serializable
45
{
@@ -34,20 +35,20 @@ public override SerializableInstallationOptions Copy()
3435

3536
public override void LoadFromJson(JsonNode data)
3637
{
37-
this.SkipHashCheck = data[nameof(SkipHashCheck)]?.GetValue<bool>() ?? false;
38-
this.InteractiveInstallation = data[nameof(InteractiveInstallation)]?.GetValue<bool>() ?? false;
39-
this.RunAsAdministrator = data[nameof(RunAsAdministrator)]?.GetValue<bool>() ?? false;
40-
this.Architecture = data[nameof(Architecture)]?.GetValue<string>() ?? "";
41-
this.InstallationScope = data[nameof(InstallationScope)]?.GetValue<string>() ?? "";
38+
this.SkipHashCheck = data[nameof(SkipHashCheck)]?.GetVal<bool>() ?? false;
39+
this.InteractiveInstallation = data[nameof(InteractiveInstallation)]?.GetVal<bool>() ?? false;
40+
this.RunAsAdministrator = data[nameof(RunAsAdministrator)]?.GetVal<bool>() ?? false;
41+
this.Architecture = data[nameof(Architecture)]?.GetVal<string>() ?? "";
42+
this.InstallationScope = data[nameof(InstallationScope)]?.GetVal<string>() ?? "";
4243

4344
this.CustomParameters = new List<string>();
44-
foreach(var element in data[nameof(CustomParameters)]?.AsArray() ?? [])
45-
if (element is not null) this.CustomParameters.Add(element.GetValue<string>());
45+
foreach(var element in data[nameof(CustomParameters)]?.AsArray2() ?? [])
46+
if (element is not null) this.CustomParameters.Add(element.GetVal<string>());
4647

47-
this.PreRelease = data[nameof(PreRelease)]?.GetValue<bool>() ?? false;
48-
this.CustomInstallLocation = data[nameof(CustomInstallLocation)]?.GetValue<string>() ?? "";
49-
this.Version = data[nameof(Version)]?.GetValue<string>() ?? "";
50-
this.SkipMinorUpdates = data[nameof(SkipMinorUpdates)]?.GetValue<bool>() ?? false;
48+
this.PreRelease = data[nameof(PreRelease)]?.GetVal<bool>() ?? false;
49+
this.CustomInstallLocation = data[nameof(CustomInstallLocation)]?.GetVal<string>() ?? "";
50+
this.Version = data[nameof(Version)]?.GetVal<string>() ?? "";
51+
this.SkipMinorUpdates = data[nameof(SkipMinorUpdates)]?.GetVal<bool>() ?? false;
5152
}
5253

5354
public SerializableInstallationOptions() : base()

src/UniGetUI.PackageEngine.Serializable/SerializablePackage.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Text.Json.Nodes;
2+
using UniGetUI.Core.Data;
23
using UniGetUI.PackageEngine.Serializable;
34

45
namespace UniGetUI.PackageEngine.Classes.Serializable
@@ -30,11 +31,11 @@ public override SerializablePackage Copy()
3031

3132
public override void LoadFromJson(JsonNode data)
3233
{
33-
this.Name = data[nameof(Name)]?.GetValue<string>() ?? "";
34-
this.Id = data[nameof(Id)]?.GetValue<string>() ?? "";
35-
this.Version = data[nameof(Version)]?.GetValue<string>() ?? "";
36-
this.Source = data[nameof(Source)]?.GetValue<string>() ?? "";
37-
this.ManagerName = data[nameof(ManagerName)]?.GetValue<string>() ?? "";
34+
this.Name = data[nameof(Name)]?.GetVal<string>() ?? "";
35+
this.Id = data[nameof(Id)]?.GetVal<string>() ?? "";
36+
this.Version = data[nameof(Version)]?.GetVal<string>() ?? "";
37+
this.Source = data[nameof(Source)]?.GetVal<string>() ?? "";
38+
this.ManagerName = data[nameof(ManagerName)]?.GetVal<string>() ?? "";
3839

3940
this.InstallationOptions = new(data[nameof(InstallationOptions)] ?? new JsonObject());
4041
this.Updates = new(data[nameof(Updates)] ?? new JsonObject());

src/UniGetUI.PackageEngine.Serializable/SerializableUpdatesOptions.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Text.Json.Nodes;
2+
using UniGetUI.Core.Data;
23
using UniGetUI.PackageEngine.Serializable;
34

45
namespace UniGetUI.PackageEngine.Classes.Serializable
@@ -15,8 +16,8 @@ public override SerializableUpdatesOptions Copy()
1516

1617
public override void LoadFromJson(JsonNode data)
1718
{
18-
this.UpdatesIgnored = data[nameof(UpdatesIgnored)]?.GetValue<bool>() ?? false;
19-
this.IgnoredVersion = data[nameof(IgnoredVersion)]?.GetValue<string>() ?? "";
19+
this.UpdatesIgnored = data[nameof(UpdatesIgnored)]?.GetVal<bool>() ?? false;
20+
this.IgnoredVersion = data[nameof(IgnoredVersion)]?.GetVal<string>() ?? "";
2021
}
2122

2223
public SerializableUpdatesOptions() : base()

src/UniGetUI/Pages/SoftwarePages/PackageBundlesPage.cs

Lines changed: 14 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System.Diagnostics;
22
using System.Text.Json;
3+
using System.Text.Json.Nodes;
34
using System.Xml;
45
using System.Xml.Serialization;
56
using ExternalLibraries.Pickers;
@@ -489,10 +490,10 @@ public async Task OpenFromFile(string? file = null)
489490

490491
DialogHelper.HideLoadingDialog();
491492

492-
if ((int)(open_version*10) != (int)(SerializableBundle_Data.ExpectedVersion*10))
493+
if ((int)(open_version*10) != (int)(SerializableBundle.ExpectedVersion*10))
493494
{ // Check only up to first decimal digit, prevent floating point precision error.
494495
Logger.Warn($"The loaded bundle \"{file}\" is based on schema version {open_version}, " +
495-
$"while this UniGetUI build expects version {SerializableBundle_Data.ExpectedVersion}." +
496+
$"while this UniGetUI build expects version {SerializableBundle.ExpectedVersion}." +
496497
$"\nThis should not be a problem if packages show up, but be careful");
497498
}
498499
}
@@ -579,10 +580,7 @@ public async Task SaveFile()
579580

580581
public static async Task<string> CreateBundle(IReadOnlyList<IPackage> unsorted_packages, BundleFormatType formatType = BundleFormatType.UBUNDLE)
581582
{
582-
SerializableBundle exportable = new()
583-
{
584-
export_version = 2.1,
585-
};
583+
SerializableBundle exportable = new();
586584

587585
List<IPackage> packages = unsorted_packages.ToList();
588586
packages.Sort(Comparison);
@@ -651,33 +649,24 @@ public async Task<double> AddFromBundle(string content, BundleFormatType format)
651649
Logger.ImportantInfo("XML payload was converted to JSON dynamically before deserialization");
652650
}
653651

654-
DeserializedData = await Task.Run(() => JsonSerializer.Deserialize<SerializableBundle>(content, SerializationHelpers.ImportBundleOptions));
655-
656-
657-
if (DeserializedData is null || DeserializedData.export_version is -1)
652+
DeserializedData = await Task.Run(() =>
658653
{
659-
throw new ArgumentException("DeserializedData was null");
660-
}
654+
return new SerializableBundle(JsonNode.Parse(content) ?? throw new Exception("Could not parse JSON object"));
655+
});
661656

662657
List<IPackage> packages = [];
663658

664-
foreach (SerializablePackage DeserializedPackage in DeserializedData.packages)
665-
{
666-
packages.Add(PackageFromSerializable(DeserializedPackage));
667-
}
659+
foreach (var pkg in DeserializedData.packages)
660+
packages.Add(DeserializePackage(pkg));
668661

669-
foreach (SerializableIncompatiblePackage DeserializedPackage in DeserializedData
670-
.incompatible_packages)
671-
{
672-
packages.Add(InvalidPackageFromSerializable(DeserializedPackage, NullSource.Instance));
673-
}
662+
foreach (var pkg in DeserializedData.incompatible_packages)
663+
packages.Add(DeserializeIncompatiblePackage(pkg, NullSource.Instance));
674664

675665
await PEInterface.PackageBundlesLoader.AddPackagesAsync(packages);
676-
677666
return DeserializedData.export_version;
678667
}
679668

680-
public static IPackage PackageFromSerializable(SerializablePackage raw_package)
669+
public static IPackage DeserializePackage(SerializablePackage raw_package)
681670
{
682671
IPackageManager? manager = null;
683672
IManagerSource? source;
@@ -700,13 +689,13 @@ public static IPackage PackageFromSerializable(SerializablePackage raw_package)
700689

701690
if (manager is null || source is null)
702691
{
703-
return InvalidPackageFromSerializable(raw_package.GetInvalidEquivalent(), NullSource.Instance);
692+
return DeserializeIncompatiblePackage(raw_package.GetInvalidEquivalent(), NullSource.Instance);
704693
}
705694

706695
return new ImportedPackage(raw_package, manager, source);
707696
}
708697

709-
public static IPackage InvalidPackageFromSerializable(SerializableIncompatiblePackage raw_package, IManagerSource source)
698+
public static IPackage DeserializeIncompatiblePackage(SerializableIncompatiblePackage raw_package, IManagerSource source)
710699
{
711700
return new InvalidImportedPackage(raw_package, source);
712701
}

0 commit comments

Comments
 (0)