public override object ReadJson(
            JsonReader reader,
            Type objectType,
            object existingValue,
            JsonSerializer serializer)
        {
            if (reader.TokenType == JsonToken.Null)
            {
                return(null);
            }

            if (reader.TokenType != JsonToken.StartObject)
            {
                throw new JsonSerializationException(ClientResources.FeedToken_UnknownFormat);
            }

            JObject jObject = JObject.Load(reader);

            if (!jObject.TryGetValue(FeedTokenInternalConverter.TypePropertyName, out JToken typeJtoken) ||
                !Enum.TryParse(typeJtoken.Value <int>().ToString(), ignoreCase: true, out FeedTokenType feedTokenType))
            {
                throw new JsonSerializationException(ClientResources.FeedToken_UnknownFormat);
            }

            switch (feedTokenType)
            {
            case FeedTokenType.EPKRange:
            {
                if (!jObject.TryGetValue(FeedTokenInternalConverter.RidPropertyName, out JToken ridJToken) ||
                    string.IsNullOrEmpty(ridJToken.Value <string>()))
                {
                    throw new JsonSerializationException(ClientResources.FeedToken_UnknownFormat);
                }

                if (!jObject.TryGetValue(FeedTokenInternalConverter.ContinuationPropertyName, out JToken continuationJToken))
                {
                    throw new JsonSerializationException(ClientResources.FeedToken_UnknownFormat);
                }

                if (!jObject.TryGetValue(FeedTokenInternalConverter.RangePropertyName, out JToken rangeJToken))
                {
                    throw new JsonSerializationException(ClientResources.FeedToken_UnknownFormat);
                }

                List <CompositeContinuationToken> ranges        = serializer.Deserialize <List <CompositeContinuationToken> >(continuationJToken.CreateReader());
                Documents.Routing.Range <string>  completeRange = serializer.Deserialize <Documents.Routing.Range <string> >(rangeJToken.CreateReader());
                return(new FeedTokenEPKRange(ridJToken.Value <string>(), completeRange, ranges));
            }

            case FeedTokenType.PartitionKeyValue:
            {
                if (!jObject.TryGetValue(FeedTokenInternalConverter.ContinuationPropertyName, out JToken continuationJToken))
                {
                    throw new JsonSerializationException(ClientResources.FeedToken_UnknownFormat);
                }

                if (!jObject.TryGetValue(FeedTokenInternalConverter.PartitionKeyPropertyName, out JToken pkJToken))
                {
                    throw new JsonSerializationException(ClientResources.FeedToken_UnknownFormat);
                }

                if (!PartitionKey.TryParseJsonString(pkJToken.Value <string>(), out PartitionKey partitionKey))
                {
                    throw new JsonSerializationException(ClientResources.FeedToken_UnknownFormat);
                }

                FeedTokenPartitionKey feedTokenPartitionKey = new FeedTokenPartitionKey(partitionKey);
                feedTokenPartitionKey.UpdateContinuation(continuationJToken.Value <string>());
                return(feedTokenPartitionKey);
            }

            case FeedTokenType.PartitionKeyRangeId:
            {
                if (!jObject.TryGetValue(FeedTokenInternalConverter.ContinuationPropertyName, out JToken continuationJToken))
                {
                    throw new JsonSerializationException(ClientResources.FeedToken_UnknownFormat);
                }

                if (!jObject.TryGetValue(FeedTokenInternalConverter.PartitionKeyRangeIdPropertyName, out JToken pkJToken))
                {
                    throw new JsonSerializationException(ClientResources.FeedToken_UnknownFormat);
                }

                FeedTokenPartitionKeyRange feedTokenPartitionKeyRange = new FeedTokenPartitionKeyRange(pkJToken.Value <string>());
                feedTokenPartitionKeyRange.UpdateContinuation(continuationJToken.Value <string>());
                return(feedTokenPartitionKeyRange);
            }
            }

            throw new JsonSerializationException(ClientResources.FeedToken_UnknownFormat);
        }