In the Previous Posts

So far, we covered JSON Schema fundamentals, schema declarations for validating JSON, schema composition, conditional schemas, and schema reuse. In this post, we implement a JSON Schema validator in Java.



Validator Library

There are many JSON Schema implementations. In Java ecosystem, json-schema-validator has high adoption. So this example uses that library for JSON validation.



Define JSON Schema

Let’s define a simple schema for this example. Refer to comments for each part. (JSON conceptually does not allow comments, but shown here for explanation.) If you need deeper schema rules, refer to previous posts.

Save as sample_schema.json directly under project resources.

{
  "type": "object", // top-level type is object
  "properties": { // has properties
    "contents": {
      "type": "array", // property `contents` is array
      "items": [ // item definitions
        {
          "type": "object", // object type
          "$ref": "#/definitions/photo" // follows `photo` definition
        },
        {
          "type": "object",
          "$ref": "#/definitions/photo"
        },
        {
          "type": "object",
          "$ref": "#/definitions/text" // follows `text` definition
        }
      ]
    }
  },
  "required": [ // `contents` is required
    "contents"
  ],
  "definitions": { // reusable type definitions
    "text": {
      "type": "object",
      "properties": {
        "id": {
          "type": "string"
        },
        "type": {
          "type": "string",
          "enum": [ "text" ]
        }
      },
      "required": [
        "id"
      ]
    },
    "photo": {
      "type": "object",
      "properties": {
        "id": {
          "type": "string"
        },
        "type": {
          "type": "string",
          "enum": [
            "photo", "video"
          ]
        },
        "title": {
          "type": "string"
        }
      },
      "required": [
        "id"
      ]
    }
  }
}


Write the Code

This example uses a Maven project, but the same approach works with Gradle.

Add Maven Dependency

Add dependency in pom.xml. Latest version in the original example is 2.2.13.

<dependency>
    <groupId>com.github.java-json-tools</groupId>
    <artifactId>json-schema-validator</artifactId>
    <version>2.2.13</version>
</dependency>


Read Schema File

This method reads schema file and joins lines into a single string. Exception-handling details are omitted.

private String getJsonSchemaFromFile() {
    try {
        Path path = Paths.get(ClassLoader.getSystemResource("sample_schema.json").toURI());
        return Files.readAllLines(path).stream().collect(Collectors.joining());
    } catch (IOException | URISyntaxException e) {
        // exception handling
    }
    return "";
}


JsonNode Conversion Methods

Most json-schema-validator APIs take jackson.databind.JsonNode. So we need conversion methods from String schema and target objects into JsonNode.

// Reuse mapper as instance field instead of recreating each time.
final ObjectMapper mapper = new ObjectMapper();

/**
 * Converts schema string to JsonNode.
 */
private JsonNode convertCardRuleToJsonNode(String cardRule) {
    try {
        return mapper.readTree(cardRule);
    } catch (Exception e) {
        // exception handling
    }
    return null;
}

/**
 * Converts object to JsonNode.
 */
private JsonNode convertObjToJsonNode(Object object) {
    try {
        return mapper.valueToTree(object);
    } catch (Exception e) {
        // exception handling
    }
    return null;
}

Define Class

You can prepare test JSON files directly, but here we define POJO and convert to JSON format via methods above. Declare class as abstraction for text and photo in schema.

class Content {
    private String id;
    private String title;
    private String type;

    public Content(String id, String title, String type) {
        this.id = id;
        this.title = title;
        this.type = type;
    }

    // getters/setters omitted
}

Then create test data method:

private HashMap<String, Object> getTestData() {
    List<Content> contents = List.of(
            new Content("1", "Title1", "text"),
            new Content("2", "Title2", "text"),
            new Content("3", "Title3", "text")
    );

    return new HashMap<>() {
        {
            put("contents", contents);
        }
    };
}

Validation Code

Now write validation logic. Library usage is relatively simple.

public void validate() {
    // create JsonNode from schema string
    JsonNode schemaNode = convertCardRuleToJsonNode(getJsonSchemaFromFile());

    // initialize validator factory
    JsonSchemaFactory factory = JsonSchemaFactory.byDefault();

    // validation result holder
    ProcessingReport report = null;
    try {
        // create schema object
        JsonSchema schema = factory.getJsonSchema(schemaNode);

        // convert test data to JsonNode
        JsonNode data = convertObjToJsonNode(getTestData());

        // validate
        report = schema.validate(data);
    } catch (Exception e) {
        // exception handling
    }
}

Check Validation Result

Validation returns ProcessingReport. You can check success via isSuccess. Since toString is overridden, printing report directly yields formatted messages like below.

com.github.fge.jsonschema.core.report.ListProcessingReport: failure
--- BEGIN MESSAGES ---
error: instance value ("text") not found in enum (possible values: ["photo","video"])
    level: "error"
    schema: {"loadingURI":"#","pointer":"/definitions/photo/properties/type"}
    instance: {"pointer":"/contents/0/type"}
    domain: "validation"
    keyword: "enum"
    value: "text"
    enum: ["photo","video"]
---  END MESSAGES  ---


Closing

We implemented JSON Schema validation in Java using json-schema-validator.

Usage is straightforward, but the library does not support every latest JSON Schema draft feature. For example, it may not recognize newer keywords such as const in some contexts. Current release plans for major updates appear limited.