Skip to content

Commit

Permalink
fix: specific deserialization errors showing in Playnite logs (#728)
Browse files Browse the repository at this point in the history
  • Loading branch information
andrew-codes authored Feb 9, 2025
1 parent 23ebd04 commit bfc4591
Showing 1 changed file with 146 additions and 84 deletions.
230 changes: 146 additions & 84 deletions apps/PlayniteWebPlugin/src/Services/ObjectDeserializer.cs
Original file line number Diff line number Diff line change
@@ -1,112 +1,174 @@
using Playnite.SDK;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Dynamic;
using System.Globalization;
using System.Reflection;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace PlayniteWeb.Services
{
public class PascalCaseJsonConverter : JsonConverter<ExpandoObject>
{
public override ExpandoObject Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
public class PascalCaseJsonConverter : JsonConverter<ExpandoObject>
{
using (JsonDocument doc = JsonDocument.ParseValue(ref reader))
{
var jsonObject = doc.RootElement;
if (jsonObject.ValueKind == JsonValueKind.Object)
private dynamic ReadValue(JsonElement valueDoc, JsonSerializerOptions options)
{
var result = new ExpandoObject() as IDictionary<string, object>;
foreach (var prop in jsonObject.EnumerateObject())
{
var name = ConvertToPascalCase(prop.Name);
using (JsonDocument valueDoc = JsonDocument.Parse(prop.Value.GetRawText()))
if (valueDoc.ValueKind == JsonValueKind.Object)
{
dynamic value = null;
if (valueDoc.RootElement.ValueKind == JsonValueKind.Object)
{
value = JsonSerializer.Deserialize<ExpandoObject>(prop.Value.GetRawText(), options);
}
else if (valueDoc.RootElement.ValueKind == JsonValueKind.Array)
{
var list = new List<dynamic>();
foreach (var valueItem in valueDoc.RootElement.EnumerateArray())
dynamic value = null;
foreach (var prop in valueDoc.EnumerateObject())
{
list.Add(JsonSerializer.Deserialize<ExpandoObject>(valueItem.GetRawText(), options));

value[prop.Name] = ReadValue(prop.Value, options);
}
value = list;
}
else if (valueDoc.RootElement.ValueKind == JsonValueKind.String)
{
value = valueDoc.RootElement.GetString();
}
else if (valueDoc.RootElement.ValueKind == JsonValueKind.Number)
{
value = valueDoc.RootElement.GetInt32();
}
else if (valueDoc.RootElement.ValueKind == JsonValueKind.True || valueDoc.RootElement.ValueKind == JsonValueKind.False)
{
value = valueDoc.RootElement.GetBoolean();
}
else
{
value = valueDoc.RootElement.GetRawText();
}
return value;
}
else if (valueDoc.ValueKind == JsonValueKind.Array)
{
var list = new ArrayList();
foreach (var valueItem in valueDoc.EnumerateArray())
{
list.Add(ReadValue(valueItem, options));

result[name] = value;
return list;
}
}
else if (valueDoc.ValueKind == JsonValueKind.String)
{
return valueDoc.GetString();
}
else if (valueDoc.ValueKind == JsonValueKind.Number)
{
return valueDoc.GetInt32();
}
else if (valueDoc.ValueKind == JsonValueKind.True || valueDoc.ValueKind == JsonValueKind.False)
{
return valueDoc.GetBoolean();
}
else
{
return valueDoc.GetRawText();
}
}
return result as ExpandoObject;

return null;
}

return null;
}
}
public override ExpandoObject Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
using (JsonDocument doc = JsonDocument.ParseValue(ref reader))
{
var jsonObject = doc.RootElement;
if (jsonObject.ValueKind == JsonValueKind.Object)
{
var result = new ExpandoObject() as IDictionary<string, object>;
foreach (var prop in jsonObject.EnumerateObject())
{
var name = ConvertToPascalCase(prop.Name);
using (JsonDocument valueDoc = JsonDocument.Parse(prop.Value.GetRawText()))
{
dynamic value = null;
if (valueDoc.RootElement.ValueKind == JsonValueKind.Object)
{
value = JsonSerializer.Deserialize<ExpandoObject>(prop.Value.GetRawText(), options);
}
else if (valueDoc.RootElement.ValueKind == JsonValueKind.Array)
{
var list = new ArrayList();
foreach (var valueItem in valueDoc.RootElement.EnumerateArray())
{
if (valueItem.ValueKind == JsonValueKind.Object)
{
list.Add(JsonSerializer.Deserialize<ExpandoObject>(valueItem.GetRawText(), options));
}
else if (valueItem.ValueKind == JsonValueKind.Array)
{
list.Add(JsonSerializer.Deserialize<ExpandoObject>(valueItem.GetRawText(), options));
}
else if (valueItem.ValueKind == JsonValueKind.String)
{
list.Add(valueItem.GetString());
}
else if (valueItem.ValueKind == JsonValueKind.Number)
{
list.Add(valueItem.GetInt32());
}
else if (valueItem.ValueKind == JsonValueKind.True || valueItem.ValueKind == JsonValueKind.False)
{
list.Add(valueItem.GetBoolean());
}
else
{
list.Add(valueItem.GetRawText());
}
value = list;
}
}
else if (valueDoc.RootElement.ValueKind == JsonValueKind.String)
{
value = valueDoc.RootElement.GetString();
}
else if (valueDoc.RootElement.ValueKind == JsonValueKind.Number)
{
value = valueDoc.RootElement.GetInt32();
}
else if (valueDoc.RootElement.ValueKind == JsonValueKind.True || valueDoc.RootElement.ValueKind == JsonValueKind.False)
{
value = valueDoc.RootElement.GetBoolean();
}
else
{
value = valueDoc.RootElement.GetRawText();
}

public override void Write(Utf8JsonWriter writer, ExpandoObject value, JsonSerializerOptions options)
{
JsonSerializer.Serialize(writer, value, options);
}
result[name] = value;
}
}
return result as ExpandoObject;
}

private string ConvertToPascalCase(string name)
{
if (string.IsNullOrEmpty(name))
return name;
return null;
}
}

return char.ToUpper(name[0], CultureInfo.InvariantCulture) + name.Substring(1);
}
}
public override void Write(Utf8JsonWriter writer, ExpandoObject value, JsonSerializerOptions options)
{
JsonSerializer.Serialize(writer, value, options);
}

public class ObjectDeserializer : IDeserializeObjects
{
private string ConvertToPascalCase(string name)
{
if (string.IsNullOrEmpty(name))
return name;

return char.ToUpper(name[0], CultureInfo.InvariantCulture) + name.Substring(1);
}
}

public ExpandoObject Deserialize(string data)
public class ObjectDeserializer : IDeserializeObjects
{
try
{
var options = new JsonSerializerOptions

public ExpandoObject Deserialize(string data)
{
PropertyNameCaseInsensitive = true, // Allows case-insensitive matches
Converters = { new PascalCaseJsonConverter() } // Apply custom converter
};
return JsonSerializer.Deserialize<ExpandoObject>(data, options);
}
catch (NotSupportedException nse)
{
// Specific catch for NotSupportedException to handle serialization issues more specifically
LogManager.GetLogger().Error($"Unsupported serialization attempt for {data.GetType()}: {nse.Message}");
throw;
}
catch (Exception error)
{
// General exception handling
LogManager.GetLogger().Error($"Error serializing object: {error}");
throw;
}
try
{
var options = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true, // Allows case-insensitive matches
Converters = { new PascalCaseJsonConverter() } // Apply custom converter
};
return JsonSerializer.Deserialize<ExpandoObject>(data, options);
}
catch (NotSupportedException nse)
{
// Specific catch for NotSupportedException to handle serialization issues more specifically
LogManager.GetLogger().Error($"Unsupported serialization attempt for {data.GetType()}: {nse.Message}");
throw;
}
catch (Exception error)
{
// General exception handling
LogManager.GetLogger().Error($"Error serializing object: {error}");
throw;
}
}
}
}
}

0 comments on commit bfc4591

Please sign in to comment.