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.64k stars 397 forks source link

Union Types (section 5.1 of draft 3) of schemas are not implemented: report as such #1

Closed derammo closed 13 years ago

derammo commented 13 years ago

A schema for a heterogeneous/polymorphic array fails to validate. Here is an example, which is the schema for an array of objects that match one of two schema versions:

[EDIT: ignore this schema, it is written incorrectly. Please see corrected example below]

{ "type" : "array", "items" : [ { "type" : "object", "properties" :
{ "a" : { "type" : "string", "required" : true }, "b" : { "type" : "string", "required" : true } } }, { "type" : "object", "properties" :
{ "c" : { "type" : "string", "required" : true }, "d" : { "type" : "string", "required" : true } } } ] }

Here is a conformant object:

[ {"a" : "1", "b" : "2"}, {"c":"3", "d":"4"}]

validation fails with messages like "property c is required but was not found". The suspected reason is that separate schema versions are somehow collapsed internally and validation of required properties is not done separately for each schema that can match. As a result, any non-homogeneous arrays cannot contain objects with required properties.

derammo commented 13 years ago

note: matches on "pattern" are also collapsed, so that different versions of a schema cannot have different regular expression patterns. This is most likely the same issue, so I did not create an additional item.

fge commented 13 years ago

Hmm, I'll look into it. But can you post the exact error messages? Normally the path to the failing object is written along with the error message.

fge commented 13 years ago

Hmm, it works for me. I have added this test file in JasonSchemaTest:

{
    "schema": {
        "type" : "array",
        "items": [
            {
                "type" : "object",
                "properties": {
                    "a": {
                        "type": "string",
                        "required": true
                    },
                    "b": {
                        "type": "string",
                        "required": true
                    }
                }
            },
            {
                "type": "object",
                "properties": {
                    "c": {
                        "type" : "string",
                        "required" : true
                    },
                    "d": {
                        "type" : "string",
                        "required" : true
                    }
                }
            }
        ]
    },
    "ko": [
        false,
        64
    ],
    "ok": [
        { "a": "1", "b": "2" },
        { "c": "3", "d": "4" }
    ]
}
    @Test
    public void test5()
        throws IOException
    {
        node = JasonHelper.load("fullschemas/test5.json");
        schema = new JasonSchema(node.get("schema"));

        assertFalse(schema.validate(node.get("ko")));
        messages = schema.getMessages();
        assertEquals(messages.size(), 2);
        assertEquals(messages.get(0), "#/0: node is of type boolean, "
            + "expected [object]");
        assertEquals(messages.get(1), "#/1: node is of type integer, "
            + "expected [object]");

        assertTrue(schema.validate(node.get("ok")));
        messages = schema.getMessages();
        assertTrue(messages.isEmpty());
    }

And the test succeeds.

Remember that when you specify "items", the schemas match the JSON node at the exact position. Are you sure that in the schema you validate, the members in your array are in the exact order?

fge commented 13 years ago

OK, wait. If I understand correctly, what you want is a schema like the following. Unfortunately my implementation does not support this currently because it requires schema expansion from the "type" keyword (work is in progress for this on branch v2):

{
    "type": "array",
    "items": {
        "type": [
            {   
                "type": "object",
                "properties": {
                    "a": {
                        "type": "string",
                        "required": true
                    },
                    "b": {
                        "type": "string",
                        "required": true
                    }
                }
            },
            {
                "type": "object",
                "properties": {
                    "c": {
                        "type": "string",
                        "required": true
                    },
                    "d": {
                        "type": "string",
                        "required": true
                    }
                }
            }
        ]
    }
}

The "items" keyword can be either of:

Maybe your confusion comes from there?

derammo commented 13 years ago

Excellent deduction, thanks! I am in fact trying to do what you show in your post above, only I expressed it incorrectly in the schema. Thank you very much for figuring that out. A better description of the issue would have been:

"Union Types (section 5.1 of draft 3) of schemas are not implemented."

Do you agree with that? I would suggest that the current implementation should be adjusted to not even try to validate such schema and just report an error that this isn't supported.

fge commented 13 years ago

Fully agree. Will correct that.

Assigned the task to myself. Can you modify the title of the issue?

fge commented 13 years ago

Updated the master branch: union types are now reported as non implemented.

A test has been added for unsupported schemas and union types is the first of it reported as such. I guess I should do the same for "extends", "$ref" and schemas in "dependencies"...

derammo commented 13 years ago

Downloaded the changes and confirmed it now emits the correct errors messages against my schema and data files:

/client/request_filters/0: Sorry, union types not implemented yet (found subschema in field type)

/client/request_filters/1: Sorry, union types not implemented yet (found subschema in field type)

/client/request_filters/2: Sorry, union types not implemented yet (found subschema in field type)

/client/request_filters/3: Sorry, union types not implemented yet (found subschema in field type)

fge commented 13 years ago

Hello,

At this URL:

https://github.com/fge/json-schema-validator

is a pure Java JSON Schema implementation, which is approaching completion as to fully supporting draft v3, section 5. THE missing keyword is $ref, but I am planning to support this very soon, at least for local $refs.

Right now, the implementation supports:

I have written a bucketload of bizarre tests which all pass, see the files in src/test/resources for examples of procrastination... When you read this mail, note that the master branch WILL receive updates, and hopefully about detected bugs -- and README improvements.

I am definitely interested in sharing this, and on Maven in particular, as v0.1 when I have:

Torture it!

Have fun,

Francis Galiegue, fgaliegue@gmail.com "It seems obvious [...] that at least some 'business intelligence' tools invest so much intelligence on the business side that they have nothing left for generating SQL queries" (Stéphane Faroult, in "The Art of SQL", ISBN 0-596-00894-5)