Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deferencing by $id with $ref in same schema doesn't seem to resolve #270

Closed
mtokumaru opened this issue Jan 31, 2019 · 10 comments
Closed

Deferencing by $id with $ref in same schema doesn't seem to resolve #270

mtokumaru opened this issue Jan 31, 2019 · 10 comments

Comments

@mtokumaru
Copy link
Contributor

Hi there, we have used your library a few times but are currently experiencing an issue in 1.11.0 (actually I have tried older versions too).
I was trying to use $id references as in the example here: https://json-schema.org/understanding-json-schema/structuring.html#using-id-with-ref

The issue I have is with a schema that looks like simple-schema.json:

{
  "$schema": "http://json-schema.org/draft-06/schema#",
  "type": "object",
  "properties": {
    "events": {
      "type": "array",
      "items": {
        "oneOf": [
          {
            "$ref": "#event"
          }
        ]
      }
    }
  },
  "additionalProperties": false,
  "required": [
    "events"
  ],
  "definitions": {
    "event": {
      "$id": "#event",
      "type": "object",
      "properties": {
        "name": {
          "type": "string"
        }
      }
    }
  }
}

And a sample JSON that looks like simple-event.json:

{
  "events": [
    {
      "name": "example"
    }
  ]
}

Example test:

import static com.google.common.io.Resources.getResource;

import com.google.common.io.Resources;
import org.everit.json.schema.Schema;
import org.everit.json.schema.loader.SchemaLoader;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.nio.charset.Charset;

class JsonSchemaTest {

    @Test
    void dereferencing() throws JSONException, IOException {
        String stringSchema = Resources.toString(getResource("simple-schema.json"), Charset.forName("utf-8"));
        JSONObject jsonSchema = new JSONObject(new JSONTokener(stringSchema));

        Schema schema = SchemaLoader.load(jsonSchema);
        String simple = Resources.toString(getResource("simple-event.json"), Charset.forName("utf-8"));
        schema.validate(new JSONObject(simple));
    }
}

Validation fails seemingly because the event object definition cannot be found.

If I use the absolute reference "$ref": "#/defintions/event", it works fine.

I've tried using the SchemaLoader with resolutionScope pointing to its own schema, but that also didn't work.

There is a javascript validator that seems to be okay in this example: https://github.com/epoberezkin/ajv

I saw a similar issue that is closed #244 and seemed to be closed because the problem wasn't meant to work with external schemas.

Thanks in advance for your feedback!

@mtokumaru
Copy link
Contributor Author

I've forked your repo with the examples in issue270 in https://github.com/mtokumaru/json-schema

@erosb
Copy link
Contributor

erosb commented Feb 1, 2019

Hello @mtokumaru ,

the problem is that the validator by default assumes that your schema is a json schema draft-4 schema. In this older version of the schema specification the "$id" keyword was called "id" , therefore in this default mode the validator won't take "$id" into account. You can enable draft-7 mode this way:

SchemaLoader loader = SchemaLoader.builder()
                .schemaJson(yourSchemaJSON)
                .draftV7Support()
                .build();
Schema schema = loader.load().build();

Thanks for opening the issue, I will try to fit this bit into the documentation as a follow-up.

Let me know if you can make it work.

@mtokumaru
Copy link
Contributor Author

Thanks for the suggestion. However, I've tried this and it still fails for the same reason (using the above examples):

org.everit.json.schema.ValidationException: #/events/0: #: 0 subschemas matched instead of one

	at org.everit.json.schema.ValidationException.prepend(ValidationException.java:395)
	at org.everit.json.schema.ValidationException.prepend(ValidationException.java:375)
	at org.everit.json.schema.ObjectSchemaValidatingVisitor.visitPropertySchema(ObjectSchemaValidatingVisitor.java:160)
	at org.everit.json.schema.Visitor.visitObjectSchema(Visitor.java:131)
	at org.everit.json.schema.ObjectSchemaValidatingVisitor.visitObjectSchema(ObjectSchemaValidatingVisitor.java:36)
	at org.everit.json.schema.ObjectSchema.accept(ObjectSchema.java:267)
	at org.everit.json.schema.ValidatingVisitor.visitObjectSchema(ValidatingVisitor.java:143)
	at org.everit.json.schema.ObjectSchema.accept(ObjectSchema.java:267)
	at org.everit.json.schema.Visitor.visit(Visitor.java:43)
	at org.everit.json.schema.ValidatingVisitor.visit(ValidatingVisitor.java:52)
	at org.everit.json.schema.DefaultValidator.performValidation(Validator.java:69)
	at org.everit.json.schema.Schema.validate(Schema.java:152)

@erosb
Copy link
Contributor

erosb commented Feb 3, 2019

Take a second look at the exception, now you got a ValidationException and not a SchemaException (so the "$ref" resolution worked).

@mtokumaru
Copy link
Contributor Author

Yes, but why doesn't this example validate? Is #/events/0 referring to the first element of the events array? If so it has a name field as the schema mentions. If I change "$ref": "#event" to `"$ref": "#/definitions/event" the validation passes.

@erosb
Copy link
Contributor

erosb commented Feb 3, 2019

Eg. ValidationException#toJSON() gives a more verbose output. See in the manual.

@mtokumaru
Copy link
Contributor Author

Thanks, it still doesn't make any sense:

#/events/0: #: 0 subschemas matched instead of one
#/events/0: required key [events] not found
#/events/0: extraneous key [name] is not permitted

This implies that the inner object is not valid ("$ref": "#event") and is being validated against its parent instead.

    {
      "name": "example"
    }

Conforms to:

 "event": {
      "$id": "#event",
      "type": "object",
      "properties": {
        "name": {
          "type": "string"
        }
      }
    }

from the schema above.

So why does referencing "$ref": "#event" not work as expected? Again, simply changing "$ref": "#event" to "$ref": "#/definitions/event" works

@mtokumaru
Copy link
Contributor Author

Here's the JSON output of that exception:

#/events/0: #: 0 subschemas matched instead of one
{"schemaLocation":"#","pointerToViolation":"#\/events\/0","causingExceptions":[],"keyword":"required","message":"required key [events] not found"}
{"schemaLocation":"#","pointerToViolation":"#\/events\/0","causingExceptions":[],"keyword":"additionalProperties","message":"extraneous key [name] is not permitted"}

@erosb
Copy link
Contributor

erosb commented Feb 3, 2019

Good question. It also works if you use "event" without the leading hashmark. I will investigate this in detail at some time during the week. Thanks for raising the issue & writing a reproduction test.

@erosb
Copy link
Contributor

erosb commented Mar 17, 2019

The fix is released in version 1.11.1.

@erosb erosb closed this as completed Mar 18, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants