diff --git a/src/ServiceStack.Text/PlatformExtensions.cs b/src/ServiceStack.Text/PlatformExtensions.cs index a0d475bf6..e0d5069fb 100644 --- a/src/ServiceStack.Text/PlatformExtensions.cs +++ b/src/ServiceStack.Text/PlatformExtensions.cs @@ -628,6 +628,11 @@ public void SetValue(object instance, object value) if (SetValueFn == null) return; + if (value is IReadOnlyDictionary dictionary) + { + value = dictionary.FromObjectDictionary(Type); + } + if (!Type.IsInstanceOfType(value)) { lock (this) diff --git a/src/ServiceStack.Text/TranslateListWithElements.cs b/src/ServiceStack.Text/TranslateListWithElements.cs index d7049572e..6daa032bc 100644 --- a/src/ServiceStack.Text/TranslateListWithElements.cs +++ b/src/ServiceStack.Text/TranslateListWithElements.cs @@ -102,12 +102,8 @@ public static object TryTranslateCollections(Type fromPropertyType, Type toPrope if (fromElType == null || toElType == null) return null; - if (fromElType == typeof(object) || toElType.IsAssignableFrom(fromElType)) - return TranslateToGenericICollectionCache(fromValue, toPropertyType, toElType); - - return null; + return TranslateToGenericICollectionCache(fromValue, toPropertyType, toElType); } - } public class ConvertibleTypeKey @@ -199,7 +195,15 @@ public static ICollection TranslateToGenericICollection( var to = (ICollection)CreateInstance(toInstanceOfType); foreach (var item in fromList) { - to.Add((T)item); + if (item is IReadOnlyDictionary dictionary) + { + var convertedItem = dictionary.FromObjectDictionary(); + to.Add(convertedItem); + } + else + { + to.Add((T)item); + } } return to; } diff --git a/tests/ServiceStack.Text.Tests/AutoMappingObjectDictionaryTests.cs b/tests/ServiceStack.Text.Tests/AutoMappingObjectDictionaryTests.cs index 447ad0efd..c90e3b2e3 100644 --- a/tests/ServiceStack.Text.Tests/AutoMappingObjectDictionaryTests.cs +++ b/tests/ServiceStack.Text.Tests/AutoMappingObjectDictionaryTests.cs @@ -405,6 +405,146 @@ public void Can_convert_Dictionary_FromObjectDictionary() Assert.That(to == dict); } + [Test] + public void Can_convert_inner_dictionary() + { + var map = new Dictionary + { + { "FirstName", "Foo" }, + { "LastName", "Bar" }, + { "Car", new Dictionary + { + { "Name", "Tesla" }, + { "Age", 2 } + }} + }; + + var user = map.FromObjectDictionary(); + + Assert.That(user.FirstName, Is.EqualTo("Foo")); + Assert.That(user.LastName, Is.EqualTo("Bar")); + Assert.That(user.Car, Is.Not.Null); + Assert.That(user.Car.Name, Is.EqualTo("Tesla")); + Assert.That(user.Car.Age, Is.EqualTo(2)); + } + + [Test] + public void Can_convert_inner_collection_of_dictionaries() + { + var map = new Dictionary + { + { "Name", "Tesla" }, + { "Age", "2" }, + { "Specs", new List> + { + new Dictionary + { + {"Item", "Model"}, + {"Value", "S"} + }, + new Dictionary + { + {"Item", "Engine"}, + {"Value", "Electric"} + }, + new Dictionary + { + {"Item", "Color"}, + {"Value", "Red"} + }, + new Dictionary + { + {"Item", "PowerKW"}, + {"Value", 285} + }, + new Dictionary + { + {"Item", "TorqueNm"}, + {"Value", 430} + }, + }} + }; + + var carWithSpecs = map.FromObjectDictionary(); + + Assert.That(carWithSpecs.Name, Is.EqualTo("Tesla")); + Assert.That(carWithSpecs.Age, Is.EqualTo(2)); + Assert.That(carWithSpecs.Specs.Count, Is.EqualTo(5)); + var model = carWithSpecs.Specs.SingleOrDefault(s => s.Item == "Model"); + Assert.That(model, Is.Not.Null); + Assert.That(model.Value, Is.EqualTo("S")); + var engine = carWithSpecs.Specs.SingleOrDefault(s => s.Item == "Engine"); + Assert.That(engine, Is.Not.Null); + Assert.That(engine.Value, Is.EqualTo("Electric")); + var color = carWithSpecs.Specs.SingleOrDefault(s => s.Item == "Color"); + Assert.That(color, Is.Not.Null); + Assert.That(color.Value, Is.EqualTo("Red")); + var power = carWithSpecs.Specs.SingleOrDefault(s => s.Item == "PowerKW"); + Assert.That(power, Is.Not.Null); + Assert.That(power.Value, Is.EqualTo("285")); + var torque = carWithSpecs.Specs.SingleOrDefault(s => s.Item == "TorqueNm"); + Assert.That(torque, Is.Not.Null); + Assert.That(torque.Value, Is.EqualTo("430")); + } + + [Test] + public void Can_convert_inner_array_of_dictionaries() + { + var map = new Dictionary + { + { "Name", "Tesla" }, + { "Age", "2" }, + { "Specs", new[] + { + new Dictionary + { + {"Item", "Model"}, + {"Value", "S"} + }, + new Dictionary + { + {"Item", "Engine"}, + {"Value", "Electric"} + }, + new Dictionary + { + {"Item", "Color"}, + {"Value", "Red"} + }, + new Dictionary + { + {"Item", "PowerKW"}, + {"Value", 285} + }, + new Dictionary + { + {"Item", "TorqueNm"}, + {"Value", 430} + }, + }} + }; + + var carWithSpecs = map.FromObjectDictionary(); + + Assert.That(carWithSpecs.Name, Is.EqualTo("Tesla")); + Assert.That(carWithSpecs.Age, Is.EqualTo(2)); + Assert.That(carWithSpecs.Specs.Count, Is.EqualTo(5)); + var model = carWithSpecs.Specs.SingleOrDefault(s => s.Item == "Model"); + Assert.That(model, Is.Not.Null); + Assert.That(model.Value, Is.EqualTo("S")); + var engine = carWithSpecs.Specs.SingleOrDefault(s => s.Item == "Engine"); + Assert.That(engine, Is.Not.Null); + Assert.That(engine.Value, Is.EqualTo("Electric")); + var color = carWithSpecs.Specs.SingleOrDefault(s => s.Item == "Color"); + Assert.That(color, Is.Not.Null); + Assert.That(color.Value, Is.EqualTo("Red")); + var power = carWithSpecs.Specs.SingleOrDefault(s => s.Item == "PowerKW"); + Assert.That(power, Is.Not.Null); + Assert.That(power.Value, Is.EqualTo("285")); + var torque = carWithSpecs.Specs.SingleOrDefault(s => s.Item == "TorqueNm"); + Assert.That(torque, Is.Not.Null); + Assert.That(torque.Value, Is.EqualTo("430")); + } } diff --git a/tests/ServiceStack.Text.Tests/AutoMappingTests.cs b/tests/ServiceStack.Text.Tests/AutoMappingTests.cs index a34ddd860..b9987c9ba 100644 --- a/tests/ServiceStack.Text.Tests/AutoMappingTests.cs +++ b/tests/ServiceStack.Text.Tests/AutoMappingTests.cs @@ -43,6 +43,17 @@ public class SubCar : Car public string Custom { get; set; } } + public class CarWithSpecs : Car + { + public List Specs { get; set; } + } + + public class CarSpec + { + public string Item { get; set; } + public string Value { get; set; } + } + public class UserDto { public string FirstName { get; set; }