Пример #1
0
 // This constructor is used when we're scanning already-parsed JSON nodes - see
 // JsonStreamConverterSystemTextJson.cs
 internal PropertyNameToken(JsonProperty fromJsonProperty)
 {
     _jsonProperty = fromJsonProperty;
     _string       = null;
     _asciiBytes   = null;
     _defined      = true;
 }
        public static bool GetStringLength(JsonProperty?property, out int minimumLength, out int maximumLength)
        {
            if (property != null)
            {
                Attribute?attribute = GetAttributeByName(property, StringLengthAttributeName, out Type? matchingType);
                if (attribute != null)
                {
                    if (_stringLengthReflectionObject == null)
                    {
                        _stringLengthReflectionObject = ReflectionObject.Create(
                            matchingType !,
#if !NET35
                            "MinimumLength",
#endif
                            "MaximumLength");
                    }

#if !NET35
                    minimumLength = (int)_stringLengthReflectionObject.GetValue(attribute, "MinimumLength") !;
#else
                    minimumLength = 0;
#endif
                    maximumLength = (int)_stringLengthReflectionObject.GetValue(attribute, "MaximumLength") !;
                    return(true);
                }
            }

            minimumLength = 0;
            maximumLength = 0;
            return(false);
        }
        private TypeSchemaKey CreateKey(Required valueRequired, JsonProperty?memberProperty, JsonContract contract)
        {
            Type nonNullableUnderlyingType = GetNonNullableUnderlyingType(contract);

            int?   minLength   = AttributeHelpers.GetMinLength(memberProperty);
            int?   maxLength   = AttributeHelpers.GetMaxLength(memberProperty);
            string?title       = GetTitle(nonNullableUnderlyingType, memberProperty);
            string?description = GetDescription(nonNullableUnderlyingType, memberProperty);

            Required resolvedRequired;

            switch (valueRequired)
            {
            case Required.Default:
            case Required.AllowNull:
                resolvedRequired = Required.AllowNull;
                break;

            case Required.Always:
            case Required.DisallowNull:
                resolvedRequired = Required.DisallowNull;
                break;

            default:
                throw new ArgumentOutOfRangeException(nameof(valueRequired));
            }

            TypeSchemaKey key = new TypeSchemaKey(contract.UnderlyingType, resolvedRequired, minLength, maxLength, title, description);

            return(key);
        }
Пример #4
0
 internal PropertyNameToken(string fromString)
 {
     _string       = fromString;
     _jsonProperty = null;
     _asciiBytes   = null;
     _defined      = true;
 }
Пример #5
0
 internal PropertyNameToken(ReadOnlySpan <byte> fromAsciiBytes)
 {
     _asciiBytes   = fromAsciiBytes;
     _jsonProperty = null;
     _string       = null;
     _defined      = true;
 }
Пример #6
0
 public static bool TryGetFirstFromObject(this JsonElement?src, out JsonProperty?element)
 {
     element = null;
     if (src.HasValue)
     {
         return(src.Value.TryGetFirstFromObject(out element));
     }
     return(false);
 }
Пример #7
0
        public JsonFormatterConverter(JsonSerializerInternalReader reader, JsonISerializableContract contract, JsonProperty?member)
        {
            ValidationUtils.ArgumentNotNull(reader, nameof(reader));
            ValidationUtils.ArgumentNotNull(contract, nameof(contract));

            _reader   = reader;
            _contract = contract;
            _member   = member;
        }
Пример #8
0
        private bool TryGetValue(string key, [NotNullWhen(true)] out JsonProperty?item)
        {
            if (Dictionary == null)
            {
                item = default;
                return(false);
            }

            return(Dictionary.TryGetValue(key, out item));
        }
Пример #9
0
        protected override JsonProperty CreatePropertyFromConstructorParameter(JsonProperty?matchingMemberProperty, ParameterInfo parameterInfo)
        {
            var property = base.CreatePropertyFromConstructorParameter(matchingMemberProperty, parameterInfo);

            if (matchingMemberProperty != null)
            {
                property.ItemConverter = matchingMemberProperty.ItemConverter;
            }
            return(property);
        }
Пример #10
0
        /// <summary>
        /// Gets the closest matching <see cref="JsonProperty"/> object.
        /// First attempts to get an exact case match of <paramref name="propertyName"/> and then
        /// a case insensitive match.
        /// </summary>
        /// <param name="propertyName">Name of the property.</param>
        /// <returns>A matching property if found.</returns>
        public JsonProperty?GetClosestMatchProperty(string propertyName)
        {
            JsonProperty?property = GetProperty(propertyName, StringComparison.Ordinal);

            if (property == null)
            {
                property = GetProperty(propertyName, StringComparison.OrdinalIgnoreCase);
            }

            return(property);
        }
        private string?GetDescription(Type type, JsonProperty?memberProperty)
        {
            JsonContainerAttribute?containerAttribute = ReflectionUtils.GetAttribute <JsonContainerAttribute>(type);

            if (!string.IsNullOrEmpty(containerAttribute?.Description))
            {
                return(containerAttribute !.Description);
            }

            AttributeHelpers.GetDescription(type, memberProperty, out string?description);
            return(description);
        }
        private string?GetTitle(Type type, JsonProperty?memberProperty)
        {
            JsonContainerAttribute?containerAttribute = ReflectionUtils.GetAttribute <JsonContainerAttribute>(type);

            if (!string.IsNullOrEmpty(containerAttribute?.Title))
            {
                return(containerAttribute !.Title);
            }

            AttributeHelpers.GetDisplayName(type, memberProperty, out string?displayName);
            return(displayName);
        }
        public static string?GetFormat(JsonProperty?property)
        {
            if (property != null)
            {
                if (GetAttributeByName(property, UrlAttributeName, out _) != null)
                {
                    return(Constants.Formats.Uri);
                }

                if (GetAttributeByName(property, PhoneAttributeName, out _) != null)
                {
                    return(Constants.Formats.Phone);
                }

                if (GetAttributeByName(property, EmailAddressAttributeName, out _) != null)
                {
                    return(Constants.Formats.Email);
                }

                Attribute?dataTypeAttribute = GetAttributeByName(property, DataTypeAttributeName, out Type? matchingType);
                if (dataTypeAttribute != null)
                {
                    if (_dataTypeReflectionObject == null)
                    {
                        _dataTypeReflectionObject = ReflectionObject.Create(matchingType !, "DataType");
                    }
                    string s = _dataTypeReflectionObject.GetValue(dataTypeAttribute, "DataType") !.ToString();
                    switch (s)
                    {
                    case "Url":
                        return(Constants.Formats.Uri);

                    case "Date":
                        return(Constants.Formats.Date);

                    case "Time":
                        return(Constants.Formats.Time);

                    case "DateTime":
                        return(Constants.Formats.DateTime);

                    case "EmailAddress":
                        return(Constants.Formats.Email);

                    case "PhoneNumber":
                        return(Constants.Formats.Phone);
                    }
                }
            }

            return(null);
        }
Пример #14
0
 public static bool TryGetFirstFromObject(this JsonElement src, out JsonProperty?element)
 {
     element = null;
     if (src.ValueKind == JsonValueKind.Object)
     {
         var currentObject = src.EnumerateObject();
         if (currentObject.MoveNext())
         {
             element = currentObject.Current;
             return(true);
         }
     }
     return(false);
 }
Пример #15
0
 public static bool TryMoveNextFromObject(this JsonElement src, int cycle, out JsonProperty?element)
 {
     element = null;
     if (src.ValueKind == JsonValueKind.Object)
     {
         var currentObject = src.EnumerateObject();
         for (int i = 0; i < cycle; i++)
         {
             currentObject.MoveNext();
         }
         element = currentObject.Current;
         return(true);
     }
     return(false);
 }
Пример #16
0
 internal JSchemaTypeGenerationContext(
     Type objectType,
     Required required,
     JsonProperty?memberProperty,
     JsonContainerContract?parentContract,
     JSchemaGeneratorInternal generatorInternal,
     string?schemaTitle,
     string?schemaDescription)
 {
     SchemaTitle        = schemaTitle;
     SchemaDescription  = schemaDescription;
     ObjectType         = objectType;
     Required           = required;
     MemberProperty     = memberProperty;
     ParentContract     = parentContract;
     _generatorInternal = generatorInternal;
 }
        public static Type?GetEnumDataType(JsonProperty?property)
        {
            if (property != null)
            {
                Attribute?attribute = GetAttributeByName(property, EnumDataTypeAttributeName, out Type? matchingType);
                if (attribute != null)
                {
                    if (_enumTypeReflectionObject == null)
                    {
                        _enumTypeReflectionObject = ReflectionObject.Create(matchingType !, "EnumType");
                    }
                    return((Type)_enumTypeReflectionObject.GetValue(attribute, "EnumType") !);
                }
            }

            return(null);
        }
        public static int?GetMaxLength(JsonProperty?property)
        {
            if (property != null)
            {
                Attribute?maxLengthAttribute = GetAttributeByName(property, MaxLengthAttributeName, out Type? matchingType);
                if (maxLengthAttribute != null)
                {
                    if (_maxLengthReflectionObject == null)
                    {
                        _maxLengthReflectionObject = ReflectionObject.Create(matchingType !, "Length");
                    }
                    return((int)_maxLengthReflectionObject.GetValue(maxLengthAttribute, "Length") !);
                }
            }

            return(null);
        }
        public static string?GetPattern(JsonProperty?property)
        {
            if (property != null)
            {
                Attribute?regexAttribute = GetAttributeByName(property, RegularExpressionAttributeName, out Type? matchingType);
                if (regexAttribute != null)
                {
                    if (_regexReflectionObject == null)
                    {
                        _regexReflectionObject = ReflectionObject.Create(matchingType !, "Pattern");
                    }
                    return((string)_regexReflectionObject.GetValue(regexAttribute, "Pattern") !);
                }
            }

            return(null);
        }
        private static Attribute?GetAttributeByNameFromTypeOrProperty(Type type, JsonProperty?memberProperty, string name, out Type?matchingType)
        {
            matchingType = null;
            Attribute?attribute = null;

            // check for property attribute first
            if (memberProperty != null)
            {
                attribute = GetAttributeByName(memberProperty.AttributeProvider, name, out matchingType);
            }

            // fall back to type attribute
            if (attribute == null)
            {
                attribute = GetAttributeByName(new ReflectionAttributeProvider(type), name, out matchingType);
            }

            return(attribute);
        }
        private static bool GetDisplay(Type type, JsonProperty?memberProperty, out string?name, out string?description)
        {
            Attribute?displayAttribute = GetAttributeByNameFromTypeOrProperty(type, memberProperty, DisplayAttributeName, out Type? matchingType);

            if (displayAttribute != null)
            {
                if (_displayReflectionObject == null)
                {
                    _displayReflectionObject = ReflectionObject.Create(matchingType !, "GetName", "GetDescription");
                }
                name        = (string?)_displayReflectionObject.GetValue(displayAttribute, "GetName");
                description = (string?)_displayReflectionObject.GetValue(displayAttribute, "GetDescription");
                return(true);
            }

            name        = null;
            description = null;
            return(false);
        }
        public static bool GetRange(JsonProperty?property, out double minimum, out double maximum)
        {
            if (property != null)
            {
                Attribute?rangeAttribute = GetAttributeByName(property, RangeAttributeName, out Type? matchingType);
                if (rangeAttribute != null)
                {
                    if (_rangeReflectionObject == null)
                    {
                        _rangeReflectionObject = ReflectionObject.Create(matchingType !, "Minimum", "Maximum");
                    }
                    minimum = Convert.ToDouble(_rangeReflectionObject.GetValue(rangeAttribute, "Minimum"), CultureInfo.InvariantCulture);
                    maximum = Convert.ToDouble(_rangeReflectionObject.GetValue(rangeAttribute, "Maximum"), CultureInfo.InvariantCulture);
                    return(true);
                }
            }

            minimum = 0;
            maximum = 0;
            return(false);
        }
        private void PopulatePrimativeSchema(JSchema schema, JsonContract contract, JsonProperty?memberProperty, Required valueRequired)
        {
            Type        nonNullableUnderlyingType = GetNonNullableUnderlyingType(contract);
            JSchemaType type = GetJSchemaType(contract.UnderlyingType, valueRequired);

            if (type != Constants.AnyType)
            {
                schema.Type = GetJSchemaType(contract.UnderlyingType, valueRequired);
            }

            if (JSchemaTypeHelpers.HasFlag(schema.Type, JSchemaType.String))
            {
                if (AttributeHelpers.GetStringLength(memberProperty, out int minimumLength, out int maximumLength))
                {
                    schema.MinimumLength = minimumLength;
                    schema.MaximumLength = maximumLength;
                }
                else
                {
                    schema.MinimumLength = AttributeHelpers.GetMinLength(memberProperty);
                    schema.MaximumLength = AttributeHelpers.GetMaxLength(memberProperty);
                }

                schema.Pattern = AttributeHelpers.GetPattern(memberProperty);
                schema.Format  = AttributeHelpers.GetFormat(memberProperty);

                // no format specified, derive from type
                if (schema.Format == null)
                {
                    if (nonNullableUnderlyingType == typeof(DateTime) ||
                        nonNullableUnderlyingType == typeof(DateTimeOffset))
                    {
                        schema.Format = Constants.Formats.DateTime;
                    }
                    else if (nonNullableUnderlyingType == typeof(Uri))
                    {
                        schema.Format = Constants.Formats.Uri;
                    }
                }
            }
        public static bool GetDescription(Type type, JsonProperty?memberProperty, out string?description)
        {
            if (GetDisplay(type, memberProperty, out _, out description) && !string.IsNullOrEmpty(description))
            {
                return(true);
            }

            Attribute?descriptionAttribute = GetAttributeByNameFromTypeOrProperty(type, memberProperty, DescriptionAttributeName, out Type? matchingType);

            if (descriptionAttribute != null)
            {
                if (_descriptionReflectionObject == null)
                {
                    _descriptionReflectionObject = ReflectionObject.Create(matchingType !, "Description");
                }
                description = (string?)_descriptionReflectionObject.GetValue(descriptionAttribute, "Description");
                return(true);
            }

            description = null;
            return(false);
        }
        private JSchemaGenerationProvider?ResolveTypeProvider(Type nonNullableType, JsonProperty?memberProperty)
        {
            JSchemaGenerationProviderAttribute?providerAttribute = null;

            if (memberProperty?.AttributeProvider != null)
            {
                providerAttribute = (JSchemaGenerationProviderAttribute)memberProperty.AttributeProvider.GetAttributes(typeof(JSchemaGenerationProviderAttribute), true).SingleOrDefault();
            }

            if (providerAttribute == null)
            {
                providerAttribute = ReflectionUtils.GetAttribute <JSchemaGenerationProviderAttribute>(nonNullableType, true);

                if (providerAttribute == null)
                {
                    return(null);
                }
            }

            JSchemaGenerationProvider provider = (JSchemaGenerationProvider)Activator.CreateInstance(providerAttribute.ProviderType, providerAttribute.ProviderParameters);

            return(provider);
        }
        private JSchema GenerateInternal(Type type, Required?valueRequired, JsonProperty?memberProperty, JsonContainerContract?container, JSchemaGenerationProvider?currentGenerationProvider)
        {
            ValidationUtils.ArgumentNotNull(type, nameof(type));

            Type nonNullableType = ReflectionUtils.IsNullableType(type) ? Nullable.GetUnderlyingType(type) : type;

            Uri?explicitId = GetTypeId(nonNullableType, true);

            JsonContract contract = _generator.ContractResolver.ResolveContract(type);

            Required resolvedRequired = valueRequired ?? _generator.DefaultRequired;

            TypeSchemaKey key = CreateKey(resolvedRequired, memberProperty, contract);

            if (ShouldReferenceType(contract))
            {
                TypeSchema typeSchema = GetCachedSchema(key);
                if (typeSchema != null)
                {
                    return(typeSchema.Schema);
                }
            }

            JSchema?schema = null;

            JSchemaGenerationProvider?provider = ResolveTypeProvider(nonNullableType, memberProperty);

            if (provider != null && provider != currentGenerationProvider)
            {
                JSchemaTypeGenerationContext context = new JSchemaTypeGenerationContext(
                    type,
                    resolvedRequired,
                    memberProperty,
                    container,
                    this,
                    GetTitle(type, memberProperty),
                    GetDescription(type, memberProperty));
                context.GenerationProvider = provider;

                schema = provider.GetSchema(context);

                if (schema == null)
                {
                    throw new JSchemaException("Could not get schema for type '{0}' from provider '{1}'.".FormatWith(CultureInfo.InvariantCulture, type.FullName, provider.GetType().FullName));
                }
            }

            if (_generator._generationProviders != null)
            {
                JSchemaTypeGenerationContext context = new JSchemaTypeGenerationContext(
                    type,
                    resolvedRequired,
                    memberProperty,
                    container,
                    this,
                    GetTitle(type, memberProperty),
                    GetDescription(type, memberProperty));

                foreach (JSchemaGenerationProvider generationProvider in _generator._generationProviders)
                {
                    if (generationProvider != currentGenerationProvider && generationProvider.CanGenerateSchema(context))
                    {
                        context.GenerationProvider = generationProvider;

                        schema = generationProvider.GetSchema(context);
                        break;
                    }
                }
            }

            if (schema != null)
            {
                // check to see whether the generation provide had already generated the type recursively
                // and reuse that cached schema rather than duplicate
                TypeSchema typeSchema = GetCachedSchema(key);

                if (typeSchema != null)
                {
                    schema = typeSchema.Schema;
                }
                else
                {
                    if (ShouldReferenceType(contract))
                    {
                        _typeSchemas.Add(new TypeSchema(key, schema));
                    }
                }
            }
            else
            {
                schema = new JSchema();
                if (explicitId != null)
                {
                    schema.Id = explicitId;
                }

                if (ShouldReferenceType(contract))
                {
                    _typeSchemas.Add(new TypeSchema(key, schema));
                }

                PopulateSchema(schema, contract, memberProperty, resolvedRequired);
            }

            return(schema);
        }
Пример #27
0
        //=====================================================================

        /// <summary>
        /// This is used to load the package reference information from the given project
        /// </summary>
        /// <param name="project">The MSBuild project from which to get the package references</param>
        /// <param name="targetFramework">A target framework value used to resolve implicit package references</param>
        /// <returns>True if package reference info was loaded, false if not</returns>
        public bool LoadPackageReferenceInfo(Project project, string targetFramework)
        {
            if (project == null)
            {
                throw new ArgumentNullException(nameof(project));
            }

            if (targetFramework == null)
            {
                throw new ArgumentNullException(nameof(targetFramework));
            }

            packages = null;
            resolvedDependencies.Clear();
            packageReferences.Clear();

            // This is mostly guesswork so it may still need some revisions
            string targetingPackRoot = project.GetPropertyValue("NetCoreTargetingPackRoot");

            // Strip off the OS part if there
            int dash = targetFramework.IndexOf('-');

            if (dash > 0)
            {
                targetFramework = targetFramework.Substring(0, dash);
            }

            try
            {
                projectFilename = project.FullPath;

                if (project.GetPropertyValue("NuGetProjectStyle") == "PackageReference")
                {
                    string assetFile = project.GetPropertyValue("ProjectAssetsFile");

                    if (!String.IsNullOrWhiteSpace(assetFile) && File.Exists(assetFile))
                    {
                        JsonElement root;

                        using (JsonDocument packageInfo = JsonDocument.Parse(File.ReadAllText(assetFile),
                                                                             new JsonDocumentOptions {
                            AllowTrailingCommas = true,
                            CommentHandling = JsonCommentHandling.Skip
                        }))
                        {
                            root = packageInfo.RootElement.Clone();
                        }

                        if (root.TryGetProperty("targets", out JsonElement targets))
                        {
                            packages = targets.EnumerateObject().First();

                            string folders = project.GetPropertyValue("NuGetPackageFolders");

                            if (!String.IsNullOrWhiteSpace(folders))
                            {
                                nugetPackageFolders = folders.Split(';');
                            }
                            else
                            {
                                nugetPackageFolders = Array.Empty <string>();
                            }

                            foreach (var reference in project.GetItems("PackageReference"))
                            {
                                var version = reference.Metadata.FirstOrDefault(m => m.Name == "Version");

                                if (version != null)
                                {
                                    packageReferences.Add(reference.EvaluatedInclude + "/" + version.EvaluatedValue);
                                }
                            }
                        }
                        else
                        {
                            buildProcess.ReportWarning("BE0011", "Unable to load package reference information " +
                                                       "for '{0}'.  Reason: Unable to locate targets element in project assets file '{1}'.",
                                                       projectFilename, assetFile);
                        }

                        // See if there's a frameworks element.  If so, get the package names from it to use
                        // with the implicit package references below.
                        if (root.TryGetProperty("project", out JsonElement projectNode))
                        {
                            if (projectNode.TryGetProperty("frameworks", out JsonElement frameworks) &&
                                frameworks.EnumerateObject().Any())
                            {
                                var f = frameworks.EnumerateObject().First();

                                if (f.Value.TryGetProperty("frameworkReferences", out JsonElement references))
                                {
                                    foreach (var prop in references.EnumerateObject())
                                    {
                                        string rootPath = Path.Combine(targetingPackRoot, prop.Name);

                                        // Most exist with a ".Ref" suffix
                                        if (!Directory.Exists(rootPath))
                                        {
                                            rootPath += ".Ref";

                                            // We may need to strip off the last part of the identifier (i.e. ".Windows")
                                            if (!Directory.Exists(rootPath))
                                            {
                                                rootPath = rootPath.Substring(0, rootPath.Length - 4);

                                                int dot = rootPath.LastIndexOf('.');

                                                if (dot != -1)
                                                {
                                                    rootPath = rootPath.Substring(0, dot);

                                                    if (!Directory.Exists(rootPath))
                                                    {
                                                        rootPath += ".Ref";
                                                    }
                                                }
                                            }
                                        }

                                        if (Directory.Exists(rootPath))
                                        {
                                            foreach (string path in Directory.EnumerateDirectories(rootPath, "*", SearchOption.AllDirectories))
                                            {
                                                if (path.EndsWith(targetFramework, StringComparison.OrdinalIgnoreCase))
                                                {
                                                    implicitPackageFolders.Add(path);
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                    else
                    {
                        buildProcess.ReportWarning("BE0011", "Unable to load package reference information " +
                                                   "for '{0}'.  Reason: Project assets file '{1}' does not exist.", projectFilename,
                                                   assetFile);
                    }
                }
            }
            catch (Exception ex)
            {
                // We won't prevent the build from continuing if there's an error.  We'll just report it.
                System.Diagnostics.Debug.WriteLine(ex);

                buildProcess.ReportWarning("BE0011", "Unable to load package reference information for '{0}'.  " +
                                           "Reason: {1}", projectFilename, ex.Message);
            }

            // If we have a target framework, look for default implicit packages.  This will helps us find
            // references for .NETStandard 2.1 and later which don't have an explicit package reference.
            if (!String.IsNullOrWhiteSpace(targetFramework))
            {
                string defaultImplicitPackages = project.GetPropertyValue("DefaultImplicitPackages");

                if (!String.IsNullOrWhiteSpace(defaultImplicitPackages) && !String.IsNullOrWhiteSpace(targetingPackRoot))
                {
                    foreach (string package in defaultImplicitPackages.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
                    {
                        string rootPath = Path.Combine(targetingPackRoot, package);

                        // Most exist with a ".Ref" suffix
                        if (!Directory.Exists(rootPath))
                        {
                            rootPath += ".Ref";

                            // We may need to strip off the last part of the identifier (i.e. ".Windows")
                            if (!Directory.Exists(rootPath))
                            {
                                rootPath = rootPath.Substring(0, rootPath.Length - 4);

                                int dot = rootPath.LastIndexOf('.');

                                if (dot != -1)
                                {
                                    rootPath = rootPath.Substring(0, dot);

                                    if (!Directory.Exists(rootPath))
                                    {
                                        rootPath += ".Ref";
                                    }
                                }
                            }
                        }

                        if (Directory.Exists(rootPath))
                        {
                            foreach (string path in Directory.EnumerateDirectories(rootPath, "*", SearchOption.AllDirectories))
                            {
                                if (path.EndsWith(targetFramework, StringComparison.OrdinalIgnoreCase))
                                {
                                    implicitPackageFolders.Add(path);
                                }
                            }
                        }
                    }
                }
            }

            return((packages != null && packageReferences.Count != 0) || implicitPackageFolders.Count != 0);
        }
        private void PopulateSchema(JSchema schema, JsonContract contract, JsonProperty?memberProperty, Required valueRequired)
        {
            Type nonNullableUnderlyingType = GetNonNullableUnderlyingType(contract);

            schema.Title       = GetTitle(nonNullableUnderlyingType, memberProperty);
            schema.Description = GetDescription(nonNullableUnderlyingType, memberProperty);

            JsonConverter?converter;

            if (contract.Converter != null && contract.Converter.CanWrite)
            {
                converter = contract.Converter;
            }
            else if (contract.InternalConverter != null && contract.InternalConverter.CanWrite)
            {
                converter = contract.InternalConverter;
            }
            else
            {
                converter = null;
            }

            if (converter != null)
            {
                schema.Type = null;
            }
            else
            {
                switch (contract)
                {
                case JsonObjectContract objectContract:
                    if (nonNullableUnderlyingType == typeof(object))
                    {
                        PopulatePrimativeSchema(schema, objectContract, memberProperty, valueRequired);
                    }
                    else
                    {
                        if (schema.Id == null)
                        {
                            schema.Id = GetTypeId(nonNullableUnderlyingType, false);
                        }

                        schema.Type = AddNullType(JSchemaType.Object, valueRequired);
                        GenerateObjectSchema(schema, nonNullableUnderlyingType, objectContract);
                    }
                    break;

                case JsonArrayContract arrayContract:
                    if (schema.Id == null)
                    {
                        schema.Id = GetTypeId(nonNullableUnderlyingType, false);
                    }

                    schema.Type         = AddNullType(JSchemaType.Array, valueRequired);
                    schema.MinimumItems = AttributeHelpers.GetMinLength(memberProperty);
                    schema.MaximumItems = AttributeHelpers.GetMaxLength(memberProperty);

                    JsonArrayAttribute?arrayAttribute = ReflectionUtils.GetAttribute <JsonArrayAttribute>(nonNullableUnderlyingType);

                    Required?required = null;
                    if (arrayAttribute != null && !arrayAttribute.AllowNullItems)
                    {
                        required = Required.Always;
                    }

                    if (arrayContract.CollectionItemType != null)
                    {
                        schema.Items.Add(GenerateInternal(arrayContract.CollectionItemType, required, null, arrayContract, null));
                    }
                    break;

                case JsonStringContract stringContract:
                    JSchemaType schemaType = (!ReflectionUtils.IsNullable(stringContract.UnderlyingType))
                            ? JSchemaType.String
                            : AddNullType(JSchemaType.String, valueRequired);

                    schema.Type          = schemaType;
                    schema.MinimumLength = AttributeHelpers.GetMinLength(memberProperty);
                    schema.MaximumLength = AttributeHelpers.GetMaxLength(memberProperty);
                    break;

                case JsonPrimitiveContract primitiveContract:
                    PopulatePrimativeSchema(schema, primitiveContract, memberProperty, valueRequired);
                    break;

                case JsonDictionaryContract dictionaryContract:
                    schema.Type = AddNullType(JSchemaType.Object, valueRequired);
                    schema.MinimumProperties = AttributeHelpers.GetMinLength(memberProperty);
                    schema.MaximumProperties = AttributeHelpers.GetMaxLength(memberProperty);

                    if (dictionaryContract.DictionaryKeyType != null)
                    {
                        JsonContract keyContract = _generator.ContractResolver.ResolveContract(dictionaryContract.DictionaryKeyType);

                        // can be converted to a string
                        if (keyContract is JsonPrimitiveContract)
                        {
                            schema.AdditionalProperties = GenerateInternal(dictionaryContract.DictionaryValueType !, _generator.DefaultRequired, null, dictionaryContract, null);
                        }
                    }
                    break;

#if !PORTABLE || NETSTANDARD1_3 || NETSTANDARD2_0
                case JsonISerializableContract serializableContract:
                    if (schema.Id == null)
                    {
                        schema.Id = GetTypeId(nonNullableUnderlyingType, false);
                    }

                    schema.Type = AddNullType(JSchemaType.Object, valueRequired);
                    schema.AllowAdditionalPropertiesSpecified = false;
                    break;
#endif
#if !NET35
                case JsonDynamicContract dynamicContract:
#endif
                case JsonLinqContract linqContract:
                    schema.Type = null;
                    break;

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