Пример #1
0
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            var jsonTypeHint = JsonTypeHintAttribute.For(value.GetType()).FirstOrDefault();

            //JToken token;
            //using (JTokenWriter jTokenWriter = new JTokenWriter())
            //{
            //	serializer.Serialize(jTokenWriter, value);
            //	token = jTokenWriter.Token;
            //}

            //using (JTokenReader jTokenReader = new JTokenReader(token))
            //{
            //	if (jsonTypeHint != null)
            //	{
            //		JObject jo = JObject.FromObject(value);
            //		jo.AddFirst(new JProperty(jsonTypeHint.Property, jsonTypeHint.Value));
            //		writer.WriteToken(jo.CreateReader());
            //	}
            //	else
            //	{
            //		writer.WriteToken(jTokenReader);
            //	}
            //}

            JObject jo = JObject.FromObject(value);

            if (jsonTypeHint != null)
            {
                jo.AddFirst(new JProperty(jsonTypeHint.Property, jsonTypeHint.Value));
            }
            writer.WriteToken(jo.CreateReader());
        }
Пример #2
0
        /// <summary>
        /// </summary>
        /// <param name="baseType">The property type that is get or set (aka the assignable type).</param>
        internal ConfigTypeJsonConverter(Type baseType) //, JsonSerializer innerSerializer)
        {
            Contract.Requires <ArgumentNullException>(baseType != null);
            //Contract.Requires<ArgumentNullException>(innerSerializer != null);

            //_innerSerializer = innerSerializer;

            _baseType = baseType;
            // Determine possible types
            _possibleTypes = LogJamConfigTypes.GetConcreteTypesFor(baseType).ToArray();
            // Create property name => types Lookup
            _typesWithProperty = _possibleTypes.SelectMany(type => type.GetProperties().Select(property => new
            {
                type,
                property
            }))
                                 .ToLookup(a => a.property.Name, a => a.type);
            // Create TypeHint -> type lookup
            _typesWithTypeHint = _possibleTypes.SelectMany(type => JsonTypeHintAttribute.For(type).Select(jsonHint => new
            {
                jsonHint,
                type
            }))
                                 .ToLookup(a => a.jsonHint, a => a.type);
            // Create list of TypeHint properties
            _typeHintProperties = new HashSet <string>(_typesWithTypeHint.Select(grouping => grouping.Key.Property), StringComparer.OrdinalIgnoreCase);
        }
Пример #3
0
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            if (!CanConvert(objectType))
            {
                throw new InvalidOperationException("Can't convert type " + objectType + "; expected " + _baseType);
            }

            // Load JObject from stream.  Turns out we're also called for null arrays of our objects,
            // so handle a null by returning one.
            var jToken = JToken.Load(reader);

            if (jToken.Type == JTokenType.Null)
            {
                return(null);
            }
            if (jToken.Type != JTokenType.Object)
            {
                throw new InvalidOperationException("Json: expected " + _baseType + "; got " + jToken.Type);
            }

            JObject jObject = (JObject)jToken;

            // Narrow down the object type to 1, starting from all possible
            HashSet <Type> remainingTypes = new HashSet <Type>(_possibleTypes);

            foreach (var property in jObject)
            {
                if (remainingTypes.Count <= 1)
                {
                    break;
                }

                // Check if it's a JsonTypeHint property
                if (_typeHintProperties.Contains(property.Key) &&
                    (property.Value.Type == JTokenType.String))
                {
                    var lookupTypeHint        = new JsonTypeHintAttribute(property.Key, (string)property.Value);
                    var typesWithMatchingHint = _typesWithTypeHint[lookupTypeHint];
                    if (typesWithMatchingHint.Any())
                    { // Narrow down based on the type hint
                        remainingTypes.IntersectWith(typesWithMatchingHint);
                        continue;
                    }
                }

                // Narrow down types to only those with this property
                var typesWithProperty = _typesWithProperty[property.Key];
                remainingTypes.IntersectWith(typesWithProperty);
            }

            if (remainingTypes.Count == 1)
            {
                // Found the only possible type
                var target = Activator.CreateInstance(remainingTypes.First());
                serializer.Populate(jObject.CreateReader(), target);
                return(target);
            }
            else if (remainingTypes.Count == 0)
            {
                throw new JsonSerializationException(string.Format("No registered subclass of {0} contains all properties in JSON {1}", _baseType, jObject));
            }
            else
            {
                // Multiple types match: if a single type is inherited by all other candidate types, then that's the one we want (it's
                // marked as serialisable and there's nothing to prompt us to deserialise as one of its subtypes instead).  Otherwise,
                // we have an ambiguity: there are two or more sibling types matching the same fields, and no clear (winning) supertype.
                var commonBaseType = remainingTypes.SingleOrDefault(baseType => remainingTypes.All(childType => baseType.IsAssignableFrom(childType)));
                if (commonBaseType != null)
                {
                    var target = Activator.CreateInstance(commonBaseType);
                    serializer.Populate(jObject.CreateReader(), target);
                    return(target);
                }

                throw new JsonSerializationException(string.Format("Multiple subclasses of {0} contain all properties in JSON {1} : {2}",
                                                                   _baseType,
                                                                   jObject,
                                                                   string.Join(", ", remainingTypes)));
            }
        }
Пример #4
0
 private bool Equals(JsonTypeHintAttribute other)
 {
     return(other != null &&
            string.Equals(Property, other.Property, StringComparison.OrdinalIgnoreCase) &&
            string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase));
 }