fix: fix hashSet deserialize error (#4545)

* update hangfire version to 1.8.5

* fix: fix hashSet deserialize error

* fix: replace HashSet to ISet<T>

* Update polymorphic converter and tests

---------

Co-authored-by: Sipke Schoorstra <sipkeschoorstra@outlook.com>
This commit is contained in:
Nokecy 2023-10-18 05:14:40 +08:00 committed by GitHub
parent 170a14c914
commit 4056434e45
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 28 additions and 31 deletions

View file

@ -33,7 +33,6 @@ public class Fork : Activity
/// <summary>
/// The branches to schedule.
/// </summary>
[Port]
public ICollection<IActivity> Branches { get; set; } = new List<IActivity>();
/// <inheritdoc />

View file

@ -117,12 +117,15 @@ public class PolymorphicObjectConverter : JsonConverter<object>
var values = model.TryGetProperty(ItemsPropertyName, out var itemsProp) ? itemsProp.EnumerateArray().ToList() : model.GetProperty(ValuesPropertyName).EnumerateArray().ToList();
var id = model.TryGetProperty(IdPropertyName, out var idProp) ? idProp.GetString() : default;
var collection = targetType.IsArray ? Array.CreateInstance(elementType, values.Count) : (IList)Activator.CreateInstance(targetType)!;
var collection = targetType.IsArray ? Array.CreateInstance(elementType, values.Count) : Activator.CreateInstance(targetType)!;
var index = 0;
if (id != null)
referenceResolver?.AddReference(id, collection);
var isHashSet = targetType.GenericTypeArguments.Length == 1 && typeof(ISet<>).MakeGenericType(targetType.GenericTypeArguments[0]).IsAssignableFrom(targetType);
var addSetMethod = targetType.GetMethod("Add", new[] { elementType })!;
foreach (var element in values)
{
var deserializedElement = JsonSerializer.Deserialize(JsonSerializer.Serialize(element), elementType, newOptions)!;
@ -130,9 +133,13 @@ public class PolymorphicObjectConverter : JsonConverter<object>
{
array.SetValue(deserializedElement, index++);
}
else
else if (isHashSet)
{
collection.Add(deserializedElement);
addSetMethod.Invoke(collection, new[] { deserializedElement });
}
else if (collection is IList list)
{
list.Add(deserializedElement);
}
}
@ -163,7 +170,7 @@ public class PolymorphicObjectConverter : JsonConverter<object>
// Special case for Newtonsoft.Json and System.Text.Json types.
// Newtonsoft.Json types are not supported by the System.Text.Json serializer and should be written as a string instead.
// We include metadata about the type so that we can deserialize it later.
// We include metadata about the type so that we can deserialize it later.
if (type == typeof(JObject) || type == typeof(JArray) || type == typeof(JsonObject) || type == typeof(JsonArray))
{
writer.WriteStartObject();
@ -200,7 +207,7 @@ public class PolymorphicObjectConverter : JsonConverter<object>
value = sanitized;
}
var jsonElement = JsonDocument.Parse(JsonSerializer.Serialize(value, type, newOptions)).RootElement;
// If the value is a string, serialize it directly.
@ -265,6 +272,7 @@ public class PolymorphicObjectConverter : JsonConverter<object>
case JsonTokenType.StartArray:
depth++;
break;
case JsonTokenType.EndObject:
case JsonTokenType.EndArray:
depth--;
@ -309,6 +317,7 @@ public class PolymorphicObjectConverter : JsonConverter<object>
default:
list.Add(Read(ref reader, typeof(object), options));
break;
case JsonTokenType.EndArray:
return list;
}
@ -328,6 +337,7 @@ public class PolymorphicObjectConverter : JsonConverter<object>
if (dict.Count == 1 && dict.TryGetValue(RefPropertyName, out var referencedObject))
return referencedObject;
return dict;
case JsonTokenType.PropertyName:
var key = reader.GetString()!;
reader.Read();
@ -350,6 +360,7 @@ public class PolymorphicObjectConverter : JsonConverter<object>
}
break;
default:
throw new JsonException();
}

View file

@ -13,10 +13,10 @@ public record Model(
ICollection<Model>? Items = default,
object? Metadata = default,
object? Payload = default,
IDictionary<string, Model>? Properties = default
)
object? HashSet = default,
IDictionary<string, Model>? Properties = default)
{
public Model() : this(null, default, default, null, default, default, default)
public Model() : this(null, default, default, null, default, default, default, default)
{
}
}

View file

@ -58,33 +58,20 @@ public class Tests
},
metadata,
new Model("Payload"),
new HashSet<Model>
{
new()
{
Text = "I'm a model in a set!"
}
},
new Dictionary<string, Model>
{
["Hello"] = new("Hello", 1, true),
["World"] = new("World", 2)
["World"] = new("World", 2),
}
);
}
private Model CreateModel2()
{
// Create a model with various nested properties
var metadata = new ExpandoObject() as IDictionary<string, object>;
// Initialize metadata with test data.
metadata["Models"] = new List<Model>
{
new(Text: "Hello World")
};
return new Model(
Metadata: metadata
// Items : new List<Model>
// {
// new(Items: new List<Model> { new(Metadata: metadata) }),
// }
);
}
private JsonSerializerOptions GetSerializerOptions()
{

View file

@ -1 +1 @@
{"$id":"1","text":"Hello World","number":123,"flag":true,"items":{"$id":"2","$values":[{"$id":"3","text":"Hello","number":1,"flag":true,"items":{"$id":"4","$values":[{"$id":"5","number":0,"flag":false,"metadata":{"Foo":"Bar","Number":123,"Flag":true,"Models":{"$id":"6","$values":[{"$id":"7","text":"Hello","number":1,"flag":true,"metadata":{"Foo":"Bar","Number":123,"Flag":true,"Models":{"$ref":"6"},"CustomDictionary":{"$id":"8","content-type":["application/json"],"_type":"Elsa.IntegrationTests.Serialization.Polymorphism.CustomDictionary, Elsa.IntegrationTests"}}},{"$id":"9","text":"World","number":2,"flag":false}],"_type":"System.Collections.Generic.List\u00601[[Elsa.IntegrationTests.Serialization.Polymorphism.Model, Elsa.IntegrationTests]], System.Private.CoreLib"},"CustomDictionary":{"$ref":"8"}}}]}},{"$id":"10","text":"World","number":2,"flag":false}]},"metadata":{"Foo":"Bar","Number":123,"Flag":true,"Models":{"$ref":"6"},"CustomDictionary":{"$ref":"8"}},"payload":{"$id":"11","text":"Payload","number":0,"flag":false,"_type":"Elsa.IntegrationTests.Serialization.Polymorphism.Model, Elsa.IntegrationTests"},"properties":{"$id":"12","Hello":{"$id":"13","text":"Hello","number":1,"flag":true},"World":{"$id":"14","text":"World","number":2,"flag":false}}}
{"$id":"1","text":"Hello World","number":123,"flag":true,"items":{"$id":"2","$values":[{"$id":"3","text":"Hello","number":1,"flag":true,"items":{"$id":"4","$values":[{"$id":"5","number":0,"flag":false,"metadata":{"Foo":"Bar","Number":123,"Flag":true,"Models":{"$id":"6","$values":[{"$id":"7","text":"Hello","number":1,"flag":true,"metadata":{"Foo":"Bar","Number":123,"Flag":true,"Models":{"$ref":"6"},"CustomDictionary":{"$id":"8","content-type":["application/json"],"_type":"Elsa.IntegrationTests.Serialization.Polymorphism.CustomDictionary, Elsa.IntegrationTests"}}},{"$id":"9","text":"World","number":2,"flag":false}],"_type":"System.Collections.Generic.List\u00601[[Elsa.IntegrationTests.Serialization.Polymorphism.Model, Elsa.IntegrationTests]], System.Private.CoreLib"},"CustomDictionary":{"$ref":"8"}}}]}},{"$id":"10","text":"World","number":2,"flag":false}]},"metadata":{"Foo":"Bar","Number":123,"Flag":true,"Models":{"$ref":"6"},"CustomDictionary":{"$ref":"8"}},"payload":{"$id":"11","text":"Payload","number":0,"flag":false,"_type":"Elsa.IntegrationTests.Serialization.Polymorphism.Model, Elsa.IntegrationTests"},"hashSet":{"$id":"12","$values":[{"$id":"13","text":"I\u0027m a model in a set!","number":0,"flag":false}],"_type":"System.Collections.Generic.HashSet\u00601[[Elsa.IntegrationTests.Serialization.Polymorphism.Model, Elsa.IntegrationTests]], System.Private.CoreLib"},"properties":{"$id":"14","Hello":{"$id":"15","text":"Hello","number":1,"flag":true},"World":{"$id":"16","text":"World","number":2,"flag":false}}}