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