java 56 lines · 8 steps

Validating JSON payloads against a schema in Java

A reusable validator loads a JSON Schema once, then reports every violation as a flat list of readable messages.

Explained by highlit
1package com.example.validation;
2 
3import java.util.List;
4import java.util.stream.Collectors;
5 
6import org.everit.json.schema.Schema;
7import org.everit.json.schema.ValidationException;
8import org.everit.json.schema.loader.SchemaLoader;
9import org.json.JSONObject;
10import org.json.JSONTokener;
11 
12public class PayloadValidator {
13 
14 private final Schema schema;
15 
16 public PayloadValidator(String schemaResourcePath) {
17 try (var stream = getClass().getResourceAsStream(schemaResourcePath)) {
18 if (stream == null) {
19 throw new IllegalStateException("Schema not found: " + schemaResourcePath);
20 }
21 JSONObject rawSchema = new JSONObject(new JSONTokener(stream));
22 this.schema = SchemaLoader.builder()
23 .schemaJson(rawSchema)
24 .draftV7Support()
25 .build()
26 .load()
27 .build();
28 } catch (Exception e) {
29 throw new IllegalStateException("Failed to load schema", e);
30 }
31 }
32 
33 public List<String> validate(String json) {
34 JSONObject payload;
35 try {
36 payload = new JSONObject(new JSONTokener(json));
37 } catch (org.json.JSONException e) {
38 return List.of("Malformed JSON: " + e.getMessage());
39 }
40 try {
41 schema.validate(payload);
42 return List.of();
43 } catch (ValidationException e) {
44 return flatten(e);
45 }
46 }
47 
48 private List<String> flatten(ValidationException e) {
49 if (e.getCausingExceptions().isEmpty()) {
50 return List.of(e.getPointerToViolation() + ": " + e.getErrorMessage());
51 }
52 return e.getCausingExceptions().stream()
53 .flatMap(cause -> flatten(cause).stream())
54 .collect(Collectors.toList());
55 }
56}
01 / 01
STEP 01

Walkthrough

Space play ←→ step click any line
Three takeaways
  1. 1Compile expensive resources like schemas once in the constructor so each validation call stays cheap.
  2. 2Returning an empty-or-populated list of errors is friendlier to callers than throwing on the first failure.
  3. 3Recursively walking a nested exception's causes turns a tree of violations into one flat, actionable report.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Validating JSON payloads against a schema in Java — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code