A Java SDK for working with JSON Structure schemas, providing:
- Schema Validation: Validate JSON Structure schema documents for correctness
- Instance Validation: Validate JSON data against JSON Structure schemas
- Schema Export: Generate JSON Structure schemas from Java classes using Jackson type introspection
- Jackson Converters: Serializers/deserializers for extended numeric and temporal types
- Java 17 or later
- Maven 3.6 or later
Add to your pom.xml:
<dependency>
<groupId>org.json-structure</groupId>
<artifactId>json-structure</artifactId>
<version>${version}</version>
</dependency>Replace ${version} with the desired version number.
Validate that a JSON Structure schema is well-formed:
importorg.json_structure.validation.SchemaValidator;
importorg.json_structure.validation.ValidationResult;
SchemaValidatorvalidator = newSchemaValidator();
Stringschema = """ { "$schema": "https://json-structure.org/meta/core/v1.0", "type": "object", "properties": { "name": { "type": "string" }, "age": { "type": "int32" } }, "required": ["name"] } """;
ValidationResultresult = validator.validate(schema);
if (result.isValid()) {
System.out.println("Schema is valid!");
} else {
result.getErrors().forEach(e -> System.out.println(e.getMessage()));
}Validate JSON data against a schema:
importorg.json_structure.validation.InstanceValidator;
importorg.json_structure.validation.ValidationResult;
InstanceValidatorvalidator = newInstanceValidator();
Stringschema = """ { "type": "object", "properties": { "name": { "type": "string" }, "age": { "type": "int32", "minimum": 0 } }, "required": ["name"] } """;
Stringinstance = """ { "name": "Alice", "age": 30 } """;
ValidationResultresult = validator.validate(instance, schema);
System.out.println("Valid: " + result.isValid());Generate JSON Structure schemas from Java classes:
importorg.json_structure.schema.JsonStructureSchemaExporter;
importcom.fasterxml.jackson.databind.JsonNode;
importcom.fasterxml.jackson.databind.ObjectMapper;
publicclassPerson {
privateStringname;
privateintage;
privateLocalDatebirthDate;
// getters and setters
}
ObjectMappermapper = newObjectMapper();
JsonNodeschema = JsonStructureSchemaExporter.getSchemaAsNode(Person.class, mapper);
System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(schema));Output:
{
"$schema": "https://json-structure.org/meta/core/v1.0",
"type": "object",
"title": "Person",
"properties": {
"name": { "type": "string" },
"age": { "type": "int32" },
"birthDate": { "type": "date" }
},
"required": ["name", "age", "birthDate"]
}Register the JSON Structure module for extended type handling:
importorg.json_structure.converters.JsonStructureModule;
importcom.fasterxml.jackson.databind.ObjectMapper;
ObjectMappermapper = newObjectMapper();
mapper.registerModule(newJsonStructureModule());
// Supports extended numeric types like Int128, UInt128, Decimal, etc.The Java SDK can be used directly from other JVM languages without any wrapper code. The following examples demonstrate how to use the SDK from popular JVM languages.
Kotlin has 100% Java interoperability and is widely used for Android and backend development.
dependencies {
implementation("org.json-structure:json-structure:${version}")
}importorg.json_structure.validation.SchemaValidatorimportorg.json_structure.validation.ValidationResultfunmain() {
val validator =SchemaValidator()
val schema =""" { "type": "object", "properties": { "name": { "type": "string" }, "age": { "type": "int32" } }, "required": ["name"] }"""val result:ValidationResult= validator.validate(schema)
if (result.isValid()) {
println("Schema is valid!")
} else {
result.getErrors().forEach { error ->println(error.getMessage())
}
}
}importorg.json_structure.validation.InstanceValidatorimportorg.json_structure.validation.ValidationResultfunvalidateInstance() {
val validator =InstanceValidator()
val schema ="""{"type": "string"}"""val instance =""""Hello, World!""""val result:ValidationResult= validator.validate(instance, schema)
println("Valid: ${result.isValid()}")
}Idiomatic Notes:
- Use Kotlin's null safety features - the SDK returns non-null results
- Use
valfor immutable references (preferred in Kotlin) - Leverage Kotlin's string interpolation for output
- Consider using
applyorletfor more functional style
Scala provides full JVM interoperability and is popular in data engineering and functional programming.
libraryDependencies +="org.json-structure"%"json-structure"%"${version}"importorg.json_structure.validation.{SchemaValidator, ValidationResult}
importscala.jdk.CollectionConverters._objectSchemaValidationextendsApp {
valvalidator=newSchemaValidator()
valschema="""{ "type": "object", "properties": { "name": { "type": "string" }, "age": { "type": "int32" } }, "required": ["name"] }"""valresult:ValidationResult= validator.validate(schema)
if (result.isValid) {
println("Schema is valid!")
} else {
result.getErrors.asScala.foreach(error => println(error.getMessage))
}
}importorg.json_structure.validation.{InstanceValidator, ValidationResult}
objectInstanceValidationextendsApp {
valvalidator=newInstanceValidator()
valschema="""{"type": "string"}"""valinstance=""""Hello, Scala!""""valresult:ValidationResult= validator.validate(instance, schema)
println(s"Valid: ${result.isValid}")
}Idiomatic Notes:
- Use
scala.jdk.CollectionConverters._to convert Java collections to Scala collections - Consider wrapping results in
Optionfor functional error handling - Use Scala's pattern matching for result processing
- Leverage Scala's immutable collections when working with validation errors
Groovy is a dynamic JVM language used extensively in Gradle and scripting.
dependencies {
implementation 'org.json-structure:json-structure:${version}'
}importorg.json_structure.validation.SchemaValidatorimportorg.json_structure.validation.ValidationResultdef validator =newSchemaValidator()
def schema ='''{ "type": "object", "properties": { "name": { "type": "string" }, "age": { "type": "int32" } }, "required": ["name"]}'''ValidationResult result = validator.validate(schema)
if (result.isValid()) {
println"Schema is valid!"
} else {
result.getErrors().each { error->println error.getMessage()
}
}importorg.json_structure.validation.InstanceValidatorimportorg.json_structure.validation.ValidationResultdef validator =newInstanceValidator()
def schema ='{"type": "string"}'def instance ='"Hello, Groovy!"'ValidationResult result = validator.validate(instance, schema)
println"Valid: ${result.isValid()}"Idiomatic Notes:
- Groovy allows omitting parentheses in many cases for cleaner syntax
- Use GStrings (double quotes) for string interpolation
- Collections can be accessed with simplified syntax (
.eachinstead of.forEach) - Type declarations are optional but can improve clarity
Clojure is a functional Lisp dialect on the JVM with direct Java interoperability.
:dependencies [[org.json-structure/json-structure "${version}"]](nsmyapp.validation
(:import [org.json_structure.validation SchemaValidator ValidationResult]))
(defnvalidate-schema []
(let [validator (SchemaValidator.)
schema "{\"type\": \"object\",\"properties\": {\"name\": {\"type\": \"string\"},\"age\": {\"type\": \"int32\"} },\"required\": [\"name\"]}"]
(let [result (.validate validator schema)]
(if (.isValid result)
(println"Schema is valid!")
(doseq [error (.getErrors result)]
(println (.getMessage error)))))))(nsmyapp.validation
(:import [org.json_structure.validation InstanceValidator ValidationResult]))
(defnvalidate-instance []
(let [validator (InstanceValidator.)
schema "{\"type\": \"string\"}"
instance "\"Hello, Clojure!\""]
(let [result (.validate validator instance schema)]
(println (str"Valid: " (.isValid result))))))Idiomatic Notes:
- Use
(ClassName.)syntax to create Java objects - Call Java methods with
(.methodName object args) - Java collections can be converted to Clojure sequences with
seq - Consider using
->or->>threading macros for cleaner data flow - Leverage Clojure's immutable data structures when processing results
boolean- Javaboolean/Booleanstring- JavaStringint8- Javabyte/Byteint16- Javashort/Shortint32- Javaint/Integerint64- Javalong/Longint128- JavaBigInteger(constrained)uint8- Javashort(0-255)uint16- Javaint(0-65535)uint32- Javalong(0-4294967295)uint64- JavaBigInteger(0-18446744073709551615)uint128- JavaBigInteger(constrained)float- Javafloat/Float(single-precision 32-bit)double- Javadouble/Double(double-precision 64-bit)decimal- JavaBigDecimal
date- JavaLocalDatetime- JavaLocalTimedatetime- JavaOffsetDateTimeorInstantduration- JavaDuration
uuid- JavaUUIDuri- JavaURIbinary- Javabyte[](base64 encoded)
object- Java classes/recordsarray- JavaList<T>set- JavaSet<T>map- JavaMap<String, T>tuple- Ordered heterogeneous arrayschoice- Discriminated unions
importorg.json_structure.validation.ValidationOptions;
ValidationOptionsoptions = newValidationOptions()
.setStopOnFirstError(false) // Continue collecting all errors
.setMaxValidationDepth(100) // Maximum schema nesting depth
.setAllowDollar(true) // Allow $ in property names (for metaschemas)
.setAllowImport(true) // Enable $import/$importdefs processing
.setExternalSchemas(Map.of( // Sideloaded schemas for import resolution"https://example.com/address.json", addressSchema
));
SchemaValidatorvalidator = newSchemaValidator(options);When using $import to reference external schemas, you can provide those schemas
directly instead of fetching them from URIs:
importorg.json_structure.validation.SchemaValidator;
importorg.json_structure.validation.ValidationOptions;
importorg.json_structure.validation.ValidationResult;
importcom.fasterxml.jackson.databind.JsonNode;
importcom.fasterxml.jackson.databind.ObjectMapper;
importjava.util.Map;
ObjectMappermapper = newObjectMapper();
// External schema that would normally be fetchedJsonNodeaddressSchema = mapper.readTree(""" { "$schema": "https://json-structure.org/meta/core/v0/#", "$id": "https://example.com/address.json", "type": "object", "properties": { "street": { "type": "string" }, "city": { "type": "string" } } } """);
// Main schema that imports the address schemaJsonNodemainSchema = mapper.readTree(""" { "$schema": "https://json-structure.org/meta/core/v0/#", "type": "object", "properties": { "name": { "type": "string" }, "address": { "$ref": "#/definitions/Imported/Address" } }, "definitions": { "Imported": { "$import": "https://example.com/address.json" } } } """);
// Sideload the address schema - keyed by URIValidationOptionsoptions = newValidationOptions()
.setAllowImport(true)
.setExternalSchemas(Map.of(
"https://example.com/address.json", addressSchema
));
SchemaValidatorvalidator = newSchemaValidator(options);
ValidationResultresult = validator.validate(mainSchema);
System.out.println("Valid: " + result.isValid());mvn clean packagemvn testMIT License - see LICENSE file for details.