Diese Bibliothek befindet sich derzeit im Wartungsmodus und wird durch erosb/json-sKema ersetzt.
In diesem Repository werden keine neuen Funktionen angezeigt. Es bietet solide Unterstützung für die Versionen Draft-04, Draft-06 und Draft-07 der JSON-Schema-Spezifikation.
Der neueste Entwurf 2020-12 wird nur von erosb/json-sKema unterstützt.
Dieses Projekt ist eine Implementierung der JSON-Schema-Spezifikationen Draft v4, Draft v6 und Draft v7. Es verwendet die org.json-API (erstellt von Douglas Crockford) zur Darstellung von JSON-Daten.
Nehmen wir an, Sie wissen bereits, was ein JSON-Schema ist, und möchten es in einer Java-Anwendung zur Validierung von JSON-Daten verwenden. Aber – wie Sie vielleicht schon herausgefunden haben – gibt es auch eine andere Java-Implementierung der JSON-Schema-Spezifikation. Hier sind einige Ratschläge, welches Sie verwenden sollten:
Fügen Sie Ihrer pom.xml
die folgende Abhängigkeit hinzu:
< dependency >
< groupId >com.github.erosb</ groupId >
< artifactId >everit-json-schema</ artifactId >
< version >1.14.4</ version >
</ dependency >
Hinweis zu älteren Versionen : Versionen zwischen 1.6.0
und 1.9.1
können nur auf JitPack mit com.github.everit-org.json-schema:org.everit.json.schema
-Koordinaten gefunden werden. Die Versionen 1.0.0
... 1.5.1
sind auf Maven Central unter den Koordinaten org.everit.json:org.everit.json.schema
verfügbar.
Es gab einige Versuche, die Bibliothek unter Java 6/7 zum Laufen zu bringen.
Ein Java6-Port der Version 1.9.2 wurde von @mindbender1 entwickelt und ist über Maven Central mit den folgenden Koordinaten zugänglich:
< dependency >
< groupId >com.github.erosb</ groupId >
< artifactId >everit-json-schema-jdk6</ artifactId >
< version >1.9.2</ version >
</ dependency >
Backports älterer Versionen:
com.doctusoft:json-schema-java7:1.4.1
zurückportiertcom.github.rdruilhe.json-schema:org.everit.json.schema:1.1.1
verfügbar import org . everit . json . schema . Schema ;
import org . everit . json . schema . loader . SchemaLoader ;
import org . json . JSONObject ;
import org . json . JSONTokener ;
// ...
try ( InputStream inputStream = getClass (). getResourceAsStream ( "/path/to/your/schema.json" )) {
JSONObject rawSchema = new JSONObject ( new JSONTokener ( inputStream ));
Schema schema = SchemaLoader . load ( rawSchema );
schema . validate ( new JSONObject ( "{ " hello " : " world " }" )); // throws a ValidationException if this object is invalid
}
JSON Schema verfügt derzeit über vier Hauptversionen: Draft 3, Draft 4, Draft 6 und Draft 7. Diese Bibliothek implementiert die drei neueren Versionen. Sie können hier und hier einen kurzen Blick auf die Unterschiede werfen. Da die beiden Versionen eine Reihe von Unterschieden aufweisen und Draft 6 nicht abwärtskompatibel mit Draft 4 ist, ist es gut zu wissen, welche Version Sie verwenden werden.
Der beste Weg, die JSON-Schema-Version anzugeben, die Sie verwenden möchten, besteht darin, die Meta-Schema-URL mit dem Schlüssel "$schema"
in das Dokumentstammverzeichnis aufzunehmen. Dies ist eine gängige Notation, die von der Bibliothek unterstützt wird, um zu bestimmen, welche Version verwendet werden soll.
Kurzreferenz:
"$schema": "http://json-schema.org/draft-04/schema"
vorhanden ist, wird Draft 4 verwendet"$schema": "http://json-schema.org/draft-06/schema"
vorhanden ist, wird Draft 6 verwendet"$schema": "http://json-schema.org/draft-07/schema"
vorhanden ist, wird Draft 7 verwendetWenn Sie die Meta-Schema-Version explizit angeben möchten, können Sie den Standard von Draft 4 auf Draft 6/7 ändern, indem Sie den Loader wie folgt konfigurieren:
SchemaLoader loader = SchemaLoader . builder ()
. schemaJson ( yourSchemaJSON )
. draftV6Support () // or draftV7Support()
. build ();
Schema schema = loader . load (). build ();
Ab Version 1.1.0
sammelt der Validator alle Schemaverstöße (anstatt sofort beim ersten Fehler zu scheitern). Jeder Fehler wird durch einen JSON-Zeiger gekennzeichnet, der vom Stamm des Dokuments auf den verletzenden Teil zeigt. Wenn mehr als eine Schemaverletzung erkannt wurde, wird eine ValidationException
für die häufigsten übergeordneten Elemente der Verletzung ausgelöst, und jede einzelne Verletzung kann mit der Methode ValidationException#getCausingExceptions()
abgerufen werden.
Um die oben genannten Konzepte zu veranschaulichen, sehen wir uns ein Beispiel an. Betrachten wir das folgende Schema:
{
"type" : " object " ,
"properties" : {
"rectangle" : { "$ref" : " #/definitions/Rectangle " }
},
"definitions" : {
"size" : {
"type" : " number " ,
"minimum" : 0
},
"Rectangle" : {
"type" : " object " ,
"properties" : {
"a" : { "$ref" : " #/definitions/size " },
"b" : { "$ref" : " #/definitions/size " }
}
}
}
}
Das folgende JSON-Dokument weist nur einen Verstoß gegen das Schema auf (da „a“ nicht negativ sein darf):
{
"rectangle" : {
"a" : -5 ,
"b" : 5
}
}
In diesem Fall zeigt die ausgelöste ValidationException
auf #/rectangle/a
und enthält keine Unterausnahmen:
try {
schema . validate ( rectangleSingleFailure );
} catch ( ValidationException e ) {
// prints #/rectangle/a: -5.0 is not higher or equal to 0
System . out . println ( e . getMessage ());
}
Um nun zu veranschaulichen, wie mit mehreren Verstößen umgegangen wird, betrachten wir das folgende JSON-Dokument, in dem sowohl die Eigenschaften „a“ als auch „b“ gegen das obige Schema verstoßen:
{
"rectangle" : {
"a" : -5 ,
"b" : " asd "
}
}
In diesem Fall zeigt die ausgelöste ValidationException
auf #/rectangle
und verfügt über zwei Unterausnahmen, die auf #/rectangle/a
und #/rectangle/b
zeigen:
try {
schema . validate ( rectangleMultipleFailures );
} catch ( ValidationException e ) {
System . out . println ( e . getMessage ());
e . getCausingExceptions (). stream ()
. map ( ValidationException :: getMessage )
. forEach ( System . out :: println );
}
Dadurch wird die folgende Ausgabe gedruckt:
#/rectangle: 2 schema violations found
#/rectangle/a: -5.0 is not higher or equal to 0
#/rectangle/b: expected type: Number, found: String
Seit Version 1.4.0
ist es möglich, die ValidationException
Instanzen als JSON-formatierte Fehlerberichte auszudrucken. Die Methode ValidationException#toJSON()
gibt eine JSONObject
-Instanz mit den folgenden Schlüsseln zurück:
"message"
: die programmiererfreundliche Ausnahmemeldung (Beschreibung des Validierungsfehlers)"keyword"
: das JSON-Schema-Schlüsselwort, gegen das verstoßen wurde"pointerToViolation"
: ein JSON-Zeiger, der den Pfad vom Stamm des Eingabedokuments zu seinem Fragment angibt, das den Validierungsfehler verursacht hat"schemaLocation"
: ein JSON-Zeiger, der den Pfad vom Schema-JSON-Stamm zum verletzten Schlüsselwort angibt"causingExceptions"
: ein (möglicherweise leeres) Array von Unterausnahmen. Jede Unterausnahme wird als JSON-Objekt mit derselben Struktur wie in dieser Auflistung beschrieben dargestellt. Weitere Informationen zum Auslösen von Ausnahmen finden Sie oben. Bitte berücksichtigen Sie, dass es sich bei dem vollständigen Fehlerbericht um eine hierarchische Baumstruktur handelt: Unterursachen einer Ursache können mit #getCausingExceptions()
abgerufen werden.
ValidationListener
s können dazu dienen, Unklarheiten darüber aufzulösen, wie eine JSON-Instanz mit einem Schema übereinstimmt (oder nicht übereinstimmt). Sie können eine ValidationListener
Implementierung an den Validator anhängen, um Ereignisbenachrichtigungen über zwischenzeitliche Erfolgs-/Fehlerergebnisse zu erhalten.
Beispiel:
import org . everit . json . schema . Validator ;
...
Validator validator = Validator . builder ()
. withListener ( new YourValidationListenerImplementation ())
. build ();
validator . performValidation ( schema , input );
Die aktuell unterstützten Veranstaltungen:
"$ref"
-Referenz wird aufgelöst"allOf"
/ "anyOf"
/ "oneOf"
"allOf"
/ "anyOf"
/ "oneOf"
stimmt nicht überein"if"
-Schemaabgleich"if"
-Schema, das nicht übereinstimmt"then"
-Schema-Matching"then"
-Schema, das nicht übereinstimmt"else"
-Schema-Matching"else"
-Schema stimmt nicht überein Weitere Einzelheiten finden Sie im Javadoc der Schnittstelle org.everit.json.schema.event.ValidationListener
. Die jeweiligen Ereignisklassen verfügen außerdem über die richtigen #toJSON()
und #toString()
Implementierungen, sodass Sie sie in einem leicht zu analysierenden Format drucken können.
Standardmäßig werden Validierungsfehler im Sammelmodus gemeldet (siehe Kapitel „Fehler untersuchen“). Das ist praktisch, um einen detaillierten Fehlerbericht zu erhalten. Unter bestimmten Umständen ist es jedoch sinnvoller, die Validierung zu stoppen, wenn ein Fehler gefunden wird, ohne den Rest des JSON-Dokuments zu überprüfen. Um diesen schnell fehlschlagenden Validierungsmodus umzuschalten
Validator
-Instanz für Ihr Schema erstellen, anstatt Schema#validate(input)
aufzurufen.failEarly()
Methode von ValidatorBuilder
aufrufenBeispiel:
import org . everit . json . schema . Validator ;
...
Validator validator = Validator . builder ()
. failEarly ()
. build ();
validator . performValidation ( schema , input );
Hinweis: Die Validator
-Klasse ist unveränderlich und Thread-sicher, Sie müssen also nicht für jede Validierung eine neue Klasse erstellen, es reicht aus, sie nur einmal zu konfigurieren.
In einigen Fällen ist es bei der Validierung von Zahlen oder booleschen Werten sinnvoll, als solche Grundelemente analysierbare Zeichenfolgenwerte zu akzeptieren, da bei jeder nachfolgenden Verarbeitung diese Literale auch automatisch in die richtigen numerischen und logischen Werte geparst werden. Außerdem lässt sich die Konvertierung von Nicht-String-Primitiven in Strings problemlos durchführen. Warum also nicht JSON-Primitive als Strings zulassen?
Nehmen wir zum Beispiel dieses Schema:
{
"properties" : {
"booleanProp" : {
"type" : " boolean "
},
"integerProp" : {
"type" : " integer "
},
"nullProp" : {
"type" : " null "
},
"numberProp" : {
"type" : " number "
},
"stringProp" : {
"type" : " string "
}
}
}
Die Validierung des folgenden JSON-Dokuments schlägt fehl, obwohl alle Zeichenfolgen problemlos in geeignete Werte konvertiert werden könnten:
{
"numberProp" : " 12.34 " ,
"integerProp" : " 12 " ,
"booleanProp" : " true " ,
"nullProp" : " null " ,
"stringProp" : 12.34
}
Wenn Sie in diesem Fall möchten, dass die obige Instanz die Validierung anhand des Schemas besteht, müssen Sie die aktivierte Konfiguration der milden primitiven Validierung verwenden. Beispiel:
import org . everit . json . schema .*;
...
Validator validator = Validator . builder ()
. primitiveValidationStrategry ( PrimitiveValidationStrategy . LENIENT )
. build ();
validator . performValidation ( schema , input );
Hinweis: Im milden Parsing-Modus werden alle 22 möglichen booleschen Literale als logische Werte akzeptiert.
Die JSON-Schema-Spezifikation definiert das Schlüsselwort „default“ zur Bezeichnung von Standardwerten, gibt jedoch nicht explizit an, wie es sich auf den Validierungsprozess auswirken soll. Standardmäßig legt diese Bibliothek die Standardwerte nicht fest. Wenn Sie diese Funktion jedoch benötigen, können Sie sie vor dem Laden des Schemas mit der Methode SchemaLoaderBuilder#useDefaults(boolean)
aktivieren:
{
"properties" : {
"prop" : {
"type" : " number " ,
"default" : 1
}
}
}
JSONObject input = new JSONObject ( "{}" );
System . out . println ( input . get ( "prop" )); // prints null
Schema schema = SchemaLoader . builder ()
. useDefaults ( true )
. schemaJson ( rawSchema )
. build ()
. load (). build ();
schema . validate ( input );
System . out . println ( input . get ( "prop" )); // prints 1
Wenn in input
einige Eigenschaften fehlen, die im Schema "default"
-Werte haben, werden diese vom Validator während der Validierung festgelegt.
Zur Unterstützung des Schlüsselworts "regex"
des JSON-Schemas bietet die Bibliothek zwei mögliche Implementierungen:
java.util.regex
Obwohl die RE2J-Bibliothek eine deutlich bessere Leistung als java.util.regex
bietet, ist sie nicht vollständig mit der von java.util
oder ECMA 262 unterstützten Syntax kompatibel. Daher wird RE2J empfohlen, wenn Sie Bedenken hinsichtlich der Leistung haben und die Einschränkungen akzeptabel sind.
Die RE2J-Implementierung kann mit dem Aufruf SchemaLoaderBuilder#regexpFactory()
aktiviert werden:
SchemaLoader loader = SchemaLoader . builder ()
. regexpFactory ( new RE2JRegexpFactory ())
// ...
. build ();
Hinweise:
pom.xml
auszuschließen, damit die Größe Ihres Artefakts nicht unnötig vergrößert wirdjava.util
Implementierung verwendet, in 1.8.0 wurde die RE2J-Implementierung verwendet und in 1.9.0 haben wir sie aufgrund einiger gemeldeter Regressionen konfigurierbar gemacht. Die Bibliothek unterstützt die Schlüsselwörter readOnly
und writeOnly
die erstmals in Draft 7 auftauchten. Wenn Sie diese Funktion nutzen möchten, müssen Sie dem Validator vor der Validierung mitteilen, ob die Validierung im Lese- oder Schreibkontext erfolgt. Beispiel:
schema.json:
{
"properties" : {
"id" : {
"type" : " number " ,
"readOnly" : true
}
}
}
Validierungscode-Snippet:
Validator validator = Validator . builder ()
. readWriteContext ( ReadWriteContext . WRITE )
. build ();
validator . performValidation ( schema , new JSONObject ( "{ " id " :42}" ));
In diesem Fall haben wir dem Validator mitgeteilt, dass die Validierung im WRITE
Kontext erfolgt und im Eingabe-JSON-Objekt die Eigenschaft "id"
erscheint, die im Schema als "readOnly"
markiert ist, daher wird dieser Aufruf eine ValidationException
auslösen.
Ab Version 1.2.0
unterstützt die Bibliothek das Schlüsselwort "format"
(das ein optionaler Teil der Spezifikation ist).
Die unterstützten Formate variieren je nach der von Ihnen verwendeten Schemaspezifikationsversion (da die Standardformate in verschiedenen Versionen der Validierungsspezifikation eingeführt wurden).
Hier ist eine Kompatibilitätstabelle der unterstützten Standardformate:
Entwurf 4 | Entwurf 6 | Entwurf 7 | |
---|---|---|---|
Datum-Uhrzeit | ✅ | ✅ | ✅ |
✅ | ✅ | ✅ | |
Hostname | ✅ | ✅ | ✅ |
IPv4 | ✅ | ✅ | ✅ |
IPv6 | ✅ | ✅ | ✅ |
uri | ✅ | ✅ | ✅ |
uri-Referenz | ✅ | ✅ | |
uri-vorlage | ✅ | ✅ | |
JSON-Zeiger | ✅ | ✅ | |
Datum | ✅ | ||
Zeit | ✅ | ||
Regex | ✅ | ||
relativer-JSON-Zeiger | ✅ |
Die Bibliothek unterstützt auch das Hinzufügen benutzerdefinierter Formatvalidatoren. Um einen benutzerdefinierten Validator zu verwenden, müssen Sie grundsätzlich Folgendes tun
org.everit.json.schema.FormatValidator
implementiertorg.everit.json.schema.loader.SchemaLoader.SchemaLoaderBuilder
-Instanz, bevor Sie das eigentliche Schema ladenNehmen wir an, die Aufgabe besteht darin, einen benutzerdefinierten Validator zu erstellen, der Zeichenfolgen mit einer geraden Anzahl von Zeichen akzeptiert.
Der benutzerdefinierte FormatValidator
sieht etwa so aus:
public class EvenCharNumValidator implements FormatValidator {
@ Override
public Optional < String > validate ( final String subject ) {
if ( subject . length () % 2 == 0 ) {
return Optional . empty ();
} else {
return Optional . of ( String . format ( "the length of string [%s] is odd" , subject ));
}
}
}
Um den EvenCharNumValidator
an einen "format"
-Wert zu binden (z. B. "evenlength"
), müssen Sie eine Validatorinstanz an das Schlüsselwort in der Schema-Loader-Konfiguration binden:
JSONObject rawSchema = new JSONObject ( new JSONTokener ( inputStream ));
SchemaLoader schemaLoader = SchemaLoader . builder ()
. schemaJson ( rawSchema ) // rawSchema is the JSON representation of the schema utilizing the "evenlength" non-standard format
. addFormatValidator ( "evenlength" , new EvenCharNumValidator ()) // the EvenCharNumValidator gets bound to the "evenlength" keyword
. build ();
Schema schema = schemaLoader . load (). build (); // the schema is created using the above created configuration
schema . validate ( jsonDocument ); // the document validation happens here
In einem JSON-Schemadokument ist es möglich, relative URIs zu verwenden, um auf zuvor definierte Typen zu verweisen. Solche Referenzen werden mit den Schlüsselwörtern "$ref"
und "$id"
ausgedrückt. Während die Spezifikation die Änderung des Auflösungsbereichs und die Dereferenzierung im Detail beschreibt, erklärt sie nicht das erwartete Verhalten, wenn das erste auftretende "$ref"
oder "$id"
ein relativer URI ist.
Bei dieser Implementierung ist es möglich, mithilfe der entsprechenden Builder-Methode explizit einen absoluten URI zu definieren, der als Basis-URI (Auflösungsbereich) dient:
SchemaLoader schemaLoader = SchemaLoader . builder ()
. schemaJson ( jsonSchema )
. resolutionScope ( "http://example.org/" ) // setting the default resolution scope
. build ();
Wenn Ihre Schemata wachsen, möchten Sie diese in mehrere Quelldateien aufteilen und diese mit "$ref"
-Referenzen verbinden. Wenn Sie die Schemata im Klassenpfad speichern möchten (anstatt sie beispielsweise über HTTP bereitzustellen), empfiehlt es sich, das Protokoll classpath:
zu verwenden, damit die Schemata aufeinander verweisen. Damit das Protokoll „ classpath:
“ funktioniert:
SchemaClient
der Bibliothek verwenden, Beispiel: SchemaLoader schemaLoader = SchemaLoader . builder ()
. schemaClient ( SchemaClient . classPathAwareClient ())
. schemaJson ( jsonSchema )
. resolutionScope ( "classpath://my/schemas/directory/" ) // setting the default resolution scope
. build ();
Bei dieser Konfiguration werden die folgenden Referenzen in jsonSchema
ordnungsgemäß aufgelöst:
{
"properties" : {
"sameDir" : { "$ref" : " sameDirSchema.json " },
"absPath" : { "$ref" : " classpath://somewhere/else/otherschema.json " },
"httpPath" : { "$ref" : " http://example.org/http-works-as-usual " },
}
}
und sameDirSchema.json
wird in /my/schemas/directory/sameDirSchema.json
im Klassenpfad gesucht.
Manchmal ist es nützlich, mit vorinstallierten Schemata zu arbeiten, denen wir einen beliebigen URI (vielleicht eine UUID) zuweisen, anstatt das Schema über eine URL zu laden. Dies kann durch Zuweisen der Schemas zu einem URI mit der Methode #registerSchemaByURI()
des Schema-Loaders erfolgen. Beispiel:
SchemaLoader schemaLoader = SchemaLoader . builder ()
. registerSchemaByURI ( new URI ( "urn:uuid:a773c7a2-1a13-4f6a-a70d-694befe0ce63" ), aJSONObject )
. registerSchemaByURI ( new URI ( "http://example.org" ), otherJSONObject )
. schemaJson ( jsonSchema )
. resolutionScope ( "classpath://my/schemas/directory/" )
. build ();
Hinweise:
JSONObject
oder ein Boolean
sein (der formale Parametertyp ist nur Object
, da diese beiden keine andere gemeinsame Oberklasse haben).SchemaClient
Implementierung auch funktioniert, oder Sie können sogar die erweiterbare Protokollbehandlung des java.net
-Pakets nutzen). Einige der Abhängigkeiten können aus der Bibliothek ausgeschlossen werden und sie bleibt mit einigen Einschränkungen weiterhin verwendbar:
com.damnhandy:handy-uri-templates
ausschließen, sollte Ihr Schema nicht das Format "uri-template"
verwendencommons-validator:commons-validator
Abhängigkeit ausschließen, sollte Ihr Schema nicht die folgenden Formate verwenden: "email"
, "ipv4"
, "ipv6"
, "hostname"
Nach Bibliotheksversion:
Das generierte Javadoc der Versionen 1.0.0 – 1.5.1 ist unter javadoc.io verfügbar
Für die Versionen dazwischen (1.6.0 – 1.9.1) wird es nirgendwo veröffentlicht.