이 라이브러리는 현재 유지 관리 모드에 있으며 erosb/json-sKema로 대체됩니다.
이 저장소에는 새로운 기능이 표시되지 않습니다. JSON 스키마 사양의 초안-04, 초안-06 및 초안-07 버전에 대한 견고한 지원을 제공합니다.
최신 초안 2020-12는 erosb/json-sKema에서만 지원됩니다.
이 프로젝트는 JSON Schema Draft v4, Draft v6 및 Draft v7 사양을 구현한 것입니다. JSON 데이터를 표현하기 위해 org.json API(Douglas Crockford가 생성)를 사용합니다.
JSON 스키마가 무엇인지 이미 알고 있고 이를 Java 애플리케이션에서 활용하여 JSON 데이터의 유효성을 검사한다고 가정해 보겠습니다. 그러나 이미 발견하셨겠지만 JSON 스키마 사양의 다른 Java 구현도 있습니다. 따라서 어떤 것을 사용해야 하는지에 대한 몇 가지 조언은 다음과 같습니다.
pom.xml
에 다음 종속성을 추가합니다.
< dependency >
< groupId >com.github.erosb</ groupId >
< artifactId >everit-json-schema</ artifactId >
< version >1.14.4</ version >
</ dependency >
이전 버전에 대한 참고 사항 : 1.6.0
에서 1.9.1
사이의 버전은 com.github.everit-org.json-schema:org.everit.json.schema
좌표가 있는 JitPack에서만 찾을 수 있습니다. 버전 1.0.0
... 1.5.1
Maven Central의 org.everit.json:org.everit.json.schema
좌표에서 사용할 수 있습니다.
Java 6/7에서 라이브러리가 작동하도록 만들려는 시도가 두 번 있었습니다.
버전 1.9.2의 java6 포트는 @mindbender1에 의해 개발되었으며 다음 좌표를 사용하여 Maven Central을 통해 액세스할 수 있습니다.
< dependency >
< groupId >com.github.erosb</ groupId >
< artifactId >everit-json-schema-jdk6</ artifactId >
< version >1.9.2</ version >
</ dependency >
이전 버전의 백포트:
com.doctusoft:json-schema-java7:1.4.1
좌표로 백포트되었습니다.com.github.rdruilhe.json-schema:org.everit.json.schema:1.1.1
로 사용할 수 있습니다. 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 스키마에는 현재 Draft 3, Draft 4, Draft 6 및 Draft 7의 4가지 주요 릴리스가 있습니다. 이 라이브러리는 3개의 최신 릴리스를 구현하며 여기와 여기에서 차이점을 빠르게 확인할 수 있습니다. 두 버전에는 많은 차이점이 있고, 초안 6은 초안 4와 하위 호환되지 않으므로 어떤 버전을 사용할지 아는 것이 좋습니다.
사용하려는 JSON 스키마 버전을 표시하는 가장 좋은 방법은 "$schema"
키를 사용하여 문서 루트에 메타스키마 URL을 포함하는 것입니다. 이는 라이브러리에서 사용해야 하는 버전을 결정하는 데 사용되는 일반적인 표기법입니다.
빠른 참조:
"$schema": "http://json-schema.org/draft-04/schema"
가 있는 경우 Draft 4가 사용됩니다."$schema": "http://json-schema.org/draft-06/schema"
가 있으면 Draft 6이 사용됩니다."$schema": "http://json-schema.org/draft-07/schema"
가 있으면 Draft 7이 사용됩니다.메타 스키마 버전을 명시적으로 지정하려면 다음과 같이 로더를 구성하여 기본값을 Draft 4에서 Draft 6/7로 변경할 수 있습니다.
SchemaLoader loader = SchemaLoader . builder ()
. schemaJson ( yourSchemaJSON )
. draftV6Support () // or draftV7Support()
. build ();
Schema schema = loader . load (). build ();
버전 1.1.0
부터 유효성 검사기는 모든 스키마 위반을 수집합니다(첫 번째 위반에서 즉시 실패하는 대신). 각 실패는 문서의 루트에서 위반 부분을 가리키는 JSON 포인터로 표시됩니다. 둘 이상의 스키마 위반이 감지되면 위반의 가장 일반적인 상위 요소에서 ValidationException
이 발생하며 ValidationException#getCausingExceptions()
메서드를 사용하여 각각의 개별 위반을 얻을 수 있습니다.
위의 개념을 설명하기 위해 예를 살펴보겠습니다. 다음 스키마를 고려해 보겠습니다.
{
"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 " }
}
}
}
}
다음 JSON 문서에는 스키마에 대한 위반이 하나만 있습니다("a"는 음수일 수 없으므로).
{
"rectangle" : {
"a" : -5 ,
"b" : 5
}
}
이 경우 던져진 ValidationException
은 #/rectangle/a
가리키며 하위 예외를 포함하지 않습니다.
try {
schema . validate ( rectangleSingleFailure );
} catch ( ValidationException e ) {
// prints #/rectangle/a: -5.0 is not higher or equal to 0
System . out . println ( e . getMessage ());
}
이제 여러 위반이 처리되는 방식을 설명하기 위해 "a" 및 "b" 속성이 모두 위의 스키마를 위반하는 다음 JSON 문서를 고려해 보겠습니다.
{
"rectangle" : {
"a" : -5 ,
"b" : " asd "
}
}
이 경우 던져진 ValidationException
#/rectangle
가리키며 #/rectangle/a
및 #/rectangle/b
가리키는 2개의 하위 예외가 있습니다.
try {
schema . validate ( rectangleMultipleFailures );
} catch ( ValidationException e ) {
System . out . println ( e . getMessage ());
e . getCausingExceptions (). stream ()
. map ( ValidationException :: getMessage )
. forEach ( System . out :: println );
}
그러면 다음과 같은 출력이 인쇄됩니다.
#/rectangle: 2 schema violations found
#/rectangle/a: -5.0 is not higher or equal to 0
#/rectangle/b: expected type: Number, found: String
버전 1.4.0
부터 ValidationException
인스턴스를 JSON 형식의 실패 보고서로 인쇄할 수 있습니다. ValidationException#toJSON()
메서드는 다음 키가 포함된 JSONObject
인스턴스를 반환합니다.
"message"
: 프로그래머에게 친숙한 예외 메시지(검증 실패에 대한 설명)"keyword"
: 위반된 JSON 스키마 키워드"pointerToViolation"
: 입력 문서 루트에서 유효성 검사 실패를 일으킨 조각까지의 경로를 나타내는 JSON 포인터"schemaLocation"
: 스키마 JSON 루트에서 위반된 키워드까지의 경로를 나타내는 JSON 포인터"causingExceptions"
: 하위 예외의 배열(비어 있을 수 있음)입니다. 각 하위 예외는 이 목록에 설명된 것과 동일한 구조를 가진 JSON 개체로 표시됩니다. 예외 발생에 대한 자세한 내용은 위를 참조하세요. 전체 실패 보고서는 계층적 트리 구조 라는 점을 고려하세요. 원인의 하위 원인은 #getCausingExceptions()
사용하여 얻을 수 있습니다.
ValidationListener
는 인스턴스 JSON이 스키마와 어떻게 일치하는지(또는 일치하지 않는지)에 대한 모호성을 해결하는 목적으로 사용할 수 있습니다. ValidationListener
구현을 유효성 검사기에 연결하여 중간 성공/실패 결과에 대한 이벤트 알림을 받을 수 있습니다.
예:
import org . everit . json . schema . Validator ;
...
Validator validator = Validator . builder ()
. withListener ( new YourValidationListenerImplementation ())
. build ();
validator . performValidation ( schema , input );
현재 지원되는 이벤트:
"$ref"
참조가 해결되는 중"allOf"
/ "anyOf"
/ "oneOf"
스키마 일치 아래의 하위 스키마"allOf"
/ "anyOf"
/ "oneOf"
스키마 아래의 하위 스키마가 일치하지 않습니다."if"
스키마 일치"if"
스키마"then"
스키마 일치"then"
스키마"else"
스키마 일치"else"
스키마 자세한 내용은 org.everit.json.schema.event.ValidationListener
인터페이스의 javadoc을 참조하세요. 특정 이벤트 클래스에는 적절한 #toJSON()
및 #toString()
구현도 있으므로 쉽게 구문 분석할 수 있는 형식으로 인쇄할 수 있습니다.
기본적으로 수집 모드에서 유효성 검사 오류가 보고됩니다("실패 조사" 장 참조). 이는 자세한 오류 보고서를 작성하는 데 편리하지만 일부 상황에서는 JSON 문서의 나머지 부분을 확인하지 않고 실패가 발견되면 유효성 검사를 중지하는 것이 더 적절합니다. 빠르게 실패하는 검증 모드를 전환하려면
Schema#validate(input)
호출하는 대신 스키마에 대한 Validator
인스턴스를 명시적으로 구축해야 합니다.ValidatorBuilder
의 failEarly()
메소드를 호출해야 합니다.예:
import org . everit . json . schema . Validator ;
...
Validator validator = Validator . builder ()
. failEarly ()
. build ();
validator . performValidation ( schema , input );
참고: Validator
클래스는 변경이 불가능하고 스레드로부터 안전하므로 각 검증마다 새 클래스를 생성할 필요가 없으며 한 번만 구성하면 충분합니다.
어떤 경우에는 숫자나 부울의 유효성을 검사할 때 이러한 기본 형식으로 구문 분석할 수 있는 문자열 값을 허용하는 것이 합리적입니다. 왜냐하면 연속 처리 시 이러한 리터럴을 자동으로 적절한 숫자 및 논리 값으로 구문 분석하기 때문입니다. 또한 문자열이 아닌 기본 값은 문자열로 변환하기가 쉽지 않으므로 json 기본 형식을 문자열로 허용하지 않는 이유는 무엇입니까?
예를 들어 다음 스키마를 살펴보겠습니다.
{
"properties" : {
"booleanProp" : {
"type" : " boolean "
},
"integerProp" : {
"type" : " integer "
},
"nullProp" : {
"type" : " null "
},
"numberProp" : {
"type" : " number "
},
"stringProp" : {
"type" : " string "
}
}
}
모든 문자열을 적절한 값으로 쉽게 변환할 수 있지만 다음 JSON 문서는 유효성 검사에 실패합니다.
{
"numberProp" : " 12.34 " ,
"integerProp" : " 12 " ,
"booleanProp" : " true " ,
"nullProp" : " null " ,
"stringProp" : 12.34
}
이 경우 위의 인스턴스가 스키마에 대한 유효성 검사를 통과하도록 하려면 관대한 기본 유효성 검사 구성을 활성화해야 합니다. 예:
import org . everit . json . schema .*;
...
Validator validator = Validator . builder ()
. primitiveValidationStrategry ( PrimitiveValidationStrategy . LENIENT )
. build ();
validator . performValidation ( schema , input );
참고: 관대한 구문 분석 모드에서는 가능한 22개의 모든 부울 리터럴이 논리 값으로 허용됩니다.
JSON 스키마 사양은 기본값을 표시하기 위한 "default" 키워드를 정의하지만 유효성 검사 프로세스에 어떤 영향을 미치는지 명시적으로 명시하지는 않습니다. 기본적으로 이 라이브러리는 기본값을 설정하지 않지만 이 기능이 필요한 경우 스키마를 로드하기 전에 SchemaLoaderBuilder#useDefaults(boolean)
메서드를 사용하여 설정할 수 있습니다.
{
"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
스키마에 "default"
값이 있는 input
에서 누락된 일부 속성이 있는 경우 유효성 검사 중에 유효성 검사기에 의해 설정됩니다.
JSON 스키마의 "regex"
키워드를 지원하기 위해 라이브러리는 두 가지 가능한 구현을 제공합니다.
java.util.regex
패키지를 기반으로 합니다. RE2J 라이브러리는 java.util.regex
보다 훨씬 더 나은 성능을 제공하지만 java.util
또는 ECMA 262에서 지원하는 구문과 완전히 호환되지는 않습니다. 따라서 성능이 염려되고 제한 사항이 허용되는 경우 RE2J를 권장합니다.
RE2J 구현은 SchemaLoaderBuilder#regexpFactory()
호출을 통해 활성화될 수 있습니다.
SchemaLoader loader = SchemaLoader . builder ()
. regexpFactory ( new RE2JRegexpFactory ())
// ...
. build ();
참고:
pom.xml
에서 제외하는 것이 좋습니다.java.util
구현이 사용되었고, 1.8.0에서는 RE2J 구현이 사용되었으며, 1.9.0에서는 보고된 일부 회귀로 인해 이를 구성 가능하게 만들었습니다. 라이브러리는 Draft 7에 처음 등장한 readOnly
및 writeOnly
키워드를 지원합니다. 이 기능을 활용하려면 검증 전에 검증이 읽기 또는 쓰기 컨텍스트에서 발생하는지 검증자에게 알려야 합니다. 예:
스키마.json:
{
"properties" : {
"id" : {
"type" : " number " ,
"readOnly" : true
}
}
}
확인 코드 조각:
Validator validator = Validator . builder ()
. readWriteContext ( ReadWriteContext . WRITE )
. build ();
validator . performValidation ( schema , new JSONObject ( "{ " id " :42}" ));
이 경우 유효성 검사기에 WRITE
컨텍스트에서 유효성 검사가 발생하고 입력 JSON 개체에 "id"
속성이 나타나며 스키마에서 "readOnly"
로 표시되므로 이 호출은 ValidationException
을 발생시킵니다.
버전 1.2.0
부터 라이브러리는 "format"
키워드(사양의 선택적 부분)를 지원합니다.
지원되는 형식은 사용하는 스키마 사양 버전에 따라 다릅니다(표준 형식은 유효성 검사 사양의 다른 버전에서 도입되었으므로).
지원되는 표준 형식의 호환성 표는 다음과 같습니다.
초안 4 | 초안 6 | 초안 7 | |
---|---|---|---|
날짜-시간 | ✅ | ✅ | ✅ |
이메일 | ✅ | ✅ | ✅ |
호스트 이름 | ✅ | ✅ | ✅ |
IPv4 | ✅ | ✅ | ✅ |
IPv6 | ✅ | ✅ | ✅ |
우리 | ✅ | ✅ | ✅ |
URI 참조 | ✅ | ✅ | |
uri 템플릿 | ✅ | ✅ | |
JSON 포인터 | ✅ | ✅ | |
날짜 | ✅ | ||
시간 | ✅ | ||
정규식 | ✅ | ||
상대 JSON 포인터 | ✅ |
라이브러리는 사용자 정의 형식 유효성 검사기 추가도 지원합니다. 사용자 정의 유효성 검사기를 사용하려면 기본적으로 다음을 수행해야 합니다.
org.everit.json.schema.FormatValidator
인터페이스를 구현하는 클래스에서 자체 유효성 검사를 만듭니다.org.everit.json.schema.loader.SchemaLoader.SchemaLoaderBuilder
인스턴스의 이름에 바인딩합니다.작업이 짝수 개의 문자가 포함된 문자열을 허용하는 사용자 정의 유효성 검사기를 만드는 것이라고 가정해 보겠습니다.
사용자 정의 FormatValidator
다음과 같습니다.
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 ));
}
}
}
EvenCharNumValidator
"format"
값(예: "evenlength"
)에 바인딩하려면 유효성 검사기 인스턴스를 스키마 로더 구성의 키워드에 바인딩해야 합니다.
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
JSON 스키마 문서에서는 상대 URI를 사용하여 이전에 정의된 유형을 참조할 수 있습니다. 이러한 참조는 "$ref"
및 "$id"
키워드를 사용하여 표현됩니다. 사양에서는 확인 범위 변경 및 역참조를 자세히 설명하지만 처음 나타나는 "$ref"
또는 "$id"
가 상대 URI일 때 예상되는 동작은 설명하지 않습니다.
이 구현의 경우 적절한 빌더 메서드를 사용하여 기본 URI(확인 범위) 역할을 하는 절대 URI를 명시적으로 정의하는 것이 가능합니다.
SchemaLoader schemaLoader = SchemaLoader . builder ()
. schemaJson ( jsonSchema )
. resolutionScope ( "http://example.org/" ) // setting the default resolution scope
. build ();
스키마가 커짐에 따라 이를 여러 소스 파일로 분할하고 "$ref"
참조로 연결하려고 할 것입니다. 스키마를 HTTP를 통해 제공하는 대신 클래스 경로에 저장하려는 경우 권장되는 방법은 classpath:
프로토콜을 사용하여 스키마가 서로 참조하도록 만드는 것입니다. classpath:
프로토콜을 작동시키려면:
SchemaClient
활용할 수 있습니다. 예: SchemaLoader schemaLoader = SchemaLoader . builder ()
. schemaClient ( SchemaClient . classPathAwareClient ())
. schemaJson ( jsonSchema )
. resolutionScope ( "classpath://my/schemas/directory/" ) // setting the default resolution scope
. build ();
이 구성을 사용하면 다음 참조가 jsonSchema
에서 올바르게 해결됩니다.
{
"properties" : {
"sameDir" : { "$ref" : " sameDirSchema.json " },
"absPath" : { "$ref" : " classpath://somewhere/else/otherschema.json " },
"httpPath" : { "$ref" : " http://example.org/http-works-as-usual " },
}
}
sameDirSchema.json
은 클래스 경로의 /my/schemas/directory/sameDirSchema.json
에서 검색됩니다.
때로는 URL을 통해 스키마를 로드하는 대신 임의의 URI(아마도 uuid)를 할당하는 미리 로드된 스키마로 작업하는 것이 유용합니다. 이는 스키마 로더의 #registerSchemaByURI()
메소드를 사용하여 스키마를 URI에 할당하여 수행할 수 있습니다. 예:
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 ();
참고:
JSONObject
또는 Boolean
이어야 합니다(이 두 객체에는 다른 공통 슈퍼클래스가 없기 때문에 형식 매개변수 유형은 Object
입니다).SchemaClient
구현을 정의하는 것도 가능하지만 java.net
패키지의 확장 가능한 프로토콜 처리를 활용할 수도 있음). 일부 종속성은 라이브러리에서 제외될 수 있으며 몇 가지 제한 사항이 있지만 계속 사용할 수 있습니다.
com.damnhandy:handy-uri-templates
종속성을 제외하는 경우 스키마는 "uri-template"
형식을 사용해서는 안 됩니다.commons-validator:commons-validator
종속성을 제외하는 경우 스키마는 "email"
, "ipv4"
, "ipv6"
, "hostname"
형식을 사용하면 안 됩니다. 라이브러리 버전별:
버전 1.0.0 - 1.5.1의 생성된 javadoc은 javadoc.io에서 사용할 수 있습니다.
(1.6.0 - 1.9.1) 사이 버전의 경우 어디에도 게시되지 않습니다.