/// <summary>
        /// Read JSON string to the object.
        /// </summary>
        /// <param name="reader">JSON reader.</param>
        /// <param name="objectType">Object type.</param>
        /// <param name="existingValue">Existing value.</param>
        /// <param name="serializer">Json serializer</param>
        /// <returns>Deserialized object.</returns>
        /// <remarks>
        /// 1. Check if this is an array or a single element.
        ///     If Array, deserialize each element as DirectoryObject and return the list
        /// 2. Deserialize using the default property set
        /// 3. Find the non-deserialized properties and add them to the Dictionary.
        /// </remarks>
        public override object ReadJson(
            JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            if (reader.TokenType == JsonToken.StartArray)
            {
                JToken jsonToken = JArray.ReadFrom(reader);
                List<JToken> jsonTokens = jsonToken.ToList();

                // This converter can only handle an array of graph objects.
                // Not native types. When deserializing an expanded link, all linked objects will be
                // deserialized as GraphObject.
                ChangeTrackingCollection<GraphObject> resultObjects = new ChangeTrackingCollection<GraphObject>();

                AadJsonConverter jsonConverter = new AadJsonConverter();
                foreach (JToken arrayToken in jsonTokens)
                {
                    GraphObject resultElement = JsonConvert.DeserializeObject(
                        arrayToken.ToString(), typeof(GraphObject), jsonConverter) as GraphObject;

                    resultObjects.Add(resultElement);
                }

                return resultObjects;
            }

            // Load the JSON into a JsonObject so that we can inspect the odata.type property.
            Object resultObject;
            JObject jsonObject = JObject.Load(reader);
 
            List<JProperty> jsonProperties = jsonObject.Properties().ToList();
            JProperty odataTypeProperty = 
                jsonProperties.FirstOrDefault(x => x.Name == Constants.OdataTypeKey);

            // If there is odata.type value, use that to find the type to be deserialized into.
            // If not, use the type that was passed to the de-serializer.
            Type resultObjectType;

            if (odataTypeProperty != null && 
                SerializationHelper.TryGetImplementationForAadType(
                    odataTypeProperty.Value.ToString(), out resultObjectType) &&
                typeof(GraphObject).IsAssignableFrom(resultObjectType))
            {
                resultObject = Activator.CreateInstance(resultObjectType) as GraphObject;
            }
            else
            {
                resultObjectType = objectType;
                resultObject = Activator.CreateInstance(resultObjectType);
            }

            // Deserialize all known properties using the default JSON.NET serializer
            resultObject = JsonConvert.DeserializeObject(jsonObject.ToString(), resultObjectType);

            // TODO: If the odata type is null, should still try to deserialize additional values using
            // the graphObjectType.
            GraphObject graphObject = resultObject as GraphObject;
            if (graphObject != null && odataTypeProperty != null)
            {
                Dictionary<string, PropertyInfo> propertyNameToInfoMap =
                    this.GetPropertyInfosForAadType(odataTypeProperty.Value.ToString(), resultObjectType);

                foreach (JProperty jsonProperty in jsonProperties)
                {
                    PropertyInfo propertyInfo;
                    if (!propertyNameToInfoMap.TryGetValue(jsonProperty.Name, out propertyInfo))
                    {
                        graphObject.NonSerializedProperties[jsonProperty.Name] = jsonProperty.Value.ToString();
                    }
                }
            }

            return graphObject;
        }
        /// <summary>
        /// Read JSON string to the object.
        /// </summary>
        /// <param name="reader">JSON reader.</param>
        /// <param name="objectType">Object type.</param>
        /// <param name="existingValue">Existing value.</param>
        /// <param name="serializer">Json serializer</param>
        /// <returns>Deserialized object.</returns>
        /// <remarks>
        /// 1. Check if this is an array or a single element.
        ///     If Array, deserialize each element as DirectoryObject and return the list
        /// 2. Deserialize using the default property set
        /// 3. Find the non-deserialized properties and add them to the Dictionary.
        /// </remarks>
        public override object ReadJson(
            JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            if (reader.TokenType == JsonToken.StartArray)
            {
                JToken        jsonToken  = JArray.ReadFrom(reader);
                List <JToken> jsonTokens = jsonToken.ToList();

                // This converter can only handle an array of graph objects.
                // Not native types. When deserializing an expanded link, all linked objects will be
                // deserialized as GraphObject.
                ChangeTrackingCollection <GraphObject> resultObjects = new ChangeTrackingCollection <GraphObject>();

                AadJsonConverter jsonConverter = new AadJsonConverter();
                foreach (JToken arrayToken in jsonTokens)
                {
                    GraphObject resultElement = JsonConvert.DeserializeObject(
                        arrayToken.ToString(), typeof(GraphObject), jsonConverter) as GraphObject;

                    resultObjects.Add(resultElement);
                }

                return(resultObjects);
            }

            // Load the JSON into a JsonObject so that we can inspect the odata.type property.
            Object  resultObject;
            JObject jsonObject = JObject.Load(reader);

            List <JProperty> jsonProperties    = jsonObject.Properties().ToList();
            JProperty        odataTypeProperty =
                jsonProperties.FirstOrDefault(x => x.Name == Constants.OdataTypeKey);

            // If there is odata.type value, use that to find the type to be deserialized into.
            // If not, use the type that was passed to the de-serializer.
            Type resultObjectType;

            if (odataTypeProperty != null &&
                SerializationHelper.TryGetImplementationForAadType(
                    odataTypeProperty.Value.ToString(), out resultObjectType) &&
                typeof(GraphObject).IsAssignableFrom(resultObjectType))
            {
                resultObject = Activator.CreateInstance(resultObjectType) as GraphObject;
            }
            else
            {
                resultObjectType = objectType;
                resultObject     = Activator.CreateInstance(resultObjectType);
            }

            // Deserialize all known properties using the default JSON.NET serializer
            resultObject = JsonConvert.DeserializeObject(jsonObject.ToString(), resultObjectType);

            // TODO: If the odata type is null, should still try to deserialize additional values using
            // the graphObjectType.
            GraphObject graphObject = resultObject as GraphObject;

            if (graphObject != null && odataTypeProperty != null)
            {
                Dictionary <string, PropertyInfo> propertyNameToInfoMap =
                    this.GetPropertyInfosForAadType(odataTypeProperty.Value.ToString(), resultObjectType);

                foreach (JProperty jsonProperty in jsonProperties)
                {
                    PropertyInfo propertyInfo;
                    if (!propertyNameToInfoMap.TryGetValue(jsonProperty.Name, out propertyInfo))
                    {
                        graphObject.NonSerializedProperties[jsonProperty.Name] = jsonProperty.Value.ToString();
                    }
                }
            }

            return(graphObject);
        }