-
Notifications
You must be signed in to change notification settings - Fork 328
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
Error occurs if OneOf and AllOf are nested #1032
Comments
Can you provide unit test cases or at least the schema and data to elaborate on what errors you are encountering with this? I have tried but don't see anything unusual. package com.networknt.schema;
import java.util.Set;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import com.networknt.schema.SpecVersion.VersionFlag;
/**
* Tests for nested applicators.
*/
public class NestedApplicatorTest {
@Test
void anyOfOneOfOneOfFalse() {
String schemaData = "{\r\n"
+ " \"anyOf\": [\r\n"
+ " {\r\n"
+ " \"oneOf\": [\r\n"
+ " false,\r\n"
+ " false\r\n"
+ " ]\r\n"
+ " },\r\n"
+ " {\r\n"
+ " \"oneOf\": [\r\n"
+ " false,\r\n"
+ " false\r\n"
+ " ]\r\n"
+ " }\r\n"
+ " ]\r\n"
+ "}";
JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData);
Set<ValidationMessage> messages = schema.validate("{}", InputFormat.JSON);
Assertions.assertFalse(messages.isEmpty());
}
@Test
void anyOfOneOfOneOfTrue() {
String schemaData = "{\r\n"
+ " \"anyOf\": [\r\n"
+ " {\r\n"
+ " \"oneOf\": [\r\n"
+ " false,\r\n"
+ " false\r\n"
+ " ]\r\n"
+ " },\r\n"
+ " {\r\n"
+ " \"oneOf\": [\r\n"
+ " false,\r\n"
+ " true\r\n"
+ " ]\r\n"
+ " }\r\n"
+ " ]\r\n"
+ "}";
JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData);
Set<ValidationMessage> messages = schema.validate("{}", InputFormat.JSON);
Assertions.assertTrue(messages.isEmpty());
}
@Test
void allOfOneOfAnyOfFalse() {
String schemaData = "{\r\n"
+ " \"allOf\": [\r\n"
+ " {\r\n"
+ " \"oneOf\": [\r\n"
+ " false,\r\n"
+ " false\r\n"
+ " ]\r\n"
+ " },\r\n"
+ " {\r\n"
+ " \"anyOf\": [\r\n"
+ " false,\r\n"
+ " false\r\n"
+ " ]\r\n"
+ " }\r\n"
+ " ]\r\n"
+ "}";
JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData);
Set<ValidationMessage> messages = schema.validate("{}", InputFormat.JSON);
Assertions.assertFalse(messages.isEmpty());
}
@Test
void allOfOneOfAnyOfTrue() {
String schemaData = "{\r\n"
+ " \"allOf\": [\r\n"
+ " {\r\n"
+ " \"oneOf\": [\r\n"
+ " false,\r\n"
+ " true\r\n"
+ " ]\r\n"
+ " },\r\n"
+ " {\r\n"
+ " \"anyOf\": [\r\n"
+ " false,\r\n"
+ " true\r\n"
+ " ]\r\n"
+ " }\r\n"
+ " ]\r\n"
+ "}";
JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData);
Set<ValidationMessage> messages = schema.validate("{}", InputFormat.JSON);
Assertions.assertTrue(messages.isEmpty());
}
@Test
void oneOfAllOfAnyOfFalse() {
String schemaData = "{\r\n"
+ " \"oneOf\": [\r\n"
+ " {\r\n"
+ " \"allOf\": [\r\n"
+ " false,\r\n"
+ " true\r\n"
+ " ]\r\n"
+ " },\r\n"
+ " {\r\n"
+ " \"anyOf\": [\r\n"
+ " false,\r\n"
+ " false\r\n"
+ " ]\r\n"
+ " }\r\n"
+ " ]\r\n"
+ "}";
JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData);
Set<ValidationMessage> messages = schema.validate("{}", InputFormat.JSON);
Assertions.assertFalse(messages.isEmpty());
}
@Test
void oneOfAllOfAnyOfTrue() {
String schemaData = "{\r\n"
+ " \"oneOf\": [\r\n"
+ " {\r\n"
+ " \"allOf\": [\r\n"
+ " false,\r\n"
+ " true\r\n"
+ " ]\r\n"
+ " },\r\n"
+ " {\r\n"
+ " \"anyOf\": [\r\n"
+ " false,\r\n"
+ " true\r\n"
+ " ]\r\n"
+ " }\r\n"
+ " ]\r\n"
+ "}";
JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData);
Set<ValidationMessage> messages = schema.validate("{}", InputFormat.JSON);
Assertions.assertTrue(messages.isEmpty());
}
} |
Given your test examples I don't see the issue. It looks like your issue is because you are placing Take the following for instance Example1:
anyOf:
- type: object
- $ref: '#/components/schemas/SampleData1'
- $ref: '#/components/schemas/SampleData2'
description: ""
type: object Because you placed |
@justin-tay I am working on the test data now, so please wait a moment. |
@justin-tay If the element names in the json are the same
test data
- case2 : The first and second child elements are null, but there is no error (should be an error)
※If ↓, an error occurs at AnyOf.
- case3 : The first and second child elements are null, but there is no error (should be an error)
If the Json element names are all disjoint
test data
Item names are identical within anyOf
test data
|
I had a look but I don't see any issue with the behavior. If there truly is an issue with The Duplicate keys in JSON isn't recommended by the JSON spec and the general behavior is that the last key is taken and the earlier keys are ignored. This really doesn't have anything to do with this implementation or JSON Schema but with JSON itself. If you for example type the following in your browser's javascript console
you will get the following result
|
@justin-tay I am currently working on identifying any applicable cases. Thank you very much for your polite and detailed response. |
@justin-tay {
"age": 23,
"user": {
"id": 123,
}
} {
"age": 23,
"user": {
"name": "john",
}
} The JSON schema is as follows. {
"allOf": [
{
"type": "object",
"properties": {
"user": {
"required": true,
"oneOf": [
{
"type": "object",
"properties": {
"id": {
"type": "number",
"required": true
}
}
},
{
"type": "object",
"properties": {
"name": {
"type": "string",
"required": true
}
}
}
]
}
}
},
{
"type": "object",
"properties": {
"age": {
"type": "number",
"required": true
}
}
}
]
} The following is the test code. Some lines starting with package com.networknt.schema;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import com.networknt.schema.SpecVersion.VersionFlag;
/**
* Tests for nested applicators.
*/
public class NestedApplicatorTest {
@Test
void NestedAllOfOneOf() {
String schemaData = "{\r\n"
+ " \"allOf\": [\r\n"
+ " {\r\n"
+ " \"type\": \"object\",\r\n"
+ " \"properties\": {\r\n"
+ " \"user\": {\r\n"
+ " \"required\": true,\r\n"
+ " \"oneOf\": [\r\n"
+ " {\r\n"
+ " \"type\": \"object\",\r\n"
+ " \"properties\": {\r\n"
+ " \"id\": {\r\n"
+ " \"type\": \"number\",\r\n"
+ " \"required\": true\r\n"
+ " }\r\n"
+ " }\r\n"
+ " },\r\n"
+ " {\r\n"
+ " \"type\": \"object\",\r\n"
+ " \"properties\": {\r\n"
+ " \"name\": {\r\n"
+ " \"type\": \"string\",\r\n"
+ " \"required\": true\r\n"
+ " }\r\n"
+ " }\r\n"
+ " }\r\n"
+ " ]\r\n"
+ " }\r\n"
+ " }\r\n"
+ " },\r\n"
+ " {\r\n"
+ " \"type\": \"object\",\r\n"
+ " \"properties\": {\r\n"
+ " \"age\": {\r\n"
+ " \"type\": \"number\",\r\n"
+ " \"required\": true\r\n"
+ " }\r\n"
+ " }\r\n"
+ " }\r\n"
+ " ]\r\n"
+ "}";
JsonSchema schema = JsonSchemaFactory.getInstance(VersionFlag.V202012).getSchema(schemaData);
/* Following two patterns should be valid, but the tests fail */
//Assertions.assertTrue(schema.validate("{\"age\":23,\"user\":{\"id\":123}}", InputFormat.JSON).isEmpty());
//Assertions.assertTrue(schema.validate("{\"age\":23,\"user\":{\"name\":\"john\"}}", InputFormat.JSON).isEmpty());
/* Empty object should be invalid because of the allOf, but the test fails */
//Assertions.assertFalse(schema.validate("{}", InputFormat.JSON).isEmpty());
/* Following six patterns should be invalid (either age or user object is missing), but some tests fail */
Assertions.assertFalse(schema.validate("{\"age\":\"old\"}", InputFormat.JSON).isEmpty());
Assertions.assertFalse(schema.validate("{\"user\":{\"id\":123}}", InputFormat.JSON).isEmpty());
Assertions.assertFalse(schema.validate("{\"user\":{\"name\":\"john\"}}", InputFormat.JSON).isEmpty());
//Assertions.assertFalse(schema.validate("{\"age\":23}", InputFormat.JSON).isEmpty());
//Assertions.assertFalse(schema.validate("{\"user\":{\"id\":\"abc\"}}", InputFormat.JSON).isEmpty());
//Assertions.assertFalse(schema.validate("{\"user\":{\"name\":123}}", InputFormat.JSON).isEmpty());
/* Following two patterns should be invalid (either id or name is invalid format), but the tests fail */
//Assertions.assertFalse(schema.validate("{\"age\":23,\"user\":{\"id\":\"abc\"}}", InputFormat.JSON).isEmpty());
//Assertions.assertFalse(schema.validate("{\"age\":23,\"user\":{\"name\":123}}", InputFormat.JSON).isEmpty());
/* Following four patterns should be invalid (age must be a number), and the tests pass as expected */
Assertions.assertFalse(schema.validate("{\"age\":\"old\",\"user\":{\"id\":123}}", InputFormat.JSON).isEmpty());
Assertions.assertFalse(schema.validate("{\"age\":\"old\",\"user\":{\"id\":\"abc\"}}", InputFormat.JSON).isEmpty());
Assertions.assertFalse(schema.validate("{\"age\":\"old\",\"user\":{\"name\":\"john\"}}", InputFormat.JSON).isEmpty());
Assertions.assertFalse(schema.validate("{\"age\":\"old\",\"user\":{\"name\":123}}", InputFormat.JSON).isEmpty());
}
} Is the test code above seems reasonable? I'm not so familier with neither Java nor JSON Schema, but I hope the example helps our understanding or potential issues if any. |
The JSON Schema doesn't describe what you are expecting. The {
"type": "object",
"properties": {
"age": {
"type": "number"
},
"user": {
"type": "object",
"oneOf": [
{
"properties": {
"name": {
"type": "string"
}
},
"required": [
"name"
],
"additionalProperties": false
},
{
"properties": {
"id": {
"type": "number"
}
},
"required": [
"id"
],
"additionalProperties": false
}
]
}
},
"required": [
"age",
"user"
]
} |
@justin-tay I think the cause was our lack of understanding of Json and Json-schema. Thanks to your excellent support, our team was able to properly understand the documentation. Thank you very much. |
@justin-tay |
Make the Json-schema-validator program capable of handling nested OneOf and AllOf constructs.
NG Case
The text was updated successfully, but these errors were encountered: