예제 #1
0
 private void ReferenceOrWriteSchema(JsonSchema schema)
 {
     if (schema.Id != null && _resolver.GetSchema(schema.Id) != null)
     {
         _writer.WriteStartObject();
         _writer.WritePropertyName(JsonTypeReflector.RefPropertyName);
         _writer.WriteValue(schema.Id);
         _writer.WriteEndObject();
     }
     else
     {
         WriteSchema(schema);
     }
 }
예제 #2
0
        private JsonSchema ResolveReferences(JsonSchema schema)
        {
            if (schema.DeferredReference != null)
            {
                string reference = schema.DeferredReference;

                bool locationReference = (reference.StartsWith("#", StringComparison.Ordinal));
                if (locationReference)
                {
                    reference = UnescapeReference(reference);
                }

                JsonSchema resolvedSchema = _resolver.GetSchema(reference);

                if (resolvedSchema == null)
                {
                    if (locationReference)
                    {
                        string[] escapedParts = schema.DeferredReference.TrimStart('#').Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
                        JToken   currentToken = _rootSchema;
                        foreach (string escapedPart in escapedParts)
                        {
                            string part = UnescapeReference(escapedPart);

                            if (currentToken.Type == JTokenType.Object)
                            {
                                currentToken = currentToken[part];
                            }
                            else if (currentToken.Type == JTokenType.Array || currentToken.Type == JTokenType.Constructor)
                            {
                                int index;
                                if (int.TryParse(part, out index) && index >= 0 && index < currentToken.Count())
                                {
                                    currentToken = currentToken[index];
                                }
                                else
                                {
                                    currentToken = null;
                                }
                            }

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

                        if (currentToken != null)
                        {
                            resolvedSchema = BuildSchema(currentToken);
                        }
                    }

                    if (resolvedSchema == null)
                    {
                        throw new JsonException("Could not resolve schema reference '{0}'.".FormatWith(CultureInfo.InvariantCulture, schema.DeferredReference));
                    }
                }

                schema = resolvedSchema;
            }

            if (schema.ReferencesResolved)
            {
                return(schema);
            }

            schema.ReferencesResolved = true;

            if (schema.Extends != null)
            {
                for (int i = 0; i < schema.Extends.Count; i++)
                {
                    schema.Extends[i] = ResolveReferences(schema.Extends[i]);
                }
            }

            if (schema.Items != null)
            {
                for (int i = 0; i < schema.Items.Count; i++)
                {
                    schema.Items[i] = ResolveReferences(schema.Items[i]);
                }
            }

            if (schema.AdditionalItems != null)
            {
                schema.AdditionalItems = ResolveReferences(schema.AdditionalItems);
            }

            if (schema.PatternProperties != null)
            {
                foreach (KeyValuePair <string, JsonSchema> patternProperty in schema.PatternProperties.ToList())
                {
                    schema.PatternProperties[patternProperty.Key] = ResolveReferences(patternProperty.Value);
                }
            }

            if (schema.Properties != null)
            {
                foreach (KeyValuePair <string, JsonSchema> property in schema.Properties.ToList())
                {
                    schema.Properties[property.Key] = ResolveReferences(property.Value);
                }
            }

            if (schema.AdditionalProperties != null)
            {
                schema.AdditionalProperties = ResolveReferences(schema.AdditionalProperties);
            }

            return(schema);
        }
예제 #3
0
        private JsonSchema GenerateInternal(Type type, Required valueRequired, bool required)
        {
            ValidationUtils.ArgumentNotNull(type, "type");

            string resolvedId = GetTypeId(type, false);
            string explicitId = GetTypeId(type, true);

            if (!string.IsNullOrEmpty(resolvedId))
            {
                JsonSchema resolvedSchema = _resolver.GetSchema(resolvedId);
                if (resolvedSchema != null)
                {
                    // resolved schema is not null but referencing member allows nulls
                    // change resolved schema to allow nulls. hacky but what are ya gonna do?
                    if (valueRequired != Required.Always && !HasFlag(resolvedSchema.Type, JsonSchemaType.Null))
                        resolvedSchema.Type |= JsonSchemaType.Null;
                    if (required && resolvedSchema.Required != true)
                        resolvedSchema.Required = true;

                    return resolvedSchema;
                }
            }

            // test for unresolved circular reference
            if (_stack.Any(tc => tc.Type == type))
            {
                throw new JsonException("Unresolved circular reference for type '{0}'. Explicitly define an Id for the type using a JsonObject/JsonArray attribute or automatically generate a type Id using the UndefinedSchemaIdHandling property.".FormatWith(CultureInfo.InvariantCulture, type));
            }

            JsonContract contract = ContractResolver.ResolveContract(type);
            JsonConverter converter;
            if ((converter = contract.Converter) != null || (converter = contract.InternalConverter) != null)
            {
                JsonSchema converterSchema = converter.GetSchema();
                if (converterSchema != null)
                    return converterSchema;
            }

            Push(new TypeSchema(type, new JsonSchema()));

            if (explicitId != null)
                CurrentSchema.Id = explicitId;

            if (required)
                CurrentSchema.Required = true;
            CurrentSchema.Title = GetTitle(type);
            CurrentSchema.Description = GetDescription(type);

            if (converter != null)
            {
                // todo: Add GetSchema to JsonConverter and use here?
                CurrentSchema.Type = JsonSchemaType.Any;
            }
            else
            {
                switch (contract.ContractType)
                {
                    case JsonContractType.Object:
                        CurrentSchema.Type = AddNullType(JsonSchemaType.Object, valueRequired);
                        CurrentSchema.Id = GetTypeId(type, false);
                        GenerateObjectSchema(type, (JsonObjectContract)contract);
                        break;

                    case JsonContractType.Array:
                        CurrentSchema.Type = AddNullType(JsonSchemaType.Array, valueRequired);

                        CurrentSchema.Id = GetTypeId(type, false);

                        JsonArrayAttribute arrayAttribute = JsonTypeReflector.GetCachedAttribute<JsonArrayAttribute>(type);
                        bool allowNullItem = (arrayAttribute == null || arrayAttribute.AllowNullItems);

                        Type collectionItemType = ReflectionUtils.GetCollectionItemType(type);
                        if (collectionItemType != null)
                        {
                            CurrentSchema.Items = new List<JsonSchema>();
                            CurrentSchema.Items.Add(GenerateInternal(collectionItemType, (!allowNullItem) ? Required.Always : Required.Default, false));
                        }
                        break;

                    case JsonContractType.Primitive:
                        CurrentSchema.Type = GetJsonSchemaType(type, valueRequired);

                        if (CurrentSchema.Type == JsonSchemaType.Integer && type.IsEnum() && !type.IsDefined(typeof(FlagsAttribute), true))
                        {
                            CurrentSchema.Enum = new List<JToken>();

                            IList<EnumValue<long>> enumValues = EnumUtils.GetNamesAndValues<long>(type);
                            foreach (EnumValue<long> enumValue in enumValues)
                            {
                                JToken value = JToken.FromObject(enumValue.Value);

                                CurrentSchema.Enum.Add(value);
                            }
                        }
                        break;

                    case JsonContractType.String:
                        JsonSchemaType schemaType = (!ReflectionUtils.IsNullable(contract.UnderlyingType))
                            ? JsonSchemaType.String
                            : AddNullType(JsonSchemaType.String, valueRequired);

                        CurrentSchema.Type = schemaType;
                        break;

                    case JsonContractType.Dictionary:
                        CurrentSchema.Type = AddNullType(JsonSchemaType.Object, valueRequired);

                        Type keyType;
                        Type valueType;
                        ReflectionUtils.GetDictionaryKeyValueTypes(type, out keyType, out valueType);

                        if (keyType != null)
                        {
                            JsonContract keyContract = ContractResolver.ResolveContract(keyType);

                            // can be converted to a string
                            if (keyContract.ContractType == JsonContractType.Primitive)
                            {
                                CurrentSchema.AdditionalProperties = GenerateInternal(valueType, Required.Default, false);
                            }
                        }
                        break;
#if !(DOTNET || PORTABLE || PORTABLE40)
                    case JsonContractType.Serializable:
                        CurrentSchema.Type = AddNullType(JsonSchemaType.Object, valueRequired);
                        CurrentSchema.Id = GetTypeId(type, false);
                        GenerateISerializableContract(type, (JsonISerializableContract)contract);
                        break;
#endif
#if !(NET35 || NET20 || PORTABLE40)
                    case JsonContractType.Dynamic:
#endif
                    case JsonContractType.Linq:
                        CurrentSchema.Type = JsonSchemaType.Any;
                        break;

                    default:
                        throw new JsonException("Unexpected contract type: {0}".FormatWith(CultureInfo.InvariantCulture, contract));
                }
            }

            return Pop().Schema;
        }