JsonSchemaGenerator problems

Feb 11, 2011 at 10:34 AM

Hi, I have noticed some issues with JsonSchemaGenerator.

When running on a class that has a DateTime datatype, the schema generated specifies the DateTime type as string.

When creating schema for a nullable enum, the type again is string.

 

Could you take a look?

By the way love this api, it's fantastic!

 

Regards,
Jeremy.

Feb 11, 2011 at 11:56 AM
Edited Feb 11, 2011 at 12:10 PM

I've come up with a way to fix this, though would be better in JSON.NET for sure!

 

public static JsonSchema GetJsonSchemaFromObject(Type type)
        {
            JsonSchemaGenerator schemaGenerator = new JsonSchemaGenerator();
            
            JsonSchema jSchema = schemaGenerator.Generate(type);

            foreach (var js in jSchema.Properties)
            {
                Type fieldType = type.GetProperty(js.Key).PropertyType;
                
                if (fieldType.IsGenericType 
                    && fieldType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
                {
                    Type underlyingType = Nullable.GetUnderlyingType(fieldType);
                    if (underlyingType == typeof(DateTime))
                        js.Value.Format = "date-time";
                    else if (underlyingType.BaseType == typeof(Enum))
                    {
                        js.Value.Enum = new JArray(from ival in Enum.GetNames(underlyingType)
                                                   select (int)Enum.Parse(underlyingType, ival));

                        Dictionary<JToken, string> enumVals = new Dictionary<JToken,string>();
                        foreach (string name in Enum.GetNames(underlyingType))
                        {
                            enumVals.Add((int)Enum.Parse(underlyingType, name), name);
                        }
                        js.Value.Options = enumVals;
                    }
                }
                else if (fieldType == typeof(DateTime))
                {
                    js.Value.Format = "date-time";
                }
            }

            return jSchema;
        }

Feb 11, 2011 at 12:17 PM

Though actually, when using string enum converter for serialization / deserialization (settings.Converters = new JsonConverter[] { new StringEnumConverter() };)

Then, i think it is nicer to just use strings in the Enum directly.

e.g.

public static JsonSchema GetJsonSchemaFromObject(Type type)
        {
            JsonSchemaGenerator schemaGenerator = new JsonSchemaGenerator();
            
            JsonSchema jSchema = schemaGenerator.Generate(type);

            foreach (var js in jSchema.Properties)
            {
                Type fieldType = type.GetProperty(js.Key).PropertyType;
                
                if (fieldType.IsGenericType 
                    && fieldType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
                {
                    Type underlyingType = Nullable.GetUnderlyingType(fieldType);
                    if (underlyingType == typeof(DateTime))
                        js.Value.Format = "date-time";
                    else if (underlyingType.BaseType == typeof(Enum))
                        js.Value.Enum = new JArray(Enum.GetNames(underlyingType));
                }
                else if (fieldType == typeof(DateTime))
                {
                    js.Value.Format = "date-time";
                }
            }

            return jSchema;
        }

Apr 12, 2013 at 9:07 AM
added support for underlying types too:
        private static JsonSchema GetJsonSchemaFromObject(Type type)
        {
            var schemaGenerator = new JsonSchemaGenerator();

            var jSchema = schemaGenerator.Generate(type);

            jSchema = MapSchemaTypes(jSchema, type);

            return jSchema;
        }
        private static JsonSchema MapSchemaTypes(JsonSchema jSchema, Type type)
        {
            foreach (var js in jSchema.Properties)
            {
                Type fieldType = type.GetProperty(js.Key).PropertyType;

                if (fieldType.IsGenericType
                    && fieldType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
                {
                    Type underlyingType = Nullable.GetUnderlyingType(fieldType);
                    if (underlyingType == typeof(DateTime))
                        js.Value.Format = "date-time";
                    else if (underlyingType.BaseType == typeof(Enum))
                        js.Value.Enum = new JArray(Enum.GetNames(underlyingType));
                }
                else if (fieldType == typeof(DateTime))
                {
                    js.Value.Format = "date-time";
                }
                else if (fieldType.BaseType == typeof(Enum))
                {
                    js.Value.Enum = new JArray(Enum.GetNames(fieldType));
                }
                else if (js.Value.Items != null && js.Value.Items.Any())
                {
                    foreach (var item in js.Value.Items)
                    {
                        var arg = fieldType.GetGenericArguments();
                        if (arg.Any())
                            fieldType = arg[0];

                        MapSchemaTypes(item, fieldType);
                    }
                }
                else if (js.Value.Properties != null && js.Value.Properties.Any())
                {
                    MapSchemaTypes(js.Value, fieldType);
                }
            }
            return jSchema;
        }