예제 #1
0
        public static void Ignore(this JsonMapBase jsonMap, LambdaExpression expr)
        {
            MemberInfo memberInfo = GetMemberInfoFromExpression(expr);

            jsonMap.Actions.Add(
                (member, property, mode) =>
            {
                if (jsonMap.AcceptsMember(member, memberInfo))
                {
                    property.ShouldSerialize = instance => false;
                }
            });
        }
예제 #2
0
        public static void Map(this JsonMapBase jsonMap, LambdaExpression expr, string name)
        {
            MemberInfo memberInfo = GetMemberInfoFromExpression(expr);

            jsonMap.Actions.Add(
                (member, property, mode) =>
            {
                if (TypeExtraInfo.MembersAreTheSame(member, memberInfo))
                {
                    property.PropertyName    = name;
                    property.ShouldSerialize = instance => true;
                }
            });
        }
예제 #3
0
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            // the question here is: is this objectType associated with any class hierarchy in the `JsonMap` list?
            JsonMapsCache cachedData = this.GetInfoFromTypeCached(objectType);

            while (this.blockOnce == 1)
            {
                throw new Exception("Writing is blocked but should not.");
            }

            if (reader.TokenType == JsonToken.Null)
            {
                bool isNullable = Nullable.GetUnderlyingType(objectType) != null || !objectType.GetTypeInfo().IsValueType;
                if (isNullable)
                {
                    return(null);
                }
            }

            JObject jo = JObject.Load(reader);

            object?value = reader.Value;

            // Looking for discriminators:
            // - match the discriminators of the type given by `objectType`
            // - match the discriminators of subtypes of `objectType`

            // STEP 1: match the discriminators of the type given by `objectType`
            string      discriminatorFieldValue = null;
            bool        foundBaseIAndSubtypes   = false;
            JsonMapBase classMapToUse           = null;

            foreach (JsonMapBase jsonMapBase in cachedData.Mappers.Reverse())
            {
                if (foundBaseIAndSubtypes)
                {
                    throw new Exception($"IAndSubtypes mapper does not accept child mappers.");
                }

                if (jsonMapBase is IAndSubtypes)
                {
                    if (jsonMapBase.DiscriminatorFieldName != null)
                    {
                        JToken?discriminatorFieldValueToken = jo[jsonMapBase.DiscriminatorFieldName];
                        if (discriminatorFieldValueToken?.Type == JTokenType.String)
                        {
                            discriminatorFieldValue = discriminatorFieldValueToken.Value <string>();
                        }
                    }

                    foundBaseIAndSubtypes = true;
                    var jsonMapWithSubtypes = jsonMapBase as IAndSubtypes;
                    value = jsonMapWithSubtypes.CreateObject(discriminatorFieldValue);
                    serializer.Populate(jo.CreateReader(), value);
                    discriminatorFieldValue = null;
                }
                else
                {
                    var jsonSubclassMap = jsonMapBase as JsonSubclassMap;
                    if (jsonSubclassMap?.DiscriminatorFieldValue != null && discriminatorFieldValue != null)
                    {
                        if (jsonSubclassMap.DiscriminatorFieldValue != discriminatorFieldValue)
                        {
                            throw new Exception($"Discriminator does not match.");
                        }

                        discriminatorFieldValue = null;
                    }

                    if (jsonMapBase.DiscriminatorFieldName != null)
                    {
                        JToken?discriminatorFieldValueToken = jo[jsonMapBase.DiscriminatorFieldName];
                        if (discriminatorFieldValueToken?.Type == JTokenType.String)
                        {
                            discriminatorFieldValue = discriminatorFieldValueToken.Value <string>();
                        }
                    }

                    classMapToUse = jsonMapBase;
                }
            }


            // STEP 2: match the discriminators of subtypes of `objectType`
            JsonMapBase subclassMapToUse = null;

            foreach (JsonMapBase[] jsonSubmappers in cachedData.SubMappers)
            {
                string      subDiscriminatorFieldValue = discriminatorFieldValue;
                bool        foundSubIAndSubtypes       = foundBaseIAndSubtypes;
                JsonMapBase subclassMapToUse2          = null;
                foreach (JsonMapBase submapper in jsonSubmappers.Reverse())
                {
                    if (foundSubIAndSubtypes)
                    {
                        throw new Exception($"IAndSubtypes mapper does not accept child mappers.");
                    }

                    if (submapper is IAndSubtypes)
                    {
                        if (submapper.DiscriminatorFieldName != null)
                        {
                            JToken?discriminatorFieldValueToken = jo[submapper.DiscriminatorFieldName];
                            if (discriminatorFieldValueToken?.Type == JTokenType.String)
                            {
                                subDiscriminatorFieldValue = discriminatorFieldValueToken.Value <string>();
                            }

                            if (subDiscriminatorFieldValue == null)
                            {
                                throw new Exception($"Discriminator field not found.");
                            }
                        }

                        foundSubIAndSubtypes = true;
                        var jsonMapWithSubtypes = submapper as IAndSubtypes;
                        value = jsonMapWithSubtypes.CreateObject(subDiscriminatorFieldValue);
                        serializer.Populate(jo.CreateReader(), value);
                        subDiscriminatorFieldValue = null;
                    }
                    else
                    {
                        var jsonSubclassMap = submapper as JsonSubclassMap;
                        if (jsonSubclassMap != null)
                        {
                            if (jsonSubclassMap.DiscriminatorFieldValue != null)
                            {
                                if (jsonSubclassMap.DiscriminatorFieldValue != subDiscriminatorFieldValue)
                                {
                                    break;
                                }

                                if (subclassMapToUse != null)
                                {
                                    throw new Exception($"Ambiguous maps for the type `{submapper.SerializedType.Name}`");
                                }

                                subDiscriminatorFieldValue = null;
                                subclassMapToUse2          = jsonSubclassMap;
                            }
                        }
                        else
                        {
                            if (cachedData.Mappers.Length > 0)
                            {
                                throw new Exception($"Sub mappers must be subclasses of `{typeof(JsonSubclassMap).Name}`: `{cachedData.Mappers[0].GetType().Name}`");
                            }

                            if (subclassMapToUse != null)
                            {
                                throw new Exception($"Ambiguous maps for the type `{submapper.SerializedType.Name}`");
                            }

                            subclassMapToUse2 = submapper;
                        }

                        if (submapper.DiscriminatorFieldName != null)
                        {
                            JToken?discriminatorFieldValueToken = jo[submapper.DiscriminatorFieldName];
                            if (discriminatorFieldValueToken?.Type == JTokenType.String)
                            {
                                subDiscriminatorFieldValue = discriminatorFieldValueToken.Value <string>();
                            }

                            if (subDiscriminatorFieldValue == null)
                            {
                                break;
                            }
                        }
                    }
                }

                if (subclassMapToUse2 != null)
                {
                    subclassMapToUse = subclassMapToUse2;
                }

                if (subclassMapToUse2 != null && subDiscriminatorFieldValue != null)
                {
                    throw new Exception("Value of discriminator field not verified by any subclass map.");
                }
            }

            if (subclassMapToUse == null && discriminatorFieldValue != null)
            {
                throw new Exception("Value of discriminator field not verified by any subclass map.");
            }

            // STEP 3: Creating the new value with the correct JsonMapBase class if any
            // - by the way, there is no JsonMapBase when a IAndSubtypes mapper is found
            JsonMapBase classMapToUse2 = subclassMapToUse ?? classMapToUse;

            if (classMapToUse2 != null)
            {
                if (!classMapToUse2.CanCreateNew())
                {
                    throw new Exception($"Cannot create object of type `{classMapToUse2.SerializedType}`");
                }

                value = classMapToUse2.CreateNew();
                serializer.Populate(jo.CreateReader(), value);
            }

            return(value);
        }
예제 #4
0
 public JsonMapsTreeNode(JsonMapBase mapper, Type parent, Type[] children)
 {
     this.Mapper   = mapper;
     this.Parent   = parent;
     this.Children = new ReadOnlyCollection <Type>(children);
 }