Most JSON Schema libraries in Java follow the same pattern:
- Validate a JSON string
- Or validate a JsonNode
- Or validate some library-specific tree model
Which makes sense — JSON Schema was designed for JSON documents.
But in real applications, we rarely live in JSON strings.
We live in Java objects.
So the usual flow looks like this:
POJO → serialize → JsonNode → validate
It works. It’s common.
But it’s not the only possible model.
A Slightly Different Mental Model
Instead of saying:
“JSON Schema validates JSON.”
We can say:
“JSON Schema validates structured data.”
That includes:
-
POJOs/JOJOs -
Map/List - primitive values
- any Java objects.
SJF4J treats these as first-class schema nodes via an Object-Based Node Tree model.
There is no mandatory JsonNode layer in between.
So this:
class Order {
public int id;
public String user;
}
Can be validated directly:
JsonSchema schema = JsonSchema.fromJson("""
{
"type": "object",
"required": ["id"],
"properties": {
"id": { "type": "integer" },
"user": { "format": "email" }
}
}
""");
schema.compile();
Order order = new Order();
order.id = 1;
order.user = "alice@example.com";
boolean valid = schema.isValid(order);
No serialization.
No JsonNode.
No adapter layer.
Just validate the object.
JSON Schema + JSR 380: Not Competitors
JSR 380 (Bean Validation) is excellent for core invariants:
class User {
@NotNull
@Email
String email;
}
But it’s:
- Annotation-driven
- Static
- Bound to compiled code
JSON Schema handles a different layer:
- Runtime-configurable validation
- Conditional logic (
if/then/else) - Structural policies
- Externalized contracts
With SJF4J, you can layer JSON Schema directly onto your domain model:
@ValidJsonSchema("""
{
"type": "object",
"required": ["id"],
"properties": {
"id": { "type": "integer" },
"user": { "format": "email" }
}
}
""")
public class Order {
public int id;
public String user;
}
And validate it without converting anything:
SchemaValidator validator = new SchemaValidator();
ValidationResult result = validator.validate(new Order());
In practice, the split becomes very clean:
- JSR 380 → domain invariants
- JSON Schema → runtime contracts & policies
They complement each other instead of overlapping.
Performance
In local bowtie runs against the official JSON Schema test suite:
- SJF4J performs roughly 2× faster than networknt’s validator
- Currently among the fastest Java JSON Schema validators in bowtie benchmarks
By validating native objects directly, SJF4J avoids:
- Serialization
- Re-parsing
- Intermediate tree construction
The simpler model isn’t slower.
In many cases, it’s measurably faster.
A Small Architectural Shift
Most JSON tooling in Java assumes:
JSON is primary. Objects are derived.
This flips that:
Structured data is primary. JSON is just a representation.
Once validation operates directly on native objects, a surprising amount of glue code disappears.
Not dramatically.
Not heroically.
Just quietly.
And after writing more adapter layers than I care to admit, I’ve learned to appreciate quiet improvements.
If you’re curious:
Top comments (0)