cosullivan/Hypermedia

Can't deserialize collections

Closed this issue · 1 comments

There's an error in EnumerableConverter.DeserializeArray. Looks to be made by the latest change. You're changing the type to ICollection<>, then trying to create an instance of it using Activator, but Activator can't create instances of interfaces. Here's my fix for it.

@EnumerableConverter.TryGetCollectionType
- if (TypeHelper.TryGetCollectionType(type, out collectionType))

+ Type tmpCollectionType;
+ if (TypeHelper.TryGetCollectionType(type, out tmpCollectionType))

I also added support for arrays:

        public object DeserializeValue(IJsonSerializer serializer, Type type, JsonValue jsonValue)
        {
            if (type.IsArray)
                return DeserializeArray(serializer, type, (JsonArray)jsonValue);
            else
                return DeserializeCollection(serializer, type, (JsonArray)jsonValue);
        }
        static ICollection DeserializeArray(IJsonSerializer serializer, Type type, JsonArray jsonArray)
        {
            Type elementType = type.GetElementType();
            var array = Array.CreateInstance(elementType, jsonArray.Count);
            int index = 0;
            foreach (var jsonValue in jsonArray)
            {
                var value = serializer.DeserializeValue(elementType, jsonValue);
                array.SetValue(value, index);
                index++;
            }
            return array;
        }

        static ICollection DeserializeCollection(IJsonSerializer serializer, Type type, JsonArray jsonArray)
        {
            // TODO: the collection access should be converted to a dynamically compiled delegate
            Type elementType;
            MethodInfo method;
            if (TryGetCollectionType(type, out type, out elementType, out method) == false)
            {
                throw new JsonException("Can not deserialize a JSON array to a type that doesnt support ICollection<T>.");
            }

            var collection = Activator.CreateInstance(type) as ICollection;

            foreach (var jsonValue in jsonArray)
            {
                var value = serializer.DeserializeValue(elementType, jsonValue);

                method.Invoke(collection, new[] { value });
            }

            return collection;
        }

Thanks for picking that up. I have just fixed it and pushed an update to Nuget too.