From b8a0c3991bdbe105d8fcc7458fc7b87bceff817d Mon Sep 17 00:00:00 2001
From: Francis Galiegue
Date: Wed, 29 Oct 2014 12:13:10 +0100
Subject: [PATCH 01/71] Update -core dependency
---
build.gradle | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/build.gradle b/build.gradle
index fbc13551a..f9b5bd228 100644
--- a/build.gradle
+++ b/build.gradle
@@ -44,7 +44,7 @@ apply(plugin: "idea");
apply(plugin: "eclipse");
group = "com.github.fge";
-version = "2.2.5-SNAPSHOT";
+version = "2.2.6-SNAPSHOT";
sourceCompatibility = "1.6";
targetCompatibility = "1.6"; // defaults to sourceCompatibility
@@ -64,7 +64,7 @@ repositories {
*/
dependencies {
compile(group: "com.github.fge", name: "json-schema-core",
- version: "1.2.4");
+ version: "1.2.5");
compile(group: "javax.mail", name: "mailapi", version: "1.4.3");
compile(group: "joda-time", name: "joda-time", version: "2.3");
compile(group: "com.googlecode.libphonenumber", name: "libphonenumber",
From 698385765781856f86e63adec96920e71915922d Mon Sep 17 00:00:00 2001
From: Francis Galiegue
Date: Wed, 29 Oct 2014 14:20:21 +0100
Subject: [PATCH 02/71] Fill release notes
Signed-off-by: Francis Galiegue
---
RELEASE-NOTES.md | 38 +++++++++++++++++++++++++++++++++++++-
1 file changed, 37 insertions(+), 1 deletion(-)
diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md
index 33328c35c..35a219faa 100644
--- a/RELEASE-NOTES.md
+++ b/RELEASE-NOTES.md
@@ -1 +1,37 @@
-### RESET
+### 2.2.6
+
+* Fix issue #112: fix circular validation detection; use a "validation stack" to
+ detect and spot those situations.
+* Depend on -core 1.2.5.
+* Update dependencies for libphonenumber, jsr305.
+
+### 2.2.5
+
+* Fix issue #102: detect, and fail on, circular validation.
+* Simplify ValidationProcessor.
+* Remove one-jar generation; the -lib jar now includes Main-Class.
+
+### 2.2.4
+
+* Add a "lib" target to the build.
+* Issue #99: append syntax errors when throwing an InvalidSchemaException.
+* Issue #100: attempt to load resources from the context classloader if loading
+ from JsonLoader.class fails.
+
+### 2.2.3
+
+* Re-release... 2.2.2 was compiled with JDK 8 :/
+
+### 2.2.2
+
+* Depend on -core 1.2.1 to work around Rhino bug with other packages sealing the
+ context.
+
+### 2.2.1
+
+* Main now uses current working directory as default URI namespace.
+
+### 2.2.0
+
+* New major release.
+
From 5a437893f5e7d65836d048f66d74213f3d3f6310 Mon Sep 17 00:00:00 2001
From: Francis Galiegue
Date: Wed, 29 Oct 2014 14:29:30 +0100
Subject: [PATCH 03/71] 2.2.6
Signed-off-by: Francis Galiegue
---
build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/build.gradle b/build.gradle
index f9b5bd228..6aebc88d6 100644
--- a/build.gradle
+++ b/build.gradle
@@ -44,7 +44,7 @@ apply(plugin: "idea");
apply(plugin: "eclipse");
group = "com.github.fge";
-version = "2.2.6-SNAPSHOT";
+version = "2.2.6";
sourceCompatibility = "1.6";
targetCompatibility = "1.6"; // defaults to sourceCompatibility
From eed998bad029c0d6025e0ac3f750e2a1a564a9c3 Mon Sep 17 00:00:00 2001
From: Francis Galiegue
Date: Wed, 29 Oct 2014 15:15:41 +0100
Subject: [PATCH 04/71] Announce 2.2.6
Signed-off-by: Francis Galiegue
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index f2e5e6ae6..f59b24370 100644
--- a/README.md
+++ b/README.md
@@ -33,7 +33,7 @@ run by yourself.
## Versions
-* current stable version: **2.2.5**
+* current stable version: **2.2.6**
([ChangeLog](https://github.com/fge/json-schema-validator/wiki/ChangeLog_22x),
[Javadoc](http://fge.github.io/json-schema-validator/2.2.x/index.html), [code
samples](http://fge.github.io/json-schema-validator/2.2.x/index.html?com/github/fge/jsonschema/examples/package-summary.html)).
From fd781ef26318ce4b7bde294307dd32d6c2e8da03 Mon Sep 17 00:00:00 2001
From: Francis Galiegue
Date: Wed, 11 Mar 2015 12:50:30 +0100
Subject: [PATCH 05/71] Update README with the research for a new maintainer
Signed-off-by: Francis Galiegue
---
README.md | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/README.md b/README.md
index f59b24370..6ce978e2c 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,13 @@
+# This project is looking for a new maintainer
+
+I don't have the time, nor incentive anymore, to maintain this project.
+
+I am fully aware that there are now quite a few people/entities which use this project, as such I am
+looking fow a new maintainer, whether that be an individual or an entity, willing to take over.
+
+Please [contact me personally](mailto:fgaliegue@gmail.com) if you are interested. Ideally, you
+should be equally committed to this project **and** JSON Schema as a whole.
+
## Read me first
The **current** version of this project is licensed under both LGPLv3 (or later) and ASL 2.0. The old version
From 2a7a51229f08940116bdc3e22803ec0c7f6fd73f Mon Sep 17 00:00:00 2001
From: Dave Clayton
Date: Thu, 7 Jul 2016 23:25:28 +0100
Subject: [PATCH 06/71] Add configuration for testing travis
---
.travis.yml | 1 +
1 file changed, 1 insertion(+)
create mode 100644 .travis.yml
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 000000000..f5c99a7f6
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1 @@
+language: java
\ No newline at end of file
From d4c07af2bb77079c560358a29b099c1dc2579759 Mon Sep 17 00:00:00 2001
From: Dave Clayton
Date: Thu, 7 Jul 2016 23:30:39 +0100
Subject: [PATCH 07/71] Update to reflect new project maintainer
---
README.md | 10 ----------
1 file changed, 10 deletions(-)
diff --git a/README.md b/README.md
index 6ce978e2c..f59b24370 100644
--- a/README.md
+++ b/README.md
@@ -1,13 +1,3 @@
-# This project is looking for a new maintainer
-
-I don't have the time, nor incentive anymore, to maintain this project.
-
-I am fully aware that there are now quite a few people/entities which use this project, as such I am
-looking fow a new maintainer, whether that be an individual or an entity, willing to take over.
-
-Please [contact me personally](mailto:fgaliegue@gmail.com) if you are interested. Ideally, you
-should be equally committed to this project **and** JSON Schema as a whole.
-
## Read me first
The **current** version of this project is licensed under both LGPLv3 (or later) and ASL 2.0. The old version
From 73e658d12ae660304206f8e951c9e01e1a144f11 Mon Sep 17 00:00:00 2001
From: Dave Clayton
Date: Thu, 7 Jul 2016 23:45:03 +0100
Subject: [PATCH 08/71] Update documentation to link to Travis builds
---
README.md | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/README.md b/README.md
index f59b24370..98fb6f9e0 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,9 @@
+## Travis builds now enabled
+
+Builds are now verified by Travis (see [issue #20](https://github.com/daveclayton/json-patch/issues/20) from the json-patch project for details)
+
+https://travis-ci.org/daveclayton/json-schema-validator
+
## Read me first
The **current** version of this project is licensed under both LGPLv3 (or later) and ASL 2.0. The old version
From 62704bc173870e2aa1e4dafe0e81c3f807c7bd5d Mon Sep 17 00:00:00 2001
From: Phillip Wirth
Date: Wed, 10 Aug 2016 21:34:25 +0200
Subject: [PATCH 09/71] fixes gh-80, broken links
---
README.md | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/README.md b/README.md
index 98fb6f9e0..ce673cd5e 100644
--- a/README.md
+++ b/README.md
@@ -9,9 +9,9 @@ https://travis-ci.org/daveclayton/json-schema-validator
The **current** version of this project is licensed under both LGPLv3 (or later) and ASL 2.0. The old version
(2.0.x) was licensed under LGPL 3.0 (or later) only.
-**Version 2.2 is out**. See [here](https://github.com/fge/json-schema-validator/wiki/Whatsnew_22)
+**Version 2.2 is out**. See [here](https://github.com/daveclayton/json-schema-validator/wiki/Whatsnew_22)
for the list of changes compared to 2.0. And of course, it still has [all the
-features](https://github.com/fge/json-schema-validator/wiki/Features) of older versions.
+features](https://github.com/daveclayton/json-schema-validator/wiki/Features) of older versions.
## What this is
@@ -34,19 +34,19 @@ timely manner.
## Testing online
You can [test this library online](http://json-schema-validator.herokuapp.com); this web site is in
-a [project of its own](https://github.com/fge/json-schema-validator-demo), which you can fork and
+a [project of its own](https://github.com/daveclayton/json-schema-validator-demo), which you can fork and
run by yourself.
## Versions
* current stable version: **2.2.6**
- ([ChangeLog](https://github.com/fge/json-schema-validator/wiki/ChangeLog_22x),
- [Javadoc](http://fge.github.io/json-schema-validator/2.2.x/index.html), [code
- samples](http://fge.github.io/json-schema-validator/2.2.x/index.html?com/github/fge/jsonschema/examples/package-summary.html)).
+ ([ChangeLog](https://github.com/daveclayton/json-schema-validator/wiki/ChangeLog_22x),
+ [Javadoc](http://daveclayton.github.io/json-schema-validator/2.2.x/index.html), [code
+ samples](http://daveclayton.github.io/json-schema-validator/2.2.x/index.html?com/github/fge/jsonschema/examples/package-summary.html)).
* old stable version: **2.0.4**
- ([ChangeLog](https://github.com/fge/json-schema-validator/wiki/ChangeLog_20x),
- [Javadoc](http://fge.github.io/json-schema-validator/2.0.x/index.html), [code
- samples](http://fge.github.io/json-schema-validator/2.0.x/index.html?com/github/fge/jsonschema/examples/package-summary.html)).
+ ([ChangeLog](https://github.com/daveclayton/json-schema-validator/wiki/ChangeLog_20x),
+ [Javadoc](http://daveclayton.github.io/json-schema-validator/2.0.x/index.html), [code
+ samples](http://daveclayton.github.io/json-schema-validator/2.0.x/index.html?com/github/fge/jsonschema/examples/package-summary.html)).
## Available downloads
@@ -100,8 +100,8 @@ This implementation is based on the following drafts:
## More...
For a detailed discussion of the implementation, see
-[here](https://github.com/fge/json-schema-validator/wiki/Status).
+[here](https://github.com/daveclayton/json-schema-validator/wiki/Status).
-Please see the [wiki](https://github.com/fge/json-schema-validator/wiki/) for more
+Please see the [wiki](https://github.com/daveclayton/json-schema-validator/wiki/) for more
details.
From a679f30d545906a8ff152bf0f2e25160a701b3f5 Mon Sep 17 00:00:00 2001
From: Andreas Gebhardt
Date: Mon, 26 Dec 2016 18:41:23 +0100
Subject: [PATCH 10/71] add Travis badge
---
README.md | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/README.md b/README.md
index ce673cd5e..9978c15bd 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,5 @@
+[![Build Status][Travis badge]][Travis]
+
## Travis builds now enabled
Builds are now verified by Travis (see [issue #20](https://github.com/daveclayton/json-patch/issues/20) from the json-patch project for details)
@@ -105,3 +107,5 @@ For a detailed discussion of the implementation, see
Please see the [wiki](https://github.com/daveclayton/json-schema-validator/wiki/) for more
details.
+[Travis Badge]: https://api.travis-ci.org/daveclayton/json-schema-validator.svg?branch=master
+[Travis]: https://travis-ci.org/daveclayton/json-schema-validator
From c2379dcfdf743d3ccba8bf54f9168ee2c296951f Mon Sep 17 00:00:00 2001
From: Andreas Gebhardt
Date: Mon, 26 Dec 2016 19:31:15 +0100
Subject: [PATCH 11/71] update (compile time) dependencies
* com.google.code.findbugs:jsr305 :: 3.0.0 -> 3.0.1
* com.googlecode.libphonenumber:libphonenumber :: 6.2 -> 8.0.0
* joda-time:joda-time :: 2.3 -> 2.9.7
* net.sf.jopt-simple:jopt-simple :: 4.6 -> 5.0.3
---
build.gradle | 13 +++++--------
1 file changed, 5 insertions(+), 8 deletions(-)
diff --git a/build.gradle b/build.gradle
index 6aebc88d6..6f4c2797d 100644
--- a/build.gradle
+++ b/build.gradle
@@ -63,15 +63,12 @@ repositories {
* List of dependencies
*/
dependencies {
- compile(group: "com.github.fge", name: "json-schema-core",
- version: "1.2.5");
+ compile(group: "com.github.fge", name: "json-schema-core", version: "1.2.5");
compile(group: "javax.mail", name: "mailapi", version: "1.4.3");
- compile(group: "joda-time", name: "joda-time", version: "2.3");
- compile(group: "com.googlecode.libphonenumber", name: "libphonenumber",
- version: "6.2");
- compile(group: "com.google.code.findbugs", name: "jsr305",
- version: "3.0.0");
- compile(group: "net.sf.jopt-simple", name: "jopt-simple", version: "4.6");
+ compile(group: "joda-time", name: "joda-time", version: "2.9.7");
+ compile(group: "com.googlecode.libphonenumber", name: "libphonenumber", version: "8.0.0");
+ compile(group: "com.google.code.findbugs", name: "jsr305", version: "3.0.1");
+ compile(group: "net.sf.jopt-simple", name: "jopt-simple", version: "5.0.3");
testCompile(group: "org.testng", name: "testng", version: "6.8.7") {
exclude(group: "junit", module: "junit");
exclude(group: "org.beanshell", module: "bsh");
From f8fb1d63a4033bf03bbaefebad71d5f9794e3f4b Mon Sep 17 00:00:00 2001
From: Andreas Gebhardt
Date: Mon, 26 Dec 2016 19:35:07 +0100
Subject: [PATCH 12/71] update test dependencies
* org.mockito:mockito-core :: 1.9.5 -> 2.4.2
* org.testng:testng :: 6.8.7 -> 6.10
---
build.gradle | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/build.gradle b/build.gradle
index 6f4c2797d..cb84aa119 100644
--- a/build.gradle
+++ b/build.gradle
@@ -69,12 +69,12 @@ dependencies {
compile(group: "com.googlecode.libphonenumber", name: "libphonenumber", version: "8.0.0");
compile(group: "com.google.code.findbugs", name: "jsr305", version: "3.0.1");
compile(group: "net.sf.jopt-simple", name: "jopt-simple", version: "5.0.3");
- testCompile(group: "org.testng", name: "testng", version: "6.8.7") {
+ testCompile(group: "org.testng", name: "testng", version: "6.10") {
exclude(group: "junit", module: "junit");
exclude(group: "org.beanshell", module: "bsh");
exclude(group: "org.yaml", module: "snakeyaml");
};
- testCompile(group: "org.mockito", name: "mockito-core", version: "1.9.5");
+ testCompile(group: "org.mockito", name: "mockito-core", version: "2.4.2");
testCompile(group: "org.easytesting", name: "fest-assert", version: "1.4");
}
From ab7b86f612ae5939308c9473cc4c31c4d1d3a733 Mon Sep 17 00:00:00 2001
From: Andreas Gebhardt
Date: Mon, 26 Dec 2016 18:51:52 +0100
Subject: [PATCH 13/71] add badges for LGPLv3 and ASL 2.0
---
README.md | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 9978c15bd..4d252c34d 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,5 @@
+[![License LGPLv3][LGPLv3 badge]][LGPLv3]
+[![License ASL 2.0][ASL 2.0 badge]][ASL 2.0]
[![Build Status][Travis badge]][Travis]
## Travis builds now enabled
@@ -8,8 +10,8 @@ https://travis-ci.org/daveclayton/json-schema-validator
## Read me first
-The **current** version of this project is licensed under both LGPLv3 (or later) and ASL 2.0. The old version
-(2.0.x) was licensed under LGPL 3.0 (or later) only.
+The **current** version of this project is licensed under both [LGPLv3] (or later) and [ASL 2.0]. The old version
+(2.0.x) was licensed under [LGPL 3.0][LGPLv3] (or later) only.
**Version 2.2 is out**. See [here](https://github.com/daveclayton/json-schema-validator/wiki/Whatsnew_22)
for the list of changes compared to 2.0. And of course, it still has [all the
@@ -107,5 +109,9 @@ For a detailed discussion of the implementation, see
Please see the [wiki](https://github.com/daveclayton/json-schema-validator/wiki/) for more
details.
+[LGPLv3 badge]: https://img.shields.io/:license-LGPLv3-blue.svg
+[LGPLv3]: http://www.gnu.org/licenses/lgpl-3.0.html
+[ASL 2.0 badge]: https://img.shields.io/:license-Apache%202.0-blue.svg
+[ASL 2.0]: http://www.apache.org/licenses/LICENSE-2.0.html
[Travis Badge]: https://api.travis-ci.org/daveclayton/json-schema-validator.svg?branch=master
[Travis]: https://travis-ci.org/daveclayton/json-schema-validator
From 672defcaf02facc376bf77edf13edc0e3a1da513 Mon Sep 17 00:00:00 2001
From: Andreas Gebhardt
Date: Mon, 26 Dec 2016 19:05:52 +0100
Subject: [PATCH 14/71] add badge for latest version on Maven Central
---
README.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/README.md b/README.md
index 4d252c34d..e7f7a7c93 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,7 @@
[![License LGPLv3][LGPLv3 badge]][LGPLv3]
[![License ASL 2.0][ASL 2.0 badge]][ASL 2.0]
[![Build Status][Travis badge]][Travis]
+
## Travis builds now enabled
From b25b083583bbc002e3d6314947222d849df233cc Mon Sep 17 00:00:00 2001
From: zhangzhe
Date: Tue, 21 Feb 2017 12:16:59 +0800
Subject: [PATCH 15/71] Modified annotation.
---
src/main/java/com/github/fge/jsonschema/main/JsonSchema.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/com/github/fge/jsonschema/main/JsonSchema.java b/src/main/java/com/github/fge/jsonschema/main/JsonSchema.java
index 2ec548ae0..f13e50d6a 100644
--- a/src/main/java/com/github/fge/jsonschema/main/JsonSchema.java
+++ b/src/main/java/com/github/fge/jsonschema/main/JsonSchema.java
@@ -113,7 +113,7 @@ public ProcessingReport validate(final JsonNode instance,
* Validate an instance and return a processing report
*
* This calls {@link #validate(JsonNode, boolean)} with {@code false} as
- * a third argument.
+ * a second argument.
*
* @param instance the instance to validate
* @return a processing report
From 41f22fbbf94639230305346db93526f3bbb04c76 Mon Sep 17 00:00:00 2001
From: Archimedes Trajano
Date: Fri, 28 Aug 2015 13:42:22 -0400
Subject: [PATCH 16/71] Changed JsonSchema to an interface
Fixes https://github.com/fge/json-schema-validator/issues/159
---
.../fge/jsonschema/main/JsonSchema.java | 98 ++----------
.../jsonschema/main/JsonSchemaFactory.java | 2 +-
.../fge/jsonschema/main/JsonSchemaImpl.java | 150 ++++++++++++++++++
.../fge/jsonschema/main/JsonValidator.java | 4 +-
.../validation/InstanceValidator.java | 1 -
.../examples/doc-files/Example9.java | 1 +
6 files changed, 166 insertions(+), 90 deletions(-)
create mode 100644 src/main/java/com/github/fge/jsonschema/main/JsonSchemaImpl.java
diff --git a/src/main/java/com/github/fge/jsonschema/main/JsonSchema.java b/src/main/java/com/github/fge/jsonschema/main/JsonSchema.java
index 2ec548ae0..639a24713 100644
--- a/src/main/java/com/github/fge/jsonschema/main/JsonSchema.java
+++ b/src/main/java/com/github/fge/jsonschema/main/JsonSchema.java
@@ -26,69 +26,15 @@
import com.github.fge.jsonschema.core.report.ListProcessingReport;
import com.github.fge.jsonschema.core.report.MessageProvider;
import com.github.fge.jsonschema.core.report.ProcessingReport;
-import com.github.fge.jsonschema.core.report.ReportProvider;
-import com.github.fge.jsonschema.core.tree.SchemaTree;
-import com.github.fge.jsonschema.core.tree.SimpleJsonTree;
-import com.github.fge.jsonschema.processors.data.FullData;
-import com.github.fge.jsonschema.processors.validation.ValidationProcessor;
-
-import javax.annotation.concurrent.Immutable;
/**
* Single-schema instance validator
*
- * This is the class you will use the most often. It is, in essence, a {@link
+ *
This is the interface you will use the most often. It is, in essence, a {@link
* JsonValidator} initialized with a single JSON Schema. Note however that this
* class still retains the ability to resolve JSON References.
- *
- * It has no public constructors: you should use the appropriate methods in
- * {@link JsonSchemaFactory} to obtain an instance of this class.
*/
-@Immutable
-public final class JsonSchema
-{
- private final ValidationProcessor processor;
- private final SchemaTree schema;
- private final ReportProvider reportProvider;
-
- /**
- * Package private constructor
- *
- * @param processor the validation processor
- * @param schema the schema to bind to this instance
- * @param reportProvider the report provider
- */
- JsonSchema(final ValidationProcessor processor, final SchemaTree schema,
- final ReportProvider reportProvider)
- {
- this.processor = processor;
- this.schema = schema;
- this.reportProvider = reportProvider;
- }
-
- private ProcessingReport doValidate(final JsonNode node,
- final boolean deepCheck)
- throws ProcessingException
- {
- final FullData data = new FullData(schema, new SimpleJsonTree(node),
- deepCheck);
- final ProcessingReport report = reportProvider.newReport();
- final ProcessingResult result
- = ProcessingResult.of(processor, report, data);
- return result.getReport();
- }
-
- private ProcessingReport doValidateUnchecked(final JsonNode node,
- final boolean deepCheck)
- {
- final FullData data = new FullData(schema, new SimpleJsonTree(node),
- deepCheck);
- final ProcessingReport report = reportProvider.newReport();
- final ProcessingResult result
- = ProcessingResult.uncheckedResult(processor, report, data);
- return result.getReport();
- }
-
+public interface JsonSchema {
/**
* Validate an instance and return a processing report
*
@@ -102,12 +48,8 @@ private ProcessingReport doValidateUnchecked(final JsonNode node,
*
* @since 2.1.8
*/
- public ProcessingReport validate(final JsonNode instance,
- final boolean deepCheck)
- throws ProcessingException
- {
- return doValidate(instance, deepCheck);
- }
+ ProcessingReport validate(JsonNode instance, boolean deepCheck)
+ throws ProcessingException;
/**
* Validate an instance and return a processing report
@@ -119,11 +61,8 @@ public ProcessingReport validate(final JsonNode instance,
* @return a processing report
* @throws ProcessingException a processing error occurred during validation
*/
- public ProcessingReport validate(final JsonNode instance)
- throws ProcessingException
- {
- return validate(instance, false);
- }
+ ProcessingReport validate(JsonNode instance)
+ throws ProcessingException;
/**
* Validate an instance and return a processing report (unchecked version)
@@ -148,12 +87,8 @@ public ProcessingReport validate(final JsonNode instance)
*
* @since 2.1.8
*/
- public ProcessingReport validateUnchecked(final JsonNode instance,
- final boolean deepCheck)
- {
- return doValidateUnchecked(instance, deepCheck);
- }
-
+ ProcessingReport validateUnchecked(JsonNode instance,
+ boolean deepCheck);
/**
* Validate an instance and return a processing report (unchecked version)
*
@@ -164,10 +99,7 @@ public ProcessingReport validateUnchecked(final JsonNode instance,
* @return a report (a {@link ListProcessingReport} if an exception was
* thrown during processing)
*/
- public ProcessingReport validateUnchecked(final JsonNode instance)
- {
- return doValidateUnchecked(instance, false);
- }
+ ProcessingReport validateUnchecked(JsonNode instance);
/**
* Check whether an instance is valid against this schema
@@ -176,11 +108,8 @@ public ProcessingReport validateUnchecked(final JsonNode instance)
* @return true if the instance is valid
* @throws ProcessingException an error occurred during processing
*/
- public boolean validInstance(final JsonNode instance)
- throws ProcessingException
- {
- return doValidate(instance, false).isSuccess();
- }
+ boolean validInstance(JsonNode instance)
+ throws ProcessingException;
/**
* Check whether an instance is valid against this schema (unchecked
@@ -192,8 +121,5 @@ public boolean validInstance(final JsonNode instance)
* @param instance the instance to validate
* @return true if the instance is valid
*/
- public boolean validInstanceUnchecked(final JsonNode instance)
- {
- return doValidateUnchecked(instance, false).isSuccess();
- }
+ boolean validInstanceUnchecked(JsonNode instance);
}
diff --git a/src/main/java/com/github/fge/jsonschema/main/JsonSchemaFactory.java b/src/main/java/com/github/fge/jsonschema/main/JsonSchemaFactory.java
index bfaca5fe0..4977e4968 100644
--- a/src/main/java/com/github/fge/jsonschema/main/JsonSchemaFactory.java
+++ b/src/main/java/com/github/fge/jsonschema/main/JsonSchemaFactory.java
@@ -60,7 +60,7 @@
* a {@link SyntaxValidator}, to validate schemas;
* a {@link JsonValidator}, to validate an instance against a schema;
*
- * a {@link JsonSchema}, to validate instances against a fixed schema.
+ * a {@link JsonSchemaImpl}, to validate instances against a fixed schema.
*
*
*
diff --git a/src/main/java/com/github/fge/jsonschema/main/JsonSchemaImpl.java b/src/main/java/com/github/fge/jsonschema/main/JsonSchemaImpl.java
new file mode 100644
index 000000000..900e24b61
--- /dev/null
+++ b/src/main/java/com/github/fge/jsonschema/main/JsonSchemaImpl.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2014, Francis Galiegue (fgaliegue@gmail.com)
+ *
+ * This software is dual-licensed under:
+ *
+ * - the Lesser General Public License (LGPL) version 3.0 or, at your option, any
+ * later version;
+ * - the Apache Software License (ASL) version 2.0.
+ *
+ * The text of this file and of both licenses is available at the root of this
+ * project or, if you have the jar distribution, in directory META-INF/, under
+ * the names LGPL-3.0.txt and ASL-2.0.txt respectively.
+ *
+ * Direct link to the sources:
+ *
+ * - LGPL 3.0: https://www.gnu.org/licenses/lgpl-3.0.txt
+ * - ASL 2.0: http://www.apache.org/licenses/LICENSE-2.0.txt
+ */
+
+package com.github.fge.jsonschema.main;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.github.fge.jsonschema.core.exceptions.ProcessingException;
+import com.github.fge.jsonschema.core.processing.ProcessingResult;
+import com.github.fge.jsonschema.core.processing.Processor;
+import com.github.fge.jsonschema.core.report.ListProcessingReport;
+import com.github.fge.jsonschema.core.report.MessageProvider;
+import com.github.fge.jsonschema.core.report.ProcessingReport;
+import com.github.fge.jsonschema.core.report.ReportProvider;
+import com.github.fge.jsonschema.core.tree.SchemaTree;
+import com.github.fge.jsonschema.core.tree.SimpleJsonTree;
+import com.github.fge.jsonschema.processors.data.FullData;
+import com.github.fge.jsonschema.processors.validation.ValidationProcessor;
+
+import javax.annotation.concurrent.Immutable;
+
+/**
+ * Single-schema instance validator
+ *
+ * This is the class you will use the most often. It is, in essence, a {@link
+ * JsonValidator} initialized with a single JSON Schema. Note however that this
+ * class still retains the ability to resolve JSON References.
+ *
+ * It has no public constructors: you should use the appropriate methods in
+ * {@link JsonSchemaFactory} to obtain an instance of this class.
+ */
+@Immutable
+final class JsonSchemaImpl implements JsonSchema
+{
+ private final ValidationProcessor processor;
+ private final SchemaTree schema;
+ private final ReportProvider reportProvider;
+
+ /**
+ * Package private constructor
+ *
+ * @param processor the validation processor
+ * @param schema the schema to bind to this instance
+ * @param reportProvider the report provider
+ */
+ JsonSchemaImpl(final ValidationProcessor processor, final SchemaTree schema,
+ final ReportProvider reportProvider)
+ {
+ this.processor = processor;
+ this.schema = schema;
+ this.reportProvider = reportProvider;
+ }
+
+ private ProcessingReport doValidate(final JsonNode node,
+ final boolean deepCheck)
+ throws ProcessingException
+ {
+ final FullData data = new FullData(schema, new SimpleJsonTree(node),
+ deepCheck);
+ final ProcessingReport report = reportProvider.newReport();
+ final ProcessingResult result
+ = ProcessingResult.of(processor, report, data);
+ return result.getReport();
+ }
+
+ private ProcessingReport doValidateUnchecked(final JsonNode node,
+ final boolean deepCheck)
+ {
+ final FullData data = new FullData(schema, new SimpleJsonTree(node),
+ deepCheck);
+ final ProcessingReport report = reportProvider.newReport();
+ final ProcessingResult result
+ = ProcessingResult.uncheckedResult(processor, report, data);
+ return result.getReport();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public ProcessingReport validate(final JsonNode instance,
+ final boolean deepCheck)
+ throws ProcessingException
+ {
+ return doValidate(instance, deepCheck);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public ProcessingReport validate(final JsonNode instance)
+ throws ProcessingException
+ {
+ return validate(instance, false);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public ProcessingReport validateUnchecked(final JsonNode instance,
+ final boolean deepCheck)
+ {
+ return doValidateUnchecked(instance, deepCheck);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public ProcessingReport validateUnchecked(final JsonNode instance)
+ {
+ return doValidateUnchecked(instance, false);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean validInstance(final JsonNode instance)
+ throws ProcessingException
+ {
+ return doValidate(instance, false).isSuccess();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean validInstanceUnchecked(final JsonNode instance)
+ {
+ return doValidateUnchecked(instance, false).isSuccess();
+ }
+}
diff --git a/src/main/java/com/github/fge/jsonschema/main/JsonValidator.java b/src/main/java/com/github/fge/jsonschema/main/JsonValidator.java
index 72b8a31ba..0fa7cc28c 100644
--- a/src/main/java/com/github/fge/jsonschema/main/JsonValidator.java
+++ b/src/main/java/com/github/fge/jsonschema/main/JsonValidator.java
@@ -188,7 +188,7 @@ JsonSchema buildJsonSchema(final JsonNode schema, final JsonPointer pointer)
if (tree.getNode().isMissingNode())
throw new JsonReferenceException(new ProcessingMessage()
.setMessage(BUNDLE.getMessage("danglingRef")));
- return new JsonSchema(processor, tree, reportProvider);
+ return new JsonSchemaImpl(processor, tree, reportProvider);
}
/**
@@ -212,7 +212,7 @@ JsonSchema buildJsonSchema(final String uri)
if (tree.getNode().isMissingNode())
throw new JsonReferenceException(new ProcessingMessage()
.setMessage(BUNDLE.getMessage("danglingRef")));
- return new JsonSchema(processor, tree, reportProvider);
+ return new JsonSchemaImpl(processor, tree, reportProvider);
}
/**
diff --git a/src/main/java/com/github/fge/jsonschema/processors/validation/InstanceValidator.java b/src/main/java/com/github/fge/jsonschema/processors/validation/InstanceValidator.java
index 9267950bb..4b79aa145 100644
--- a/src/main/java/com/github/fge/jsonschema/processors/validation/InstanceValidator.java
+++ b/src/main/java/com/github/fge/jsonschema/processors/validation/InstanceValidator.java
@@ -31,7 +31,6 @@
import com.github.fge.jsonschema.core.tree.JsonTree;
import com.github.fge.jsonschema.core.tree.SchemaTree;
import com.github.fge.jsonschema.keyword.validator.KeywordValidator;
-import com.github.fge.jsonschema.main.JsonSchema;
import com.github.fge.jsonschema.main.JsonValidator;
import com.github.fge.jsonschema.processors.data.FullData;
import com.github.fge.jsonschema.processors.data.SchemaContext;
diff --git a/src/main/javadoc/com/github/fge/jsonschema/examples/doc-files/Example9.java b/src/main/javadoc/com/github/fge/jsonschema/examples/doc-files/Example9.java
index df3714f3d..ce02e0d65 100644
--- a/src/main/javadoc/com/github/fge/jsonschema/examples/doc-files/Example9.java
+++ b/src/main/javadoc/com/github/fge/jsonschema/examples/doc-files/Example9.java
@@ -40,6 +40,7 @@
import com.github.fge.jsonschema.library.Library;
import com.github.fge.jsonschema.library.LibraryBuilder;
import com.github.fge.jsonschema.main.JsonSchema;
+import com.github.fge.jsonschema.main.JsonSchemaImpl;
import com.github.fge.jsonschema.main.JsonSchemaFactory;
import com.github.fge.jsonschema.messages.JsonSchemaValidationBundle;
import com.github.fge.jsonschema.processors.data.FullData;
From 42ab7698dbf23110698c49527c7c7e38d07cb1fd Mon Sep 17 00:00:00 2001
From: Thomas Holmes
Date: Thu, 16 Jul 2015 16:55:37 -0700
Subject: [PATCH 17/71] Switch KeywordValidators to use a factory model
---
.../validator/KeywordValidatorFactory.java | 20 +++++++
.../ReflectionKeywordValidatorFactory.java | 52 +++++++++++++++++++
.../fge/jsonschema/library/Keyword.java | 10 ++--
.../jsonschema/library/KeywordBuilder.java | 39 +++++++-------
.../fge/jsonschema/library/Library.java | 12 ++---
.../jsonschema/library/LibraryBuilder.java | 10 ++--
.../validator/CommonValidatorDictionary.java | 41 +++++++--------
.../validator/DraftV3ValidatorDictionary.java | 31 +++++------
.../validator/DraftV4ValidatorDictionary.java | 39 ++++++--------
.../processors/build/ValidatorBuilder.java | 43 +++++----------
.../keyword/special/ExtendsKeywordTest.java | 34 ++++++------
.../keyword/special/NotKeywordTest.java | 35 +++++++------
.../keyword/special/PatternKeywordTest.java | 39 +++++++-------
.../AbstractKeywordValidatorTest.java | 40 +++++++-------
.../callback/CallbackValidatorTest.java | 40 ++++++++------
.../build/ValidatorBuilderTest.java | 36 +++++++------
16 files changed, 286 insertions(+), 235 deletions(-)
create mode 100755 src/main/java/com/github/fge/jsonschema/keyword/validator/KeywordValidatorFactory.java
create mode 100755 src/main/java/com/github/fge/jsonschema/keyword/validator/ReflectionKeywordValidatorFactory.java
diff --git a/src/main/java/com/github/fge/jsonschema/keyword/validator/KeywordValidatorFactory.java b/src/main/java/com/github/fge/jsonschema/keyword/validator/KeywordValidatorFactory.java
new file mode 100755
index 000000000..db84c642e
--- /dev/null
+++ b/src/main/java/com/github/fge/jsonschema/keyword/validator/KeywordValidatorFactory.java
@@ -0,0 +1,20 @@
+package com.github.fge.jsonschema.keyword.validator;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.github.fge.jsonschema.core.exceptions.ProcessingException;
+
+/**
+ * Interface for a keyword validator factory
+ */
+public interface KeywordValidatorFactory
+{
+ /**
+ * Create a validator for the instance
+ *
+ * @param node the instance to validate
+ * @return a validator for the given instance
+ * @throws ProcessingException an error occurs creating the validator
+ */
+ KeywordValidator getKeywordValidator(JsonNode node)
+ throws ProcessingException;
+}
diff --git a/src/main/java/com/github/fge/jsonschema/keyword/validator/ReflectionKeywordValidatorFactory.java b/src/main/java/com/github/fge/jsonschema/keyword/validator/ReflectionKeywordValidatorFactory.java
new file mode 100755
index 000000000..54e394c1c
--- /dev/null
+++ b/src/main/java/com/github/fge/jsonschema/keyword/validator/ReflectionKeywordValidatorFactory.java
@@ -0,0 +1,52 @@
+package com.github.fge.jsonschema.keyword.validator;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.github.fge.jsonschema.core.exceptions.ProcessingException;
+import com.github.fge.jsonschema.messages.JsonSchemaConfigurationBundle;
+import com.github.fge.msgsimple.bundle.MessageBundle;
+import com.github.fge.msgsimple.load.MessageBundles;
+
+/**
+ * A validator factory that uses reflection to create an instance of the
+ * specified KeywordValidator class
+ */
+public class ReflectionKeywordValidatorFactory
+ implements KeywordValidatorFactory
+{
+ private static final String ERRMSG = "failed to build keyword validator";
+ private static final MessageBundle BUNDLE
+ = MessageBundles.getBundle(JsonSchemaConfigurationBundle.class);
+
+ private final Constructor extends KeywordValidator> constructor;
+
+ public ReflectionKeywordValidatorFactory(String name,
+ Class extends KeywordValidator> clazz)
+ {
+ try {
+ constructor = clazz.getConstructor(JsonNode.class);
+ } catch (NoSuchMethodException ignored) {
+ throw new IllegalArgumentException(BUNDLE.printf(
+ "noAppropriateConstructor", name, clazz.getCanonicalName()
+ ));
+ }
+ }
+
+ @Override
+ public KeywordValidator getKeywordValidator(JsonNode node)
+ throws ProcessingException
+ {
+ try {
+ return constructor.newInstance(node);
+ } catch (InstantiationException e) {
+ throw new ProcessingException(ERRMSG, e);
+ } catch (IllegalAccessException e) {
+ throw new ProcessingException(ERRMSG, e);
+ } catch (InvocationTargetException e) {
+ throw new ProcessingException(ERRMSG, e);
+ }
+ }
+
+}
diff --git a/src/main/java/com/github/fge/jsonschema/library/Keyword.java b/src/main/java/com/github/fge/jsonschema/library/Keyword.java
index b9a6d8ea1..adace7d33 100644
--- a/src/main/java/com/github/fge/jsonschema/library/Keyword.java
+++ b/src/main/java/com/github/fge/jsonschema/library/Keyword.java
@@ -22,9 +22,7 @@
import com.github.fge.Frozen;
import com.github.fge.jsonschema.core.keyword.syntax.checkers.SyntaxChecker;
import com.github.fge.jsonschema.keyword.digest.Digester;
-import com.github.fge.jsonschema.keyword.validator.KeywordValidator;
-
-import java.lang.reflect.Constructor;
+import com.github.fge.jsonschema.keyword.validator.KeywordValidatorFactory;
/**
@@ -51,9 +49,9 @@ public final class Keyword
final Digester digester;
/**
- * {@link KeywordValidator} constructor
+ * Validator factory
*/
- final Constructor extends KeywordValidator> constructor;
+ final KeywordValidatorFactory validatorFactory;
/**
* Instantiate a new keyword builder
@@ -79,7 +77,7 @@ public static KeywordBuilder newBuilder(final String name)
name = builder.name;
syntaxChecker = builder.syntaxChecker;
digester = builder.digester;
- constructor = builder.constructor;
+ validatorFactory = builder.validatorFactory;
}
/**
diff --git a/src/main/java/com/github/fge/jsonschema/library/KeywordBuilder.java b/src/main/java/com/github/fge/jsonschema/library/KeywordBuilder.java
index fd1f9b330..553b1f8a0 100644
--- a/src/main/java/com/github/fge/jsonschema/library/KeywordBuilder.java
+++ b/src/main/java/com/github/fge/jsonschema/library/KeywordBuilder.java
@@ -19,7 +19,6 @@
package com.github.fge.jsonschema.library;
-import com.fasterxml.jackson.databind.JsonNode;
import com.github.fge.Thawed;
import com.github.fge.jackson.NodeType;
import com.github.fge.jsonschema.core.keyword.syntax.checkers.SyntaxChecker;
@@ -27,12 +26,12 @@
import com.github.fge.jsonschema.keyword.digest.helpers.IdentityDigester;
import com.github.fge.jsonschema.keyword.digest.helpers.SimpleDigester;
import com.github.fge.jsonschema.keyword.validator.KeywordValidator;
+import com.github.fge.jsonschema.keyword.validator.KeywordValidatorFactory;
+import com.github.fge.jsonschema.keyword.validator.ReflectionKeywordValidatorFactory;
import com.github.fge.jsonschema.messages.JsonSchemaConfigurationBundle;
import com.github.fge.msgsimple.bundle.MessageBundle;
import com.github.fge.msgsimple.load.MessageBundles;
-import java.lang.reflect.Constructor;
-
/**
* A keyword builder -- the thawed version of a {@link Keyword}
*
@@ -48,7 +47,7 @@ public final class KeywordBuilder
final String name;
SyntaxChecker syntaxChecker;
Digester digester;
- Constructor extends KeywordValidator> constructor;
+ KeywordValidatorFactory validatorFactory;
/**
* Create a new, empty keyword builder
@@ -74,7 +73,7 @@ public final class KeywordBuilder
name = keyword.name;
syntaxChecker = keyword.syntaxChecker;
digester = keyword.digester;
- constructor = keyword.constructor;
+ validatorFactory = keyword.validatorFactory;
}
/**
@@ -149,7 +148,20 @@ public KeywordBuilder withSimpleDigester(final NodeType first,
public KeywordBuilder withValidatorClass(
final Class extends KeywordValidator> c)
{
- constructor = getConstructor(name, c);
+ validatorFactory = new ReflectionKeywordValidatorFactory(name, c);
+ return this;
+ }
+
+ /**
+ * Set the validator factory for this keyword
+ *
+ * @param factory the factory
+ * @return this
+ */
+ public KeywordBuilder withValidatorFactory(
+ KeywordValidatorFactory factory)
+ {
+ validatorFactory = factory;
return this;
}
@@ -169,24 +181,11 @@ public Keyword freeze()
* We can have a keyword without a validator; however, if there is one,
* there must be a digester.
*/
- BUNDLE.checkArgumentPrintf(constructor == null || digester != null,
+ BUNDLE.checkArgumentPrintf(validatorFactory == null || digester != null,
"malformedKeyword", name);
return new Keyword(this);
}
-
- private static Constructor extends KeywordValidator> getConstructor(
- final String name, final Class extends KeywordValidator> c)
- {
- try {
- return c.getConstructor(JsonNode.class);
- } catch (NoSuchMethodException ignored) {
- throw new IllegalArgumentException(BUNDLE.printf(
- "noAppropriateConstructor", name, c.getCanonicalName()
- ));
- }
- }
-
private static NodeType checkType(final NodeType type)
{
return BUNDLE.checkNotNull(type, "nullType");
diff --git a/src/main/java/com/github/fge/jsonschema/library/Library.java b/src/main/java/com/github/fge/jsonschema/library/Library.java
index 74aa566ce..24087f1a6 100644
--- a/src/main/java/com/github/fge/jsonschema/library/Library.java
+++ b/src/main/java/com/github/fge/jsonschema/library/Library.java
@@ -26,9 +26,7 @@
import com.github.fge.jsonschema.core.util.Dictionary;
import com.github.fge.jsonschema.format.FormatAttribute;
import com.github.fge.jsonschema.keyword.digest.Digester;
-import com.github.fge.jsonschema.keyword.validator.KeywordValidator;
-
-import java.lang.reflect.Constructor;
+import com.github.fge.jsonschema.keyword.validator.KeywordValidatorFactory;
/**
* A schema keyword library
@@ -54,9 +52,9 @@ public final class Library
final Dictionary digesters;
/**
- * Dictionary of keyword validator constructors
+ * Dictionary of keyword validator factories
*/
- final Dictionary> validators;
+ final Dictionary validators;
/**
* Dictionary of format attributes
@@ -97,7 +95,7 @@ public static LibraryBuilder newBuilder()
*/
Library(final Dictionary syntaxCheckers,
final Dictionary digesters,
- final Dictionary> validators,
+ final Dictionary validators,
final Dictionary formatAttributes)
{
this.syntaxCheckers = syntaxCheckers;
@@ -131,7 +129,7 @@ public Dictionary getDigesters()
*
* @return a dictionary
*/
- public Dictionary> getValidators()
+ public Dictionary getValidators()
{
return validators;
}
diff --git a/src/main/java/com/github/fge/jsonschema/library/LibraryBuilder.java b/src/main/java/com/github/fge/jsonschema/library/LibraryBuilder.java
index b65f64264..93d2a170a 100644
--- a/src/main/java/com/github/fge/jsonschema/library/LibraryBuilder.java
+++ b/src/main/java/com/github/fge/jsonschema/library/LibraryBuilder.java
@@ -25,13 +25,11 @@
import com.github.fge.jsonschema.core.util.DictionaryBuilder;
import com.github.fge.jsonschema.format.FormatAttribute;
import com.github.fge.jsonschema.keyword.digest.Digester;
-import com.github.fge.jsonschema.keyword.validator.KeywordValidator;
+import com.github.fge.jsonschema.keyword.validator.KeywordValidatorFactory;
import com.github.fge.jsonschema.messages.JsonSchemaConfigurationBundle;
import com.github.fge.msgsimple.bundle.MessageBundle;
import com.github.fge.msgsimple.load.MessageBundles;
-import java.lang.reflect.Constructor;
-
/**
* Mutable version of a library
*
@@ -60,7 +58,7 @@ public final class LibraryBuilder
/**
* Dictionary builder of keyword validator constructors
*/
- final DictionaryBuilder> validators;
+ final DictionaryBuilder validators;
/**
* Dictionary builder of format attributes
@@ -107,9 +105,9 @@ public LibraryBuilder addKeyword(final Keyword keyword)
syntaxCheckers.addEntry(name, keyword.syntaxChecker);
- if (keyword.constructor != null) {
+ if (keyword.validatorFactory != null) {
digesters.addEntry(name, keyword.digester);
- validators.addEntry(name, keyword.constructor);
+ validators.addEntry(name, keyword.validatorFactory);
}
return this;
}
diff --git a/src/main/java/com/github/fge/jsonschema/library/validator/CommonValidatorDictionary.java b/src/main/java/com/github/fge/jsonschema/library/validator/CommonValidatorDictionary.java
index 20ade1257..b96141b72 100644
--- a/src/main/java/com/github/fge/jsonschema/library/validator/CommonValidatorDictionary.java
+++ b/src/main/java/com/github/fge/jsonschema/library/validator/CommonValidatorDictionary.java
@@ -19,10 +19,11 @@
package com.github.fge.jsonschema.library.validator;
-import com.fasterxml.jackson.databind.JsonNode;
import com.github.fge.jsonschema.core.util.Dictionary;
import com.github.fge.jsonschema.core.util.DictionaryBuilder;
import com.github.fge.jsonschema.keyword.validator.KeywordValidator;
+import com.github.fge.jsonschema.keyword.validator.KeywordValidatorFactory;
+import com.github.fge.jsonschema.keyword.validator.ReflectionKeywordValidatorFactory;
import com.github.fge.jsonschema.keyword.validator.common.AdditionalItemsValidator;
import com.github.fge.jsonschema.keyword.validator.common.AdditionalPropertiesValidator;
import com.github.fge.jsonschema.keyword.validator.common.EnumValidator;
@@ -35,27 +36,25 @@
import com.github.fge.jsonschema.keyword.validator.common.PatternValidator;
import com.github.fge.jsonschema.keyword.validator.common.UniqueItemsValidator;
-import java.lang.reflect.Constructor;
-
/**
* Keyword validator constructors common to draft v4 and v3
*/
public final class CommonValidatorDictionary
{
- private static final Dictionary>
+ private static final Dictionary
DICTIONARY;
private CommonValidatorDictionary()
{
}
- public static Dictionary> get()
+ public static Dictionary get()
{
return DICTIONARY;
}
static {
- final DictionaryBuilder>
+ final DictionaryBuilder
builder = Dictionary.newBuilder();
String keyword;
@@ -66,67 +65,63 @@ public static Dictionary> get()
*/
keyword = "additionalItems";
c = AdditionalItemsValidator.class;
- builder.addEntry(keyword, constructor(c));
+ builder.addEntry(keyword, factory(keyword, c));
keyword = "minItems";
c = MinItemsValidator.class;
- builder.addEntry(keyword, constructor(c));
+ builder.addEntry(keyword, factory(keyword, c));
keyword = "maxItems";
c = MaxItemsValidator.class;
- builder.addEntry(keyword, constructor(c));
+ builder.addEntry(keyword, factory(keyword, c));
keyword = "uniqueItems";
c = UniqueItemsValidator.class;
- builder.addEntry(keyword, constructor(c));
+ builder.addEntry(keyword, factory(keyword, c));
/*
* Numbers and integers
*/
keyword = "minimum";
c = MinimumValidator.class;
- builder.addEntry(keyword, constructor(c));
+ builder.addEntry(keyword, factory(keyword, c));
keyword = "maximum";
c = MaximumValidator.class;
- builder.addEntry(keyword, constructor(c));
+ builder.addEntry(keyword, factory(keyword, c));
/*
* Objects
*/
keyword = "additionalProperties";
c = AdditionalPropertiesValidator.class;
- builder.addEntry(keyword, constructor(c));
+ builder.addEntry(keyword, factory(keyword, c));
/*
* Strings
*/
keyword = "minLength";
c = MinLengthValidator.class;
- builder.addEntry(keyword, constructor(c));
+ builder.addEntry(keyword, factory(keyword, c));
keyword = "maxLength";
c = MaxLengthValidator.class;
- builder.addEntry(keyword, constructor(c));
+ builder.addEntry(keyword, factory(keyword, c));
keyword = "pattern";
c = PatternValidator.class;
- builder.addEntry(keyword, constructor(c));
+ builder.addEntry(keyword, factory(keyword, c));
keyword = "enum";
c = EnumValidator.class;
- builder.addEntry(keyword, constructor(c));
+ builder.addEntry(keyword, factory(keyword, c));
DICTIONARY = builder.freeze();
}
- private static Constructor extends KeywordValidator> constructor(
+ private static KeywordValidatorFactory factory(String name,
final Class extends KeywordValidator> c)
{
- try {
- return c.getConstructor(JsonNode.class);
- } catch (NoSuchMethodException e) {
- throw new RuntimeException("No appropriate constructor", e);
- }
+ return new ReflectionKeywordValidatorFactory(name, c);
}
}
diff --git a/src/main/java/com/github/fge/jsonschema/library/validator/DraftV3ValidatorDictionary.java b/src/main/java/com/github/fge/jsonschema/library/validator/DraftV3ValidatorDictionary.java
index a6d648c11..ecf982b1f 100644
--- a/src/main/java/com/github/fge/jsonschema/library/validator/DraftV3ValidatorDictionary.java
+++ b/src/main/java/com/github/fge/jsonschema/library/validator/DraftV3ValidatorDictionary.java
@@ -19,10 +19,11 @@
package com.github.fge.jsonschema.library.validator;
-import com.fasterxml.jackson.databind.JsonNode;
import com.github.fge.jsonschema.core.util.Dictionary;
import com.github.fge.jsonschema.core.util.DictionaryBuilder;
import com.github.fge.jsonschema.keyword.validator.KeywordValidator;
+import com.github.fge.jsonschema.keyword.validator.KeywordValidatorFactory;
+import com.github.fge.jsonschema.keyword.validator.ReflectionKeywordValidatorFactory;
import com.github.fge.jsonschema.keyword.validator.common.DependenciesValidator;
import com.github.fge.jsonschema.keyword.validator.draftv3.DisallowKeywordValidator;
import com.github.fge.jsonschema.keyword.validator.draftv3.DivisibleByValidator;
@@ -30,27 +31,25 @@
import com.github.fge.jsonschema.keyword.validator.draftv3.ExtendsValidator;
import com.github.fge.jsonschema.keyword.validator.draftv3.PropertiesValidator;
-import java.lang.reflect.Constructor;
-
/**
* Draft v3 specific keyword validator constructors
*/
public final class DraftV3ValidatorDictionary
{
- private static final Dictionary>
+ private static final Dictionary
DICTIONARY;
private DraftV3ValidatorDictionary()
{
}
- public static Dictionary> get()
+ public static Dictionary get()
{
return DICTIONARY;
}
static {
- final DictionaryBuilder>
+ final DictionaryBuilder
builder = Dictionary.newBuilder();
String keyword;
@@ -63,41 +62,37 @@ public static Dictionary> get()
*/
keyword = "divisibleBy";
c = DivisibleByValidator.class;
- builder.addEntry(keyword, constructor(c));
+ builder.addEntry(keyword, factory(keyword, c));
/*
* Object
*/
keyword = "properties";
c = PropertiesValidator.class;
- builder.addEntry(keyword, constructor(c));
+ builder.addEntry(keyword, factory(keyword, c));
keyword = "dependencies";
c = DependenciesValidator.class;
- builder.addEntry(keyword, constructor(c));
+ builder.addEntry(keyword, factory(keyword, c));
keyword = "type";
c = DraftV3TypeValidator.class;
- builder.addEntry(keyword, constructor(c));
+ builder.addEntry(keyword, factory(keyword, c));
keyword = "disallow";
c = DisallowKeywordValidator.class;
- builder.addEntry(keyword, constructor(c));
+ builder.addEntry(keyword, factory(keyword, c));
keyword = "extends";
c = ExtendsValidator.class;
- builder.addEntry(keyword, constructor(c));
+ builder.addEntry(keyword, factory(keyword, c));
DICTIONARY = builder.freeze();
}
- private static Constructor extends KeywordValidator> constructor(
+ private static KeywordValidatorFactory factory(String name,
final Class extends KeywordValidator> c)
{
- try {
- return c.getConstructor(JsonNode.class);
- } catch (NoSuchMethodException e) {
- throw new RuntimeException("No appropriate constructor found", e);
- }
+ return new ReflectionKeywordValidatorFactory(name, c);
}
}
diff --git a/src/main/java/com/github/fge/jsonschema/library/validator/DraftV4ValidatorDictionary.java b/src/main/java/com/github/fge/jsonschema/library/validator/DraftV4ValidatorDictionary.java
index 6e517c7c9..a82a74b49 100644
--- a/src/main/java/com/github/fge/jsonschema/library/validator/DraftV4ValidatorDictionary.java
+++ b/src/main/java/com/github/fge/jsonschema/library/validator/DraftV4ValidatorDictionary.java
@@ -19,10 +19,11 @@
package com.github.fge.jsonschema.library.validator;
-import com.fasterxml.jackson.databind.JsonNode;
import com.github.fge.jsonschema.core.util.Dictionary;
import com.github.fge.jsonschema.core.util.DictionaryBuilder;
import com.github.fge.jsonschema.keyword.validator.KeywordValidator;
+import com.github.fge.jsonschema.keyword.validator.KeywordValidatorFactory;
+import com.github.fge.jsonschema.keyword.validator.ReflectionKeywordValidatorFactory;
import com.github.fge.jsonschema.keyword.validator.common.DependenciesValidator;
import com.github.fge.jsonschema.keyword.validator.draftv4.AllOfValidator;
import com.github.fge.jsonschema.keyword.validator.draftv4.AnyOfValidator;
@@ -34,27 +35,25 @@
import com.github.fge.jsonschema.keyword.validator.draftv4.OneOfValidator;
import com.github.fge.jsonschema.keyword.validator.draftv4.RequiredKeywordValidator;
-import java.lang.reflect.Constructor;
-
/**
* Draft v4 specific keyword validator constructors
*/
public final class DraftV4ValidatorDictionary
{
- private static final Dictionary>
+ private static final Dictionary
DICTIONARY;
private DraftV4ValidatorDictionary()
{
}
- public static Dictionary> get()
+ public static Dictionary get()
{
return DICTIONARY;
}
static {
- final DictionaryBuilder>
+ final DictionaryBuilder
builder = Dictionary.newBuilder();
String keyword;
@@ -67,60 +66,56 @@ public static Dictionary> get()
*/
keyword = "multipleOf";
c = MultipleOfValidator.class;
- builder.addEntry(keyword, constructor(c));
+ builder.addEntry(keyword, factory(keyword, c));
/*
* Object
*/
keyword = "minProperties";
c = MinPropertiesValidator.class;
- builder.addEntry(keyword, constructor(c));
+ builder.addEntry(keyword, factory(keyword, c));
keyword = "maxProperties";
c = MaxPropertiesValidator.class;
- builder.addEntry(keyword, constructor(c));
+ builder.addEntry(keyword, factory(keyword, c));
keyword = "required";
c = RequiredKeywordValidator.class;
- builder.addEntry(keyword, constructor(c));
+ builder.addEntry(keyword, factory(keyword, c));
keyword = "dependencies";
c = DependenciesValidator.class;
- builder.addEntry(keyword, constructor(c));
+ builder.addEntry(keyword, factory(keyword, c));
/*
* All
*/
keyword = "anyOf";
c = AnyOfValidator.class;
- builder.addEntry(keyword, constructor(c));
+ builder.addEntry(keyword, factory(keyword, c));
keyword = "allOf";
c = AllOfValidator.class;
- builder.addEntry(keyword, constructor(c));
+ builder.addEntry(keyword, factory(keyword, c));
keyword = "oneOf";
c = OneOfValidator.class;
- builder.addEntry(keyword, constructor(c));
+ builder.addEntry(keyword, factory(keyword, c));
keyword = "not";
c = NotValidator.class;
- builder.addEntry(keyword, constructor(c));
+ builder.addEntry(keyword, factory(keyword, c));
keyword = "type";
c = DraftV4TypeValidator.class;
- builder.addEntry(keyword, constructor(c));
+ builder.addEntry(keyword, factory(keyword, c));
DICTIONARY = builder.freeze();
}
- private static Constructor extends KeywordValidator> constructor(
+ private static KeywordValidatorFactory factory(String name,
final Class extends KeywordValidator> c)
{
- try {
- return c.getConstructor(JsonNode.class);
- } catch (NoSuchMethodException e) {
- throw new RuntimeException("No appropriate constructor found", e);
- }
+ return new ReflectionKeywordValidatorFactory(name, c);
}
}
diff --git a/src/main/java/com/github/fge/jsonschema/processors/build/ValidatorBuilder.java b/src/main/java/com/github/fge/jsonschema/processors/build/ValidatorBuilder.java
index f8fba5171..27409c83b 100644
--- a/src/main/java/com/github/fge/jsonschema/processors/build/ValidatorBuilder.java
+++ b/src/main/java/com/github/fge/jsonschema/processors/build/ValidatorBuilder.java
@@ -19,23 +19,22 @@
package com.github.fge.jsonschema.processors.build;
+import java.util.Map;
+import java.util.SortedMap;
+
import com.fasterxml.jackson.databind.JsonNode;
import com.github.fge.jsonschema.core.exceptions.ProcessingException;
import com.github.fge.jsonschema.core.processing.Processor;
import com.github.fge.jsonschema.core.report.ProcessingReport;
import com.github.fge.jsonschema.core.util.Dictionary;
import com.github.fge.jsonschema.keyword.validator.KeywordValidator;
+import com.github.fge.jsonschema.keyword.validator.KeywordValidatorFactory;
import com.github.fge.jsonschema.library.Library;
import com.github.fge.jsonschema.processors.data.SchemaDigest;
import com.github.fge.jsonschema.processors.data.ValidatorList;
import com.github.fge.jsonschema.processors.validation.ValidationProcessor;
import com.google.common.collect.Maps;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.util.Map;
-import java.util.SortedMap;
-
/**
* Keyword builder processor
*
@@ -48,20 +47,18 @@
public final class ValidatorBuilder
implements Processor
{
- private static final String ERRMSG = "failed to build keyword validator";
-
- private final Map>
- constructors;
+ private final Map
+ factories;
public ValidatorBuilder(final Library library)
{
- constructors = library.getValidators().entries();
+ factories = library.getValidators().entries();
}
public ValidatorBuilder(
- final Dictionary> dict)
+ final Dictionary dict)
{
- constructors = dict.entries();
+ factories = dict.entries();
}
/**
@@ -82,35 +79,19 @@ public ValidatorList process(final ProcessingReport report,
String keyword;
JsonNode digest;
KeywordValidator validator;
- Constructor extends KeywordValidator> constructor;
+ KeywordValidatorFactory factory;
for (final Map.Entry entry:
input.getDigests().entrySet()) {
keyword = entry.getKey();
digest = entry.getValue();
- constructor = constructors.get(keyword);
- validator = buildKeyword(constructor, digest);
+ factory = factories.get(keyword);
+ validator = factory.getKeywordValidator(digest);
map.put(keyword, validator);
}
return new ValidatorList(input.getContext(), map.values());
}
- private static KeywordValidator buildKeyword(
- final Constructor extends KeywordValidator> constructor,
- final JsonNode node)
- throws ProcessingException
- {
- try {
- return constructor.newInstance(node);
- } catch (InstantiationException e) {
- throw new ProcessingException(ERRMSG, e);
- } catch (IllegalAccessException e) {
- throw new ProcessingException(ERRMSG, e);
- } catch (InvocationTargetException e) {
- throw new ProcessingException(ERRMSG, e);
- }
- }
-
@Override
public String toString()
{
diff --git a/src/test/java/com/github/fge/jsonschema/keyword/special/ExtendsKeywordTest.java b/src/test/java/com/github/fge/jsonschema/keyword/special/ExtendsKeywordTest.java
index 36bcee0c9..32fab2b55 100644
--- a/src/test/java/com/github/fge/jsonschema/keyword/special/ExtendsKeywordTest.java
+++ b/src/test/java/com/github/fge/jsonschema/keyword/special/ExtendsKeywordTest.java
@@ -19,6 +19,19 @@
package com.github.fge.jsonschema.keyword.special;
+import static com.github.fge.jsonschema.TestUtils.anyMessage;
+import static com.github.fge.jsonschema.matchers.ProcessingMessageAssert.assertMessage;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.fail;
+
+import org.mockito.ArgumentCaptor;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.github.fge.jackson.JacksonUtils;
@@ -33,22 +46,12 @@
import com.github.fge.jsonschema.core.tree.SimpleJsonTree;
import com.github.fge.jsonschema.core.tree.key.SchemaKey;
import com.github.fge.jsonschema.keyword.validator.KeywordValidator;
+import com.github.fge.jsonschema.keyword.validator.KeywordValidatorFactory;
import com.github.fge.jsonschema.library.validator.DraftV3ValidatorDictionary;
import com.github.fge.jsonschema.messages.JsonSchemaValidationBundle;
import com.github.fge.jsonschema.processors.data.FullData;
import com.github.fge.msgsimple.bundle.MessageBundle;
import com.github.fge.msgsimple.load.MessageBundles;
-import org.mockito.ArgumentCaptor;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-
-import static com.github.fge.jsonschema.TestUtils.*;
-import static com.github.fge.jsonschema.matchers.ProcessingMessageAssert.*;
-import static org.mockito.Mockito.*;
-import static org.testng.Assert.*;
public final class ExtendsKeywordTest
{
@@ -65,13 +68,12 @@ public final class ExtendsKeywordTest
private ProcessingMessage msg;
public ExtendsKeywordTest()
- throws IllegalAccessException, InvocationTargetException,
- InstantiationException
+ throws ProcessingException
{
- final Constructor extends KeywordValidator> constructor
+ final KeywordValidatorFactory factory
= DraftV3ValidatorDictionary.get().entries().get("extends");
- validator = constructor == null ? null
- : constructor.newInstance(FACTORY.nullNode());
+ validator = factory == null ? null
+ : factory.getKeywordValidator(FACTORY.nullNode());
}
@BeforeMethod
diff --git a/src/test/java/com/github/fge/jsonschema/keyword/special/NotKeywordTest.java b/src/test/java/com/github/fge/jsonschema/keyword/special/NotKeywordTest.java
index 3270529a3..243f1ddf8 100644
--- a/src/test/java/com/github/fge/jsonschema/keyword/special/NotKeywordTest.java
+++ b/src/test/java/com/github/fge/jsonschema/keyword/special/NotKeywordTest.java
@@ -19,6 +19,20 @@
package com.github.fge.jsonschema.keyword.special;
+import static com.github.fge.jsonschema.TestUtils.anyMessage;
+import static com.github.fge.jsonschema.matchers.ProcessingMessageAssert.assertMessage;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.fail;
+
+import org.mockito.ArgumentCaptor;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.github.fge.jackson.JacksonUtils;
@@ -34,22 +48,12 @@
import com.github.fge.jsonschema.core.tree.SimpleJsonTree;
import com.github.fge.jsonschema.core.tree.key.SchemaKey;
import com.github.fge.jsonschema.keyword.validator.KeywordValidator;
+import com.github.fge.jsonschema.keyword.validator.KeywordValidatorFactory;
import com.github.fge.jsonschema.library.validator.DraftV4ValidatorDictionary;
import com.github.fge.jsonschema.messages.JsonSchemaValidationBundle;
import com.github.fge.jsonschema.processors.data.FullData;
import com.github.fge.msgsimple.bundle.MessageBundle;
import com.github.fge.msgsimple.load.MessageBundles;
-import org.mockito.ArgumentCaptor;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-
-import static com.github.fge.jsonschema.TestUtils.*;
-import static com.github.fge.jsonschema.matchers.ProcessingMessageAssert.*;
-import static org.mockito.Mockito.*;
-import static org.testng.Assert.*;
public final class NotKeywordTest
{
@@ -65,13 +69,12 @@ public final class NotKeywordTest
private ProcessingReport report;
public NotKeywordTest()
- throws IllegalAccessException, InvocationTargetException,
- InstantiationException
+ throws ProcessingException
{
- final Constructor extends KeywordValidator> constructor
+ final KeywordValidatorFactory factory
= DraftV4ValidatorDictionary.get().entries().get("not");
- validator = constructor == null ? null
- : constructor.newInstance(FACTORY.nullNode());
+ validator = factory == null ? null
+ : factory.getKeywordValidator(FACTORY.nullNode());
}
@BeforeMethod
diff --git a/src/test/java/com/github/fge/jsonschema/keyword/special/PatternKeywordTest.java b/src/test/java/com/github/fge/jsonschema/keyword/special/PatternKeywordTest.java
index 6ff655ae0..873041061 100644
--- a/src/test/java/com/github/fge/jsonschema/keyword/special/PatternKeywordTest.java
+++ b/src/test/java/com/github/fge/jsonschema/keyword/special/PatternKeywordTest.java
@@ -19,6 +19,22 @@
package com.github.fge.jsonschema.keyword.special;
+import static com.github.fge.jsonschema.TestUtils.anyMessage;
+import static com.github.fge.jsonschema.matchers.ProcessingMessageAssert.assertMessage;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.testng.Assert.assertNotNull;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Iterator;
+import java.util.List;
+
+import org.mockito.ArgumentCaptor;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.github.fge.jackson.JsonLoader;
@@ -33,26 +49,13 @@
import com.github.fge.jsonschema.core.tree.SimpleJsonTree;
import com.github.fge.jsonschema.core.tree.key.SchemaKey;
import com.github.fge.jsonschema.keyword.validator.KeywordValidator;
+import com.github.fge.jsonschema.keyword.validator.KeywordValidatorFactory;
import com.github.fge.jsonschema.library.validator.CommonValidatorDictionary;
import com.github.fge.jsonschema.messages.JsonSchemaValidationBundle;
import com.github.fge.jsonschema.processors.data.FullData;
import com.github.fge.msgsimple.bundle.MessageBundle;
import com.github.fge.msgsimple.load.MessageBundles;
import com.google.common.collect.Lists;
-import org.mockito.ArgumentCaptor;
-import org.testng.annotations.DataProvider;
-import org.testng.annotations.Test;
-
-import java.io.IOException;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.util.Iterator;
-import java.util.List;
-
-import static com.github.fge.jsonschema.TestUtils.*;
-import static com.github.fge.jsonschema.matchers.ProcessingMessageAssert.*;
-import static org.mockito.Mockito.*;
-import static org.testng.Assert.*;
public final class PatternKeywordTest
{
@@ -65,20 +68,20 @@ public final class PatternKeywordTest
private static final MessageBundle BUNDLE
= MessageBundles.getBundle(JsonSchemaValidationBundle.class);
- private final Constructor extends KeywordValidator> constructor;
+ private final KeywordValidatorFactory factory;
private final JsonNode testData;
public PatternKeywordTest()
throws IOException
{
- constructor = CommonValidatorDictionary.get().entries().get("pattern");
+ factory = CommonValidatorDictionary.get().entries().get("pattern");
testData = JsonLoader.fromResource("/keyword/special/pattern.json");
}
@Test
public void keywordExists()
{
- assertNotNull(constructor, "no support for pattern??");
+ assertNotNull(factory, "no support for pattern??");
}
@DataProvider
@@ -120,7 +123,7 @@ public void instancesAreValidatedCorrectly(final JsonNode schema,
// It is a null node which is ignored by the constructor, so we can
// do that
- final KeywordValidator validator = constructor.newInstance(schema);
+ final KeywordValidator validator = factory.getKeywordValidator(schema);
validator.validate(processor, report, BUNDLE, data);
if (valid) {
diff --git a/src/test/java/com/github/fge/jsonschema/keyword/validator/AbstractKeywordValidatorTest.java b/src/test/java/com/github/fge/jsonschema/keyword/validator/AbstractKeywordValidatorTest.java
index aa69bcec9..9916d8a8d 100644
--- a/src/test/java/com/github/fge/jsonschema/keyword/validator/AbstractKeywordValidatorTest.java
+++ b/src/test/java/com/github/fge/jsonschema/keyword/validator/AbstractKeywordValidatorTest.java
@@ -19,6 +19,22 @@
package com.github.fge.jsonschema.keyword.validator;
+import static com.github.fge.jsonschema.TestUtils.anyMessage;
+import static com.github.fge.jsonschema.matchers.ProcessingMessageAssert.assertMessage;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.testng.Assert.assertNotNull;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Iterator;
+import java.util.List;
+
+import org.mockito.ArgumentCaptor;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.github.fge.jackson.JsonLoader;
@@ -38,20 +54,6 @@
import com.github.fge.msgsimple.bundle.MessageBundle;
import com.github.fge.msgsimple.load.MessageBundles;
import com.google.common.collect.Lists;
-import org.mockito.ArgumentCaptor;
-import org.testng.annotations.DataProvider;
-import org.testng.annotations.Test;
-
-import java.io.IOException;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.util.Iterator;
-import java.util.List;
-
-import static com.github.fge.jsonschema.TestUtils.*;
-import static com.github.fge.jsonschema.matchers.ProcessingMessageAssert.*;
-import static org.mockito.Mockito.*;
-import static org.testng.Assert.*;
@Test
public abstract class AbstractKeywordValidatorTest
@@ -60,16 +62,16 @@ public abstract class AbstractKeywordValidatorTest
= MessageBundles.getBundle(JsonSchemaValidationBundle.class);
private final String keyword;
- private final Constructor extends KeywordValidator> constructor;
+ private final KeywordValidatorFactory factory;
private final JsonNode testNode;
protected AbstractKeywordValidatorTest(
- final Dictionary> dict,
+ final Dictionary dict,
final String prefix, final String keyword)
throws IOException
{
this.keyword = keyword;
- constructor = dict.entries().get(keyword);
+ factory = dict.entries().get(keyword);
final String resourceName
= String.format("/keyword/validators/%s/%s.json", prefix, keyword);
testNode = JsonLoader.fromResource(resourceName);
@@ -78,7 +80,7 @@ protected AbstractKeywordValidatorTest(
@Test
public final void keywordExists()
{
- assertNotNull(constructor, "no support for " + keyword + "??");
+ assertNotNull(factory, "no support for " + keyword + "??");
}
@DataProvider
@@ -120,7 +122,7 @@ public final void instancesAreValidatedCorrectly(final JsonNode digest,
@SuppressWarnings("unchecked")
final Processor processor = mock(Processor.class);
- final KeywordValidator validator = constructor.newInstance(digest);
+ final KeywordValidator validator = factory.getKeywordValidator(digest);
validator.validate(processor, report, BUNDLE, data);
if (valid) {
diff --git a/src/test/java/com/github/fge/jsonschema/keyword/validator/callback/CallbackValidatorTest.java b/src/test/java/com/github/fge/jsonschema/keyword/validator/callback/CallbackValidatorTest.java
index 07ba21ec8..d5d936e94 100644
--- a/src/test/java/com/github/fge/jsonschema/keyword/validator/callback/CallbackValidatorTest.java
+++ b/src/test/java/com/github/fge/jsonschema/keyword/validator/callback/CallbackValidatorTest.java
@@ -19,6 +19,21 @@
package com.github.fge.jsonschema.keyword.validator.callback;
+import static com.github.fge.jsonschema.TestUtils.anyReport;
+import static com.github.fge.jsonschema.TestUtils.onlyOnce;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.fail;
+
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
@@ -36,19 +51,11 @@
import com.github.fge.jsonschema.core.tree.key.SchemaKey;
import com.github.fge.jsonschema.core.util.Dictionary;
import com.github.fge.jsonschema.keyword.validator.KeywordValidator;
+import com.github.fge.jsonschema.keyword.validator.KeywordValidatorFactory;
import com.github.fge.jsonschema.messages.JsonSchemaValidationBundle;
import com.github.fge.jsonschema.processors.data.FullData;
import com.github.fge.msgsimple.bundle.MessageBundle;
import com.github.fge.msgsimple.load.MessageBundles;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-
-import static com.github.fge.jsonschema.TestUtils.*;
-import static org.mockito.Mockito.*;
-import static org.testng.Assert.*;
@Test
public abstract class CallbackValidatorTest
@@ -62,7 +69,7 @@ public abstract class CallbackValidatorTest
protected static final ObjectNode sub2 = FACTORY.objectNode();
protected final String keyword;
- private final Constructor extends KeywordValidator> constructor;
+ private final KeywordValidatorFactory factory;
protected final JsonPointer ptr1;
protected final JsonPointer ptr2;
@@ -72,21 +79,20 @@ public abstract class CallbackValidatorTest
private KeywordValidator validator;
protected CallbackValidatorTest(
- final Dictionary> dict,
+ final Dictionary dict,
final String keyword, final JsonPointer ptr1, final JsonPointer ptr2)
{
this.keyword = keyword;
- constructor = dict.entries().get(keyword);
+ factory = dict.entries().get(keyword);
this.ptr1 = ptr1;
this.ptr2 = ptr2;
}
@BeforeMethod
protected final void initEnvironment()
- throws IllegalAccessException, InvocationTargetException,
- InstantiationException
+ throws ProcessingException
{
- if (constructor == null)
+ if (factory == null)
return;
final SchemaTree tree = new CanonicalSchemaTree(
@@ -95,13 +101,13 @@ protected final void initEnvironment()
data = new FullData(tree, instance);
report = mock(ProcessingReport.class);
when(report.getLogLevel()).thenReturn(LogLevel.DEBUG);
- validator = constructor.newInstance(generateDigest());
+ validator = factory.getKeywordValidator(generateDigest());
}
@Test
public final void keywordExists()
{
- assertNotNull(constructor, "no support for " + keyword + "??");
+ assertNotNull(factory, "no support for " + keyword + "??");
}
@Test(dependsOnMethods = "keywordExists")
diff --git a/src/test/java/com/github/fge/jsonschema/processors/build/ValidatorBuilderTest.java b/src/test/java/com/github/fge/jsonschema/processors/build/ValidatorBuilderTest.java
index 4887af34a..8f038c38c 100644
--- a/src/test/java/com/github/fge/jsonschema/processors/build/ValidatorBuilderTest.java
+++ b/src/test/java/com/github/fge/jsonschema/processors/build/ValidatorBuilderTest.java
@@ -19,6 +19,16 @@
package com.github.fge.jsonschema.processors.build;
+import static org.mockito.Mockito.mock;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertSame;
+import static org.testng.Assert.fail;
+
+import java.util.List;
+import java.util.Map;
+
+import org.testng.annotations.Test;
+
import com.fasterxml.jackson.databind.JsonNode;
import com.github.fge.jackson.JacksonUtils;
import com.github.fge.jsonschema.core.exceptions.ProcessingException;
@@ -27,20 +37,14 @@
import com.github.fge.jsonschema.core.util.Dictionary;
import com.github.fge.jsonschema.core.util.DictionaryBuilder;
import com.github.fge.jsonschema.keyword.validator.KeywordValidator;
+import com.github.fge.jsonschema.keyword.validator.KeywordValidatorFactory;
+import com.github.fge.jsonschema.keyword.validator.ReflectionKeywordValidatorFactory;
import com.github.fge.jsonschema.processors.data.FullData;
import com.github.fge.jsonschema.processors.data.SchemaDigest;
import com.github.fge.jsonschema.processors.data.ValidatorList;
import com.github.fge.msgsimple.bundle.MessageBundle;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
-import org.testng.annotations.Test;
-
-import java.lang.reflect.Constructor;
-import java.util.List;
-import java.util.Map;
-
-import static org.mockito.Mockito.*;
-import static org.testng.Assert.*;
public final class ValidatorBuilderTest
{
@@ -53,17 +57,17 @@ public final class ValidatorBuilderTest
public ValidatorBuilderTest()
throws NoSuchMethodException
{
- final DictionaryBuilder>
+ final DictionaryBuilder
builder = Dictionary.newBuilder();
- Constructor extends KeywordValidator> constructor;
+ KeywordValidatorFactory factory;
- constructor = Keyword1.class .getConstructor(JsonNode.class);
- builder.addEntry(K1, constructor);
- constructor = Keyword2.class.getConstructor(JsonNode.class);
- builder.addEntry(K2, constructor);
- constructor = Challenged.class.getConstructor(JsonNode.class);
- builder.addEntry(CHALLENGED, constructor);
+ factory = new ReflectionKeywordValidatorFactory(K1, Keyword1.class);
+ builder.addEntry(K1, factory);
+ factory = new ReflectionKeywordValidatorFactory(K2, Keyword2.class);
+ builder.addEntry(K2, factory);
+ factory = new ReflectionKeywordValidatorFactory(CHALLENGED, Challenged.class);
+ builder.addEntry(CHALLENGED, factory);
validatorBuilder = new ValidatorBuilder(builder.freeze());
}
From ac2e2238a3552485bd01a8cf3957eb92eed7d058 Mon Sep 17 00:00:00 2001
From: Vikas Bodke
Date: Tue, 10 Feb 2015 23:06:49 +0530
Subject: [PATCH 18/71] Fixes issue #143 opened by @rberger The secFracs field
will support upto 12 chars
---
.../format/common/DateTimeAttribute.java | 8 ++--
.../resources/format/common/date-time.json | 44 ++++++++++++++++++-
2 files changed, 46 insertions(+), 6 deletions(-)
diff --git a/src/main/java/com/github/fge/jsonschema/format/common/DateTimeAttribute.java b/src/main/java/com/github/fge/jsonschema/format/common/DateTimeAttribute.java
index d2055314b..20a4a9821 100644
--- a/src/main/java/com/github/fge/jsonschema/format/common/DateTimeAttribute.java
+++ b/src/main/java/com/github/fge/jsonschema/format/common/DateTimeAttribute.java
@@ -42,13 +42,13 @@ public final class DateTimeAttribute
extends AbstractFormatAttribute
{
private static final List FORMATS = ImmutableList.of(
- "yyyy-MM-dd'T'HH:mm:ssZ", "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
+ "yyyy-MM-dd'T'HH:mm:ssZ", "yyyy-MM-dd'T'HH:mm:ss.[0-9]{1,12}Z"
);
private static final DateTimeFormatter FORMATTER;
static {
- final DateTimeParser msParser = new DateTimeFormatterBuilder()
- .appendLiteral('.').appendDecimal(millisOfSecond(), 1, 3)
+ final DateTimeParser secFracsParser = new DateTimeFormatterBuilder()
+ .appendLiteral('.').appendFractionOfSecond(1,12)
.toParser();
DateTimeFormatterBuilder builder = new DateTimeFormatterBuilder();
@@ -64,7 +64,7 @@ public final class DateTimeAttribute
.appendFixedDecimal(minuteOfHour(), 2)
.appendLiteral(':')
.appendFixedDecimal(secondOfMinute(), 2)
- .appendOptional(msParser)
+ .appendOptional(secFracsParser)
.appendTimeZoneOffset("Z", false, 2, 2);
FORMATTER = builder.toFormatter();
diff --git a/src/test/resources/format/common/date-time.json b/src/test/resources/format/common/date-time.json
index 1f2d96f1d..f79dcc701 100644
--- a/src/test/resources/format/common/date-time.json
+++ b/src/test/resources/format/common/date-time.json
@@ -25,7 +25,7 @@
"message": "err.format.invalidDate",
"msgData": {
"value": "2012-02-30T00:00:00+0000",
- "expected": [ "yyyy-MM-dd'T'HH:mm:ssZ", "yyyy-MM-dd'T'HH:mm:ss.SSSZ" ]
+ "expected": [ "yyyy-MM-dd'T'HH:mm:ssZ", "yyyy-MM-dd'T'HH:mm:ss.[0-9]{1,12}Z" ]
},
"msgParams": [ "value", "expected" ]
},
@@ -35,8 +35,48 @@
"message": "err.format.invalidDate",
"msgData": {
"value": "201202030",
- "expected": [ "yyyy-MM-dd'T'HH:mm:ssZ", "yyyy-MM-dd'T'HH:mm:ss.SSSZ" ]
+ "expected": [ "yyyy-MM-dd'T'HH:mm:ssZ", "yyyy-MM-dd'T'HH:mm:ss.[0-9]{1,12}Z" ]
},
"msgParams": [ "value", "expected" ]
+ },
+ {
+ "data": "2012-08-07T20:42:32.1234Z",
+ "valid": true
+ },
+ {
+ "data": "2012-08-07T20:42:32.12345Z",
+ "valid": true
+ },
+ {
+ "data": "2012-08-07T20:42:32.123456Z",
+ "valid": true
+ },
+ {
+ "data": "2012-08-07T20:42:32.1234567Z",
+ "valid": true
+ },
+ {
+ "data": "2012-08-07T20:42:32.12345678Z",
+ "valid": true
+ },
+ {
+ "data": "2012-08-07T20:42:32.12345678Z",
+ "valid": true
+ },
+ {
+ "data": "2012-08-07T20:42:32.123456789Z",
+ "valid": true
+ },
+ {
+ "data": "2012-08-07T20:42:32.1234567890Z",
+ "valid": true
+ },
+ {
+ "data": "2012-08-07T20:42:32.12345678901Z",
+ "valid": true
+ },
+ {
+ "data": "2012-08-07T20:42:32.123456789012Z",
+ "valid": true
}
]
From 6b4c650f022f02f354a5e8e3099380f174f805d3 Mon Sep 17 00:00:00 2001
From: mmolina
Date: Sat, 21 Nov 2015 00:32:30 +0100
Subject: [PATCH 19/71] Configurable cache size for processing validations
Also: Changing default cache size to 512
---
.../jsonschema/cfg/ValidationConfiguration.java | 11 +++++++++++
.../cfg/ValidationConfigurationBuilder.java | 14 ++++++++++++++
.../fge/jsonschema/main/JsonSchemaFactory.java | 2 +-
.../processors/validation/ValidationChain.java | 4 ++--
.../jsonschema/validator/configuration.properties | 1 +
.../cfg/ValidationConfigurationTest.java | 12 ++++++++++++
6 files changed, 41 insertions(+), 3 deletions(-)
diff --git a/src/main/java/com/github/fge/jsonschema/cfg/ValidationConfiguration.java b/src/main/java/com/github/fge/jsonschema/cfg/ValidationConfiguration.java
index b67fdc840..54a1b9360 100644
--- a/src/main/java/com/github/fge/jsonschema/cfg/ValidationConfiguration.java
+++ b/src/main/java/com/github/fge/jsonschema/cfg/ValidationConfiguration.java
@@ -70,6 +70,11 @@ public final class ValidationConfiguration
* Whether to use {@code format} in the resulting factory
*/
final boolean useFormat;
+
+ /**
+ * Cache size for processing validations
+ */
+ final int cacheSize;
/**
* The set of syntax messages
@@ -113,6 +118,7 @@ public static ValidationConfiguration byDefault()
libraries = ImmutableMap.copyOf(builder.libraries);
defaultLibrary = builder.defaultLibrary;
useFormat = builder.useFormat;
+ cacheSize = builder.cacheSize;
syntaxMessages = builder.syntaxMessages;
validationMessages = builder.validationMessages;
}
@@ -146,6 +152,11 @@ public boolean getUseFormat()
{
return useFormat;
}
+
+ public int getCacheSize()
+ {
+ return cacheSize;
+ }
public MessageBundle getSyntaxMessages()
{
diff --git a/src/main/java/com/github/fge/jsonschema/cfg/ValidationConfigurationBuilder.java b/src/main/java/com/github/fge/jsonschema/cfg/ValidationConfigurationBuilder.java
index 61cdec21c..949a18b3b 100644
--- a/src/main/java/com/github/fge/jsonschema/cfg/ValidationConfigurationBuilder.java
+++ b/src/main/java/com/github/fge/jsonschema/cfg/ValidationConfigurationBuilder.java
@@ -80,6 +80,11 @@ public final class ValidationConfigurationBuilder
* Whether to use {@code format} ({@code true} by default)
*/
boolean useFormat = true;
+
+ /**
+ * Cache maximum size of 512 records by default
+ */
+ int cacheSize = 512;
/**
* The set of syntax messages
@@ -119,6 +124,7 @@ public final class ValidationConfigurationBuilder
libraries = Maps.newHashMap(cfg.libraries);
defaultLibrary = cfg.defaultLibrary;
useFormat = cfg.useFormat;
+ cacheSize = cfg.cacheSize;
syntaxMessages = cfg.syntaxMessages;
validationMessages = cfg.validationMessages;
}
@@ -217,6 +223,14 @@ public ValidationConfigurationBuilder setValidationMessages(
return this;
}
+ public ValidationConfigurationBuilder setCacheSize(
+ final int cacheSize)
+ {
+ BUNDLE.checkArgument(cacheSize >= -1, "invalidCacheSize");
+ this.cacheSize = cacheSize;
+ return this;
+ }
+
/**
* Return a frozen version of this configuration
*
diff --git a/src/main/java/com/github/fge/jsonschema/main/JsonSchemaFactory.java b/src/main/java/com/github/fge/jsonschema/main/JsonSchemaFactory.java
index bfaca5fe0..c9adbcc23 100644
--- a/src/main/java/com/github/fge/jsonschema/main/JsonSchemaFactory.java
+++ b/src/main/java/com/github/fge/jsonschema/main/JsonSchemaFactory.java
@@ -275,6 +275,6 @@ private Processor buildProcessor()
final Processor processor
= map.getProcessor();
return new CachingProcessor(processor,
- SchemaContextEquivalence.getInstance());
+ SchemaContextEquivalence.getInstance(), validationCfg.getCacheSize());
}
}
diff --git a/src/main/java/com/github/fge/jsonschema/processors/validation/ValidationChain.java b/src/main/java/com/github/fge/jsonschema/processors/validation/ValidationChain.java
index bc4e4ad9e..061574aec 100644
--- a/src/main/java/com/github/fge/jsonschema/processors/validation/ValidationChain.java
+++ b/src/main/java/com/github/fge/jsonschema/processors/validation/ValidationChain.java
@@ -71,7 +71,7 @@ public ValidationChain(final RefResolver refResolver,
= ProcessorChain.startWith(refResolver).chainWith(syntaxProcessor);
resolver = new CachingProcessor, ValueHolder>(
- chain1.getProcessor(), SchemaHolderEquivalence.INSTANCE
+ chain1.getProcessor(), SchemaHolderEquivalence.INSTANCE, cfg.getCacheSize()
);
final SchemaDigester digester = new SchemaDigester(library);
@@ -86,7 +86,7 @@ public ValidationChain(final RefResolver refResolver,
}
builder = new CachingProcessor(
- chain2.getProcessor(), SchemaContextEquivalence.getInstance()
+ chain2.getProcessor(), SchemaContextEquivalence.getInstance(), cfg.getCacheSize()
);
}
diff --git a/src/main/resources/com/github/fge/jsonschema/validator/configuration.properties b/src/main/resources/com/github/fge/jsonschema/validator/configuration.properties
index ae76069c4..55996e6ff 100644
--- a/src/main/resources/com/github/fge/jsonschema/validator/configuration.properties
+++ b/src/main/resources/com/github/fge/jsonschema/validator/configuration.properties
@@ -37,3 +37,4 @@ nullFormat = format attribute name cannot be null
nullAttribute = attempt to register null implementation of format attribute "%s"
nullKeyword = attempt to add null keyword to library
nullType = null type argument to digester constructor
+invalidCacheSize = cache size must be greater than -1. -1 value sets a cache with unlimited records, zero-value disables the cache
diff --git a/src/test/java/com/github/fge/jsonschema/cfg/ValidationConfigurationTest.java b/src/test/java/com/github/fge/jsonschema/cfg/ValidationConfigurationTest.java
index 79684b6ce..c508bca9f 100644
--- a/src/test/java/com/github/fge/jsonschema/cfg/ValidationConfigurationTest.java
+++ b/src/test/java/com/github/fge/jsonschema/cfg/ValidationConfigurationTest.java
@@ -103,6 +103,18 @@ public void cannotPutNullValidationMessageBundle()
}
}
+ @Test
+ public void cannotPutInvalidCacheSize()
+ {
+ try {
+ cfg.setCacheSize(-2);
+ fail("No exception thrown!!");
+ } catch (IllegalArgumentException e) {
+ assertEquals(e.getMessage(),
+ BUNDLE.getMessage("invalidCacheSize"));
+ }
+ }
+
@Test
public void defaultLibraryIsDraftV4()
{
From fe5ae3ace0b37547ea11bdb8d3fd76177c70c562 Mon Sep 17 00:00:00 2001
From: huggsboson
Date: Tue, 2 May 2017 11:46:30 -0700
Subject: [PATCH 20/71] Update README.md
---
README.md | 24 ++++++++++++------------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/README.md b/README.md
index ce673cd5e..cce802c43 100644
--- a/README.md
+++ b/README.md
@@ -1,15 +1,15 @@
## Travis builds now enabled
-Builds are now verified by Travis (see [issue #20](https://github.com/daveclayton/json-patch/issues/20) from the json-patch project for details)
+Builds are now verified by Travis (see [issue #20](https://github.com/huggsboson/json-patch/issues/20) from the json-patch project for details)
-https://travis-ci.org/daveclayton/json-schema-validator
+https://travis-ci.org/huggsboson/json-schema-validator
## Read me first
The **current** version of this project is licensed under both LGPLv3 (or later) and ASL 2.0. The old version
(2.0.x) was licensed under LGPL 3.0 (or later) only.
-**Version 2.2 is out**. See [here](https://github.com/daveclayton/json-schema-validator/wiki/Whatsnew_22)
+**Version 2.2 is out**. See [here](https://github.com/huggsboson/json-schema-validator/wiki/Whatsnew_22)
for the list of changes compared to 2.0. And of course, it still has [all the
features](https://github.com/daveclayton/json-schema-validator/wiki/Features) of older versions.
@@ -34,19 +34,19 @@ timely manner.
## Testing online
You can [test this library online](http://json-schema-validator.herokuapp.com); this web site is in
-a [project of its own](https://github.com/daveclayton/json-schema-validator-demo), which you can fork and
+a [project of its own](https://github.com/huggsboson/json-schema-validator-demo), which you can fork and
run by yourself.
## Versions
* current stable version: **2.2.6**
- ([ChangeLog](https://github.com/daveclayton/json-schema-validator/wiki/ChangeLog_22x),
- [Javadoc](http://daveclayton.github.io/json-schema-validator/2.2.x/index.html), [code
- samples](http://daveclayton.github.io/json-schema-validator/2.2.x/index.html?com/github/fge/jsonschema/examples/package-summary.html)).
+ ([ChangeLog](https://github.com/huggsboson/json-schema-validator/wiki/ChangeLog_22x),
+ [Javadoc](http://huggsboson.github.io/json-schema-validator/2.2.x/index.html), [code
+ samples](http://huggsboson.github.io/json-schema-validator/2.2.x/index.html?com/github/fge/jsonschema/examples/package-summary.html)).
* old stable version: **2.0.4**
- ([ChangeLog](https://github.com/daveclayton/json-schema-validator/wiki/ChangeLog_20x),
- [Javadoc](http://daveclayton.github.io/json-schema-validator/2.0.x/index.html), [code
- samples](http://daveclayton.github.io/json-schema-validator/2.0.x/index.html?com/github/fge/jsonschema/examples/package-summary.html)).
+ ([ChangeLog](https://github.com/huggsboson/json-schema-validator/wiki/ChangeLog_20x),
+ [Javadoc](http://huggsboson.github.io/json-schema-validator/2.0.x/index.html), [code
+ samples](http://huggsboson.github.io/json-schema-validator/2.0.x/index.html?com/github/fge/jsonschema/examples/package-summary.html)).
## Available downloads
@@ -100,8 +100,8 @@ This implementation is based on the following drafts:
## More...
For a detailed discussion of the implementation, see
-[here](https://github.com/daveclayton/json-schema-validator/wiki/Status).
+[here](https://github.com/huggsboson/json-schema-validator/wiki/Status).
-Please see the [wiki](https://github.com/daveclayton/json-schema-validator/wiki/) for more
+Please see the [wiki](https://github.com/huggsboson/json-schema-validator/wiki/) for more
details.
From ee09b5b7637ba286d9ec77597cf99f6b50f06068 Mon Sep 17 00:00:00 2001
From: huggsboson
Date: Tue, 2 May 2017 13:13:48 -0700
Subject: [PATCH 21/71] Update README.md
---
README.md | 24 ++++++++++++------------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/README.md b/README.md
index cce802c43..0d0d7256f 100644
--- a/README.md
+++ b/README.md
@@ -1,15 +1,15 @@
## Travis builds now enabled
-Builds are now verified by Travis (see [issue #20](https://github.com/huggsboson/json-patch/issues/20) from the json-patch project for details)
+Builds are now verified by Travis (see [issue #20](https://github.com/java-json-tools/json-patch/issues/20) from the json-patch project for details)
-https://travis-ci.org/huggsboson/json-schema-validator
+https://travis-ci.org/java-json-tools/json-schema-validator
## Read me first
The **current** version of this project is licensed under both LGPLv3 (or later) and ASL 2.0. The old version
(2.0.x) was licensed under LGPL 3.0 (or later) only.
-**Version 2.2 is out**. See [here](https://github.com/huggsboson/json-schema-validator/wiki/Whatsnew_22)
+**Version 2.2 is out**. See [here](https://github.com/java-json-tools/json-schema-validator/wiki/Whatsnew_22)
for the list of changes compared to 2.0. And of course, it still has [all the
features](https://github.com/daveclayton/json-schema-validator/wiki/Features) of older versions.
@@ -34,19 +34,19 @@ timely manner.
## Testing online
You can [test this library online](http://json-schema-validator.herokuapp.com); this web site is in
-a [project of its own](https://github.com/huggsboson/json-schema-validator-demo), which you can fork and
+a [project of its own](https://github.com/java-json-tools/json-schema-validator-demo), which you can fork and
run by yourself.
## Versions
* current stable version: **2.2.6**
- ([ChangeLog](https://github.com/huggsboson/json-schema-validator/wiki/ChangeLog_22x),
- [Javadoc](http://huggsboson.github.io/json-schema-validator/2.2.x/index.html), [code
- samples](http://huggsboson.github.io/json-schema-validator/2.2.x/index.html?com/github/fge/jsonschema/examples/package-summary.html)).
+ ([ChangeLog](https://github.com/java-json-tools/json-schema-validator/wiki/ChangeLog_22x),
+ [Javadoc](http://java-json-tools.github.io/json-schema-validator/2.2.x/index.html), [code
+ samples](http://java-json-tools.github.io/json-schema-validator/2.2.x/index.html?com/github/fge/jsonschema/examples/package-summary.html)).
* old stable version: **2.0.4**
- ([ChangeLog](https://github.com/huggsboson/json-schema-validator/wiki/ChangeLog_20x),
- [Javadoc](http://huggsboson.github.io/json-schema-validator/2.0.x/index.html), [code
- samples](http://huggsboson.github.io/json-schema-validator/2.0.x/index.html?com/github/fge/jsonschema/examples/package-summary.html)).
+ ([ChangeLog](https://github.com/java-json-tools/json-schema-validator/wiki/ChangeLog_20x),
+ [Javadoc](http://java-json-tools.github.io/json-schema-validator/2.0.x/index.html), [code
+ samples](http://java-json-tools.github.io/json-schema-validator/2.0.x/index.html?com/github/fge/jsonschema/examples/package-summary.html)).
## Available downloads
@@ -100,8 +100,8 @@ This implementation is based on the following drafts:
## More...
For a detailed discussion of the implementation, see
-[here](https://github.com/huggsboson/json-schema-validator/wiki/Status).
+[here](https://github.com/java-json-tools/json-schema-validator/wiki/Status).
-Please see the [wiki](https://github.com/huggsboson/json-schema-validator/wiki/) for more
+Please see the [wiki](https://github.com/java-json-tools/json-schema-validator/wiki/) for more
details.
From 33abfcac16ee2a39b738a5bf2c4910838b597255 Mon Sep 17 00:00:00 2001
From: John Huffaker
Date: Fri, 2 Jun 2017 17:05:35 -0700
Subject: [PATCH 22/71] Gradle and build updates
---
build.gradle | 98 ++++++++++--------------
dorelease.sh | 16 ++++
gradle/wrapper/gradle-wrapper.properties | 23 +-----
3 files changed, 58 insertions(+), 79 deletions(-)
diff --git a/build.gradle b/build.gradle
index 6aebc88d6..24e3be32f 100644
--- a/build.gradle
+++ b/build.gradle
@@ -17,25 +17,6 @@
* - ASL 2.0: http://www.apache.org/licenses/LICENSE-2.0.txt
*/
-/*
- * This has to be here... It will not be taken into account in common.gradle!
- *
- * Looks like a serious bug... See also:
- *
- * http://forums.gradle.org/gradle/topics/buildscript_in_subprojects_ignored
- */
-/*
- * This has to be here... It will not be taken into account in common.gradle!
- *
- * Looks like a serious bug... See also:
- *
- * http://forums.gradle.org/gradle/topics/buildscript_in_subprojects_ignored
- *
- * We also use Spring's propdeps plugin to have a _real_ provided scope. See:
- *
- * https://github.com/spring-projects/gradle-plugins/tree/master/propdeps-plugin
- */
-
apply(plugin: "java");
apply(plugin: "maven");
apply(plugin: "signing");
@@ -43,15 +24,11 @@ apply(plugin: "osgi");
apply(plugin: "idea");
apply(plugin: "eclipse");
-group = "com.github.fge";
-version = "2.2.6";
+group = "com.github.java-json-tools";
+version = "2.2.7";
sourceCompatibility = "1.6";
targetCompatibility = "1.6"; // defaults to sourceCompatibility
-project.ext {
- description = "A Java implementation of the JSON Schema specification";
-};
-
/*
* Repositories to use
*/
@@ -63,8 +40,7 @@ repositories {
* List of dependencies
*/
dependencies {
- compile(group: "com.github.fge", name: "json-schema-core",
- version: "1.2.5");
+ compile(group: "com.github.java-json-tools", name: "json-schema-core", version: "1.2.8");
compile(group: "javax.mail", name: "mailapi", version: "1.4.3");
compile(group: "joda-time", name: "joda-time", version: "2.3");
compile(group: "com.googlecode.libphonenumber", name: "libphonenumber",
@@ -90,7 +66,7 @@ javadoc.options.links("http://fge.github.io/btf/");
javadoc.options.links("http://fge.github.io/msg-simple/");
javadoc.options.links("http://fge.github.io/jackson-coreutils/");
javadoc.options.links("http://fge.github.io/uri-template/");
-javadoc.options.links("http://fge.github.io/json-schema-core/1.2.x/");
+javadoc.options.links("http://java-json-tools.github.io/json-schema-core/1.2.x/");
/*
@@ -128,12 +104,14 @@ javadoc.options {
* Equally annoyingly, the docFilesSubDirs option above does not seem to have
* any effect :/
*/
-task copyDocFiles(dependsOn: javadoc) << {
- copy {
- from("src/main/javadoc") {
- include "**/doc-files/**";
- };
- into javadoc.destinationDir;
+task copyDocFiles(dependsOn: javadoc) {
+ doLast {
+ copy {
+ from("src/main/javadoc") {
+ include "**/doc-files/**";
+ };
+ into javadoc.destinationDir;
+ }
}
}
@@ -167,12 +145,14 @@ artifacts {
}
task wrapper(type: Wrapper) {
- gradleVersion = "1.11";
+ gradleVersion = "3.5";
distributionUrl = "http://services.gradle.org/distributions/gradle-${gradleVersion}-all.zip";
}
-task pom << {
- pom {}.writeTo("${projectDir}/pom.xml");
+task pom {
+ doLast {
+ pom {}.writeTo("${projectDir}/pom.xml");
+ }
}
/*
@@ -180,25 +160,27 @@ task pom << {
*/
project.ext {
- gitrwscm = sprintf("git@github.com:fge/%s", name);
- gitroscm = sprintf("https://github.com/fge/%s.git", name);
- projectURL = sprintf("https://github.com/fge/%s", name);
+ description = "A Java implementation of the JSON Schema specification";
+ scmUrl = sprintf("git@github.com:box-metadata/%s", name);
+ projectURL = sprintf("https://github.com/box-metadata/%s", name);
sonatypeStaging = "https://oss.sonatype.org/service/local/staging/deploy/maven2/";
sonatypeSnapshots = "https://oss.sonatype.org/content/repositories/snapshots/";
};
-task checkSigningRequirements << {
- def requiredProperties = [ "sonatypeUsername", "sonatypePassword" ];
- def noDice = false;
- requiredProperties.each {
- if (project.properties[it] == null) {
- noDice = true;
- System.err.printf("property \"%s\" is not defined!", it);
+task checkSigningRequirements {
+ doLast {
+ def requiredProperties = [ "sonatypeUsername", "sonatypePassword" ];
+ def noDice = false;
+ requiredProperties.each {
+ if (project.properties[it] == null) {
+ noDice = true;
+ System.err.printf("property \"%s\" is not defined!", it);
+ }
}
+ if (noDice)
+ throw new IllegalStateException("missing required properties for " +
+ "upload");
}
- if (noDice)
- throw new IllegalStateException("missing required properties for " +
- "upload");
}
uploadArchives {
@@ -234,15 +216,15 @@ uploadArchives {
uploadArchives.repositories.mavenDeployer
]*.pom*.whenConfigured { pom ->
pom.project {
- name "${name}";
+ name "${project.name}";
packaging "jar";
- description "${description}";
+ description "${project.ext.description}";
url "${projectURL}";
scm {
- url "${gitrwscm}";
- connection "${gitrwscm}";
- developerConnection "${gitroscm}";
+ url "${scmUrl}";
+ connection "scm:git:${scmUrl}";
+ developerConnection "scm:git:${scmUrl}";
}
licenses {
@@ -260,9 +242,9 @@ uploadArchives {
developers {
developer {
- id "fge";
- name "Francis Galiegue";
- email "fgaliegue@gmail.com";
+ id "huggsboson";
+ name "John Huffaker";
+ email "jhuffaker+java-json-tools@gmail.com";
}
}
}
diff --git a/dorelease.sh b/dorelease.sh
index decafaa51..223917e47 100755
--- a/dorelease.sh
+++ b/dorelease.sh
@@ -1,4 +1,20 @@
#!/bin/bash
+# Release instructions
+# 1. Follow the gpg setup instructions: http://central.sonatype.org/pages/working-with-pgp-signatures.html
+# a. gpg2 --export-secret-keys > ~/.gnupg/secring.gpg
+# 2. In ~/.gradle add:
+# sonatypeUsername=your sonatype user name
+# sonatypePassword=password in vault for oss sonatype
+#
+# signing.keyId=generated key
+# signing.password=password for gpg key
+# signing.secretKeyRingFile=/Users/username/.gnupg/secring.gpg
+#
+# 3. ./dorelease.sh
+# 4. Go to UI at: https://oss.sonatype.org
+# 5. Login as sonatypeUsername
+# 6. Follow the instructions here: http://central.sonatype.org/pages/releasing-the-deployment.html
+
./gradlew --recompile-scripts clean test uploadArchives
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 70597454a..de9128cf2 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,25 +1,6 @@
-#
-# Copyright (c) 2014, Francis Galiegue (fgaliegue@gmail.com)
-#
-# This software is dual-licensed under:
-#
-# - the Lesser General Public License (LGPL) version 3.0 or, at your option, any
-# later version;
-# - the Apache Software License (ASL) version 2.0.
-#
-# The text of this file and of both licenses is available at the root of this
-# project or, if you have the jar distribution, in directory META-INF/, under
-# the names LGPL-3.0.txt and ASL-2.0.txt respectively.
-#
-# Direct link to the sources:
-#
-# - LGPL 3.0: https://www.gnu.org/licenses/lgpl-3.0.txt
-# - ASL 2.0: http://www.apache.org/licenses/LICENSE-2.0.txt
-#
-
-#Mon Apr 14 09:45:58 CEST 2014
+#Fri Jun 02 16:48:25 PDT 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=http\://services.gradle.org/distributions/gradle-1.11-all.zip
+distributionUrl=http\://services.gradle.org/distributions/gradle-3.5-all.zip
From 7782e512b25717b4f7ec5259fdf89a4462758269 Mon Sep 17 00:00:00 2001
From: huggsboson
Date: Fri, 2 Jun 2017 17:19:28 -0700
Subject: [PATCH 23/71] Update README.md
---
README.md | 21 ++++++++-------------
1 file changed, 8 insertions(+), 13 deletions(-)
diff --git a/README.md b/README.md
index f6f05fddb..2422c79bd 100644
--- a/README.md
+++ b/README.md
@@ -1,13 +1,7 @@
[![License LGPLv3][LGPLv3 badge]][LGPLv3]
[![License ASL 2.0][ASL 2.0 badge]][ASL 2.0]
[![Build Status][Travis badge]][Travis]
-
-
-## Travis builds now enabled
-
-Builds are now verified by Travis (see [issue #20](https://github.com/java-json-tools/json-patch/issues/20) from the json-patch project for details)
-
-https://travis-ci.org/java-json-tools/json-schema-validator
+
## Read me first
@@ -16,7 +10,7 @@ The **current** version of this project is licensed under both [LGPLv3] (or late
**Version 2.2 is out**. See [here](https://github.com/java-json-tools/json-schema-validator/wiki/Whatsnew_22)
for the list of changes compared to 2.0. And of course, it still has [all the
-features](https://github.com/daveclayton/json-schema-validator/wiki/Features) of older versions.
+features](https://github.com/java-json-tools/json-schema-validator/wiki/Features) of older versions.
## What this is
@@ -63,7 +57,7 @@ Gradle:
```groovy
dependencies {
- compile(group: "com.github.fge", name: "json-schema-validator", version: "yourVersionHere");
+ compile(group: "com.github.java-json-tools", name: "json-schema-validator", version: "2.2.8");
}
```
@@ -71,13 +65,14 @@ Maven:
```xml
- com.github.fge
+ com.github.java-json-tools
json-schema-validator
- your-version-here
+ 2.2.8
```
### "Full" jar; command line
+OUTDATED: Let me know if you need this in the issues section.
This jar contains the library plus all its dependencies. Download the **lib** jar (a little more
than 6 MiB) from [Bintray](https://bintray.com/fge/maven/json-schema-validator/view).
@@ -114,5 +109,5 @@ details.
[LGPLv3]: http://www.gnu.org/licenses/lgpl-3.0.html
[ASL 2.0 badge]: https://img.shields.io/:license-Apache%202.0-blue.svg
[ASL 2.0]: http://www.apache.org/licenses/LICENSE-2.0.html
-[Travis Badge]: https://api.travis-ci.org/daveclayton/json-schema-validator.svg?branch=master
-[Travis]: https://travis-ci.org/daveclayton/json-schema-validator
+[Travis Badge]: https://api.travis-ci.org/java-json-tools/json-schema-validator.svg?branch=master
+[Travis]: https://travis-ci.org/java-json-tools/json-schema-validator
From c2ad15d0bdcdd620e01999269e919f2a2dca215b Mon Sep 17 00:00:00 2001
From: John Huffaker
Date: Fri, 2 Jun 2017 17:23:16 -0700
Subject: [PATCH 24/71] Release 2.2.8
---
build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/build.gradle b/build.gradle
index 1f7b331fa..7093e6645 100644
--- a/build.gradle
+++ b/build.gradle
@@ -25,7 +25,7 @@ apply(plugin: "idea");
apply(plugin: "eclipse");
group = "com.github.java-json-tools";
-version = "2.2.7";
+version = "2.2.8";
sourceCompatibility = "1.6";
targetCompatibility = "1.6"; // defaults to sourceCompatibility
From 01d2d6488480008e899506f261f5fe467f276257 Mon Sep 17 00:00:00 2001
From: Tuan Dinh
Date: Sun, 11 Jun 2017 22:51:49 +1000
Subject: [PATCH 25/71] Use a stricter date-time attribute formatter(rfc3339)
---
.../common/RFC3339DateTimeAttribute.java | 68 ++++++++++++++++
.../CommonFormatAttributesDictionary.java | 4 +-
.../resources/format/common/date-time.json | 77 +++++++++++++++++--
3 files changed, 141 insertions(+), 8 deletions(-)
create mode 100644 src/main/java/com/github/fge/jsonschema/format/common/RFC3339DateTimeAttribute.java
diff --git a/src/main/java/com/github/fge/jsonschema/format/common/RFC3339DateTimeAttribute.java b/src/main/java/com/github/fge/jsonschema/format/common/RFC3339DateTimeAttribute.java
new file mode 100644
index 000000000..7e659b436
--- /dev/null
+++ b/src/main/java/com/github/fge/jsonschema/format/common/RFC3339DateTimeAttribute.java
@@ -0,0 +1,68 @@
+package com.github.fge.jsonschema.format.common;
+
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeFormatterBuilder;
+import java.time.format.DateTimeParseException;
+import java.time.temporal.ChronoField;
+import java.util.List;
+
+import com.github.fge.jackson.NodeType;
+import com.github.fge.jsonschema.core.exceptions.ProcessingException;
+import com.github.fge.jsonschema.core.report.ProcessingReport;
+import com.github.fge.jsonschema.format.AbstractFormatAttribute;
+import com.github.fge.jsonschema.format.FormatAttribute;
+import com.github.fge.jsonschema.processors.data.FullData;
+import com.github.fge.msgsimple.bundle.MessageBundle;
+import com.google.common.collect.ImmutableList;
+
+/**
+ * A {@link DateTimeFormatter} for date and time format defined in RFC3339.
+ * @see RFC 3339 - Section 5.6
+ */
+public class RFC3339DateTimeAttribute extends AbstractFormatAttribute {
+
+ private static final List RFC3339_FORMATS = ImmutableList.of(
+ "yyyy-MM-dd'T'HH:mm:ss((+|-)HH:mm|Z)", "yyyy-MM-dd'T'HH:mm:ss.[0-9]{1,9}((+|-)HH:mm|Z)"
+ );
+
+ private static final DateTimeFormatter RFC3339_FORMATTER;
+
+ static {
+ final DateTimeFormatterBuilder builder = new DateTimeFormatterBuilder()
+ .appendPattern("yyyy-MM-dd")
+ .appendLiteral('T')
+ .appendPattern("HH:mm:ss")
+ .optionalStart()
+ .appendFraction(ChronoField.NANO_OF_SECOND, 0, 9, true).parseDefaulting(ChronoField.NANO_OF_SECOND, 0)
+ .optionalEnd()
+ .appendOffset("+HH:mm", "Z");
+ RFC3339_FORMATTER = builder.toFormatter();
+ }
+
+ private static final FormatAttribute INSTANCE = new RFC3339DateTimeAttribute();
+
+ public static FormatAttribute getInstance()
+ {
+ return INSTANCE;
+ }
+
+ private RFC3339DateTimeAttribute()
+ {
+ super("date-time", NodeType.STRING);
+ }
+
+ @Override
+ public void validate(final ProcessingReport report,
+ final MessageBundle bundle, final FullData data)
+ throws ProcessingException
+ {
+ final String value = data.getInstance().getNode().textValue();
+
+ try {
+ RFC3339_FORMATTER.parse(value);
+ } catch (DateTimeParseException ignored) {
+ report.error(newMsg(data, bundle, "err.format.invalidDate")
+ .putArgument("value", value).putArgument("expected", RFC3339_FORMATS));
+ }
+ }
+}
diff --git a/src/main/java/com/github/fge/jsonschema/library/format/CommonFormatAttributesDictionary.java b/src/main/java/com/github/fge/jsonschema/library/format/CommonFormatAttributesDictionary.java
index 919758bf9..97e9d884b 100644
--- a/src/main/java/com/github/fge/jsonschema/library/format/CommonFormatAttributesDictionary.java
+++ b/src/main/java/com/github/fge/jsonschema/library/format/CommonFormatAttributesDictionary.java
@@ -22,9 +22,9 @@
import com.github.fge.jsonschema.core.util.Dictionary;
import com.github.fge.jsonschema.core.util.DictionaryBuilder;
import com.github.fge.jsonschema.format.FormatAttribute;
-import com.github.fge.jsonschema.format.common.DateTimeAttribute;
import com.github.fge.jsonschema.format.common.EmailAttribute;
import com.github.fge.jsonschema.format.common.IPv6Attribute;
+import com.github.fge.jsonschema.format.common.RFC3339DateTimeAttribute;
import com.github.fge.jsonschema.format.common.RegexAttribute;
import com.github.fge.jsonschema.format.common.URIAttribute;
@@ -49,7 +49,7 @@ private CommonFormatAttributesDictionary()
FormatAttribute attribute;
name = "date-time";
- attribute = DateTimeAttribute.getInstance();
+ attribute = RFC3339DateTimeAttribute.getInstance();
builder.addEntry(name, attribute);
name = "email";
diff --git a/src/test/resources/format/common/date-time.json b/src/test/resources/format/common/date-time.json
index f79dcc701..7b755a5ab 100644
--- a/src/test/resources/format/common/date-time.json
+++ b/src/test/resources/format/common/date-time.json
@@ -1,6 +1,6 @@
[
{
- "data": "2012-12-02T13:05:00+0100",
+ "data": "2012-12-02T13:05:00+01:00",
"valid": true
},
{
@@ -19,13 +19,60 @@
"data": "2012-08-07T20:42:32.13Z",
"valid": true
},
+ {
+ "data": "2012-08-07T20:42:32+10:00",
+ "valid": true
+ },
+ {
+ "data": "2012-08-07T20:42:32-05:30",
+ "valid": true
+ },
+ {
+ "data": "2012-12-02T13:05:00+0100",
+ "valid": false,
+ "message": "err.format.invalidDate",
+ "msgData": {
+ "value": "2012-12-02T13:05:00+0100",
+ "expected": [ "yyyy-MM-dd'T'HH:mm:ss((+|-)HH:mm|Z)", "yyyy-MM-dd'T'HH:mm:ss.[0-9]{1,9}((+|-)HH:mm|Z)" ]
+ },
+ "msgParams": [ "value", "expected" ]
+ },
+ {
+ "data": "2012-12-02T13:05:00+0100",
+ "valid": false,
+ "message": "err.format.invalidDate",
+ "msgData": {
+ "value": "2012-12-02T13:05:00+0100",
+ "expected": [ "yyyy-MM-dd'T'HH:mm:ss((+|-)HH:mm|Z)", "yyyy-MM-dd'T'HH:mm:ss.[0-9]{1,9}((+|-)HH:mm|Z)" ]
+ },
+ "msgParams": [ "value", "expected" ]
+ },
+ {
+ "data": "2012-12-02T13:05:00Z[Europe/Paris]",
+ "valid": false,
+ "message": "err.format.invalidDate",
+ "msgData": {
+ "value": "2012-12-02T13:05:00Z[Europe/Paris]",
+ "expected": [ "yyyy-MM-dd'T'HH:mm:ss((+|-)HH:mm|Z)", "yyyy-MM-dd'T'HH:mm:ss.[0-9]{1,9}((+|-)HH:mm|Z)" ]
+ },
+ "msgParams": [ "value", "expected" ]
+ }, {
+ "data": "2012-12-02T13:05:00+0100",
+ "valid": false,
+ "message": "err.format.invalidDate",
+ "msgData": {
+ "value": "2012-12-02T13:05:00+0100",
+ "expected": [ "yyyy-MM-dd'T'HH:mm:ss((+|-)HH:mm|Z)", "yyyy-MM-dd'T'HH:mm:ss.[0-9]{1,9}((+|-)HH:mm|Z)" ]
+ },
+ "msgParams": [ "value", "expected" ]
+ },
{
"data": "2012-02-30T00:00:00+0000",
"valid": false,
"message": "err.format.invalidDate",
"msgData": {
"value": "2012-02-30T00:00:00+0000",
- "expected": [ "yyyy-MM-dd'T'HH:mm:ssZ", "yyyy-MM-dd'T'HH:mm:ss.[0-9]{1,12}Z" ]
+ "expected": [ "yyyy-MM-dd'T'HH:mm:ss((+|-)HH:mm|Z)", "yyyy-MM-dd'T'HH:mm:ss.[0-9]{1,9}((+|-)HH:mm|Z)" ]
},
"msgParams": [ "value", "expected" ]
},
@@ -35,7 +82,7 @@
"message": "err.format.invalidDate",
"msgData": {
"value": "201202030",
- "expected": [ "yyyy-MM-dd'T'HH:mm:ssZ", "yyyy-MM-dd'T'HH:mm:ss.[0-9]{1,12}Z" ]
+ "expected": [ "yyyy-MM-dd'T'HH:mm:ss((+|-)HH:mm|Z)", "yyyy-MM-dd'T'HH:mm:ss.[0-9]{1,9}((+|-)HH:mm|Z)" ]
},
"msgParams": [ "value", "expected" ]
},
@@ -69,14 +116,32 @@
},
{
"data": "2012-08-07T20:42:32.1234567890Z",
- "valid": true
+ "valid": false,
+ "message": "err.format.invalidDate",
+ "msgData": {
+ "value": "2012-08-07T20:42:32.1234567890Z",
+ "expected": [ "yyyy-MM-dd'T'HH:mm:ss((+|-)HH:mm|Z)", "yyyy-MM-dd'T'HH:mm:ss.[0-9]{1,9}((+|-)HH:mm|Z)" ]
+ },
+ "msgParams": [ "value", "expected" ]
},
{
"data": "2012-08-07T20:42:32.12345678901Z",
- "valid": true
+ "valid": false,
+ "message": "err.format.invalidDate",
+ "msgData": {
+ "value": "2012-08-07T20:42:32.12345678901Z",
+ "expected": [ "yyyy-MM-dd'T'HH:mm:ss((+|-)HH:mm|Z)", "yyyy-MM-dd'T'HH:mm:ss.[0-9]{1,9}((+|-)HH:mm|Z)" ]
+ },
+ "msgParams": [ "value", "expected" ]
},
{
"data": "2012-08-07T20:42:32.123456789012Z",
- "valid": true
+ "valid": false,
+ "message": "err.format.invalidDate",
+ "msgData": {
+ "value": "2012-08-07T20:42:32.123456789012Z",
+ "expected": [ "yyyy-MM-dd'T'HH:mm:ss((+|-)HH:mm|Z)", "yyyy-MM-dd'T'HH:mm:ss.[0-9]{1,9}((+|-)HH:mm|Z)" ]
+ },
+ "msgParams": [ "value", "expected" ]
}
]
From d273e06cc4e604ceb833dc6fae9c8123fb155c1d Mon Sep 17 00:00:00 2001
From: Tuan Dinh
Date: Wed, 14 Jun 2017 23:26:43 +1000
Subject: [PATCH 26/71] Used joda-time lib for RFC3339DateTimeAttribute. Added
more unit tests
---
.../common/RFC3339DateTimeAttribute.java | 80 ++++++++++++-----
.../resources/format/common/date-time.json | 89 ++++++++++---------
2 files changed, 108 insertions(+), 61 deletions(-)
diff --git a/src/main/java/com/github/fge/jsonschema/format/common/RFC3339DateTimeAttribute.java b/src/main/java/com/github/fge/jsonschema/format/common/RFC3339DateTimeAttribute.java
index 7e659b436..18e73f035 100644
--- a/src/main/java/com/github/fge/jsonschema/format/common/RFC3339DateTimeAttribute.java
+++ b/src/main/java/com/github/fge/jsonschema/format/common/RFC3339DateTimeAttribute.java
@@ -1,11 +1,11 @@
package com.github.fge.jsonschema.format.common;
-import java.time.format.DateTimeFormatter;
-import java.time.format.DateTimeFormatterBuilder;
-import java.time.format.DateTimeParseException;
-import java.time.temporal.ChronoField;
import java.util.List;
+import org.joda.time.format.DateTimeFormatter;
+import org.joda.time.format.DateTimeFormatterBuilder;
+import org.joda.time.format.DateTimeParser;
+
import com.github.fge.jackson.NodeType;
import com.github.fge.jsonschema.core.exceptions.ProcessingException;
import com.github.fge.jsonschema.core.report.ProcessingReport;
@@ -22,21 +22,22 @@
public class RFC3339DateTimeAttribute extends AbstractFormatAttribute {
private static final List RFC3339_FORMATS = ImmutableList.of(
- "yyyy-MM-dd'T'HH:mm:ss((+|-)HH:mm|Z)", "yyyy-MM-dd'T'HH:mm:ss.[0-9]{1,9}((+|-)HH:mm|Z)"
+ "yyyy-MM-dd'T'HH:mm:ss((+|-)HH:mm|Z)", "yyyy-MM-dd'T'HH:mm:ss.[0-9]{1,12}((+|-)HH:mm|Z)"
);
- private static final DateTimeFormatter RFC3339_FORMATTER;
+ private static final DateTimeFormatter FORMATTER;
static {
- final DateTimeFormatterBuilder builder = new DateTimeFormatterBuilder()
- .appendPattern("yyyy-MM-dd")
- .appendLiteral('T')
- .appendPattern("HH:mm:ss")
- .optionalStart()
- .appendFraction(ChronoField.NANO_OF_SECOND, 0, 9, true).parseDefaulting(ChronoField.NANO_OF_SECOND, 0)
- .optionalEnd()
- .appendOffset("+HH:mm", "Z");
- RFC3339_FORMATTER = builder.toFormatter();
+ final DateTimeParser secFracsParser = new DateTimeFormatterBuilder()
+ .appendLiteral('.').appendFractionOfSecond(1,12)
+ .toParser();
+
+ DateTimeFormatterBuilder builder = new DateTimeFormatterBuilder()
+ .appendPattern("yyyy-MM-dd'T'HH:mm:ss")
+ .appendOptional(secFracsParser)
+ .appendTimeZoneOffset("Z", true, 2, 2);
+
+ FORMATTER = builder.toFormatter();
}
private static final FormatAttribute INSTANCE = new RFC3339DateTimeAttribute();
@@ -58,11 +59,50 @@ public void validate(final ProcessingReport report,
{
final String value = data.getInstance().getNode().textValue();
- try {
- RFC3339_FORMATTER.parse(value);
- } catch (DateTimeParseException ignored) {
- report.error(newMsg(data, bundle, "err.format.invalidDate")
- .putArgument("value", value).putArgument("expected", RFC3339_FORMATS));
+ try
+ {
+ FORMATTER.parseDateTime(value);
+
+ final String secFracsAndOffset = value.substring("yyyy-MM-ddTHH:mm:ss".length());
+ final String offset;
+ if (!secFracsAndOffset.startsWith(".")) {
+ offset = secFracsAndOffset;
+ } else{
+ if (secFracsAndOffset.contains("Z")) {
+ offset = secFracsAndOffset.substring(secFracsAndOffset.indexOf("Z"));
+ } else if (secFracsAndOffset.contains("+")) {
+ offset = secFracsAndOffset.substring(secFracsAndOffset.indexOf("+"));
+ } else {
+ offset = secFracsAndOffset.substring(secFracsAndOffset.indexOf("-"));
+ }
+ }
+ if (!isOffSetStrictRFC3339(offset)) {
+ throw new IllegalArgumentException();
+ }
+
+ } catch (IllegalArgumentException ignored) {
+ report.error(newMsg(data, bundle, "err.format.invalidDate")
+ .putArgument("value", value).putArgument("expected", RFC3339_FORMATS));
}
+
}
+
+ /**
+ * Return true if date-time offset stricly follows RFC3339:
+ * time-hour = 2DIGIT ; 00-23
+ * time-minute = 2DIGIT ; 00-59
+ * time-numoffset = ("+" / "-") time-hour ":" time-minute
+ * time-offset = "Z" / time-numoffset,
+ * and false otherwise
+ * @param offset
+ * @return
+ */
+ private boolean isOffSetStrictRFC3339(final String offset)
+ {
+ if (offset.endsWith("Z")) return true;
+ if (offset.length() == 6 && offset.contains(":")) {
+ return true;
+ }
+ return false;
+ }
}
diff --git a/src/test/resources/format/common/date-time.json b/src/test/resources/format/common/date-time.json
index 7b755a5ab..1ee20602d 100644
--- a/src/test/resources/format/common/date-time.json
+++ b/src/test/resources/format/common/date-time.json
@@ -26,14 +26,14 @@
{
"data": "2012-08-07T20:42:32-05:30",
"valid": true
- },
+ },
{
- "data": "2012-12-02T13:05:00+0100",
+ "data": "201202030",
"valid": false,
"message": "err.format.invalidDate",
"msgData": {
- "value": "2012-12-02T13:05:00+0100",
- "expected": [ "yyyy-MM-dd'T'HH:mm:ss((+|-)HH:mm|Z)", "yyyy-MM-dd'T'HH:mm:ss.[0-9]{1,9}((+|-)HH:mm|Z)" ]
+ "value": "201202030",
+ "expected": [ "yyyy-MM-dd'T'HH:mm:ss((+|-)HH:mm|Z)", "yyyy-MM-dd'T'HH:mm:ss.[0-9]{1,12}((+|-)HH:mm|Z)" ]
},
"msgParams": [ "value", "expected" ]
},
@@ -43,7 +43,17 @@
"message": "err.format.invalidDate",
"msgData": {
"value": "2012-12-02T13:05:00+0100",
- "expected": [ "yyyy-MM-dd'T'HH:mm:ss((+|-)HH:mm|Z)", "yyyy-MM-dd'T'HH:mm:ss.[0-9]{1,9}((+|-)HH:mm|Z)" ]
+ "expected": [ "yyyy-MM-dd'T'HH:mm:ss((+|-)HH:mm|Z)", "yyyy-MM-dd'T'HH:mm:ss.[0-9]{1,12}((+|-)HH:mm|Z)" ]
+ },
+ "msgParams": [ "value", "expected" ]
+ },
+ {
+ "data": "2012-12-02T13:05:00+01:30:30",
+ "valid": false,
+ "message": "err.format.invalidDate",
+ "msgData": {
+ "value": "2012-12-02T13:05:00+01:30:30",
+ "expected": [ "yyyy-MM-dd'T'HH:mm:ss((+|-)HH:mm|Z)", "yyyy-MM-dd'T'HH:mm:ss.[0-9]{1,12}((+|-)HH:mm|Z)" ]
},
"msgParams": [ "value", "expected" ]
},
@@ -53,36 +63,47 @@
"message": "err.format.invalidDate",
"msgData": {
"value": "2012-12-02T13:05:00Z[Europe/Paris]",
- "expected": [ "yyyy-MM-dd'T'HH:mm:ss((+|-)HH:mm|Z)", "yyyy-MM-dd'T'HH:mm:ss.[0-9]{1,9}((+|-)HH:mm|Z)" ]
+ "expected": [ "yyyy-MM-dd'T'HH:mm:ss((+|-)HH:mm|Z)", "yyyy-MM-dd'T'HH:mm:ss.[0-9]{1,12}((+|-)HH:mm|Z)" ]
},
"msgParams": [ "value", "expected" ]
- }, {
- "data": "2012-12-02T13:05:00+0100",
+ },
+ {
+ "data": "2012-12-02T13:05:00+10:00Z",
"valid": false,
"message": "err.format.invalidDate",
"msgData": {
- "value": "2012-12-02T13:05:00+0100",
- "expected": [ "yyyy-MM-dd'T'HH:mm:ss((+|-)HH:mm|Z)", "yyyy-MM-dd'T'HH:mm:ss.[0-9]{1,9}((+|-)HH:mm|Z)" ]
+ "value": "2012-12-02T13:05:00+10:00Z",
+ "expected": [ "yyyy-MM-dd'T'HH:mm:ss((+|-)HH:mm|Z)", "yyyy-MM-dd'T'HH:mm:ss.[0-9]{1,12}((+|-)HH:mm|Z)" ]
},
"msgParams": [ "value", "expected" ]
},
{
- "data": "2012-02-30T00:00:00+0000",
+ "data": "2012-12-02T13:05:00America/New_York",
"valid": false,
"message": "err.format.invalidDate",
"msgData": {
- "value": "2012-02-30T00:00:00+0000",
- "expected": [ "yyyy-MM-dd'T'HH:mm:ss((+|-)HH:mm|Z)", "yyyy-MM-dd'T'HH:mm:ss.[0-9]{1,9}((+|-)HH:mm|Z)" ]
+ "value": "2012-12-02T13:05:00America/New_York",
+ "expected": [ "yyyy-MM-dd'T'HH:mm:ss((+|-)HH:mm|Z)", "yyyy-MM-dd'T'HH:mm:ss.[0-9]{1,12}((+|-)HH:mm|Z)" ]
},
"msgParams": [ "value", "expected" ]
},
{
- "data": "201202030",
+ "data": "2012-12-02T13:05:00[America/New_York]",
"valid": false,
"message": "err.format.invalidDate",
"msgData": {
- "value": "201202030",
- "expected": [ "yyyy-MM-dd'T'HH:mm:ss((+|-)HH:mm|Z)", "yyyy-MM-dd'T'HH:mm:ss.[0-9]{1,9}((+|-)HH:mm|Z)" ]
+ "value": "2012-12-02T13:05:00[America/New_York]",
+ "expected": [ "yyyy-MM-dd'T'HH:mm:ss((+|-)HH:mm|Z)", "yyyy-MM-dd'T'HH:mm:ss.[0-9]{1,12}((+|-)HH:mm|Z)" ]
+ },
+ "msgParams": [ "value", "expected" ]
+ },
+ {
+ "data": "2012-12-02T13:05:00.123456",
+ "valid": false,
+ "message": "err.format.invalidDate",
+ "msgData": {
+ "value": "2012-12-02T13:05:00.123456",
+ "expected": [ "yyyy-MM-dd'T'HH:mm:ss((+|-)HH:mm|Z)", "yyyy-MM-dd'T'HH:mm:ss.[0-9]{1,12}((+|-)HH:mm|Z)" ]
},
"msgParams": [ "value", "expected" ]
},
@@ -91,19 +112,19 @@
"valid": true
},
{
- "data": "2012-08-07T20:42:32.12345Z",
+ "data": "2012-08-07T20:42:32.1234+05:00",
"valid": true
},
{
- "data": "2012-08-07T20:42:32.123456Z",
+ "data": "2012-08-07T20:42:32.12345Z",
"valid": true
},
{
- "data": "2012-08-07T20:42:32.1234567Z",
+ "data": "2012-08-07T20:42:32.123456Z",
"valid": true
},
{
- "data": "2012-08-07T20:42:32.12345678Z",
+ "data": "2012-08-07T20:42:32.1234567Z",
"valid": true
},
{
@@ -116,32 +137,18 @@
},
{
"data": "2012-08-07T20:42:32.1234567890Z",
- "valid": false,
- "message": "err.format.invalidDate",
- "msgData": {
- "value": "2012-08-07T20:42:32.1234567890Z",
- "expected": [ "yyyy-MM-dd'T'HH:mm:ss((+|-)HH:mm|Z)", "yyyy-MM-dd'T'HH:mm:ss.[0-9]{1,9}((+|-)HH:mm|Z)" ]
- },
- "msgParams": [ "value", "expected" ]
+ "valid": true
},
{
"data": "2012-08-07T20:42:32.12345678901Z",
- "valid": false,
- "message": "err.format.invalidDate",
- "msgData": {
- "value": "2012-08-07T20:42:32.12345678901Z",
- "expected": [ "yyyy-MM-dd'T'HH:mm:ss((+|-)HH:mm|Z)", "yyyy-MM-dd'T'HH:mm:ss.[0-9]{1,9}((+|-)HH:mm|Z)" ]
- },
- "msgParams": [ "value", "expected" ]
+ "valid": true
},
{
"data": "2012-08-07T20:42:32.123456789012Z",
- "valid": false,
- "message": "err.format.invalidDate",
- "msgData": {
- "value": "2012-08-07T20:42:32.123456789012Z",
- "expected": [ "yyyy-MM-dd'T'HH:mm:ss((+|-)HH:mm|Z)", "yyyy-MM-dd'T'HH:mm:ss.[0-9]{1,9}((+|-)HH:mm|Z)" ]
- },
- "msgParams": [ "value", "expected" ]
+ "valid": true
+ },
+ {
+ "data": "2012-08-07T20:42:32.123456789012+05:00",
+ "valid": true
}
]
From 70ae8c09650faccd685441bd6e984ddf380ea3d5 Mon Sep 17 00:00:00 2001
From: Joshua Ali
Date: Tue, 24 Apr 2018 11:52:03 +1000
Subject: [PATCH 27/71] Support email address formats from RFC 6531
---
build.gradle | 2 +-
src/test/resources/format/common/email.json | 7 +------
2 files changed, 2 insertions(+), 7 deletions(-)
diff --git a/build.gradle b/build.gradle
index 7093e6645..42c67baf5 100644
--- a/build.gradle
+++ b/build.gradle
@@ -41,7 +41,7 @@ repositories {
*/
dependencies {
compile(group: "com.github.java-json-tools", name: "json-schema-core", version: "1.2.8");
- compile(group: "javax.mail", name: "mailapi", version: "1.4.3");
+ compile(group: "com.sun.mail", name: "mailapi", version: "1.6.1");
compile(group: "joda-time", name: "joda-time", version: "2.9.7");
compile(group: "com.googlecode.libphonenumber", name: "libphonenumber", version: "8.0.0");
compile(group: "com.google.code.findbugs", name: "jsr305", version: "3.0.1");
diff --git a/src/test/resources/format/common/email.json b/src/test/resources/format/common/email.json
index 452e548aa..669b42c08 100644
--- a/src/test/resources/format/common/email.json
+++ b/src/test/resources/format/common/email.json
@@ -14,12 +14,7 @@
},
{
"data": "éioaj@my.name",
- "valid": false,
- "message": "err.format.invalidEmail",
- "msgData": {
- "value": "éioaj@my.name"
- },
- "msgParams": [ "value" ]
+ "valid": true
},
{
"data": "a@",
From 3c0b7bbb4dcd2459d1020c41329c3d45e528c75f Mon Sep 17 00:00:00 2001
From: John Huffaker
Date: Fri, 11 May 2018 21:38:26 -0700
Subject: [PATCH 28/71] Set version to 2.2.10-SNAPSHOT
---
build.gradle | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/build.gradle b/build.gradle
index 7093e6645..46fbe230e 100644
--- a/build.gradle
+++ b/build.gradle
@@ -25,7 +25,7 @@ apply(plugin: "idea");
apply(plugin: "eclipse");
group = "com.github.java-json-tools";
-version = "2.2.8";
+version = "2.2.10-SNAPSHOT";
sourceCompatibility = "1.6";
targetCompatibility = "1.6"; // defaults to sourceCompatibility
@@ -40,7 +40,7 @@ repositories {
* List of dependencies
*/
dependencies {
- compile(group: "com.github.java-json-tools", name: "json-schema-core", version: "1.2.8");
+ compile(group: "com.github.java-json-tools", name: "json-schema-core", version: "1.2.9");
compile(group: "javax.mail", name: "mailapi", version: "1.4.3");
compile(group: "joda-time", name: "joda-time", version: "2.9.7");
compile(group: "com.googlecode.libphonenumber", name: "libphonenumber", version: "8.0.0");
From 0992fe13bc1b788480bdd4fa1a4f652299970b49 Mon Sep 17 00:00:00 2001
From: John Huffaker
Date: Tue, 15 May 2018 14:25:52 -0700
Subject: [PATCH 29/71] Roll back to old date time validator (#262)
Allow people to still use the new formatter via the mechanism described
in example 8.
fixes #261
---
.../common/RFC3339DateTimeAttribute.java | 9 +
.../CommonFormatAttributesDictionary.java | 4 +-
.../format/rfc3339/DateTimeTest.java | 45 +++++
.../resources/format/common/date-time.json | 94 ++---------
.../resources/format/rfc3339/date-time.json | 154 ++++++++++++++++++
5 files changed, 221 insertions(+), 85 deletions(-)
create mode 100644 src/test/java/com/github/fge/jsonschema/format/rfc3339/DateTimeTest.java
create mode 100644 src/test/resources/format/rfc3339/date-time.json
diff --git a/src/main/java/com/github/fge/jsonschema/format/common/RFC3339DateTimeAttribute.java b/src/main/java/com/github/fge/jsonschema/format/common/RFC3339DateTimeAttribute.java
index 18e73f035..b8a0fbe4c 100644
--- a/src/main/java/com/github/fge/jsonschema/format/common/RFC3339DateTimeAttribute.java
+++ b/src/main/java/com/github/fge/jsonschema/format/common/RFC3339DateTimeAttribute.java
@@ -2,6 +2,8 @@
import java.util.List;
+import com.github.fge.jsonschema.cfg.ValidationConfiguration;
+import com.github.fge.jsonschema.library.DraftV4Library;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.DateTimeFormatterBuilder;
import org.joda.time.format.DateTimeParser;
@@ -18,6 +20,13 @@
/**
* A {@link DateTimeFormatter} for date and time format defined in RFC3339.
* @see RFC 3339 - Section 5.6
+ *
+ * This is backwards incompat with the original DateTimeAttribute. It will become the default in the future
+ * to use it currently you need to:
+ * Library library = DraftV4Library.get().thaw()
+ * .addFormatAttribute("date-time", RFC3339DateTimeAttribute.getInstance())
+ * .freeze();
+ * Then follow the rest of the steps in example 8 to hook it into your flow.
*/
public class RFC3339DateTimeAttribute extends AbstractFormatAttribute {
diff --git a/src/main/java/com/github/fge/jsonschema/library/format/CommonFormatAttributesDictionary.java b/src/main/java/com/github/fge/jsonschema/library/format/CommonFormatAttributesDictionary.java
index 97e9d884b..919758bf9 100644
--- a/src/main/java/com/github/fge/jsonschema/library/format/CommonFormatAttributesDictionary.java
+++ b/src/main/java/com/github/fge/jsonschema/library/format/CommonFormatAttributesDictionary.java
@@ -22,9 +22,9 @@
import com.github.fge.jsonschema.core.util.Dictionary;
import com.github.fge.jsonschema.core.util.DictionaryBuilder;
import com.github.fge.jsonschema.format.FormatAttribute;
+import com.github.fge.jsonschema.format.common.DateTimeAttribute;
import com.github.fge.jsonschema.format.common.EmailAttribute;
import com.github.fge.jsonschema.format.common.IPv6Attribute;
-import com.github.fge.jsonschema.format.common.RFC3339DateTimeAttribute;
import com.github.fge.jsonschema.format.common.RegexAttribute;
import com.github.fge.jsonschema.format.common.URIAttribute;
@@ -49,7 +49,7 @@ private CommonFormatAttributesDictionary()
FormatAttribute attribute;
name = "date-time";
- attribute = RFC3339DateTimeAttribute.getInstance();
+ attribute = DateTimeAttribute.getInstance();
builder.addEntry(name, attribute);
name = "email";
diff --git a/src/test/java/com/github/fge/jsonschema/format/rfc3339/DateTimeTest.java b/src/test/java/com/github/fge/jsonschema/format/rfc3339/DateTimeTest.java
new file mode 100644
index 000000000..d871bc6b4
--- /dev/null
+++ b/src/test/java/com/github/fge/jsonschema/format/rfc3339/DateTimeTest.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2014, Francis Galiegue (fgaliegue@gmail.com)
+ *
+ * This software is dual-licensed under:
+ *
+ * - the Lesser General Public License (LGPL) version 3.0 or, at your option, any
+ * later version;
+ * - the Apache Software License (ASL) version 2.0.
+ *
+ * The text of this file and of both licenses is available at the root of this
+ * project or, if you have the jar distribution, in directory META-INF/, under
+ * the names LGPL-3.0.txt and ASL-2.0.txt respectively.
+ *
+ * Direct link to the sources:
+ *
+ * - LGPL 3.0: https://www.gnu.org/licenses/lgpl-3.0.txt
+ * - ASL 2.0: http://www.apache.org/licenses/LICENSE-2.0.txt
+ */
+
+package com.github.fge.jsonschema.format.rfc3339;
+
+import com.github.fge.jsonschema.core.util.Dictionary;
+import com.github.fge.jsonschema.core.util.DictionaryBuilder;
+import com.github.fge.jsonschema.format.AbstractFormatAttributeTest;
+import com.github.fge.jsonschema.format.FormatAttribute;
+import com.github.fge.jsonschema.format.common.RFC3339DateTimeAttribute;
+
+import java.io.IOException;
+import java.text.Format;
+
+public final class DateTimeTest
+ extends AbstractFormatAttributeTest
+{
+ private static final Dictionary dict =
+ Dictionary
+ .newBuilder()
+ .addEntry("date-time", RFC3339DateTimeAttribute.getInstance())
+ .freeze();
+
+ public DateTimeTest()
+ throws IOException
+ {
+ super(dict, "rfc3339", "date-time");
+ }
+}
diff --git a/src/test/resources/format/common/date-time.json b/src/test/resources/format/common/date-time.json
index 1ee20602d..f79dcc701 100644
--- a/src/test/resources/format/common/date-time.json
+++ b/src/test/resources/format/common/date-time.json
@@ -1,6 +1,6 @@
[
{
- "data": "2012-12-02T13:05:00+01:00",
+ "data": "2012-12-02T13:05:00+0100",
"valid": true
},
{
@@ -20,90 +20,22 @@
"valid": true
},
{
- "data": "2012-08-07T20:42:32+10:00",
- "valid": true
- },
- {
- "data": "2012-08-07T20:42:32-05:30",
- "valid": true
- },
- {
- "data": "201202030",
- "valid": false,
- "message": "err.format.invalidDate",
- "msgData": {
- "value": "201202030",
- "expected": [ "yyyy-MM-dd'T'HH:mm:ss((+|-)HH:mm|Z)", "yyyy-MM-dd'T'HH:mm:ss.[0-9]{1,12}((+|-)HH:mm|Z)" ]
- },
- "msgParams": [ "value", "expected" ]
- },
- {
- "data": "2012-12-02T13:05:00+0100",
- "valid": false,
- "message": "err.format.invalidDate",
- "msgData": {
- "value": "2012-12-02T13:05:00+0100",
- "expected": [ "yyyy-MM-dd'T'HH:mm:ss((+|-)HH:mm|Z)", "yyyy-MM-dd'T'HH:mm:ss.[0-9]{1,12}((+|-)HH:mm|Z)" ]
- },
- "msgParams": [ "value", "expected" ]
- },
- {
- "data": "2012-12-02T13:05:00+01:30:30",
- "valid": false,
- "message": "err.format.invalidDate",
- "msgData": {
- "value": "2012-12-02T13:05:00+01:30:30",
- "expected": [ "yyyy-MM-dd'T'HH:mm:ss((+|-)HH:mm|Z)", "yyyy-MM-dd'T'HH:mm:ss.[0-9]{1,12}((+|-)HH:mm|Z)" ]
- },
- "msgParams": [ "value", "expected" ]
- },
- {
- "data": "2012-12-02T13:05:00Z[Europe/Paris]",
- "valid": false,
- "message": "err.format.invalidDate",
- "msgData": {
- "value": "2012-12-02T13:05:00Z[Europe/Paris]",
- "expected": [ "yyyy-MM-dd'T'HH:mm:ss((+|-)HH:mm|Z)", "yyyy-MM-dd'T'HH:mm:ss.[0-9]{1,12}((+|-)HH:mm|Z)" ]
- },
- "msgParams": [ "value", "expected" ]
- },
- {
- "data": "2012-12-02T13:05:00+10:00Z",
- "valid": false,
- "message": "err.format.invalidDate",
- "msgData": {
- "value": "2012-12-02T13:05:00+10:00Z",
- "expected": [ "yyyy-MM-dd'T'HH:mm:ss((+|-)HH:mm|Z)", "yyyy-MM-dd'T'HH:mm:ss.[0-9]{1,12}((+|-)HH:mm|Z)" ]
- },
- "msgParams": [ "value", "expected" ]
- },
- {
- "data": "2012-12-02T13:05:00America/New_York",
+ "data": "2012-02-30T00:00:00+0000",
"valid": false,
"message": "err.format.invalidDate",
"msgData": {
- "value": "2012-12-02T13:05:00America/New_York",
- "expected": [ "yyyy-MM-dd'T'HH:mm:ss((+|-)HH:mm|Z)", "yyyy-MM-dd'T'HH:mm:ss.[0-9]{1,12}((+|-)HH:mm|Z)" ]
+ "value": "2012-02-30T00:00:00+0000",
+ "expected": [ "yyyy-MM-dd'T'HH:mm:ssZ", "yyyy-MM-dd'T'HH:mm:ss.[0-9]{1,12}Z" ]
},
"msgParams": [ "value", "expected" ]
},
{
- "data": "2012-12-02T13:05:00[America/New_York]",
- "valid": false,
- "message": "err.format.invalidDate",
- "msgData": {
- "value": "2012-12-02T13:05:00[America/New_York]",
- "expected": [ "yyyy-MM-dd'T'HH:mm:ss((+|-)HH:mm|Z)", "yyyy-MM-dd'T'HH:mm:ss.[0-9]{1,12}((+|-)HH:mm|Z)" ]
- },
- "msgParams": [ "value", "expected" ]
- },
- {
- "data": "2012-12-02T13:05:00.123456",
+ "data": "201202030",
"valid": false,
"message": "err.format.invalidDate",
"msgData": {
- "value": "2012-12-02T13:05:00.123456",
- "expected": [ "yyyy-MM-dd'T'HH:mm:ss((+|-)HH:mm|Z)", "yyyy-MM-dd'T'HH:mm:ss.[0-9]{1,12}((+|-)HH:mm|Z)" ]
+ "value": "201202030",
+ "expected": [ "yyyy-MM-dd'T'HH:mm:ssZ", "yyyy-MM-dd'T'HH:mm:ss.[0-9]{1,12}Z" ]
},
"msgParams": [ "value", "expected" ]
},
@@ -111,10 +43,6 @@
"data": "2012-08-07T20:42:32.1234Z",
"valid": true
},
- {
- "data": "2012-08-07T20:42:32.1234+05:00",
- "valid": true
- },
{
"data": "2012-08-07T20:42:32.12345Z",
"valid": true
@@ -131,6 +59,10 @@
"data": "2012-08-07T20:42:32.12345678Z",
"valid": true
},
+ {
+ "data": "2012-08-07T20:42:32.12345678Z",
+ "valid": true
+ },
{
"data": "2012-08-07T20:42:32.123456789Z",
"valid": true
@@ -146,9 +78,5 @@
{
"data": "2012-08-07T20:42:32.123456789012Z",
"valid": true
- },
- {
- "data": "2012-08-07T20:42:32.123456789012+05:00",
- "valid": true
}
]
diff --git a/src/test/resources/format/rfc3339/date-time.json b/src/test/resources/format/rfc3339/date-time.json
new file mode 100644
index 000000000..1ee20602d
--- /dev/null
+++ b/src/test/resources/format/rfc3339/date-time.json
@@ -0,0 +1,154 @@
+[
+ {
+ "data": "2012-12-02T13:05:00+01:00",
+ "valid": true
+ },
+ {
+ "data": "2001-02-12T00:00:00Z",
+ "valid": true
+ },
+ {
+ "data": "2012-08-07T20:42:32Z",
+ "valid": true
+ },
+ {
+ "data": "2012-08-07T20:42:32.123Z",
+ "valid": true
+ },
+ {
+ "data": "2012-08-07T20:42:32.13Z",
+ "valid": true
+ },
+ {
+ "data": "2012-08-07T20:42:32+10:00",
+ "valid": true
+ },
+ {
+ "data": "2012-08-07T20:42:32-05:30",
+ "valid": true
+ },
+ {
+ "data": "201202030",
+ "valid": false,
+ "message": "err.format.invalidDate",
+ "msgData": {
+ "value": "201202030",
+ "expected": [ "yyyy-MM-dd'T'HH:mm:ss((+|-)HH:mm|Z)", "yyyy-MM-dd'T'HH:mm:ss.[0-9]{1,12}((+|-)HH:mm|Z)" ]
+ },
+ "msgParams": [ "value", "expected" ]
+ },
+ {
+ "data": "2012-12-02T13:05:00+0100",
+ "valid": false,
+ "message": "err.format.invalidDate",
+ "msgData": {
+ "value": "2012-12-02T13:05:00+0100",
+ "expected": [ "yyyy-MM-dd'T'HH:mm:ss((+|-)HH:mm|Z)", "yyyy-MM-dd'T'HH:mm:ss.[0-9]{1,12}((+|-)HH:mm|Z)" ]
+ },
+ "msgParams": [ "value", "expected" ]
+ },
+ {
+ "data": "2012-12-02T13:05:00+01:30:30",
+ "valid": false,
+ "message": "err.format.invalidDate",
+ "msgData": {
+ "value": "2012-12-02T13:05:00+01:30:30",
+ "expected": [ "yyyy-MM-dd'T'HH:mm:ss((+|-)HH:mm|Z)", "yyyy-MM-dd'T'HH:mm:ss.[0-9]{1,12}((+|-)HH:mm|Z)" ]
+ },
+ "msgParams": [ "value", "expected" ]
+ },
+ {
+ "data": "2012-12-02T13:05:00Z[Europe/Paris]",
+ "valid": false,
+ "message": "err.format.invalidDate",
+ "msgData": {
+ "value": "2012-12-02T13:05:00Z[Europe/Paris]",
+ "expected": [ "yyyy-MM-dd'T'HH:mm:ss((+|-)HH:mm|Z)", "yyyy-MM-dd'T'HH:mm:ss.[0-9]{1,12}((+|-)HH:mm|Z)" ]
+ },
+ "msgParams": [ "value", "expected" ]
+ },
+ {
+ "data": "2012-12-02T13:05:00+10:00Z",
+ "valid": false,
+ "message": "err.format.invalidDate",
+ "msgData": {
+ "value": "2012-12-02T13:05:00+10:00Z",
+ "expected": [ "yyyy-MM-dd'T'HH:mm:ss((+|-)HH:mm|Z)", "yyyy-MM-dd'T'HH:mm:ss.[0-9]{1,12}((+|-)HH:mm|Z)" ]
+ },
+ "msgParams": [ "value", "expected" ]
+ },
+ {
+ "data": "2012-12-02T13:05:00America/New_York",
+ "valid": false,
+ "message": "err.format.invalidDate",
+ "msgData": {
+ "value": "2012-12-02T13:05:00America/New_York",
+ "expected": [ "yyyy-MM-dd'T'HH:mm:ss((+|-)HH:mm|Z)", "yyyy-MM-dd'T'HH:mm:ss.[0-9]{1,12}((+|-)HH:mm|Z)" ]
+ },
+ "msgParams": [ "value", "expected" ]
+ },
+ {
+ "data": "2012-12-02T13:05:00[America/New_York]",
+ "valid": false,
+ "message": "err.format.invalidDate",
+ "msgData": {
+ "value": "2012-12-02T13:05:00[America/New_York]",
+ "expected": [ "yyyy-MM-dd'T'HH:mm:ss((+|-)HH:mm|Z)", "yyyy-MM-dd'T'HH:mm:ss.[0-9]{1,12}((+|-)HH:mm|Z)" ]
+ },
+ "msgParams": [ "value", "expected" ]
+ },
+ {
+ "data": "2012-12-02T13:05:00.123456",
+ "valid": false,
+ "message": "err.format.invalidDate",
+ "msgData": {
+ "value": "2012-12-02T13:05:00.123456",
+ "expected": [ "yyyy-MM-dd'T'HH:mm:ss((+|-)HH:mm|Z)", "yyyy-MM-dd'T'HH:mm:ss.[0-9]{1,12}((+|-)HH:mm|Z)" ]
+ },
+ "msgParams": [ "value", "expected" ]
+ },
+ {
+ "data": "2012-08-07T20:42:32.1234Z",
+ "valid": true
+ },
+ {
+ "data": "2012-08-07T20:42:32.1234+05:00",
+ "valid": true
+ },
+ {
+ "data": "2012-08-07T20:42:32.12345Z",
+ "valid": true
+ },
+ {
+ "data": "2012-08-07T20:42:32.123456Z",
+ "valid": true
+ },
+ {
+ "data": "2012-08-07T20:42:32.1234567Z",
+ "valid": true
+ },
+ {
+ "data": "2012-08-07T20:42:32.12345678Z",
+ "valid": true
+ },
+ {
+ "data": "2012-08-07T20:42:32.123456789Z",
+ "valid": true
+ },
+ {
+ "data": "2012-08-07T20:42:32.1234567890Z",
+ "valid": true
+ },
+ {
+ "data": "2012-08-07T20:42:32.12345678901Z",
+ "valid": true
+ },
+ {
+ "data": "2012-08-07T20:42:32.123456789012Z",
+ "valid": true
+ },
+ {
+ "data": "2012-08-07T20:42:32.123456789012+05:00",
+ "valid": true
+ }
+]
From 1b4c46fc0fbb46f3e67c5f78a7b04760eb92c9f3 Mon Sep 17 00:00:00 2001
From: John Huffaker
Date: Tue, 15 May 2018 20:51:25 -0700
Subject: [PATCH 30/71] Update README.md
---
README.md | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/README.md b/README.md
index 2422c79bd..83fd13c79 100644
--- a/README.md
+++ b/README.md
@@ -38,7 +38,7 @@ run by yourself.
## Versions
-* current stable version: **2.2.6**
+* current stable version: **2.2.10**
([ChangeLog](https://github.com/java-json-tools/json-schema-validator/wiki/ChangeLog_22x),
[Javadoc](http://java-json-tools.github.io/json-schema-validator/2.2.x/index.html), [code
samples](http://java-json-tools.github.io/json-schema-validator/2.2.x/index.html?com/github/fge/jsonschema/examples/package-summary.html)).
@@ -57,7 +57,7 @@ Gradle:
```groovy
dependencies {
- compile(group: "com.github.java-json-tools", name: "json-schema-validator", version: "2.2.8");
+ compile(group: "com.github.java-json-tools", name: "json-schema-validator", version: "2.2.10");
}
```
@@ -67,7 +67,7 @@ Maven:
com.github.java-json-tools
json-schema-validator
- 2.2.8
+ 2.2.10
```
From 4bf148aa2463270483cb19d4d3d6360fc9ccaa1c Mon Sep 17 00:00:00 2001
From: John Huffaker
Date: Tue, 22 May 2018 17:05:02 -0700
Subject: [PATCH 31/71] Update README.md
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 83fd13c79..fa5c60ed9 100644
--- a/README.md
+++ b/README.md
@@ -33,7 +33,7 @@ timely manner.
## Testing online
You can [test this library online](http://json-schema-validator.herokuapp.com); this web site is in
-a [project of its own](https://github.com/java-json-tools/json-schema-validator-demo), which you can fork and
+a [project of its own](https://github.com/fge/json-schema-validator-demo), which you can fork and
run by yourself.
## Versions
From 35aae670774fe201c2fa73c8d040f62251c1fc46 Mon Sep 17 00:00:00 2001
From: Nathan Herring
Date: Mon, 22 Apr 2019 16:26:24 +0200
Subject: [PATCH 32/71] Update to Gradle 5.6.1.
---
build.gradle | 6 +-
gradle/wrapper/gradle-wrapper.jar | Bin 51106 -> 55616 bytes
gradle/wrapper/gradle-wrapper.properties | 3 +-
gradlew | 98 ++++++++++++++---------
gradlew.bat | 30 ++++---
5 files changed, 85 insertions(+), 52 deletions(-)
diff --git a/build.gradle b/build.gradle
index 46fbe230e..757585494 100644
--- a/build.gradle
+++ b/build.gradle
@@ -142,8 +142,8 @@ artifacts {
archives libJar;
}
-task wrapper(type: Wrapper) {
- gradleVersion = "3.5";
+wrapper {
+ gradleVersion = "5.6.1";
distributionUrl = "http://services.gradle.org/distributions/gradle-${gradleVersion}-all.zip";
}
@@ -172,7 +172,7 @@ task checkSigningRequirements {
requiredProperties.each {
if (project.properties[it] == null) {
noDice = true;
- System.err.printf("property \"%s\" is not defined!", it);
+ System.err.printf("property \"%s\" is not defined!\n", it);
}
}
if (noDice)
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index 3c7abdf12790879c06b07176de29647f77aa4129..5c2d1cf016b3885f6930543d57b744ea8c220a1a 100644
GIT binary patch
literal 55616
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