JsonSchemaGenerator
Generates a JsonSchema4 object for a given type.
using Newtonsoft.Json;
using NJsonSchema.Infrastructure;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace NJsonSchema
{
public class JsonSchemaGenerator
{
public JsonSchemaGeneratorSettings Settings { get; set; }
public JsonSchemaGenerator(JsonSchemaGeneratorSettings settings)
{
Settings = settings;
}
public JsonSchema4 Generate(Type type, ISchemaResolver schemaResolver)
{
return Generate<JsonSchema4>(type, schemaResolver);
}
public TSchemaType Generate<TSchemaType>(Type type, ISchemaResolver schemaResolver) where TSchemaType : JsonSchema4, new
{
return Generate<TSchemaType>(type, null, schemaResolver);
}
private TSchemaType Generate<TSchemaType>(Type type, PropertyInfo propertyInfo, ISchemaResolver schemaResolver) where TSchemaType : JsonSchema4, new
{
TSchemaType val = new TSchemaType();
JsonObjectTypeDescription jsonObjectTypeDescription = JsonObjectTypeDescription.FromType(type);
val.Type = jsonObjectTypeDescription.Type;
val.Format = jsonObjectTypeDescription.Format;
if (val.Type.HasFlag(JsonObjectType.Object)) {
if (jsonObjectTypeDescription.IsDictionary)
GenerateDictionary(type, val, schemaResolver);
else {
if ((object)type == typeof(object)) {
TSchemaType val2 = new TSchemaType();
val2.Type = JsonObjectType.Object;
val2.AllowAdditionalProperties = false;
return val2;
}
val.TypeName = GetTypeName(type);
if (schemaResolver.HasSchema(type, JsonObjectType.Object)) {
val.SchemaReference = schemaResolver.GetSchema(type, JsonObjectType.Object);
return val;
}
val.Description = GetDescription(type.GetTypeInfo(), type.GetTypeInfo().GetCustomAttributes());
GenerateObject(type, val, schemaResolver);
}
} else if (val.Type.HasFlag(JsonObjectType.Array)) {
val.Type = JsonObjectType.Array;
Type type2 = (type.GenericTypeArguments.Length == 0) ? type.GetElementType() : type.GenericTypeArguments[0];
if ((object)type2 == null)
throw new InvalidOperationException("Could not find item type of enumeration type '" + type.FullName + "'.");
val.Item = Generate<JsonSchema4>(type2, schemaResolver);
} else if (type.GetTypeInfo().get_IsEnum()) {
JsonObjectType enumerationType = GetEnumerationType(propertyInfo);
if (schemaResolver.HasSchema(type, enumerationType)) {
val.Type = enumerationType;
val.SchemaReference = schemaResolver.GetSchema(type, enumerationType);
return val;
}
LoadEnumerations(type, val, enumerationType);
val.TypeName = GetTypeName(type);
schemaResolver.AddSchema(type, enumerationType, val);
}
return val;
}
protected JsonObjectType GetEnumerationType(PropertyInfo propertyInfo)
{
JsonObjectType result = (Settings.DefaultEnumHandling == EnumHandling.String) ? JsonObjectType.String : JsonObjectType.Integer;
dynamic val = ((object)propertyInfo != null) ? propertyInfo.GetCustomAttributes().SingleOrDefault((Attribute a) => a.GetType().get_Name() == "JsonConverterAttribute") : null;
if ((val != null) && ((Type)val.ConverterType).get_Name() == "StringEnumConverter")
result = JsonObjectType.String;
return result;
}
private string GetTypeName(Type type)
{
if (type.IsConstructedGenericType)
return type.get_Name().Split(new char[1] {
'`'
}).First() + GetTypeName(type.GenericTypeArguments[0]);
return type.get_Name();
}
private void GenerateDictionary<TSchemaType>(Type type, TSchemaType schema, ISchemaResolver schemaResolver) where TSchemaType : JsonSchema4, new
{
if (type.GenericTypeArguments.Length != 2)
throw new InvalidOperationException("Could not find value type of dictionary type '" + type.FullName + "'.");
Type type2 = type.GenericTypeArguments[1];
schema.AdditionalPropertiesSchema = Generate<JsonProperty>(type2, schemaResolver);
schema.AllowAdditionalProperties = true;
}
protected virtual void GenerateObject<TSchemaType>(Type type, TSchemaType schema, ISchemaResolver schemaResolver) where TSchemaType : JsonSchema4, new
{
schemaResolver.AddSchema(type, JsonObjectType.Object, schema);
schema.AllowAdditionalProperties = false;
GeneratePropertiesAndInheritance(type, schema, schemaResolver);
}
private void GeneratePropertiesAndInheritance<TSchemaType>(Type type, TSchemaType schema, ISchemaResolver schemaResolver) where TSchemaType : JsonSchema4, new
{
string[] properties = GetTypeProperties(type);
foreach (PropertyInfo item in type.GetTypeInfo().DeclaredProperties.Where(delegate(PropertyInfo p) {
if (properties != null)
return Enumerable.Contains<string>((IEnumerable<string>)properties, p.Name);
return true;
})) {
LoadProperty(item, schema, schemaResolver);
}
GenerateInheritance(type, schema, schemaResolver);
}
private void GenerateInheritance(Type type, JsonSchema4 schema, ISchemaResolver schemaResolver)
{
Type baseType = type.GetTypeInfo().get_BaseType();
if ((object)baseType != null && (object)baseType != typeof(object)) {
if (Settings.FlattenInheritanceHierarchy)
GeneratePropertiesAndInheritance(baseType, schema, schemaResolver);
else {
JsonProperty item = Generate<JsonProperty>(baseType, schemaResolver);
schema.AllOf.Add(item);
}
}
}
protected virtual string[] GetTypeProperties(Type type)
{
if ((object)type == typeof(Exception))
return new string[4] {
"InnerException",
"Message",
"Source",
"StackTrace"
};
return null;
}
private void LoadEnumerations<TSchemaType>(Type type, TSchemaType schema, JsonObjectType enumHandling) where TSchemaType : JsonSchema4, new
{
switch (enumHandling) {
case JsonObjectType.String: {
schema.Type = JsonObjectType.String;
schema.Enumeration.Clear();
schema.EnumerationNames.Clear();
string[] names = Enum.GetNames(type);
foreach (string item in names) {
schema.Enumeration.Add((object)item);
schema.EnumerationNames.Add(item);
}
break;
}
case JsonObjectType.Integer: {
schema.Type = JsonObjectType.Integer;
schema.Enumeration.Clear();
schema.EnumerationNames.Clear();
string[] names = Enum.GetNames(type);
foreach (string text in names) {
int num = (int)Enum.Parse(type, text);
schema.Enumeration.Add((object)num);
schema.EnumerationNames.Add(text);
}
break;
}
default:
throw new NotImplementedException("The enum handling " + enumHandling + " is not supported.");
}
}
private void LoadProperty<TSchemaType>(PropertyInfo property, TSchemaType parentSchema, ISchemaResolver schemaResolver) where TSchemaType : JsonSchema4, new
{
Type propertyType = property.PropertyType;
JsonObjectTypeDescription jsonObjectTypeDescription = JsonObjectTypeDescription.FromType(propertyType);
Attribute[] array = property.GetCustomAttributes().ToArray();
if (array.All((Attribute a) => !(a is JsonIgnoreAttribute))) {
JsonProperty jsonProperty = Generate<JsonProperty>(propertyType, property, schemaResolver);
string propertyName = JsonPathUtilities.GetPropertyName(property);
parentSchema.Properties.Add(propertyName, jsonProperty);
Attribute attribute = TryGetAttribute(array, "System.ComponentModel.DataAnnotations.RequiredAttribute");
if (jsonObjectTypeDescription.IsAlwaysRequired || attribute != null)
parentSchema.RequiredProperties.Add(propertyName);
jsonProperty.Description = GetDescription(property, array);
dynamic val = TryGetAttribute(array, "System.ComponentModel.DataAnnotations.RegularExpressionAttribute");
if (val != null)
jsonProperty.Pattern = (string)val.Pattern;
dynamic val2 = TryGetAttribute(array, "System.ComponentModel.DataAnnotations.RangeAttribute");
if (val2 != null) {
if (val2.Minimum != null)
jsonProperty.Minimum = (double?)val2.Minimum;
if (val2.Maximum != null)
jsonProperty.Maximum = (double?)val2.Maximum;
}
}
}
private string GetDescription(MemberInfo memberInfo, IEnumerable<Attribute> attributes)
{
dynamic val = TryGetAttribute(attributes, "System.ComponentModel.DescriptionAttribute");
if (val != null)
return (string)val.Description;
string xmlDocumentation = memberInfo.GetXmlDocumentation();
if (xmlDocumentation != string.Empty)
return xmlDocumentation;
return null;
}
private Attribute TryGetAttribute(IEnumerable<Attribute> attributes, string attributeType)
{
return attributes.FirstOrDefault((Attribute a) => a.GetType().FullName == attributeType);
}
}
}