public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            var serializationData = SerializationData.GetSerializationData(reader);

            reader = new ForkableJsonReader(reader);

            var contract   = (JsonObjectContract)serializer.ContractResolver.ResolveContract(objectType);
            var rootObject = contract.DefaultCreator();

            serializationData.HasProcessedDocumentRoot = true;

            var includedConverter = new IncludedConverter();

            foreach (var propName in ReaderUtil.IterateProperties(reader))
            {
                switch (propName)
                {
                case PropertyNames.Data:

                    var documentRootInterfaceType = TypeInfoShim.GetInterfaces(objectType.GetTypeInfo())
                                                    .Select(x => x.GetTypeInfo())
                                                    .FirstOrDefault(x =>
                                                                    x.IsGenericType &&
                                                                    x.GetGenericTypeDefinition() == typeof(IDocumentRoot <>));
                    var dataType = documentRootInterfaceType.GenericTypeArguments[0];

                    var dataObj = serializer.Deserialize(reader, dataType);
                    contract.Properties.GetClosestMatchProperty(PropertyNames.Data).ValueProvider.SetValue(rootObject, dataObj);
                    break;

                case PropertyNames.Included:

                    //if our object has an included property we will do our best to populate it
                    var property = contract.Properties.GetClosestMatchProperty(propName);
                    if (ReaderUtil.CanPopulateProperty(property))
                    {
                        ReaderUtil.TryPopulateProperty(serializer, rootObject, contract.Properties.GetClosestMatchProperty(propName), ((ForkableJsonReader)reader).Fork());
                    }

                    //still need to read our values so they are updated
                    foreach (var obj in ReaderUtil.IterateList(reader))
                    {
                        var includedObject = includedConverter.ReadJson(reader, typeof(object), null, serializer);
                    }

                    break;

                default:
                    ReaderUtil.TryPopulateProperty(serializer, rootObject, contract.Properties.GetClosestMatchProperty(propName), reader);
                    break;
                }
            }
            return(rootObject);
        }
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            reader = new ForkableJsonReader(reader);

            var contract   = (JsonObjectContract)serializer.ContractResolver.ResolveContract(objectType);
            var rootObject = contract.DefaultCreator();

            serializer.ReferenceResolver.AddReference(null, IncludedReferenceResolver.RootReference, rootObject);

            var includedConverter = new IncludedConverter();

            foreach (var propName in ReaderUtil.IterateProperties(reader))
            {
                switch (propName)
                {
                case PropertyNames.Data:

                    var documentRootInterfaceType = TypeInfoShim.GetInterfaces(objectType.GetTypeInfo())
                                                    .Select(x => x.GetTypeInfo())
                                                    .FirstOrDefault(x =>
                                                                    x.IsGenericType &&
                                                                    x.GetGenericTypeDefinition() == typeof(IDocumentRoot <>));
                    var dataType = documentRootInterfaceType.GenericTypeArguments[0];

                    var dataObj = serializer.Deserialize(reader, dataType);
                    contract.Properties.GetClosestMatchProperty(PropertyNames.Data).ValueProvider.SetValue(rootObject, dataObj);
                    break;

                case PropertyNames.Included:
                    foreach (var obj in ReaderUtil.IterateList(reader))
                    {
                        var includedObject = includedConverter.ReadJson(reader, typeof(object), null, serializer);
                    }
                    break;

                default:
                    ReaderUtil.TryPopulateProperty(serializer, rootObject, contract.Properties.GetClosestMatchProperty(propName), reader);
                    break;
                }
            }
            return(rootObject);
        }