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:
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:
- 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}"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:
- 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}'
}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:
- 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}"]](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:
- 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
import 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 packagemvn testMIT License - see LICENSE file for details.