Skip to content

Generating JSON Schema

Basics

After analyzing a type, extracting and modifying data, the JSON schema is created with two main steps: 1. generateJsonSchema: generates an independent JSON schema for each processed type. At this stage, the schemas may not be 100% valid JSON schemas. 2. compile[...]: this step takes the independent JSON Schemas created by the generateJsonSchema-step and merges them into one or multiple final valid schemas

class ExampleClass(
    val nested: NestedClass,
    val number: Int,
    val text: String?,
)
class NestedClass(
    val flag: Boolean
)

compileInlining() takes the independent JSON Schemas generated by generateJsonSchema and creates a single schema by simply inlining all referenced schemas.

initial<ExampleClass>()
    .analyzeTypeUsingReflection()
    .generateJsonSchema()
    .compileInlining()
    .json
Resulting Root JSON Schema:
{
   "type": "object",
   "required": [ "nested", "number" ],
   "properties": {
      "nested": {
         "type": "object",
         "required": [ "flag" ],
         "properties": {
            "flag": {
               "type": "boolean"
            }
         }
      },
      "number": {
         "type": "integer",
         "minimum": -2147483648,
         "maximum": 2147483647
      },
      "text": {
         "type": "string"
      }
   }
}

compileReferencing() takes the independent JSON Schemas generated by generateJsonSchema and only references them. Very simple schemas like primitives are still inlined.
Referenced schemas are returned in an extra property .compileReferencing().definitions.

initial<ExampleClass>()
    .analyzeTypeUsingReflection()
    .generateJsonSchema()
    .compileReferencing()
    .json
Resulting Root JSON Schema:
{
   "type": "object",
   "required": [ "nested", "number" ],
   "properties": {
      "nested": {
         "$ref": "#/definitions/examples.NestedClass"
      },
      "number": {
         "type": "integer",
         "minimum": -2147483648,
         "maximum": 2147483647
      },
      "text": {
         "type": "string"
      }
   }
}
Referenced JSON Schema (e.g. .compileReferencing().definitions["examples.NestedClass"]):
{
   "type": "object",
   "required": ["flag"],
   "properties": {
      "flag": {
         "type": "boolean"
      }
   }
}

compileReferencingRoot() behaves the same as compileReferencing(), but also references the root schema.
Referenced schemas are returned in an extra property .compileReferencing().definitions.

initial<ExampleClass>()
    .analyzeTypeUsingReflection()
    .generateJsonSchema()
    .compileReferencingRoot()
    .json
Resulting Root JSON Schema:
{
   "$ref": "#/definitions/examples.ExampleClass
}
Referenced JSON Schema (e.g. .compileReferencingRoot().definitions["examples.ExampleClass"]):
{
   "type": "object",
   "required": [
      "nested",
      "number"
   ],
   "properties": {
      "nested": {
         "$ref": "#/definitions/examples.NestedClass"
      },
      "number": {
         "type": "integer",
         "minimum": -2147483648,
         "maximum": 2147483647
      },
      "text": {
         "type": "string"
      }
   }
}

Configuration Options

API Reference for generateJsonSchema

Required Dependencies
implementation("io.github.smiley4:schema-kenerator-jsonschema:$version")
implementation 'io.github.smiley4:schema-kenerator-jsonschema:$version'
<dependency>
    <groupId>io.github.smiley4</groupId>
    <artifactId>schema-kenerator-jsonschema</artifactId>
    <version>${version}</version>
</dependency>

Reference Path Type

Schemas can be referenced using different paths or "ids" when using compileReferencing or compileReferencingRoot

  • RefType.FULL: uses the full qualified version of the type names, e.g. some.examples.MyClass<kotlin.Int>
  • RefType.SIMPLE: uses a shorter simple version of the type names, e.g. MyClass<Int>
Simple Path Type

initial<List<GenericClass<String>>>()
    .analyzeTypeUsingReflection()
    .generateJsonSchema()
    .compileReferencing(pathType = RefType.SIMPLE)
{
   "type": "array",
   "items": {
      "$ref": "#/definitions/GenericClass<String>"
   }
}

Required Dependencies
implementation("io.github.smiley4:schema-kenerator-jsonschema:$version")
implementation 'io.github.smiley4:schema-kenerator-jsonschema:$version'
<dependency>
    <groupId>io.github.smiley4</groupId>
    <artifactId>schema-kenerator-jsonschema</artifactId>
    <version>${version}</version>
</dependency>

Automatically Adding Titles

A "title" property can be automatically added to all types in the JSON Schema.

initial<List<GenericClass<String>>>()
    .analyzeTypeUsingReflection()
    .generateJsonSchema()
    .withTitle(type = TitleType.SIMPLE)
    .compileInlining()
{
   "title": "List<GenericClass<String>>",
   "type": "array",
   "items": {
      "title": "GenericClass<String>",
      "type": "object",
      "required": [ "value" ],
      "properties": {
         "value": {
            "title": "String",
            "type": "string"
         }
      }
   }
}

The type of the title can be configured:

  • TitleType.FULL: uses the full qualified version of the type names, e.g. some.examples.MyClass<kotlin.Int>
  • TitleType.SIMPLE: uses a shorter simple version of the type names, e.g. MyClass<Int>
Required Dependencies
implementation("io.github.smiley4:schema-kenerator-jsonschema:$version")
implementation 'io.github.smiley4:schema-kenerator-jsonschema:$version'
<dependency>
    <groupId>io.github.smiley4</groupId>
    <artifactId>schema-kenerator-jsonschema</artifactId>
    <version>${version}</version>
</dependency>

Schema-Kenerator Annotations

Additional properties of the JSON Schema can be filled with extra information from annotations, e.g. descriptions or default values. The handleCoreAnnotations()-step adds information from annotations from schema-kenerator-core to the schemas.

@Title("Annotated Class")
@Description("some description")
@Default("default value")
@Example("example 1")
@Deprecated
class CoreAnnotatedClass(
    @Description("String field description")
    @Default("A default String value")
    @Example("An example of a String value")
    val stringValue: String,
    @Description("Int field description")
    @Default("1111")
    @Example("2222")
    val intValue: Int,
)
initial<CoreAnnotatedClass>()
    .analyzeTypeUsingReflection()
    .generateJsonSchema()
    .handleCoreAnnotations()
    .compileInlining()
{
   "title": "Annotated Class",
   "description": "some description",
   "type": "object",
   "default": "default value",
   "deprecated": true,
   "examples": [ "example 1" ],
   "required": [ "intValue",  "stringValue" ],
   "properties": {
      "stringValue": {
         "type": "string",
         "description": "String field description",
         "default": "A default String value",
         "examples": [ "An example of a String value" ]
      },
      "intValue": {
         "type": "integer",
         "description": "Int field description",
         "minimum": -2147483648,
         "maximum": 2147483647,
         "default": "1111",
         "examples": [ "2222" ]
      }
   }
}

Required Dependencies

implementation("io.github.smiley4:schema-kenerator-core:$version")
implementation("io.github.smiley4:schema-kenerator-jsonschema:$version")

implementation 'io.github.smiley4:schema-kenerator-core:$version'
implementation 'io.github.smiley4:schema-kenerator-jsonschema:$version'

<dependency>
    <groupId>io.github.smiley4</groupId>
    <artifactId>schema-kenerator-core</artifactId>
    <version>${version}</version>
</dependency>
<dependency>
    <groupId>io.github.smiley4</groupId>
    <artifactId>schema-kenerator-jsonschema</artifactId>
    <version>${version}</version>
</dependency>

Jackson Annotations

Additional properties of the JSON Schema can be filled with extra information from annotations, e.g. descriptions or default values. The handleJacksonJsonSchemaAnnotations()-step adds information from Jackson annotations to the schemas.

class JacksonAnnotatedClass(
    @JsonPropertyDescription("Example description of the field")
    val value: String
)
initial<JacksonAnnotatedClass>()
    .analyzeTypeUsingReflection()
    .generateJsonSchema()
    .handleJacksonJsonSchemaAnnotations()
    .compileInlining()
{
   "type": "object",
   "required": [ "value" ],
   "properties": {
      "value": {
         "description": "Example description of the field"
         "type": "string",
      }
   }
}

Required Dependencies

implementation("io.github.smiley4:schema-kenerator-jackson-jsonschema:$version")
implementation("io.github.smiley4:schema-kenerator-jsonschema:$version")

implementation 'io.github.smiley4:schema-kenerator-jackson-jsonschema:$version'
implementation 'io.github.smiley4:schema-kenerator-jsonschema:$version'

<dependency>
    <groupId>io.github.smiley4</groupId>
    <artifactId>schema-kenerator-jackson-jsonschema</artifactId>
    <version>${version}</version>
</dependency>
<dependency>
    <groupId>io.github.smiley4</groupId>
    <artifactId>schema-kenerator-jsonschema</artifactId>
    <version>${version}</version>
</dependency>