Skip to content

Regression: Newtonsoft.Json 12.0.2 upgrade causes certain serialization casts to fail #3891

@Aaronontheweb

Description

@Aaronontheweb

Version: Akka.NET Dev (v1.4.0-beta1)

Since merging in #3671 it looks like we've been suffering from some serialization regression errors related to the upgrade from Newtonsoft.Json v9.0.1 --> v12.0.2

For instance, in #3671 (comment) we have these errors in this test:

Akka.MultiNodeTestRunner.Shared.Tests.Persistence.JsonPersistentTestRunStoreSpec.Should_load_saved_JSON_TestRunTree

System.InvalidCastException : Unable to cast object of type 'System.Collections.Generic.SortedSet`1[Akka.MultiNodeTestRunner.Shared.Reporting.MultiNodeMessage]' to type 'System.Collections.IList'.

   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObjectUsingCreatorWithParameters(JsonReader reader, JsonObjectContract contract, JsonProperty containerProperty, ObjectConstructor`1 creator, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateDictionary(IDictionary dictionary, JsonReader reader, JsonDictionaryContract contract, JsonProperty containerProperty, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ResolvePropertyAndCreatorValues(JsonObjectContract contract, JsonProperty containerProperty, JsonReader reader, Type objectType)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObjectUsingCreatorWithParameters(JsonReader reader, JsonObjectContract contract, JsonProperty containerProperty, ObjectConstructor`1 creator, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateList(IList list, JsonReader reader, JsonArrayContract contract, JsonProperty containerProperty, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateList(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, Object existingValue, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ReadMetadataProperties(JsonReader reader, Type& objectType, JsonContract& contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue, Object& newValue, String& id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ResolvePropertyAndCreatorValues(JsonObjectContract contract, JsonProperty containerProperty, JsonReader reader, Type objectType)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObjectUsingCreatorWithParameters(JsonReader reader, JsonObjectContract contract, JsonProperty containerProperty, ObjectConstructor`1 creator, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
   at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
   at Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings)
   at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value, JsonSerializerSettings settings)
   at Akka.MultiNodeTestRunner.Shared.Tests.Persistence.JsonPersistentTestRunStoreSpec.Should_load_saved_JSON_TestRunTree() in D:\a\1\s\src\core\Akka.MultiNodeTestRunner.Shared.Tests\Persistence\JsonPersistentTestRunStoreSpec.cs:line 83

[Fact]
public void Should_load_saved_JSON_TestRunTree()
{
var testRunStore = new JsonPersistentTestRunStore();
var testRunCoordinator = Sys.ActorOf(Props.Create<TestRunCoordinator>());
var nodeIndexes = Enumerable.Range(1, 4).ToArray();
var nodeTests = NodeMessageHelpers.BuildNodeTests(nodeIndexes);
var beginSpec = new BeginNewSpec(nodeTests.First().TypeName, nodeTests.First().MethodName, nodeTests);
//begin a new spec
testRunCoordinator.Tell(beginSpec);
// create some messages for each node, the test runner, and some result messages
// just like a real MultiNodeSpec
var allMessages = NodeMessageHelpers.GenerateMessageSequence(nodeIndexes, 300);
var runnerMessages = NodeMessageHelpers.GenerateTestRunnerMessageSequence(20);
var successMessages = NodeMessageHelpers.GenerateResultMessage(nodeIndexes, true);
var messageFragments = NodeMessageHelpers.GenerateMessageFragmentSequence(nodeIndexes, 100);
allMessages.UnionWith(runnerMessages);
allMessages.UnionWith(successMessages);
allMessages.UnionWith(messageFragments);
foreach (var message in allMessages)
testRunCoordinator.Tell(message);
//end the spec
testRunCoordinator.Tell(new EndTestRun(), TestActor);
var testRunData = ExpectMsg<TestRunTree>();
//save the test run
var file = Path.GetTempFileName();
testRunStore.SaveTestRun(file, testRunData).ShouldBeTrue("Should have been able to save test run");
//retrieve the test run from file
var retrievedFile = testRunStore.FetchTestRun(file);
Assert.NotNull(retrievedFile);
Assert.True(testRunData.Equals(retrievedFile));
}

We can't safely upgrade given these types of errors unless we know what this change was made - who knows what other issues actual end-users are going to run into?

Going to revert #3671 until we know more.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions