jsonschema-generator
jsonschema-generator copied to clipboard
Validate Json error
Hi,
I have the following class with the @JsonTypeInfo annotation.
@JsonTypeInfo(
use = JsonTypeInfo.Id.CLASS,
include = JsonTypeInfo.As.PROPERTY,
property = "type")
public class MyEvent {
@JsonProperty(required = true)
private final String name;
public MyEvent(String name) {
this.name = name;
}
}
When I generate the schema (with the Jackson-module) for this class I get the following result with two sub-schemas.
{
"$schema" : "http://json-schema.org/draft-07/schema#",
"allOf" : [ {
"type" : "object",
"properties" : {
"name" : { }
},
"required" : [ "name" ],
"additionalProperties" : false
}, {
"type" : "object",
"properties" : {
"type" : {
"const" : "com.event.MyEvent"
}
}
} ]
}
When I try to validate the following Json against the schema above
{
"name": "Test",
"type": "com.event.MyEvent"
}
using the following code:
@Test
public void testMyEvent() throws JsonProcessingException {
JSONObject jsonSchema = new JSONObject(
new JSONTokener(SchemaGeneratorApp.class.getResourceAsStream("/schemas/com.event.MyEvent.json")));
JSONObject jsonSubject = new JSONObject(
new JSONTokener(SchemaGeneratorApp.class.getResourceAsStream("/data/MyEvent.json")));
JsonSchema schema = validatorFactory.getSchema(jsonSchema.toString());
schema
.validate(mapper.readTree(jsonSubject.toString()))
.forEach(System.out::println);
}
I get the following error:
$.type: is not defined in the schema and the schema does not allow additional properties
How can I resolve this error in the simplest way?
Hi @cbuchmann,
The starting point would be to determine what configuration is producing this line in the first subschema:
"additionalProperties" : false
That is blocking any additional properties defined in the second subschema, which are not already mentioned in the first.
In other words:
- The validation result is correct. The first subschema (in the
"allOf") says: there is exactly one property called "name" and nothing else. The second subschema says, there may be "type" property and if that is present, it has a particular value. The combination of those two schemas would only allow for a JSON like this one:
{
"name": "Test"
}
- As stated above, the culprit is the
"additionalProperties": false. That is not being added by default. I suspect you have explicitly included it – one way or another (e.g. by including theOption.FORBIDDEN_ADDITIONAL_PROPERTIES_BY_DEFAULT, which is not compatible with your currently selected subtype resolution. You'd have to remove thisOptionor implement the type resolution yourself in some different way). - I can only help more specifically if you share your generator configuration. 😉
Thanks for your quick response. I removed the option FORBIDDEN_ADDITIONAL_PROPERTIES_BY_DEFAULT in the jackson-module and then the validation works. But then if I add a property in the Json data that should not be there it will also pass.
{
"name": "Test",
"type": "com.event.MyEvent",
"abcd": "efgh"
}
Is there another way to prevent that? I guess what I would like is for the two subschemas to be merged into one so that additionalProperties can be set to false. Is there a way to make the second sub-schema that is produced by the annotation @JsonTypeInfo to be incorporated in the first.
Theoretically, that should be possible I guess. I can have a look. Generally speaking, I'm also in favor of pull requests. 😃
Now I remember why I did it like this. It avoids an endless loop that results in a StackOverflowError.
Have to think about it again, but can't promise anything at this point.
Thanks, I appreciate your effort. Instead of changing the schema Is it possible to change anything in the validation process to make this work?
I'm afraid not. The validation is working as it should.
The first subschema forbids the "type" property. You could either remove the"additionalProperties": false or already declare the "type" property in the first subschema.
Thanks for your suggestions. One other option would be to do some post processing on the generated schema node outside of the framework and manually merge the two sub-schemas.
Yes.
There is already some post-processing going on (e.g. to merge unnecessary allOf parts), which could probably be enhanced somewhat. However, in this particular case, merging the two subschemas alters their meaning.
You know that you want this different meaning and can therefore do it in your particular use case, but that prevents a generic solution.
I haven't given up though. I'm still looking into avoiding the endless loops (which would already be a good thing on its own 😅 ), which would, in turn, allow for the Jackson subtype handling to never even produce the allOf parts that you want to get rid off.
I think this is a pretty common issue with JSON schemas. https://stackoverflow.com/a/23001194/5153063
Solutions seem to have all sorts of ugly duplication involved. Maybe this is why the ajv library seems to be pushing people towards JTD?
While I haven't found a way to avoid the allOf parts being added here without messing up the generated schema or running into endless loops, I'm happy to say that the built-in clean-up logic for the allOf blocks has been improved (as long as there is no "additionalProperties": false in there) with the result of the ´allOf` being removed during the postprocessing (in most/simple scenarios).
This will be available with the next release 4.28.0.
I'm closing this issue accordingly, as I currently don't see a way of further enhancing the described use-case. Always happy to receive pull requests though. 😉