JSON Structure is a data structure definition language that enforces strict typing, modularity, and determinism.
A Java SDK for working with JSON Structure schemas, providing:
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:
import org.json_structure.validation.SchemaValidator;
import org.json_structure.validation.ValidationResult;
SchemaValidator validator = new SchemaValidator();
String schema = """
{
"$schema": "https://json-structure.org/meta/core/v1.0",
"type": "object",
"properties": {
"name": { "type": "string" },
"age": { "type": "int32" }
},
"required": ["name"]
}
""";
ValidationResult result = 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:
import org.json_structure.validation.InstanceValidator;
import org.json_structure.validation.ValidationResult;
InstanceValidator validator = new InstanceValidator();
String schema = """
{
"type": "object",
"properties": {
"name": { "type": "string" },
"age": { "type": "int32", "minimum": 0 }
},
"required": ["name"]
}
""";
String instance = """
{
"name": "Alice",
"age": 30
}
""";
ValidationResult result = validator.validate(instance, schema);
System.out.println("Valid: " + result.isValid());
Generate JSON Structure schemas from Java classes:
import org.json_structure.schema.JsonStructureSchemaExporter;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
public class Person {
private String name;
private int age;
private LocalDate birthDate;
// getters and setters
}
ObjectMapper mapper = new ObjectMapper();
JsonNode schema = 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:
import org.json_structure.converters.JsonStructureModule;
import com.fasterxml.jackson.databind.ObjectMapper;
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JsonStructureModule());
// 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}")
}
import org.json_structure.validation.SchemaValidator
import org.json_structure.validation.ValidationResult
fun main() {
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())
}
}
}
import org.json_structure.validation.InstanceValidator
import org.json_structure.validation.ValidationResult
fun validateInstance() {
val validator = InstanceValidator()
val schema = """{"type": "string"}"""
val instance = """"Hello, World!""""
val result: ValidationResult = validator.validate(instance, schema)
println("Valid: ${result.isValid()}")
}
Idiomatic Notes:
val for immutable references (preferred in Kotlin)apply or let for more functional styleScala provides full JVM interoperability and is popular in data engineering and functional programming.
libraryDependencies += "org.json-structure" % "json-structure" % "${version}"
import org.json_structure.validation.{SchemaValidator, ValidationResult}
import scala.jdk.CollectionConverters._
object SchemaValidation extends App {
val validator = new 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.asScala.foreach(error => println(error.getMessage))
}
}
import org.json_structure.validation.{InstanceValidator, ValidationResult}
object InstanceValidation extends App {
val validator = new InstanceValidator()
val schema = """{"type": "string"}"""
val instance = """"Hello, Scala!""""
val result: ValidationResult = validator.validate(instance, schema)
println(s"Valid: ${result.isValid}")
}
Idiomatic Notes:
scala.jdk.CollectionConverters._ to convert Java collections to Scala collectionsOption for functional error handlingGroovy is a dynamic JVM language used extensively in Gradle and scripting.
dependencies {
implementation 'org.json-structure:json-structure:${version}'
}
import org.json_structure.validation.SchemaValidator
import org.json_structure.validation.ValidationResult
def validator = new SchemaValidator()
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()
}
}
import org.json_structure.validation.InstanceValidator
import org.json_structure.validation.ValidationResult
def validator = new InstanceValidator()
def schema = '{"type": "string"}'
def instance = '"Hello, Groovy!"'
ValidationResult result = validator.validate(instance, schema)
println "Valid: ${result.isValid()}"
Idiomatic Notes:
.each instead of .forEach)Clojure is a functional Lisp dialect on the JVM with direct Java interoperability.
:dependencies [[org.json-structure/json-structure "${version}"]]
(ns myapp.validation
(:import [org.json_structure.validation SchemaValidator ValidationResult]))
(defn validate-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)))))))
(ns myapp.validation
(:import [org.json_structure.validation InstanceValidator ValidationResult]))
(defn validate-instance []
(let [validator (InstanceValidator.)
schema "{\"type\": \"string\"}"
instance "\"Hello, Clojure!\""]
(let [result (.validate validator instance schema)]
(println (str "Valid: " (.isValid result))))))
Idiomatic Notes:
(ClassName.) syntax to create Java objects(.methodName object args)seq-> or ->> threading macros for cleaner data flowboolean - Java boolean/Booleanstring - Java Stringint8 - Java byte/Byteint16 - Java short/Shortint32 - Java int/Integerint64 - Java long/Longint128 - Java BigInteger (constrained)uint8 - Java short (0-255)uint16 - Java int (0-65535)uint32 - Java long (0-4294967295)uint64 - Java BigInteger (0-18446744073709551615)uint128 - Java BigInteger (constrained)float - Java float/Float (single-precision 32-bit)double - Java double/Double (double-precision 64-bit)decimal - Java BigDecimaldate - Java LocalDatetime - Java LocalTimedatetime - Java OffsetDateTime or Instantduration - Java Durationuuid - Java UUIDuri - Java URIbinary - Java byte[] (base64 encoded)object - Java classes/recordsarray - Java List<T>set - Java Set<T>map - Java Map<String, T>tuple - Ordered heterogeneous arrayschoice - Discriminated unionsimport org.json_structure.validation.ValidationOptions;
ValidationOptions options = new ValidationOptions()
.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
));
SchemaValidator validator = new SchemaValidator(options);
When using $import to reference external schemas, you can provide those schemas
directly instead of fetching them from URIs:
import org.json_structure.validation.SchemaValidator;
import org.json_structure.validation.ValidationOptions;
import org.json_structure.validation.ValidationResult;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Map;
ObjectMapper mapper = new ObjectMapper();
// External schema that would normally be fetched
JsonNode addressSchema = 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 schema
JsonNode mainSchema = 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 URI
ValidationOptions options = new ValidationOptions()
.setAllowImport(true)
.setExternalSchemas(Map.of(
"https://example.com/address.json", addressSchema
));
SchemaValidator validator = new SchemaValidator(options);
ValidationResult result = validator.validate(mainSchema);
System.out.println("Valid: " + result.isValid());
mvn clean package
mvn test
MIT License - see LICENSE file for details.