mirror of
https://github.com/ppy/osu.git
synced 2025-01-18 11:02:57 +08:00
Rework logic of TypedListConverter to remove extra converter for bindables
This commit is contained in:
parent
6c8f4addb8
commit
cae5677605
@ -22,7 +22,7 @@ namespace osu.Game.Beatmaps.ControlPoints
|
|||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public IBindableList<ControlPoint> ControlPoints => controlPoints;
|
public IBindableList<ControlPoint> ControlPoints => controlPoints;
|
||||||
|
|
||||||
[JsonConverter(typeof(BindableListConverter<ControlPoint>))]
|
[JsonConverter(typeof(TypedListConverter<ControlPoint>))]
|
||||||
[JsonProperty]
|
[JsonProperty]
|
||||||
private readonly BindableList<ControlPoint> controlPoints = new BindableList<ControlPoint>();
|
private readonly BindableList<ControlPoint> controlPoints = new BindableList<ControlPoint>();
|
||||||
|
|
||||||
|
@ -1,114 +0,0 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
using osu.Framework.Bindables;
|
|
||||||
using osu.Framework.Extensions.ObjectExtensions;
|
|
||||||
|
|
||||||
namespace osu.Game.IO.Serialization.Converters
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A type of <see cref="JsonConverter"/> that serializes an <see cref="IBindableList{T}"/> alongside
|
|
||||||
/// a lookup table for the types contained. The lookup table is used in deserialization to
|
|
||||||
/// reconstruct the objects with their original types.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">The type of objects contained in the <see cref="IBindableList{T}"/> this attribute is attached to.</typeparam>
|
|
||||||
public class BindableListConverter<T> : JsonConverter<IBindableList<T>>
|
|
||||||
{
|
|
||||||
private readonly bool requiresTypeVersion;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Constructs a new <see cref="BindableListConverter{T}"/>.
|
|
||||||
/// </summary>
|
|
||||||
// ReSharper disable once UnusedMember.Global
|
|
||||||
public BindableListConverter()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Constructs a new <see cref="BindableListConverter{T}"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="requiresTypeVersion">Whether the version of the type should be serialized.</param>
|
|
||||||
// ReSharper disable once UnusedMember.Global (Used in Beatmap)
|
|
||||||
public BindableListConverter(bool requiresTypeVersion)
|
|
||||||
{
|
|
||||||
this.requiresTypeVersion = requiresTypeVersion;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override IBindableList<T> ReadJson(JsonReader reader, Type objectType, IBindableList<T> existingValue, bool hasExistingValue, JsonSerializer serializer)
|
|
||||||
{
|
|
||||||
var list = new BindableList<T>();
|
|
||||||
|
|
||||||
var obj = JObject.Load(reader);
|
|
||||||
|
|
||||||
if (obj["$lookup_table"] == null)
|
|
||||||
return list;
|
|
||||||
|
|
||||||
var lookupTable = serializer.Deserialize<List<string>>(obj["$lookup_table"].CreateReader());
|
|
||||||
if (lookupTable == null)
|
|
||||||
return list;
|
|
||||||
|
|
||||||
if (obj["$items"] == null)
|
|
||||||
return list;
|
|
||||||
|
|
||||||
foreach (var tok in obj["$items"])
|
|
||||||
{
|
|
||||||
var itemReader = tok.CreateReader();
|
|
||||||
|
|
||||||
if (tok["$type"] == null)
|
|
||||||
throw new JsonException("Expected $type token.");
|
|
||||||
|
|
||||||
string typeName = lookupTable[(int)tok["$type"]];
|
|
||||||
var instance = (T)Activator.CreateInstance(Type.GetType(typeName).AsNonNull())!;
|
|
||||||
serializer.Populate(itemReader, instance);
|
|
||||||
|
|
||||||
list.Add(instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void WriteJson(JsonWriter writer, IBindableList<T> value, JsonSerializer serializer)
|
|
||||||
{
|
|
||||||
var lookupTable = new List<string>();
|
|
||||||
var objects = new List<JObject>();
|
|
||||||
|
|
||||||
foreach (var item in value)
|
|
||||||
{
|
|
||||||
var type = item.GetType();
|
|
||||||
var assemblyName = type.Assembly.GetName();
|
|
||||||
|
|
||||||
string typeString = $"{type.FullName}, {assemblyName.Name}";
|
|
||||||
if (requiresTypeVersion)
|
|
||||||
typeString += $", {assemblyName.Version}";
|
|
||||||
|
|
||||||
int typeId = lookupTable.IndexOf(typeString);
|
|
||||||
|
|
||||||
if (typeId == -1)
|
|
||||||
{
|
|
||||||
lookupTable.Add(typeString);
|
|
||||||
typeId = lookupTable.Count - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
var itemObject = JObject.FromObject(item, serializer);
|
|
||||||
itemObject.AddFirst(new JProperty("$type", typeId));
|
|
||||||
objects.Add(itemObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
writer.WriteStartObject();
|
|
||||||
|
|
||||||
writer.WritePropertyName("$lookup_table");
|
|
||||||
serializer.Serialize(writer, lookupTable);
|
|
||||||
|
|
||||||
writer.WritePropertyName("$items");
|
|
||||||
serializer.Serialize(writer, objects);
|
|
||||||
|
|
||||||
writer.WriteEndObject();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -7,17 +7,18 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Extensions.ObjectExtensions;
|
using osu.Framework.Extensions.ObjectExtensions;
|
||||||
|
|
||||||
namespace osu.Game.IO.Serialization.Converters
|
namespace osu.Game.IO.Serialization.Converters
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A type of <see cref="JsonConverter"/> that serializes an <see cref="IReadOnlyList{T}"/> alongside
|
/// A type of <see cref="JsonConverter"/> that serializes a list alongside
|
||||||
/// a lookup table for the types contained. The lookup table is used in deserialization to
|
/// a lookup table for the types contained. The lookup table is used in deserialization to
|
||||||
/// reconstruct the objects with their original types.
|
/// reconstruct the objects with their original types.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">The type of objects contained in the <see cref="IReadOnlyList{T}"/> this attribute is attached to.</typeparam>
|
/// <typeparam name="T">The type of objects contained in the list this attribute is attached to.</typeparam>
|
||||||
public class TypedListConverter<T> : JsonConverter<IReadOnlyList<T>>
|
public class TypedListConverter<T> : JsonConverter
|
||||||
{
|
{
|
||||||
private readonly bool requiresTypeVersion;
|
private readonly bool requiresTypeVersion;
|
||||||
|
|
||||||
@ -39,10 +40,9 @@ namespace osu.Game.IO.Serialization.Converters
|
|||||||
this.requiresTypeVersion = requiresTypeVersion;
|
this.requiresTypeVersion = requiresTypeVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IReadOnlyList<T> ReadJson(JsonReader reader, Type objectType, IReadOnlyList<T> existingValue, bool hasExistingValue, JsonSerializer serializer)
|
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||||
{
|
{
|
||||||
var list = new List<T>();
|
var list = new List<T>();
|
||||||
|
|
||||||
var obj = JObject.Load(reader);
|
var obj = JObject.Load(reader);
|
||||||
|
|
||||||
if (obj["$lookup_table"] == null)
|
if (obj["$lookup_table"] == null)
|
||||||
@ -69,15 +69,25 @@ namespace osu.Game.IO.Serialization.Converters
|
|||||||
list.Add(instance);
|
list.Add(instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (objectType == typeof(IBindableList<T>) || objectType == typeof(BindableList<T>))
|
||||||
|
return new BindableList<T>(list);
|
||||||
|
|
||||||
|
if (objectType == typeof(IReadOnlyList<T>))
|
||||||
|
return list.AsReadOnly();
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void WriteJson(JsonWriter writer, IReadOnlyList<T> value, JsonSerializer serializer)
|
public override bool CanConvert(Type objectType)
|
||||||
|
=> objectType == typeof(IBindableList<T>) || objectType == typeof(BindableList<T>) || objectType == typeof(IReadOnlyList<T>) || objectType == typeof(List<T>);
|
||||||
|
|
||||||
|
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||||
{
|
{
|
||||||
|
var enumerable = (IEnumerable<T>)value!;
|
||||||
var lookupTable = new List<string>();
|
var lookupTable = new List<string>();
|
||||||
var objects = new List<JObject>();
|
var objects = new List<JObject>();
|
||||||
|
|
||||||
foreach (var item in value)
|
foreach (var item in enumerable)
|
||||||
{
|
{
|
||||||
var type = item.GetType();
|
var type = item.GetType();
|
||||||
var assemblyName = type.Assembly.GetName();
|
var assemblyName = type.Assembly.GetName();
|
||||||
|
Loading…
Reference in New Issue
Block a user