3

We are now going to use NJsonSchema to check the Json files for required fields only, and we allow user to add some extra fields for their local use. So, it has to allow additional properties in the Json file.

By using the NJsonSchma, there has the setting for additionalProperties, but when we gernate the schema using FromType, and then set the option AllowAdditionalProperties, it will apply to the top level only,

For example:

NJsonSchema.JsonSchema4 schema = JsonSchema4.FromType<Top>();
schema.AllowAdditionalProperties = true;

public class Item
{
    public string code { get; set; }
    public string name { get; set; }
}

public class Top
{
    public List<Item> data { get; set; }
}

Now, it allows additional properties for Top, but not for Item. i.e.

// allowed even ref is not defined in Top
var js = "{\"data\":[{\"code\":\"A01\",\"name\":\"apple\"}],\"ref\":\"A01\"}";  

// ArrayItemNotValid as price is not defined in Item
var js = "{\"data\":[{\"code\":\"A01\",\"name\":\"apple\",\"price\":1.0}],\"ref\":\"A01\"}";

We even try to build a iteration function to set the value in properties dictionary, but it still cannot change the behavior:

public static void SetAditionalProperties(JsonProperty jp)
{
    jp.AllowAdditionalProperties = true;
    foreach (KeyValuePair<string, JsonProperty> kv in jp.Properties)
    {
        SetAditionalProperties(kv.Value);
    }
}

The only thing we can do now is to download the source, and change the getter of AllowAdditionalProperties to return true all the time. Of course we know that this is not a proper way, but we can't find any alternative at this moment, and we'd like to use a proper way later if any.

It seems that this is just a default setting in generating the schema, but we can't find such option (maybe we have missed), does anyone know how we can change this setting in generating the schema?

James MA
  • 323
  • 5
  • 14

2 Answers2

3

You have to implement your own JsonSchemaGenerator:

public class MyJsonSchemaGenerator : JsonSchemaGenerator
{
    public MyJsonSchemaGenerator(JsonSchemaGeneratorSettings settings)
        : base(settings)
    {
    }

    protected override void GenerateObject<TSchemaType>(Type type, TSchemaType schema, ISchemaResolver schemaResolver, ISchemaDefinitionAppender schemaDefinitionAppender)
        where TSchemaType : JsonSchema4, new()
    {
        base.GenerateObject(type, schema, rootSchema, schemaDefinitionAppender, schemaResolver);
        schema.AllowAdditionalProperties = true;
    }
}

Then you can generate the schema like this:

var generator = new MyJsonSchemaGenerator(new JsonSchemaGeneratorSettings());
var schema = generator.Generate(typeof (Person), new SchemaResolver());
Rico Suter
  • 11,548
  • 6
  • 67
  • 93
  • 1
    Thanks a lot, it works without modifying the source. However, just check the comment of AllowAdditionalProperties in JsonSchema4.cs, it seems there has some bug inside the source, as it is expected that the default of this setting should be true, but now, it's false. – James MA Aug 13 '16 at 20:51
  • 1
    This is not a bug: By default AllowAdditionalProperties is true (when you `new JsonSchema4()`), but because the schema is generated from a C# class, this property is set to false (because a C# class usually cannot have additional properties - they will be lost during deserialization). – Rico Suter Apr 28 '17 at 08:21
  • 1
    While c# classes cannot have additional properties, a the json which is validated might – David K Mar 29 '18 at 11:08
0

In SetAdditionalProperties, you also have to set AllowAdditionalProperties to true on the jp.Item property if it is not null...

You should also set it on the other properties (ie Items, AdditionalPropertiesSchema, etc)

Rico Suter
  • 11,548
  • 6
  • 67
  • 93
  • jp.Item is inside the Properties, the foreach loop is used to set the AllowAdditionalProperties to true for all jp.Item, and we have checked in debug mode. However, it doesn't work when validate with the modified schema. – James MA Aug 06 '16 at 14:24
  • BTW, do you know if there has any other way to change the setting directly? I don;t think this recursion method is a proper way to do it. It'd be better if i can change the default setting directly in single command (i.e. the same effect as I change the source to return true all the time). – James MA Aug 06 '16 at 14:29
  • I would recommend for readability to combine these three answers into the first. The second two are really just comments/clarifications :) – theMayer Jan 16 '19 at 18:20