Skip to content

Commit

Permalink
🧆 Use source generation for Settings serialization and deserialization
Browse files Browse the repository at this point in the history
  • Loading branch information
database64128 committed May 1, 2022
1 parent 1e0c2ae commit 51947e6
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 24 deletions.
4 changes: 2 additions & 2 deletions YoutubeDl.Wpf/Models/Settings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ public class Settings : ReactiveObject
/// </returns>
public static async Task<(Settings settings, string? errMsg)> LoadSettingsAsync(CancellationToken cancellationToken = default)
{
var (settings, errMsg) = await FileHelper.LoadJsonAsync<Settings>("Settings.json", FileHelper.commonJsonDeserializerOptions, cancellationToken).ConfigureAwait(false);
var (settings, errMsg) = await FileHelper.LoadJsonAsync("Settings.json", SettingsJsonSerializerContext.Default.Settings, cancellationToken).ConfigureAwait(false);
if (errMsg is null && settings.Version != DefaultVersion)
{
settings.UpdateSettings();
Expand All @@ -140,7 +140,7 @@ public static async Task<(Settings settings, string? errMsg)> LoadSettingsAsync(
/// Null if no errors occurred.
/// </returns>
public static Task<string?> SaveSettingsAsync(Settings settings, CancellationToken cancellationToken = default)
=> FileHelper.SaveJsonAsync("Settings.json", settings, FileHelper.commonJsonSerializerOptions, false, false, cancellationToken);
=> FileHelper.SaveJsonAsync("Settings.json", settings, SettingsJsonSerializerContext.Default.Settings, false, false, cancellationToken);

/// <summary>
/// Updates the current object to the latest version.
Expand Down
11 changes: 11 additions & 0 deletions YoutubeDl.Wpf/Models/SettingsJsonSerializerContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System.Text.Json.Serialization;

namespace YoutubeDl.Wpf.Models;

[JsonSerializable(typeof(Settings))]
[JsonSourceGenerationOptions(
IgnoreReadOnlyProperties = true,
WriteIndented = true)]
public partial class SettingsJsonSerializerContext : JsonSerializerContext
{
}
30 changes: 8 additions & 22 deletions YoutubeDl.Wpf/Utils/FileHelper.cs
Original file line number Diff line number Diff line change
@@ -1,28 +1,14 @@
using System;
using System.IO;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Serialization.Metadata;
using System.Threading;
using System.Threading.Tasks;

namespace YoutubeDl.Wpf.Utils
{
public static class FileHelper
{
public static readonly JsonSerializerOptions commonJsonSerializerOptions = new()
{
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
IgnoreReadOnlyProperties = true,
WriteIndented = true,
};

public static readonly JsonSerializerOptions commonJsonDeserializerOptions = new()
{
AllowTrailingCommas = true,
ReadCommentHandling = JsonCommentHandling.Skip,
WriteIndented = true,
};

public static readonly string configDirectory;

static FileHelper()
Expand Down Expand Up @@ -53,13 +39,13 @@ public static string GetAbsolutePath(string path)
/// </summary>
/// <typeparam name="T">Data object type.</typeparam>
/// <param name="filename">JSON file name.</param>
/// <param name="jsonSerializerOptions">Deserialization options.</param>
/// <param name="jsonTypeInfo">Metadata about the type to convert.</param>
/// <param name="cancellationToken">A token that may be used to cancel the read operation.</param>
/// <returns>
/// A ValueTuple containing a data object loaded from the JSON file and an error message.
/// The error message is null if no errors occurred.
/// </returns>
public static async Task<(T, string? errMsg)> LoadJsonAsync<T>(string filename, JsonSerializerOptions? jsonSerializerOptions = null, CancellationToken cancellationToken = default) where T : class, new()
public static async Task<(T, string? errMsg)> LoadJsonAsync<T>(string filename, JsonTypeInfo<T> jsonTypeInfo, CancellationToken cancellationToken = default) where T : class, new()
{
// extend relative path
filename = GetAbsolutePath(filename);
Expand All @@ -77,7 +63,7 @@ public static async Task<(T, string? errMsg)> LoadJsonAsync<T>(string filename,
try
{
jsonFile = new(filename, FileMode.Open);
jsonData = await JsonSerializer.DeserializeAsync<T>(jsonFile, jsonSerializerOptions, cancellationToken).ConfigureAwait(false);
jsonData = await JsonSerializer.DeserializeAsync<T>(jsonFile, jsonTypeInfo, cancellationToken).ConfigureAwait(false);
}
catch (Exception ex)
{
Expand All @@ -99,15 +85,15 @@ public static async Task<(T, string? errMsg)> LoadJsonAsync<T>(string filename,
/// <typeparam name="T">Data object type.</typeparam>
/// <param name="filename">JSON file name.</param>
/// <param name="jsonData">The data object to save.</param>
/// <param name="jsonSerializerOptions">Serialization options.</param>
/// <param name="jsonTypeInfo">Metadata about the type to convert.</param>
/// <param name="alwaysOverwrite">Always overwrite the original file.</param>
/// <param name="noBackup">Do not create `filename.old` as backup.</param>
/// <param name="cancellationToken">A token that may be used to cancel the write operation.</param>
/// <returns>An error message. Null if no errors occurred.</returns>
public static async Task<string?> SaveJsonAsync<T>(
string filename,
T jsonData,
JsonSerializerOptions? jsonSerializerOptions = null,
JsonTypeInfo<T> jsonTypeInfo,
bool alwaysOverwrite = false,
bool noBackup = false,
CancellationToken cancellationToken = default)
Expand All @@ -134,12 +120,12 @@ public static async Task<(T, string? errMsg)> LoadJsonAsync<T>(string filename,
if (alwaysOverwrite || !File.Exists(filename)) // alwaysOverwrite or file doesn't exist. Just write to it.
{
jsonFile = new(filename, FileMode.Create);
await JsonSerializer.SerializeAsync(jsonFile, jsonData, jsonSerializerOptions, cancellationToken).ConfigureAwait(false);
await JsonSerializer.SerializeAsync(jsonFile, jsonData, jsonTypeInfo, cancellationToken).ConfigureAwait(false);
}
else // File exists. Write to `filename.new` and then replace with the new file and creates backup `filename.old`.
{
jsonFile = new($"{filename}.new", FileMode.Create);
await JsonSerializer.SerializeAsync(jsonFile, jsonData, jsonSerializerOptions, cancellationToken).ConfigureAwait(false);
await JsonSerializer.SerializeAsync(jsonFile, jsonData, jsonTypeInfo, cancellationToken).ConfigureAwait(false);
jsonFile.Close();
File.Replace($"{filename}.new", filename, noBackup ? null : $"{filename}.old");
}
Expand Down

0 comments on commit 51947e6

Please sign in to comment.