java-json-tools / json-schema-validator

A JSON Schema validation implementation in pure Java, which aims for correctness and performance, in that order
http://json-schema-validator.herokuapp.com/
Other
1.63k stars 399 forks source link

the following keywords are unknown and will be ignored: [extends] #294

Closed michaelboyles closed 5 years ago

michaelboyles commented 5 years ago

I have the following 2 schemas

ChildMessage:

{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "extends": {
    "$ref": "Message.schema.json"
  }
}

Message:

{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "properties": {
    "foo": {
      "type": "string"
    }
  }
}

I get the error "the following keywords are unknown and will be ignored: [extends]" when trying to validate the following JSON against the ChildMessage schema.

My validation code is:

final String json = "{\"foo\":\"bar\"}";

final URI schemaUri = Test.class.getResource("ChildMessage.schema.json").toURI();
final JsonSchema schema = JsonSchemaFactory.byDefault().getJsonSchema(schemaUri.toString());
final ProcessingReport report = schema.validate(new ObjectMapper().readTree(json));

report.forEach(message -> System.out.println(message.getMessage()));

What's the problem here? 'extends' is a valid keyword - why's it coming up as unknown? Browsing through previous GitHub issues, it seems to be supported.

Using version 2.2.10. I tried dropping back to 2.0.0 but it displays a similar but differently worded error.

michaelboyles commented 5 years ago

It seems like 'extends' is no longer supported in JSON schema v4. I couldn't use allOf etc because of constraints of jsonschema2pojo, but also didn't want to fall back to v3 just for the sake of validation.

Instead, I created a library which adds the 'extends' keyword to v4. There is no way to create a ValidationConfigurationBuilder to override a default schema without getting an illegal argument exception, so I had to use reflection to clear out the map (will raise a separate issue about this).

public static void main(String[] args) throws ProcessingException, IOException, URISyntaxException
{
    final String json = "{\"fool\":\"bar\"}";

    final URI schemaUri = Test.class.getResource("ChildMessage.schema.json").toURI();

    final JsonSchema schema = JsonSchemaFactory.newBuilder()
        .setValidationConfiguration(getValidationConfiguration())
        .freeze()
        .getJsonSchema(schemaUri.toString());

    final JsonNode schemaNode = new ObjectMapper().readTree(json);
    final ProcessingReport report = schema.validate(schemaNode);

    report.forEach(message -> System.out.println(message.getMessage()));
}

private static Library getExtendedV4Library()
{
    return DraftV4Library.get()
        .thaw()
        .addKeyword(
            Keyword.newBuilder("extends")
            .withSyntaxChecker(
                ExtendsSyntaxChecker.getInstance()
            )
            .withValidatorClass(ExtendsValidator.class)
            .withDigester(new NullDigester("extends", NodeType.ARRAY, NodeType.values()))
            .freeze()
        )
        .freeze();
}

private static ValidationConfiguration getValidationConfiguration()
{
    final ValidationConfigurationBuilder configBuilder = ValidationConfiguration.newBuilder();
    try
    {
        configBuilder.setDefaultLibrary("http://json-schema.org/draft-04/schema#", getExtendedV4Library());
    }
    catch (final IllegalArgumentException e)
    {
        // This is fine. I want to override it...
    }
    return configBuilder.freeze();
}